esc_html__('Tab 切换显示不同分类/排序的文章(懒加载)。', 'aksrt'), 'customize_selective_refresh' => true, ] ); } /** * @param mixed $tabs * @return list */ public static function normalize_tabs_static($tabs): array { if (is_string($tabs) && $tabs !== '') { $legacy_keys = array_map('trim', explode(',', $tabs)); $legacy_defs = [ 'latest' => ['title' => '最新', 'orderby' => 'date'], 'comments' => ['title' => '热评', 'orderby' => 'comments'], 'random' => ['title' => '随机', 'orderby' => 'rand'], 'views' => ['title' => '热门', 'orderby' => 'views'], ]; $result = []; foreach ($legacy_keys as $key) { if (isset($legacy_defs[$key])) { $result[] = [ 'title' => __($legacy_defs[$key]['title'], 'aksrt'), 'category_id' => 0, 'orderby' => $legacy_defs[$key]['orderby'], 'count' => 0, 'enabled' => true, ]; } elseif (is_numeric($key) && absint($key) > 0) { $term = get_term(absint($key), 'category'); $result[] = [ 'title' => ($term && !is_wp_error($term)) ? $term->name : '', 'category_id' => absint($key), 'orderby' => 'date', 'count' => 0, 'enabled' => true, ]; } } return $result; } if (is_array($tabs)) { $allowed = ['date', 'modified', 'views', 'likes', 'comments', 'favorites', 'downloads', 'rand']; $result = []; foreach ($tabs as $tab) { if (!is_array($tab)) { continue; } $orderby = sanitize_key($tab['orderby'] ?? 'date'); if (!in_array($orderby, $allowed, true)) { $orderby = 'date'; } $result[] = [ 'title' => sanitize_text_field((string) ($tab['title'] ?? '')), 'category_id' => absint($tab['category_id'] ?? 0), 'orderby' => $orderby, 'count' => max(0, min(20, (int) ($tab['count'] ?? 0))), 'enabled' => !empty($tab['enabled']), ]; } return $result; } return []; } private function normalize_tabs($tabs): array { return self::normalize_tabs_static($tabs); } /** * Build query for a tab → reuse main posts payload renderer. * * @param array $tab * @param int $default_count * @return array */ public static function tab_to_main_instance(array $tab, int $default_count, array $opts = []): array { $count = !empty($tab['count']) ? (int) $tab['count'] : $default_count; $style = sanitize_key((string) ($opts['style'] ?? $tab['style'] ?? 'mini')); if (!in_array($style, ['list', 'card', 'mini'], true)) { $style = 'mini'; } $paginate = sanitize_key((string) ($opts['paginate'] ?? $tab['paginate'] ?? 'none')); if (!in_array($paginate, ['none', 'ajax', 'number'], true)) { $paginate = 'none'; } return [ 'count' => max(1, min(30, $count)), 'orderby' => sanitize_key((string) ($tab['orderby'] ?? 'date')), 'cat' => absint($tab['category_id'] ?? 0), 'style' => $style, 'show_thumb' => !isset($opts['show_thumb']) ? 1 : (int) $opts['show_thumb'], 'show_meta' => !isset($opts['show_meta']) ? 1 : (int) $opts['show_meta'], 'show_number' => !empty($opts['show_number']) ? 1 : 0, 'paginate' => $paginate, ]; } /** * REST helper: render one tab list HTML. * * @param array $opts */ public static function render_tab_html(array $tab, int $default_count, array $opts = []): string { $payload = self::render_tab_payload($tab, $default_count, $opts, 1); return (string) ($payload['html'] ?? ''); } /** * Full tab payload (html + pager) for REST/ajax. * * @param array $opts * @return array{html:string,paginate_html:string,has_more:bool,page:int,max_pages:int,total:int} */ public static function render_tab_payload(array $tab, int $default_count, array $opts = [], int $page = 1): array { $inst = self::tab_to_main_instance($tab, $default_count, $opts); if (class_exists('\AKSRT\Widgets\WidgetMainPosts')) { return WidgetMainPosts::query_payload($inst, $page); } return [ 'html' => '', 'paginate_html' => '', 'has_more' => false, 'page' => 1, 'max_pages' => 1, 'total' => 0, ]; } /** Skeleton rows for lazy tab panels. */ public static function skeleton_html(int $count = 5, string $style = 'mini'): string { $count = max(1, min(12, $count)); ob_start(); echo '
'; for ($i = 0; $i < $count; $i++) { echo '
'; echo '
'; echo '
'; echo '
'; } echo '
'; return (string) ob_get_clean(); } public function widget($args, $instance): void { echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base); $count = absint($instance['count'] ?? 5); $style = sanitize_key((string) ($instance['style'] ?? 'mini')); if (!in_array($style, ['list', 'card', 'mini'], true)) { $style = 'mini'; } $paginate = sanitize_key((string) ($instance['paginate'] ?? 'none')); if (!in_array($paginate, ['none', 'ajax', 'number'], true)) { $paginate = 'none'; } $tabs = $this->normalize_tabs($instance['tabs'] ?? 'latest,comments,random'); $tabs = array_values(array_filter($tabs, static fn($t) => !empty($t['enabled']))); if (!$tabs) { if (current_user_can('manage_options')) { echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('请至少启用一个 Tab', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped : '

' . esc_html__('请至少启用一个 Tab', 'aksrt') . '

'; } echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped return; } if ($title !== '') { echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } $widget_id = $this->id; $rest = rest_url('aksrt/v1/widgets/tab-posts'); $use_shared = function_exists('aksrt_render_mini_list'); ?>
    $tab) : $tab_key = 'tab-' . $i; $tab_title = $tab['title'] !== '' ? $tab['title'] : sprintf(__('Tab %d', 'aksrt'), $i + 1); ?>
$tab) : $tab_key = 'tab-' . $i; ?>
> $style, 'paginate' => $paginate]; $payload = self::render_tab_payload($tab, $count, $opts, 1); $html = (string) ($payload['html'] ?? ''); if ($html !== '') { echo '
' . $html . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped if (!empty($payload['paginate_html'])) { echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } } else { echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('暂无文章', 'aksrt')) : '

' . esc_html__('暂无文章', 'aksrt') . '

'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } else : ?>
normalize_tabs($instance['tabs'] ?? 'latest,comments,random'); $orderby_options = [ 'date' => __('最新', 'aksrt'), 'modified' => __('更新', 'aksrt'), 'views' => __('浏览', 'aksrt'), 'likes' => __('点赞', 'aksrt'), 'comments' => __('评论', 'aksrt'), 'favorites' => __('收藏', 'aksrt'), 'downloads' => __('下载', 'aksrt'), 'rand' => __('随机', 'aksrt'), ]; ?>


'', 'category_id' => 0, 'orderby' => 'date', 'count' => 0, 'enabled' => false]; } foreach ($tabs as $i => $tab) : ?>

" value="" placeholder="">

" value="" placeholder="0">

" value="">

sanitize_text_field((string) ($new_instance['title'] ?? '')), 'count' => max(1, min(20, (int) ($new_instance['count'] ?? 5))), 'style' => $style, 'paginate' => $paginate, ]; $tabs = []; if (isset($new_instance['tabs']) && is_array($new_instance['tabs'])) { $allowed = ['date', 'modified', 'views', 'likes', 'comments', 'favorites', 'downloads', 'rand']; foreach ($new_instance['tabs'] as $tab) { if (!is_array($tab)) { continue; } $orderby = sanitize_key($tab['orderby'] ?? 'date'); if (!in_array($orderby, $allowed, true)) { $orderby = 'date'; } $tabs[] = [ 'title' => sanitize_text_field((string) ($tab['title'] ?? '')), 'category_id' => absint($tab['category_id'] ?? 0), 'orderby' => $orderby, 'count' => max(0, min(20, (int) ($tab['count'] ?? 0))), 'enabled' => !empty($tab['enabled']), ]; } } $result['tabs'] = !empty($tabs) ? $tabs : 'latest,comments,random'; return $result; } }