diff --git a/src/AKSRT/Forum/Forum.php b/src/AKSRT/Forum/Forum.php index f04561e8..1d9b8fae 100644 --- a/src/AKSRT/Forum/Forum.php +++ b/src/AKSRT/Forum/Forum.php @@ -252,6 +252,11 @@ class Forum { 'callback' => [$this, 'rest_widget_topics'], 'permission_callback' => '__return_true', ]); + register_rest_route('aksrt/v1', '/forum/frontend/widgets/plates', [ + 'methods' => 'GET', + 'callback' => [$this, 'rest_widget_plates'], + 'permission_callback' => '__return_true', + ]); } public function rest_widget_topics(\WP_REST_Request $request) { @@ -278,6 +283,24 @@ class Forum { ], 200); } + public function rest_widget_plates(\WP_REST_Request $request) { + if (!class_exists('\AKSRT\Widgets\WidgetForumPlateLists')) { + return new \WP_REST_Response(['success' => false, 'message' => 'widget unavailable'], 500); + } + $instance = [ + 'showposts' => max(1, min(30, (int) ($request->get_param('showposts') ?? $request->get_param('count') ?? 8))), + 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'menu_order')), + 'style' => sanitize_key((string) ($request->get_param('style') ?? 'default')), + 'filter' => sanitize_key((string) ($request->get_param('filter') ?? '')), + 'cat' => sanitize_text_field((string) ($request->get_param('cat') ?? '')), + ]; + $payload = \AKSRT\Widgets\WidgetForumPlateLists::query_payload($instance); + return new \WP_REST_Response([ + 'success' => true, + 'html' => (string) ($payload['html'] ?? ''), + ], 200); + } + public function render_board_cards(array $boards): void { diff --git a/src/AKSRT/Widgets/WidgetForumPlateLists.php b/src/AKSRT/Widgets/WidgetForumPlateLists.php index 0dbe1afd..89d0e256 100644 --- a/src/AKSRT/Widgets/WidgetForumPlateLists.php +++ b/src/AKSRT/Widgets/WidgetForumPlateLists.php @@ -1,6 +1,6 @@ esc_html__('展示论坛 plate 版块列表,支持排序与卡片样式。', 'aksrt'), + 'description' => esc_html__('展示论坛 plate 版块列表,支持排序/卡片/AJAX。', 'aksrt'), 'classname' => 'widget_aksrt_forum_plate_lists', ] ); } - public function widget($args, $instance): void { - if (!post_type_exists('aksrt_forum_plate')) { - return; - } - + /** + * @return array + */ + public static function build_query_args(array $instance): array { $limit = max(1, min(30, (int) ($instance['showposts'] ?? 8))); $orderby = sanitize_key((string) ($instance['orderby'] ?? 'menu_order')); - $style = sanitize_key((string) ($instance['style'] ?? 'default')); $filter = sanitize_key((string) ($instance['filter'] ?? '')); $cat_raw = (string) ($instance['cat'] ?? ''); $cat_ids = array_values(array_filter(array_map('intval', preg_split('/[\s,]+/', $cat_raw) ?: []))); @@ -39,6 +37,7 @@ class WidgetForumPlateLists extends \WP_Widget { 'post_status' => 'publish', 'posts_per_page' => $limit, 'order' => 'ASC', + 'no_found_rows' => true, ]; switch ($orderby) { @@ -81,8 +80,61 @@ class WidgetForumPlateLists extends \WP_Widget { ]]; } - $plates = get_posts($query_args); + return $query_args; + } + + public static function render_items_html(array $plates, string $style = 'default'): string { if (!$plates) { + return ''; + } + ob_start(); + $self = new self(); + if ($style === 'card') { + echo '
'; + foreach ($plates as $post) { + if ($post instanceof \WP_Post) { + $self->render_card($post); + } + } + echo '
'; + } else { + echo '
'; + foreach ($plates as $post) { + if ($post instanceof \WP_Post) { + $self->render_row($post); + } + } + echo '
'; + } + return (string) ob_get_clean(); + } + + /** + * @return array{html:string} + */ + public static function query_payload(array $instance): array { + if (!post_type_exists('aksrt_forum_plate')) { + return ['html' => '']; + } + $style = sanitize_key((string) ($instance['style'] ?? 'default')); + $plates = get_posts(self::build_query_args($instance)); + $html = self::render_items_html($plates ?: [], $style === 'card' ? 'card' : 'default'); + if ($html === '') { + $html = function_exists('aksrt_get_ajax_null') + ? aksrt_get_ajax_null(__('暂无版块', 'aksrt')) + : '

' . esc_html__('暂无版块', 'aksrt') . '

'; + } + return ['html' => $html]; + } + + public function widget($args, $instance): void { + if (!post_type_exists('aksrt_forum_plate')) { + return; + } + + $style = sanitize_key((string) ($instance['style'] ?? 'default')); + $payload = self::query_payload($instance); + if ($payload['html'] === '') { return; } @@ -92,24 +144,16 @@ class WidgetForumPlateLists extends \WP_Widget { echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } - if ($style === 'card') { - echo '
'; - foreach ($plates as $post) { - $this->render_card($post); - } - echo '
'; - } else { - echo '
'; - foreach ($plates as $post) { - $this->render_row($post); - } - echo '
'; - } + // IAS-like: first paint is SSR; optional remote refresh via rest for customize. + $rest = rest_url('aksrt/v1/forum/frontend/widgets/plates'); + echo '
'; + echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo '
'; echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } - private function render_row(\WP_Post $post): void { + public function render_row(\WP_Post $post): void { $id = (int) $post->ID; $url = get_permalink($id); $thumb = get_the_post_thumbnail_url($id, 'thumbnail'); @@ -136,7 +180,7 @@ class WidgetForumPlateLists extends \WP_Widget { echo ''; } - private function render_card(\WP_Post $post): void { + public function render_card(\WP_Post $post): void { $id = (int) $post->ID; $url = get_permalink($id); $thumb = get_the_post_thumbnail_url($id, 'medium');