diff --git a/src/AKSRT/Widgets/WidgetForumHotTopics.php b/src/AKSRT/Widgets/WidgetForumHotTopics.php index a6cb4776..aa14b29e 100644 --- a/src/AKSRT/Widgets/WidgetForumHotTopics.php +++ b/src/AKSRT/Widgets/WidgetForumHotTopics.php @@ -1,5 +1,7 @@ __('显示论坛热门话题列表。', 'aksrt')] - ); - } + public function __construct() { + parent::__construct( + 'aksrt_forum_hot_topics', + __('论坛 - 热门话题', 'aksrt'), + ['description' => __('显示论坛热门话题列表。', 'aksrt')] + ); + } - public function widget($args, $instance): void { - $title = !empty($instance['title']) ? $instance['title'] : __('热门话题', 'aksrt'); - $count = !empty($instance['count']) ? max(1, min(20, (int) $instance['count'])) : 5; - $period = !empty($instance['period']) ? sanitize_key($instance['period']) : 'week'; + public static function build_query_args(array $instance, int $paged = 1): array { + $count = max(1, min(20, (int) ($instance['count'] ?? 5))); + $period = sanitize_key((string) ($instance['period'] ?? 'week')); + $orderby = sanitize_key((string) ($instance['orderby'] ?? 'views')); + $date_query = []; + if ($period === 'week') { + $date_query = [['after' => '7 days ago']]; + } elseif ($period === 'month') { + $date_query = [['after' => '30 days ago']]; + } + $query = [ + 'post_type' => 'aksrt_forum_topic', + 'posts_per_page' => $count, + 'paged' => max(1, $paged), + 'post_status' => 'publish', + 'date_query' => $date_query, + ]; + if ($orderby === 'comments') { + $query['orderby'] = 'comment_count'; + $query['order'] = 'DESC'; + } elseif ($orderby === 'date') { + $query['orderby'] = 'date'; + $query['order'] = 'DESC'; + } else { + $query['meta_key'] = '_aksrt_views'; + $query['orderby'] = 'meta_value_num'; + $query['order'] = 'DESC'; + } + return $query; + } - echo $args['before_widget']; - echo $args['before_title'] . esc_html($title) . $args['after_title']; + public static function render_items_html(\WP_Query $query, int $start = 0): string { + if (!$query->have_posts()) { + return ''; + } + ob_start(); + $i = $start; + while ($query->have_posts()) { + $query->the_post(); + $i++; + $views = (int) get_post_meta(get_the_ID(), '_aksrt_views', true); + echo '
  • '; + echo '' . esc_html((string) $i) . ''; + echo ''; + echo esc_html(get_the_title()); + echo ''; + echo ' ' . esc_html((string) $views) . ''; + echo '
  • '; + } + wp_reset_postdata(); + return (string) ob_get_clean(); + } - $date_query = []; - if ($period === 'week') { - $date_query = [['after' => '7 days ago']]; - } elseif ($period === 'month') { - $date_query = [['after' => '30 days ago']]; - } + /** + * @return array{html:string,paginate_html:string,has_more:bool,page:int,max_pages:int,total:int} + */ + public static function query_payload(array $instance, int $page = 1): array { + $page = max(1, $page); + $count = max(1, min(20, (int) ($instance['count'] ?? 5))); + $paginate = sanitize_key((string) ($instance['paginate'] ?? 'ajax')); + $q = new \WP_Query(self::build_query_args($instance, $page)); + $items = self::render_items_html($q, ($page - 1) * $count); + $html = $items !== '' ? '' : ''; + if ($html === '' && $page === 1) { + $html = '

    ' . esc_html__('暂无话题', 'aksrt') . '

    '; + } + $max_pages = max(1, (int) $q->max_num_pages); + $total = (int) $q->found_posts; + $has_more = $page < $max_pages; + $paginate_html = ''; + if ($paginate === 'ajax' && $has_more) { + $next = add_query_arg([ + 'page' => $page + 1, + 'count' => $count, + 'period' => sanitize_key((string) ($instance['period'] ?? 'week')), + 'orderby' => sanitize_key((string) ($instance['orderby'] ?? 'views')), + 'paginate' => 'ajax', + ], rest_url('aksrt/v1/widgets/forum-topics')); + $paginate_html = function_exists('aksrt_get_ajax_next_paginate') + ? aksrt_get_ajax_next_paginate($total, $page, $count, $next) + : '
    ' . esc_html__('加载更多', 'aksrt') . '
    '; + } else { + $paginate_html = '
    '; + } + return compact('html', 'paginate_html', 'has_more', 'page', 'max_pages', 'total'); + } - $query = new \WP_Query([ - 'post_type' => 'aksrt_forum_topic', - 'posts_per_page' => $count, - 'post_status' => 'publish', - 'meta_key' => '_aksrt_views', - 'orderby' => 'meta_value_num', - 'order' => 'DESC', - 'date_query' => $date_query, - ]); + public function widget($args, $instance): void { + $title = !empty($instance['title']) ? $instance['title'] : __('热门话题', 'aksrt'); + $instance['paginate'] = sanitize_key((string) ($instance['paginate'] ?? 'ajax')); + $payload = self::query_payload($instance, 1); - if ($query->have_posts()) { - echo ''; - wp_reset_postdata(); - } else { - echo '

    ' . esc_html__('暂无话题', 'aksrt') . '

    '; - } + echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $rest = rest_url('aksrt/v1/widgets/forum-topics'); + echo '
    '; + echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo ''; + echo '
    '; + echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } - echo $args['after_widget']; - } + public function form($instance): void { + $title = !empty($instance['title']) ? $instance['title'] : __('热门话题', 'aksrt'); + $count = !empty($instance['count']) ? (int) $instance['count'] : 5; + $period = !empty($instance['period']) ? $instance['period'] : 'week'; + ?> +

    + + +

    +

    + + +

    +

    + + +

    +

    + +

    + -

    - - -

    -

    - - -

    -

    - - -

    - sanitize_text_field($new_instance['title'] ?? ''), + 'count' => max(1, min(20, (int) ($new_instance['count'] ?? 5))), + 'period' => in_array($new_instance['period'] ?? '', ['all', 'week', 'month'], true) ? $new_instance['period'] : 'week', + 'paginate' => sanitize_key((string) ($new_instance['paginate'] ?? 'ajax')) === 'none' ? 'none' : 'ajax', + ]; + } } diff --git a/src/AKSRT/Widgets/WidgetForumRecentTopics.php b/src/AKSRT/Widgets/WidgetForumRecentTopics.php index 97565ea4..2202bda8 100644 --- a/src/AKSRT/Widgets/WidgetForumRecentTopics.php +++ b/src/AKSRT/Widgets/WidgetForumRecentTopics.php @@ -1,5 +1,7 @@ __('显示论坛最新话题列表。', 'aksrt')] - ); - } + public function __construct() { + parent::__construct( + 'aksrt_forum_recent_topics', + __('论坛 - 最新话题', 'aksrt'), + ['description' => __('显示论坛最新话题列表。', 'aksrt')] + ); + } - public function widget($args, $instance): void { - $title = !empty($instance['title']) ? $instance['title'] : __('最新话题', 'aksrt'); - $count = !empty($instance['count']) ? max(1, min(20, (int) $instance['count'])) : 5; + public function widget($args, $instance): void { + $title = !empty($instance['title']) ? $instance['title'] : __('最新话题', 'aksrt'); + $instance['orderby'] = 'date'; + $instance['period'] = 'all'; + $instance['paginate'] = sanitize_key((string) ($instance['paginate'] ?? 'ajax')); + $payload = WidgetForumHotTopics::query_payload($instance, 1); - echo $args['before_widget']; - echo $args['before_title'] . esc_html($title) . $args['after_title']; + echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $rest = rest_url('aksrt/v1/widgets/forum-topics'); + echo '
    '; + echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo ''; + echo '
    '; + echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } - $query = new \WP_Query([ - 'post_type' => 'aksrt_forum_topic', - 'posts_per_page' => $count, - 'post_status' => 'publish', - 'orderby' => 'date', - 'order' => 'DESC', - ]); + public function form($instance): void { + $title = !empty($instance['title']) ? $instance['title'] : __('最新话题', 'aksrt'); + $count = !empty($instance['count']) ? (int) $instance['count'] : 5; + ?> +

    + + +

    +

    + + +

    +

    + +

    + have_posts()) { - echo ''; - wp_reset_postdata(); - } else { - echo '

    ' . esc_html__('暂无话题', 'aksrt') . '

    '; - } - - echo $args['after_widget']; - } - - public function form($instance): void { - $title = !empty($instance['title']) ? $instance['title'] : __('最新话题', 'aksrt'); - $count = !empty($instance['count']) ? (int) $instance['count'] : 5; - ?> -

    - - -

    -

    - - -

    - sanitize_text_field($new_instance['title'] ?? ''), + 'count' => max(1, min(20, (int) ($new_instance['count'] ?? 5))), + 'paginate' => sanitize_key((string) ($new_instance['paginate'] ?? 'ajax')) === 'none' ? 'none' : 'ajax', + ]; + } } diff --git a/src/AKSRT/Widgets/WidgetForumTopicTerms.php b/src/AKSRT/Widgets/WidgetForumTopicTerms.php index 26f426af..14da9c03 100644 --- a/src/AKSRT/Widgets/WidgetForumTopicTerms.php +++ b/src/AKSRT/Widgets/WidgetForumTopicTerms.php @@ -1,6 +1,6 @@ */ + 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 { $tax = taxonomy_exists('aksrt_forum_tag') ? 'aksrt_forum_tag' : (taxonomy_exists('aksrt_forum_topic_cat') ? 'aksrt_forum_topic_cat' : ''); if ($tax === '') { - return; + return ''; } - $number = max(1, min(40, (int) ($instance['number'] ?? 12))); $orderby = sanitize_key((string) ($instance['orderby'] ?? 'count')); $hide_empty = !isset($instance['hide_empty']) || !empty($instance['hide_empty']); - $include = $this->parse_ids((string) ($instance['include'] ?? '')); + $include = self::parse_ids_static((string) ($instance['include'] ?? '')); $style = sanitize_key((string) ($instance['style'] ?? 'mini')); $term_args = [ 'taxonomy' => $tax, 'number' => $number, - 'hide_empty' => $hide_empty, + 'hide_empty' => (bool) $hide_empty, ]; if ($include) { $term_args['include'] = $include; $term_args['orderby'] = 'include'; + } elseif ($orderby === 'name') { + $term_args['orderby'] = 'name'; + $term_args['order'] = 'ASC'; + } elseif ($orderby === 'views') { + $term_args['meta_key'] = '_aksrt_views'; + $term_args['orderby'] = 'meta_value_num'; + $term_args['order'] = 'DESC'; } else { - if ($orderby === 'name') { - $term_args['orderby'] = 'name'; - $term_args['order'] = 'ASC'; - } elseif ($orderby === 'views') { - $term_args['meta_key'] = '_aksrt_views'; - $term_args['orderby'] = 'meta_value_num'; - $term_args['order'] = 'DESC'; - } else { - $term_args['orderby'] = 'count'; - $term_args['order'] = 'DESC'; - } + $term_args['orderby'] = 'count'; + $term_args['order'] = 'DESC'; } $terms = get_terms($term_args); if (is_wp_error($terms) || !$terms) { - return; + return function_exists('aksrt_get_ajax_null') + ? aksrt_get_ajax_null(__('暂无话题', 'aksrt')) + : '

    ' . esc_html__('暂无话题', 'aksrt') . '

    '; } - - 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 - } - - $list_cls = $style === 'card' ? 'aksrt-ftag-list is-card' : 'aksrt-ftag-list is-mini'; + ob_start(); + $list_cls = $style === 'card' ? 'aksrt-ftag-list is-card ajax-item' : 'aksrt-ftag-list is-mini ajax-item'; echo '
    '; foreach ($terms as $term) { $link = get_term_link($term); @@ -84,23 +92,28 @@ class WidgetForumTopicTerms extends \WP_Widget { echo ''; } echo '
    '; + return (string) ob_get_clean(); + } + public function widget($args, $instance): void { + $html = self::render_html($instance); + if ($html === '') { + return; + } + 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 + } + // IAS-style wrap for remote refresh. + echo '
    '; + echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo '
    '; echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } - /** @return array */ private function parse_ids(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)); + return self::parse_ids_static($raw); } public function form($instance): void { diff --git a/src/AKSRT/Widgets/WidgetProductOneline.php b/src/AKSRT/Widgets/WidgetProductOneline.php index 22cdcd5f..81848bcd 100644 --- a/src/AKSRT/Widgets/WidgetProductOneline.php +++ b/src/AKSRT/Widgets/WidgetProductOneline.php @@ -1,5 +1,7 @@ __('AKSRT 单行横滑商品 Swiper 组件。', 'aksrt')] - ); - } + public function __construct() { + \WP_Widget::__construct( + 'aksrt_product_oneline', + __('横滑商品', 'aksrt'), + ['description' => __('AKSRT 单行横滑商品列表(AJAX 同源)。', 'aksrt')] + ); + } - public function widget($args, $instance): void { - $instance['style'] = 'oneline'; - parent::widget($args, $instance); - } + public function widget($args, $instance): void { + $instance['style'] = 'oneline'; + // Prefer no paginate for horizontal scroller (zibll loads fixed count). + if (!isset($instance['paginate'])) { + $instance['paginate'] = 'none'; + } + parent::widget($args, $instance); + } - public function form($instance): void { - $instance = wp_parse_args($instance, ['style' => 'oneline']); - parent::form($instance); - } + public function form($instance): void { + $instance = wp_parse_args($instance, ['style' => 'oneline', 'paginate' => 'none']); + parent::form($instance); + } + + public function update($new_instance, $old_instance): array { + $out = parent::update($new_instance, $old_instance); + $out['style'] = 'oneline'; + return $out; + } }