diff --git a/assets/css/frontend/widget-batch5.css b/assets/css/frontend/widget-batch5.css index 835d1ac8..3fc342b3 100644 --- a/assets/css/frontend/widget-batch5.css +++ b/assets/css/frontend/widget-batch5.css @@ -787,3 +787,99 @@ overflow: hidden; text-overflow: ellipsis; } + +/* ---- batch9: plate info actions / mods grid / board list / term polish ---- */ +.aksrt-plate-info__cover.is-icon { + display: flex; + align-items: center; + justify-content: center; + font-size: 32px; + color: var(--color-primary, #3b82f6); + background: linear-gradient(135deg, #eff6ff, #f5f3ff); +} +.aksrt-plate-info__actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 12px; +} +.aksrt-plate-info__btn { + display: inline-flex; + align-items: center; + gap: 6px; + border: 0; + border-radius: 999px; + padding: 6px 12px; + font-size: 12px; + font-weight: 600; + cursor: pointer; + text-decoration: none; + line-height: 1.2; +} +.aksrt-plate-info__follow { + background: #ef4444; + color: #fff !important; +} +.aksrt-plate-info__follow.is-followed { + background: var(--surface-2, #e5e7eb); + color: inherit !important; +} +.aksrt-plate-info__compose { + background: var(--color-primary, #3b82f6); + color: #fff !important; +} + +.aksrt-plate-mods.style-grid .aksrt-plate-mods__list { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; +} +.aksrt-plate-mods.style-grid .aksrt-plate-mods__item { + flex-direction: column; + text-align: center; + gap: 4px; +} +.aksrt-plate-mods.style-grid .aksrt-plate-mods__name { + font-size: 12px; + width: 100%; +} +.aksrt-plate-mods.style-grid .aksrt-plate-mods__role { + font-size: 10px; +} +.aksrt-plate-mods__item.role-author .aksrt-plate-mods__role, +.aksrt-plate-mods__item.role-super .aksrt-plate-mods__role { + color: #b45309; +} + +.aksrt-forum-widget__boards .aksrt-forum-widget__name { + flex: 1; + min-width: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.aksrt-forum-widget__boards .aksrt-forum-widget__count { + margin-left: 8px; + color: var(--muted-2-color, #999); + font-size: 12px; + flex-shrink: 0; +} +.aksrt-forum-widget__boards.style-mini .aksrt-forum-widget__board a { + gap: 8px; +} +.aksrt-forum-widget__thumb { + width: 28px; + height: 28px; + border-radius: 6px; + object-fit: cover; + flex-shrink: 0; + margin-right: 4px; +} + +.aksrt-tag-cloud .c-blue-2 { background: #bfdbfe; color: #1e40af; } +.aksrt-tag-cloud .c-green-2 { background: #bbf7d0; color: #166534; } +.aksrt-tag-cloud .c-yellow-2 { background: #fde68a; color: #92400e; } +.aksrt-tag-cloud .c-purple-2 { background: #ddd6fe; color: #5b21b6; } +.aksrt-tag-cloud .c-red-2 { background: #fecaca; color: #991b1b; } + +.aksrt-home-widget__ajax .ajax-pag { margin-top: 12px; text-align: center; } diff --git a/src/AKSRT/Core/WidgetAjax.php b/src/AKSRT/Core/WidgetAjax.php index 5cd0166d..82145a25 100644 --- a/src/AKSRT/Core/WidgetAjax.php +++ b/src/AKSRT/Core/WidgetAjax.php @@ -25,17 +25,24 @@ class WidgetAjax { public function register_routes(): void { $routes = [ - '/widgets/posts' => 'rest_main_posts', - '/widgets/tab-posts' => 'rest_tab_posts', - '/widgets/paid-posts' => 'rest_paid_posts', - '/widgets/category-tabs' => 'rest_category_tabs', - '/widgets/hot-posts' => 'rest_hot_posts', - '/widgets/oneline-posts' => 'rest_oneline_posts', - '/widgets/recent-comments'=> 'rest_recent_comments', - '/widgets/user-lists' => 'rest_user_lists', - '/widgets/forum-topics' => 'rest_forum_topics', - '/widgets/forum-terms' => 'rest_forum_terms', - ]; + '/widgets/posts' => 'rest_main_posts', + '/widgets/tab-posts' => 'rest_tab_posts', + '/widgets/paid-posts' => 'rest_paid_posts', + '/widgets/category-tabs' => 'rest_category_tabs', + '/widgets/category-block' => 'rest_category_block', + '/widgets/category-recommend' => 'rest_category_recommend', + '/widgets/hot-posts' => 'rest_hot_posts', + '/widgets/oneline-posts' => 'rest_oneline_posts', + '/widgets/recent-comments' => 'rest_recent_comments', + '/widgets/user-lists' => 'rest_user_lists', + '/widgets/forum-topics' => 'rest_forum_topics', + '/widgets/forum-terms' => 'rest_forum_terms', + '/widgets/forum-boards' => 'rest_forum_boards', + '/widgets/tag-cloud' => 'rest_tag_cloud', + '/widgets/categories' => 'rest_categories', + '/widgets/term-cards' => 'rest_term_cards', + '/widgets/term-aggregation' => 'rest_term_aggregation', + ]; foreach ($routes as $path => $cb) { register_rest_route('aksrt/v1', $path, [ 'methods' => 'GET', @@ -222,6 +229,127 @@ class WidgetAjax { return new \WP_REST_Response(['success' => true, 'html' => $html], 200); } + + public function rest_category_block(\WP_REST_Request $request) { + if (!class_exists('\AKSRT\Widgets\CategoryBlockWidget')) { + return $this->fail(); + } + $instance = [ + 'category_id' => max(0, (int) ($request->get_param('cat') ?? $request->get_param('category_id') ?? 0)), + 'count' => max(1, min(12, (int) ($request->get_param('count') ?? 6))), + 'columns' => max(1, min(4, (int) ($request->get_param('columns') ?? 3))), + 'layout' => sanitize_key((string) ($request->get_param('layout') ?? 'card')), + 'paginate' => sanitize_key((string) ($request->get_param('paginate') ?? 'ajax')), + ]; + $context = sanitize_key((string) ($request->get_param('context') ?? 'homepage')); + $page = max(1, (int) ($request->get_param('page') ?? 1)); + return $this->payload(\AKSRT\Widgets\CategoryBlockWidget::query_payload($instance, $page, $context), $page); + } + + public function rest_category_recommend(\WP_REST_Request $request) { + if (!class_exists('\AKSRT\Widgets\CategoryRecommendWidget')) { + return $this->fail(); + } + $raw_ids = $request->get_param('category_ids'); + if (is_string($raw_ids)) { + $raw_ids = array_filter(array_map('intval', preg_split('/[\s,]+/', $raw_ids) ?: [])); + } + $instance = [ + 'category_ids' => is_array($raw_ids) ? $raw_ids : [], + 'posts_per_category' => max(1, min(8, (int) ($request->get_param('posts_per_category') ?? 5))), + 'columns' => max(1, min(4, (int) ($request->get_param('columns') ?? 2))), + 'show_views' => (int) ($request->get_param('show_views') ?? 0), + 'show_description' => $request->get_param('show_description') === null ? 1 : (int) $request->get_param('show_description'), + 'show_dates' => $request->get_param('show_dates') === null ? 1 : (int) $request->get_param('show_dates'), + 'show_more' => $request->get_param('show_more') === null ? 1 : (int) $request->get_param('show_more'), + ]; + $html = \AKSRT\Widgets\CategoryRecommendWidget::render_html($instance); + return new \WP_REST_Response(['success' => true, 'html' => $html], 200); + } + + public function rest_forum_boards(\WP_REST_Request $request) { + if (!class_exists('\AKSRT\Widgets\WidgetForumBoardList')) { + return $this->fail(); + } + $instance = [ + 'count' => max(1, min(50, (int) ($request->get_param('count') ?? 30))), + 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'menu_order')), + 'style' => sanitize_key((string) ($request->get_param('style') ?? 'list')), + 'hide_empty' => $request->get_param('hide_empty') === null ? 1 : (int) $request->get_param('hide_empty'), + ]; + $html = \AKSRT\Widgets\WidgetForumBoardList::render_html($instance); + return new \WP_REST_Response(['success' => true, 'html' => $html], 200); + } + + public function rest_tag_cloud(\WP_REST_Request $request) { + if (!class_exists('\AKSRT\Widgets\TagCloudWidget')) { + return $this->fail(); + } + $instance = [ + 'taxonomy' => sanitize_key((string) ($request->get_param('taxonomy') ?? 'post_tag')), + 'count' => max(1, min(80, (int) ($request->get_param('count') ?? 15))), + 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'count')), + 'color' => sanitize_html_class((string) ($request->get_param('color') ?? 'rand')), + 'show_count' => (int) ($request->get_param('show_count') ?? 0), + 'blank' => (int) ($request->get_param('blank') ?? 0), + 'fixed_width' => (int) ($request->get_param('fixed_width') ?? 0), + 'hide_empty' => (int) ($request->get_param('hide_empty') ?? 0), + ]; + $html = \AKSRT\Widgets\TagCloudWidget::render_html($instance); + return new \WP_REST_Response(['success' => true, 'html' => $html], 200); + } + + public function rest_categories(\WP_REST_Request $request) { + if (!class_exists('\AKSRT\Widgets\CategoriesWidget')) { + return $this->fail(); + } + $instance = [ + 'count' => max(1, min(50, (int) ($request->get_param('count') ?? 8))), + 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'count')), + 'order' => sanitize_key((string) ($request->get_param('order') ?? 'DESC')), + 'parent' => max(0, (int) ($request->get_param('parent') ?? 0)), + 'include' => sanitize_text_field((string) ($request->get_param('include') ?? '')), + 'exclude' => sanitize_text_field((string) ($request->get_param('exclude') ?? '')), + 'show_count' => $request->get_param('show_count') === null ? 1 : (int) $request->get_param('show_count'), + 'hide_empty' => $request->get_param('hide_empty') === null ? 1 : (int) $request->get_param('hide_empty'), + 'hierarchical' => (int) ($request->get_param('hierarchical') ?? 0), + ]; + $html = \AKSRT\Widgets\CategoriesWidget::render_html($instance); + return new \WP_REST_Response(['success' => true, 'html' => $html], 200); + } + + public function rest_term_cards(\WP_REST_Request $request) { + if (!class_exists('\AKSRT\Widgets\WidgetTermCards')) { + 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'), + ]; + $html = \AKSRT\Widgets\WidgetTermCards::render_html($instance); + return new \WP_REST_Response(['success' => true, 'html' => $html], 200); + } + + public function rest_term_aggregation(\WP_REST_Request $request) { + if (!class_exists('\AKSRT\Widgets\WidgetTermAggregation')) { + 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))), + ]; + $html = \AKSRT\Widgets\WidgetTermAggregation::render_html($instance); + return new \WP_REST_Response(['success' => true, 'html' => $html], 200); + } + private function fail(): \WP_REST_Response { return new \WP_REST_Response(['success' => false, 'message' => 'unavailable'], 500); } diff --git a/src/AKSRT/Widgets/CategoriesWidget.php b/src/AKSRT/Widgets/CategoriesWidget.php index fe2362ce..5e412231 100644 --- a/src/AKSRT/Widgets/CategoriesWidget.php +++ b/src/AKSRT/Widgets/CategoriesWidget.php @@ -22,14 +22,22 @@ class CategoriesWidget extends \WP_Widget { ); } - 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); - if ($title !== '') { - echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + /** @return array */ + public static function parse_ids_static(string $raw): array { + if ($raw === '') { + return []; } + $ids = []; + foreach (preg_split('/[\s,]+/', $raw) ?: [] as $p) { + $id = (int) $p; + if ($id > 0) { + $ids[] = $id; + } + } + return array_values(array_unique($ids)); + } + public static function render_html(array $instance): string { $count = max(1, min(50, (int) ($instance['count'] ?? 8))); $orderby = sanitize_key((string) ($instance['orderby'] ?? 'count')); if (!in_array($orderby, ['count', 'name', 'id', 'slug'], true)) { @@ -40,8 +48,8 @@ class CategoriesWidget extends \WP_Widget { $hierarchical = !empty($instance['hierarchical']); $parent = max(0, (int) ($instance['parent'] ?? 0)); $show_count = !isset($instance['show_count']) || !empty($instance['show_count']); - $exclude = $this->parse_ids((string) ($instance['exclude'] ?? '')); - $include = $this->parse_ids((string) ($instance['include'] ?? '')); + $exclude = self::parse_ids_static((string) ($instance['exclude'] ?? '')); + $include = self::parse_ids_static((string) ($instance['include'] ?? '')); $term_args = [ 'taxonomy' => 'category', @@ -65,11 +73,13 @@ class CategoriesWidget extends \WP_Widget { $cats = get_categories($term_args); if (!$cats) { - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - return; + return function_exists('aksrt_get_ajax_null') + ? aksrt_get_ajax_null(__('暂无分类', 'aksrt')) + : '

' . esc_html__('暂无分类', 'aksrt') . '

'; } - echo '