feat(forum): plate lists widget payload + REST

Shared query_payload for plate lists and
/forum/frontend/widgets/plates for remote refresh.
This commit is contained in:
2026-07-20 20:50:58 +08:00
parent c52651f647
commit 425ca6cd2e
2 changed files with 91 additions and 24 deletions
+23
View File
@@ -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 {
+68 -24
View File
@@ -1,6 +1,6 @@
<?php
/**
* Forum plate list (zibll zib_bbs_widget_ui_plate_lists lite).
* Forum plate list (zibll zib_bbs_widget_ui_plate_lists + ajax).
*
* @package AKSRT
*/
@@ -16,20 +16,18 @@ class WidgetForumPlateLists extends \WP_Widget {
'aksrt_forum_plate_lists',
esc_html__('论坛 - 版块列表(Plate)', 'aksrt'),
[
'description' => 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 '<div class="aksrt-plate-cards ajax-item">';
foreach ($plates as $post) {
if ($post instanceof \WP_Post) {
$self->render_card($post);
}
}
echo '</div>';
} else {
echo '<div class="aksrt-plate-lists ajax-item">';
foreach ($plates as $post) {
if ($post instanceof \WP_Post) {
$self->render_row($post);
}
}
echo '</div>';
}
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'))
: '<p class="aksrt-plate-empty ajax-item">' . esc_html__('暂无版块', 'aksrt') . '</p>';
}
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 '<div class="aksrt-plate-cards">';
foreach ($plates as $post) {
$this->render_card($post);
}
echo '</div>';
} else {
echo '<div class="aksrt-plate-lists">';
foreach ($plates as $post) {
$this->render_row($post);
}
echo '</div>';
}
// IAS-like: first paint is SSR; optional remote refresh via rest for customize.
$rest = rest_url('aksrt/v1/forum/frontend/widgets/plates');
echo '<div class="widget-plate-lists ajaxpager mb20" data-aksrt-ajaxpager data-aksrt-ajax-url="' . esc_url($rest) . '">';
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '</div>';
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 '</div></a>';
}
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');