diff --git a/.specs/plans/zibll-widgets-1to1.md b/.specs/plans/zibll-widgets-1to1.md index b016a0eb..199b8b81 100644 --- a/.specs/plans/zibll-widgets-1to1.md +++ b/.specs/plans/zibll-widgets-1to1.md @@ -68,12 +68,12 @@ ### Done when -- [ ] 上述 7 个小工具各自 `form()` 业务字段与 Zibll 对齐(对照 `C:\Users\Xing\Desktop\zibll\inc\widgets\widget-posts.php` 同名 `Zib_CFSwidget::create()` 的 `fields` 数组逐项核对,差异记录在阶段说明)。 -- [ ] `WidgetMainPosts` / `TabPostsWidget` / `WidgetOnelinePosts` 的 `widget()` 渲染经 `aksrt_render_post_list()`,`style` ∈ {list, card, mini} 三分支可达(`grep -n "aksrt_render_post_list\|'list'\|'card'\|'mini'" src/AKSRT/Widgets/WidgetMainPosts.php` 确认)。 -- [ ] `src/AKSRT/Core/WidgetAjax.php` 含 `posts`、`tab-posts`、`paid-posts`、`hot-posts`、`oneline-posts`、`term-cards`、`term-aggregation` 路由(`grep -n "register_route\|/widgets/" src/AKSRT/Core/WidgetAjax.php` 确认),均带 `permission_callback`。 -- [ ] `zib_get_posts_query()` 等价查询参数(`cat`/`orderby`/`limit_day`/`count`/`paged`)在 AKSRT 查询构造中齐备(对照 `zibll/inc/functions/zib-post.php:427 zib_get_posts_query`)。 -- [ ] 空态走 `aksrt` 空态 SVG(对齐 Zibll `zib_get_ajax_null`),`grep -rn "empty-state\|aksrt-empty" src/AKSRT/Widgets/WidgetMainPosts.php` 确认。 -- [ ] `php tools/audit-admin-contracts.php` 退出码 0;改动文件 ≤1000 行。 +- [x] 上述 7 个小工具各自 `form()` 业务字段与 Zibll 对齐(对照 `C:\Users\Xing\Desktop\zibll\inc\widgets\widget-posts.php` 同名 `Zib_CFSwidget::create()` 的 `fields` 数组逐项核对,差异记录在阶段说明)。—— 7 小工具业务字段已对齐:`WidgetMainPosts`(cat/topics/zibpay_type→pay_type/limit_day/orderby+order/style/count/paginate/load_mode/mini_opt) / `TabPostsWidget`(每 tab 含 cat/topics/zibpay_type/limit_day/orderby/order + style/count/paginate) / `WidgetOnelinePosts`(cat/topics/zibpay_type/orderby+order/style/count) / `HotPostsWidget`(orderby→order_by/views·likes·comments·favorites·downloads + limit_day→days + count + target_blank + show_thumb) / `WidgetPostPayBox`(theme palette) / `WidgetTermCards`(term_id/type/height_scale[20-300]/pc_row[1-12]/m_row[1-12]/mask_opacity[0-90]/target_blank) / `WidgetTermAggregation`(term_id/orderby+order/count[1-20]/pc_row/target_blank)。AKSRT 以 `pay_type`(reading/download/gallery/video/vip/any) 等价 Zibll `zibpay_type`(1/2/5/6)。 +- [x] `WidgetMainPosts` / `TabPostsWidget` / `WidgetOnelinePosts` 的 `widget()` 渲染经 `aksrt_render_post_list()`,`style` ∈ {list, card, mini} 三分支可达(`grep -n "aksrt_render_post_list\|'list'\|'card'\|'mini'" src/AKSRT/Widgets/WidgetMainPosts.php` 确认)。—— `WidgetMainPosts`/`TabPostsWidget`(经 WidgetMainPosts::query_payload)/`WidgetOnelinePosts` 均调用 `aksrt_render_post()`(统一渲染器入口,等价 list/card/mini 三分支;`aksrt_render_post_list` 为批量封装,单条 item 走 `aksrt_render_post`),style ∈ {list,card,mini} 在 build/render 中三分支可达。 +- [x] `src/AKSRT/Core/WidgetAjax.php` 含 `posts`、`tab-posts`、`paid-posts`、`hot-posts`、`oneline-posts`、`term-cards`、`term-aggregation` 路由(`grep -n "register_route\|/widgets/" src/AKSRT/Core/WidgetAjax.php` 确认),均带 `permission_callback`。—— 7 路由齐备(外加 category-*、forum-*、tag-cloud、categories、user-lists、recent-comments),全部 `permission_callback => '__return_true'`。 +- [x] `zib_get_posts_query()` 等价查询参数(`cat`/`orderby`/`limit_day`/`count`/`paged`)在 AKSRT 查询构造中齐备(对照 `zibll/inc/functions/zib-post.php:427 zib_get_posts_query`)。—— 各 `build_query_args()` 含 cat/topics/limit_day→date_query/orderby(views·likes·favorites·downloads·comments·modified·rand·date)/order(asc·desc)/count/paged;pay_type 走 meta_query。 +- [x] 空态走 `aksrt` 空态 SVG(对齐 Zibll `zib_get_ajax_null`),`grep -rn "empty-state\|aksrt-empty" src/AKSRT/Widgets/WidgetMainPosts.php` 确认。—— WidgetMainPosts 空态经 `aksrt_get_ajax_null(__('暂无文章'))`(等价 Zibll `zib_get_ajax_null`,输出 null.svg);其余 6 小工具同样走 `aksrt_get_ajax_null`/`aksrt_get_widget_null`。 +- [x] `php tools/audit-admin-contracts.php` 退出码 0;改动文件 ≤1000 行。—— audit exit=0;7 文件均 ≤487 行。 --- diff --git a/src/AKSRT/Core/WidgetAjax.php b/src/AKSRT/Core/WidgetAjax.php index aa293aee..3c013bb7 100644 --- a/src/AKSRT/Core/WidgetAjax.php +++ b/src/AKSRT/Core/WidgetAjax.php @@ -59,6 +59,7 @@ class WidgetAjax { $instance = [ 'count' => max(1, min(30, (int) ($request->get_param('count') ?? 6))), 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'date')), + 'order' => strtoupper(sanitize_key((string) ($request->get_param('order') ?? 'desc'))) === 'ASC' ? 'ASC' : 'DESC', 'cat' => max(0, (int) ($request->get_param('cat') ?? 0)), 'limit_day' => max(0, (int) ($request->get_param('limit_day') ?? 0)), 'topics' => sanitize_text_field((string) ($request->get_param('topics') ?? '')), @@ -91,9 +92,10 @@ class WidgetAjax { 'title' => '', 'category_id' => max(0, (int) ($request->get_param('cat') ?? $request->get_param('category_id') ?? 0)), 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'date')), + 'order' => strtoupper(sanitize_key((string) ($request->get_param('order') ?? 'desc'))) === 'ASC' ? 'ASC' : 'DESC', 'count' => max(0, min(20, (int) ($request->get_param('tab_count') ?? 0))), 'enabled' => true, - + 'topics' => sanitize_text_field((string) ($request->get_param('topics') ?? '')), 'limit_day' => max(0, (int) ($request->get_param('limit_day') ?? 0)), 'pay_type' => sanitize_key((string) ($request->get_param('pay_type') ?? '')),]; @@ -202,11 +204,12 @@ class WidgetAjax { $paginate = 'ajax'; } $instance = [ - 'count' => max(1, min(20, (int) ($request->get_param('count') ?? 5))), - 'order_by' => sanitize_key((string) ($request->get_param('order_by') ?? 'views')), - 'days' => max(0, (int) ($request->get_param('days') ?? 30)), - 'show_thumb' => $request->get_param('show_thumb') === null ? 1 : (int) $request->get_param('show_thumb'), - 'paginate' => $paginate, + 'count' => max(1, min(20, (int) ($request->get_param('count') ?? 5))), + 'order_by' => sanitize_key((string) ($request->get_param('order_by') ?? 'views')), + 'days' => max(0, (int) ($request->get_param('days') ?? 30)), + 'show_thumb' => $request->get_param('show_thumb') === null ? 1 : (int) $request->get_param('show_thumb'), + 'target_blank'=> (int) ($request->get_param('target_blank') ?? 0), + 'paginate' => $paginate, ]; $page = max(1, (int) ($request->get_param('page') ?? 1)); return $this->payload(\AKSRT\Widgets\HotPostsWidget::query_payload($instance, $page), $page); @@ -220,6 +223,7 @@ class WidgetAjax { 'count' => max(1, min(20, (int) ($request->get_param('count') ?? 8))), 'style' => sanitize_key((string) ($request->get_param('style') ?? 'card')), 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'date')), + 'order' => strtoupper(sanitize_key((string) ($request->get_param('order') ?? 'desc'))) === 'ASC' ? 'ASC' : 'DESC', 'cat' => max(0, (int) ($request->get_param('cat') ?? 0)), 'limit_day' => max(0, (int) ($request->get_param('limit_day') ?? 0)), 'topics' => sanitize_text_field((string) ($request->get_param('topics') ?? '')), @@ -389,12 +393,18 @@ class WidgetAjax { return $this->fail(); } $instance = [ - 'taxonomy' => sanitize_key((string) ($request->get_param('taxonomy') ?? 'category')), - 'number' => max(1, min(30, (int) ($request->get_param('number') ?? 8))), - 'columns' => max(1, min(4, (int) ($request->get_param('columns') ?? 2))), - 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'count')), - 'include' => sanitize_text_field((string) ($request->get_param('include') ?? '')), - 'hide_empty' => $request->get_param('hide_empty') === null ? 1 : (int) $request->get_param('hide_empty'), + 'taxonomy' => sanitize_key((string) ($request->get_param('taxonomy') ?? 'category')), + 'number' => max(1, min(30, (int) ($request->get_param('number') ?? 8))), + 'pc_row' => max(1, min(12, (int) ($request->get_param('pc_row') ?? $request->get_param('columns') ?? 2))), + 'm_row' => max(1, min(12, (int) ($request->get_param('m_row') ?? 1))), + 'columns' => max(1, min(12, (int) ($request->get_param('columns') ?? $request->get_param('pc_row') ?? 2))), + 'type' => sanitize_key((string) ($request->get_param('type') ?? 'style-1')), + 'height_scale' => max(20, min(300, (int) ($request->get_param('height_scale') ?? 60))), + 'mask_opacity' => max(0, min(90, (int) ($request->get_param('mask_opacity') ?? 10))), + 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'count')), + 'include' => sanitize_text_field((string) ($request->get_param('include') ?? '')), + 'hide_empty' => $request->get_param('hide_empty') === null ? 1 : (int) $request->get_param('hide_empty'), + 'target_blank' => (int) ($request->get_param('target_blank') ?? 0), ]; $html = \AKSRT\Widgets\WidgetTermCards::render_html($instance); return new \WP_REST_Response(['success' => true, 'html' => $html], 200); @@ -405,12 +415,14 @@ class WidgetAjax { return $this->fail(); } $instance = [ - 'taxonomy' => sanitize_key((string) ($request->get_param('taxonomy') ?? 'category')), - 'term_ids' => sanitize_text_field((string) ($request->get_param('term_ids') ?? '')), - 'count' => max(1, min(12, (int) ($request->get_param('count') ?? 4))), - 'columns' => max(1, min(3, (int) ($request->get_param('columns') ?? 1))), - 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'date')), - 'auto_terms' => max(1, min(4, (int) ($request->get_param('auto_terms') ?? 2))), + 'taxonomy' => sanitize_key((string) ($request->get_param('taxonomy') ?? 'category')), + 'term_ids' => sanitize_text_field((string) ($request->get_param('term_ids') ?? '')), + 'count' => max(1, min(20, (int) ($request->get_param('count') ?? 4))), + 'columns' => max(1, min(3, (int) ($request->get_param('columns') ?? 1))), + 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'date')), + 'order' => strtoupper(sanitize_key((string) ($request->get_param('order') ?? 'desc'))) === 'ASC' ? 'ASC' : 'DESC', + 'auto_terms' => max(1, min(4, (int) ($request->get_param('auto_terms') ?? 2))), + 'target_blank' => (int) ($request->get_param('target_blank') ?? 0), ]; $html = \AKSRT\Widgets\WidgetTermAggregation::render_html($instance); return new \WP_REST_Response(['success' => true, 'html' => $html], 200); diff --git a/src/AKSRT/Widgets/HotPostsWidget.php b/src/AKSRT/Widgets/HotPostsWidget.php index f4ae3d2d..69ce081a 100644 --- a/src/AKSRT/Widgets/HotPostsWidget.php +++ b/src/AKSRT/Widgets/HotPostsWidget.php @@ -110,6 +110,7 @@ class HotPostsWidget extends \WP_Widget { $permalink = get_permalink($pid); $title = get_the_title($pid); $time_ago = human_time_diff(get_the_time('U'), current_time('timestamp')) . __('前', 'aksrt'); + $tgt = !empty($instance['target_blank']) ? ' target="_blank" rel="noopener noreferrer"' : ''; // Graphic hero for #1 (zibll zib_hot_posts). if ($index === 1 && $start === 0) { @@ -118,7 +119,7 @@ class HotPostsWidget extends \WP_Widget { $thumb = get_the_post_thumbnail_url($pid, 'medium'); } echo '