diff --git a/inc/modules/widgets-register.php b/inc/modules/widgets-register.php index 078e7c2a..23f51e95 100644 --- a/inc/modules/widgets-register.php +++ b/inc/modules/widgets-register.php @@ -36,10 +36,8 @@ function aksrt_register_widgets() { register_widget('\AKSRT\Widgets\SearchWidget'); register_widget('\AKSRT\Widgets\NoticeWidget'); register_widget('\AKSRT\Widgets\RecentCommentsWidget'); - register_widget('\AKSRT\Widgets\FriendLinksWidget'); register_widget('\AKSRT\Widgets\IconCardsWidget'); register_widget('\AKSRT\Widgets\ButtonsWidget'); - register_widget('\AKSRT\Widgets\CustomHtmlGapWidget'); // 公告跑马灯 register_widget('\AKSRT\Widgets\WidgetAnnouncement'); @@ -47,9 +45,6 @@ function aksrt_register_widgets() { // 用户卡片 register_widget('\AKSRT\Widgets\WidgetUserCard'); - // 用户排行榜 - register_widget('\AKSRT\Widgets\WidgetUserRanking'); - // 图文封面卡片 register_widget('\AKSRT\Widgets\WidgetCoverCards'); @@ -66,18 +61,13 @@ function aksrt_register_widgets() { register_widget('\AKSRT\Widgets\WidgetIframe'); register_widget('\AKSRT\Widgets\WidgetComboInfo'); register_widget('\AKSRT\Widgets\WidgetTextTitle'); - register_widget('\AKSRT\Widgets\WidgetUserLists'); - register_widget('\AKSRT\Widgets\WidgetFaq'); - register_widget('\AKSRT\Widgets\WidgetHighlights'); register_widget('\AKSRT\Widgets\WidgetTermCards'); register_widget('\AKSRT\Widgets\WidgetPostPayBox'); register_widget('\AKSRT\Widgets\WidgetAuthorCard'); register_widget('\AKSRT\Widgets\WidgetOnelinePosts'); - register_widget('\AKSRT\Widgets\WidgetTiltCases'); register_widget('\AKSRT\Widgets\WidgetMainPosts'); register_widget('\AKSRT\Widgets\WidgetTermAggregation'); register_widget('\AKSRT\Widgets\WidgetIconCoverCards'); - register_widget('\AKSRT\Widgets\WidgetBookmarkLinks'); } add_action('widgets_init', 'aksrt_register_widgets'); diff --git a/src/Core/WidgetAjax.php b/src/Core/WidgetAjax.php index 46a542f8..eaf61eea 100644 --- a/src/Core/WidgetAjax.php +++ b/src/Core/WidgetAjax.php @@ -33,7 +33,6 @@ class WidgetAjax { '/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/tag-cloud' => 'rest_tag_cloud', '/widgets/categories' => 'rest_categories', '/widgets/term-cards' => 'rest_term_cards', @@ -223,23 +222,6 @@ class WidgetAjax { return new \WP_REST_Response(['success' => true, 'html' => $html], 200); } - public function rest_user_lists(\WP_REST_Request $request) { - if (!class_exists('\AKSRT\Widgets\WidgetUserLists')) { - return $this->fail(); - } - $instance = [ - 'number' => max(1, min(50, (int) ($request->get_param('number') ?? 8))), - 'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'user_registered')), - 'order' => sanitize_key((string) ($request->get_param('order') ?? 'DESC')), - 'include' => sanitize_text_field((string) ($request->get_param('include') ?? '')), - 'exclude' => sanitize_text_field((string) ($request->get_param('exclude') ?? '')), - 'hide_box' => (int) ($request->get_param('hide_box') ?? 0), - 'blur_bg' => (int) ($request->get_param('blur_bg') ?? 0), - ]; - $html = \AKSRT\Widgets\WidgetUserLists::render_html($instance); - 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(); diff --git a/src/Widgets/CustomHtmlGapWidget.php b/src/Widgets/CustomHtmlGapWidget.php deleted file mode 100644 index fb4e11bb..00000000 --- a/src/Widgets/CustomHtmlGapWidget.php +++ /dev/null @@ -1,115 +0,0 @@ - esc_html__('插入自定义 HTML 或布局间距(PC/移动可分设)。', 'aksrt'), - 'classname' => 'widget_aksrt_custom_html_gap', - ]); - } - - /** - * @param array $args - * @param array $instance - */ - public function widget($args, $instance): void { - $mode = sanitize_key((string) ($instance['mode'] ?? 'html')); - - if ($mode === 'gap') { - $pc = max(0, min(500, (int) ($instance['gap_height'] ?? 20))); - $m = max(0, min(500, (int) ($instance['gap_height_m'] ?? $pc))); - // zibll layout gap: empty spacing block without widget chrome. - $style = sprintf('--aksrt-gap-pc:%dpx;--aksrt-gap-m:%dpx;height:%dpx;', $pc, $m, $pc); - echo ''; - return; - } - - $content = (string) ($instance['content'] ?? ''); - if (trim(wp_strip_all_tags($content)) === '' && trim($content) === '') { - if (current_user_can('manage_options')) { - echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo function_exists('aksrt_get_widget_null') - ? aksrt_get_widget_null(__('请填写 HTML 内容或切换为间距模式', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - : '
' . esc_html__('自定义 HTML:', 'aksrt') . '' . esc_html__('请填写内容或切换为间距模式', 'aksrt') . '
'; - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - 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 - } - $full_width = !empty($instance['full_width']); - $cls = 'widget-custom-html' . ($full_width ? ' is-full' : ''); - echo '
' . wp_kses_post($content) . '
'; - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - /** - * @param array $instance - */ - public function form($instance): void { - $mode = sanitize_key((string) ($instance['mode'] ?? 'html')); - ?> -

- - -

-

- - -

-

- - -

-

- - -

-

- - -

-

- -

- render_common_form_section($instance); -} - - /** - * @param array $new_instance - * @param array $old_instance - * @return array - */ - public function update($new_instance, $old_instance): array { - $business = [ - 'mode' => in_array(($new_instance['mode'] ?? ''), ['html', 'gap'], true) ? $new_instance['mode'] : 'html', - 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), - 'content' => wp_kses_post((string) ($new_instance['content'] ?? '')), - 'gap_height' => max(0, min(500, (int) ($new_instance['gap_height'] ?? 20))), - 'gap_height_m' => max(0, min(500, (int) ($new_instance['gap_height_m'] ?? $new_instance['gap_height'] ?? 20))), - 'full_width' => !empty($new_instance['full_width']) ? 1 : 0, - ]; return $this->update_common_fields($new_instance, $old_instance, $business); - } -} diff --git a/src/Widgets/FriendLinksWidget.php b/src/Widgets/FriendLinksWidget.php deleted file mode 100644 index 442b2466..00000000 --- a/src/Widgets/FriendLinksWidget.php +++ /dev/null @@ -1,207 +0,0 @@ - esc_html__('友情链接:card / bigcard / image / simple(共享 aksrt_links_box)。', 'aksrt'), - 'classname' => 'widget_aksrt_friend_links', - ]); - } - - /** - * @param array $args - * @param array $instance - */ - public function widget($args, $instance): void { - echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - $title = apply_filters('widget_title', (string) ($instance['title'] ?? __('友情链接', 'aksrt')), $instance, $this->id_base); - $source = sanitize_key((string) ($instance['source'] ?? 'settings')); - $go_link = !empty($instance['go_link']); - $limit = max(1, min(100, (int) ($instance['limit'] ?? 24))); - $type = sanitize_key((string) ($instance['type'] ?? 'card')); - if (!in_array($type, ['card', 'bigcard', 'image', 'simple'], true)) { - $type = 'card'; - } - $blank = !isset($instance['blank']) || !empty($instance['blank']); - $nofollow = !isset($instance['nofollow']) || !empty($instance['nofollow']); - $show_box = !empty($instance['show_box']) || !isset($instance['show_box']); - - if ($title) { - echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - $bookmarks = $this->resolve_bookmarks($source, $instance, $limit); - if (!$bookmarks) { - echo function_exists('aksrt_get_widget_null') - ? aksrt_get_widget_null(__('暂无友情链接', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - : '

' . esc_html__('暂无友情链接', 'aksrt') . '

'; - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - return; - } - - $wrap = 'aksrt-friend-links aksrt-bookmark-links links-box style-' . $type . ($show_box ? ' has-box zib-widget' : ''); - echo '
'; - if (function_exists('aksrt_links_box')) { - echo aksrt_links_box($bookmarks, $type, $nofollow, $go_link, $blank); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } else { - foreach ($bookmarks as $b) { - $row = (array) $b; - $url = (string) ($row['link_url'] ?? $row['url'] ?? ''); - $name = (string) ($row['link_name'] ?? $row['name'] ?? ''); - if ($url === '' || $name === '') { - continue; - } - if ($go_link && function_exists('aksrt_go_link')) { - $url = aksrt_go_link($url, true); - } - echo '' . esc_html($name) . ''; - } - } - echo '
'; - - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - /** - * Normalize to get_bookmarks-like objects/arrays for aksrt_links_box. - * - * @param array $instance - * @return array - */ - private function resolve_bookmarks(string $source, array $instance, int $limit): array { - if ($source === 'bookmarks') { - $bm_args = [ - 'orderby' => sanitize_key((string) ($instance['orderby'] ?? 'name')) ?: 'name', - 'order' => strtoupper((string) ($instance['order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC', - 'limit' => $limit, - ]; - $cats = trim((string) ($instance['cats'] ?? '')); - if ($cats !== '' && $cats !== 'all') { - $bm_args['category'] = $cats; - } - return get_bookmarks($bm_args) ?: []; - } - - $links = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_friend_links() : []; - if (!is_array($links) || !$links) { - return $this->resolve_bookmarks('bookmarks', $instance, $limit); - } - $out = []; - foreach (array_slice(array_values($links), 0, $limit) as $link) { - if (!is_array($link)) { - continue; - } - $out[] = (object) [ - 'link_name' => (string) ($link['name'] ?? ''), - 'link_url' => (string) ($link['url'] ?? ''), - 'link_description' => (string) ($link['description'] ?? $link['desc'] ?? ''), - 'link_image' => (string) ($link['icon'] ?? $link['image'] ?? ''), - 'link_target' => '_blank', - ]; - } - return $out; - } - - /** - * @param array $instance - */ - public function form($instance): void { - ?> -

- -

-

- -

-

- - -

-

- -

-

- -

-

-
-
-
- -

- render_common_form_section($instance); -} - - /** - * @param array $new_instance - * @param array $old_instance - * @return array - */ - public function update($new_instance, $old_instance): array { - $type = sanitize_key((string) ($new_instance['type'] ?? 'card')); - if (!in_array($type, ['card', 'bigcard', 'image', 'simple'], true)) { - $type = 'card'; - } - $business = [ - 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), - 'source' => ($new_instance['source'] ?? '') === 'bookmarks' ? 'bookmarks' : 'settings', - 'type' => $type, - 'limit' => max(1, min(100, (int) ($new_instance['limit'] ?? 24))), - 'cats' => sanitize_text_field((string) ($new_instance['cats'] ?? '')), - 'blank' => !empty($new_instance['blank']) ? 1 : 0, - 'nofollow' => !empty($new_instance['nofollow']) ? 1 : 0, - 'go_link' => !empty($new_instance['go_link']) ? 1 : 0, - 'show_box' => !empty($new_instance['show_box']) ? 1 : 0, - 'orderby' => sanitize_key((string) ($new_instance['orderby'] ?? 'name')), - 'order' => strtoupper((string) ($new_instance['order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC', - // Keep legacy keys so old instances don't explode. - 'columns' => max(1, min(4, (int) ($new_instance['columns'] ?? 2))), - 'show_icon' => !empty($new_instance['show_icon']) ? 1 : 0, - ]; - return $this->update_common_fields($new_instance, $old_instance, $business); - } -} diff --git a/src/Widgets/WidgetBookmarkLinks.php b/src/Widgets/WidgetBookmarkLinks.php deleted file mode 100644 index 16402410..00000000 --- a/src/Widgets/WidgetBookmarkLinks.php +++ /dev/null @@ -1,179 +0,0 @@ - esc_html__('WordPress 链接(书签)列表:card / bigcard / image / simple。', 'aksrt'), - 'classname' => 'widget_aksrt_bookmark_links', - ] - ); - } - - public function widget($args, $instance): void { - $limit = max(0, min(100, (int) ($instance['links_limit'] ?? 12))); - $orderby = sanitize_key((string) ($instance['links_orderby'] ?? 'name')); - if (!in_array($orderby, ['name', 'updated', 'rating', 'rand', 'id'], true)) { - $orderby = 'name'; - } - $order = strtoupper((string) ($instance['links_order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC'; - // Zibll widget_ui_links_lists_2: type card/bigcard/image/simple. - $type = sanitize_key((string) ($instance['type'] ?? 'card')); - if (!in_array($type, ['card', 'bigcard', 'image', 'simple'], true)) { - $type = 'card'; - } - // Zibll alignment ('' / center / right). - $align = sanitize_key((string) ($instance['alignment'] ?? '')); - if (!in_array($align, ['', 'center', 'right'], true)) { - $align = ''; - } - $go_link = !empty($instance['go_link']); - $blank = !empty($instance['blank']); - $nofollow = !isset($instance['nofollow']) || !empty($instance['nofollow']); - $show_box = !empty($instance['show_box']); - - $bm_args = [ - 'orderby' => $orderby === 'rand' ? 'rand' : $orderby, - 'order' => $order, - 'limit' => $limit > 0 ? $limit : -1, - ]; - $cats = trim((string) ($instance['links_cats'] ?? '')); - if ($cats !== '' && $cats !== 'all') { - $bm_args['category'] = $cats; - } - $bookmarks = get_bookmarks($bm_args); - if (!$bookmarks) { - if (current_user_can('manage_options')) { - echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo function_exists('aksrt_get_widget_null') - ? aksrt_get_widget_null(__('暂无链接,请在「链接」中添加', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - : '

' . esc_html__('暂无链接', 'aksrt') . '

'; - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - 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 - } - - $wrap = 'aksrt-bookmark-links links-box style-' . $type . ($show_box ? ' has-box' : '') . ($align ? ' text-' . $align : ''); - echo '
'; - if (function_exists('aksrt_links_box')) { - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo aksrt_links_box($bookmarks, $type, $nofollow, $go_link, $blank); - } else { - // Minimal fallback. - foreach ($bookmarks as $b) { - $url = (string) $b->link_url; - if ($url !== '' && $go_link && function_exists('aksrt_go_link')) { - $url = aksrt_go_link($url, true); - } - echo ''; - echo esc_html((string) $b->link_name); - echo ''; - } - } - echo '
'; - - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - public function form($instance): void { - ?> -

- -

-

- -

-

- -

-

- -

-

- - -

-

- -

-

-
-
-
- -

- render_common_form_section($instance); -} - - public function update($new_instance, $old_instance): array { - $type = sanitize_key((string) ($new_instance['type'] ?? 'card')); - if (!in_array($type, ['card', 'bigcard', 'image', 'simple'], true)) { - $type = 'card'; - } - $business = [ - 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), - 'links_cats' => sanitize_text_field((string) ($new_instance['links_cats'] ?? '')), - 'links_limit' => max(0, min(100, (int) ($new_instance['links_limit'] ?? 12))), - 'links_orderby' => sanitize_key((string) ($new_instance['links_orderby'] ?? 'name')), - 'links_order' => strtoupper((string) ($new_instance['links_order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC', - 'type' => $type, - 'alignment' => in_array((string) ($new_instance['alignment'] ?? ''), ['', 'center', 'right'], true) ? $new_instance['alignment'] : '', - 'blank' => !empty($new_instance['blank']) ? 1 : 0, - 'nofollow' => !empty($new_instance['nofollow']) ? 1 : 0, - 'go_link' => !empty($new_instance['go_link']) ? 1 : 0, - 'show_box' => !empty($new_instance['show_box']) ? 1 : 0, - ]; return $this->update_common_fields($new_instance, $old_instance, $business); - } -} diff --git a/src/Widgets/WidgetFaq.php b/src/Widgets/WidgetFaq.php deleted file mode 100644 index 2ac89f0a..00000000 --- a/src/Widgets/WidgetFaq.php +++ /dev/null @@ -1,360 +0,0 @@ - esc_html__('FAQ 摘要卡 + 文档链接列表 + 帮助 CTA。', 'aksrt'), - 'classname' => 'widget_aksrt_faq', - ] - ); - } - - public function widget($args, $instance): void { - $faqs = $this->normalize_faqs($instance['faqs'] ?? []); - if (!$faqs) { - if (current_user_can('manage_options')) { - echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo function_exists('aksrt_get_widget_null') - ? aksrt_get_widget_null(__('请添加至少一条问题', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - : '
' . esc_html__('常见问题解答:', 'aksrt') . '' . esc_html__('请添加至少一条问题', 'aksrt') . '
'; - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - 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 - } - - $uid = 'aksrt-faq-' . esc_attr($this->id); - echo '
'; - - if (!empty($instance['search_s'])) { - $ph = (string) ($instance['search_placeholder'] ?? __('搜索问题…', 'aksrt')); - $btn = (string) ($instance['search_btn_text'] ?? __('搜索', 'aksrt')); - echo '
'; - echo '
'; - } - - $doc_title = trim((string) ($instance['doc_title'] ?? '')); - $doc_desc = trim((string) ($instance['doc_desc'] ?? '')); - $doc_icon = sanitize_text_field((string) ($instance['doc_icon'] ?? 'fas fa-book')); - $doc_links = $this->normalize_doc_links($instance['doc_links'] ?? []); - $help_title = trim((string) ($instance['help_title'] ?? '')); - $help_sub = trim((string) ($instance['help_subtitle'] ?? '')); - $help_icon = sanitize_text_field((string) ($instance['help_icon'] ?? 'fas fa-graduation-cap')); - $help_url = esc_url_raw(trim((string) ($instance['help_btn_url'] ?? ''))); - $help_btn = trim((string) ($instance['help_btn_text'] ?? '')); - - $has_doc = ($doc_title !== '' || $doc_desc !== '' || $doc_links); - $has_help = ($help_title !== '' || $help_sub !== '' || ($help_btn !== '' && $help_url !== '')); - - $main_cls = 'aksrt-faq__main produck-faq-main'; - if (!$has_doc && !$has_help) { - $main_cls .= ' is-full'; - } - echo '
'; - echo '
'; - - $n = 0; - foreach ($faqs as $f) { - $n++; - $num = str_pad((string) $n, 2, '0', STR_PAD_LEFT); - $tone = self::BADGE_TONES[($n - 1) % count(self::BADGE_TONES)]; - $preview = $f['answer'] !== '' ? wp_strip_all_tags($f['answer']) : ''; - if ($preview !== '') { - $preview = wp_trim_words($preview, 28); - } - echo '
'; - echo ''; - echo '' . esc_html($num) . ''; - echo ''; - echo '' . esc_html($f['question']) . ''; - if ($preview !== '') { - echo '' . esc_html($preview) . ''; - } - echo ''; - echo ''; - echo ''; - if ($f['answer'] !== '') { - echo '
' . wp_kses_post(wpautop($f['answer'])) . '
'; - } - echo '
'; - } - echo '
'; - - if ($has_doc || $has_help) { - echo ''; - } - - echo '
'; - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - /** - * @param mixed $raw - * @return array - */ - private function normalize_faqs($raw): array { - if (is_string($raw)) { - $decoded = json_decode($raw, true); - $raw = is_array($decoded) ? $decoded : []; - } - if (!is_array($raw)) { - return []; - } - $out = []; - foreach ($raw as $row) { - if (!is_array($row)) { - continue; - } - $q = sanitize_text_field((string) ($row['question'] ?? $row['q'] ?? '')); - if ($q === '') { - continue; - } - $out[] = [ - 'question' => $q, - 'answer' => wp_kses_post((string) ($row['answer'] ?? $row['a'] ?? '')), - 'category' => sanitize_key((string) ($row['category'] ?? 'all')), - ]; - if (count($out) >= 30) { - break; - } - } - return $out; - } - - /** - * @param mixed $raw - * @return array - */ - private function normalize_doc_links($raw): array { - if (is_string($raw)) { - $decoded = json_decode($raw, true); - $raw = is_array($decoded) ? $decoded : []; - } - if (!is_array($raw)) { - return []; - } - $out = []; - foreach ($raw as $row) { - if (!is_array($row)) { - continue; - } - $title = sanitize_text_field((string) ($row['title'] ?? '')); - $url = esc_url_raw(trim((string) ($row['url'] ?? $row['link'] ?? ''))); - if ($title === '' && $url === '') { - continue; - } - $out[] = [ - 'title' => $title, - 'url' => $url, - 'desc' => sanitize_text_field((string) ($row['desc'] ?? '')), - 'icon' => sanitize_text_field((string) ($row['icon'] ?? '')), - 'tag' => sanitize_text_field((string) ($row['tag'] ?? '')), - 'btn_text' => sanitize_text_field((string) ($row['btn_text'] ?? '')), - ]; - if (count($out) >= 12) { - break; - } - } - return $out; - } - - public function form($instance): void { - $faqs = $this->normalize_faqs($instance['faqs'] ?? []); - if (!$faqs) { - $faqs = [ - ['question' => '', 'answer' => '', 'category' => 'all'], - ['question' => '', 'answer' => '', 'category' => 'all'], - ]; - } - $doc_links = $this->normalize_doc_links($instance['doc_links'] ?? []); - if (!$doc_links) { - $doc_links = [ - ['title' => '', 'url' => '', 'desc' => '', 'icon' => 'fas fa-file-alt', 'tag' => '', 'btn_text' => ''], - ]; - } - ?> -

- -

-

- -

-

- -

-

- -

-

- -

-
-

-

- -

-

- -

-

- -

-

- -

-
-

-

- -

-

- -

-

- -

-

- -

-

- -

- render_common_form_section($instance); -} - - public function update($new_instance, $old_instance): array { - $business = [ - 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), - 'search_s' => !empty($new_instance['search_s']) ? 1 : 0, - 'search_placeholder' => sanitize_text_field((string) ($new_instance['search_placeholder'] ?? '')), - 'search_btn_text' => sanitize_text_field((string) ($new_instance['search_btn_text'] ?? '')), - 'faqs' => $this->normalize_faqs($new_instance['faqs'] ?? []), - 'doc_title' => sanitize_text_field((string) ($new_instance['doc_title'] ?? '')), - 'doc_desc' => sanitize_textarea_field((string) ($new_instance['doc_desc'] ?? '')), - 'doc_icon' => sanitize_text_field((string) ($new_instance['doc_icon'] ?? '')), - 'doc_links' => $this->normalize_doc_links($new_instance['doc_links'] ?? []), - 'help_title' => sanitize_text_field((string) ($new_instance['help_title'] ?? '')), - 'help_subtitle' => sanitize_textarea_field((string) ($new_instance['help_subtitle'] ?? '')), - 'help_icon' => sanitize_text_field((string) ($new_instance['help_icon'] ?? '')), - 'help_btn_text' => sanitize_text_field((string) ($new_instance['help_btn_text'] ?? '')), - 'help_btn_url' => esc_url_raw(trim((string) ($new_instance['help_btn_url'] ?? ''))), - ]; return $this->update_common_fields($new_instance, $old_instance, $business); - } -} diff --git a/src/Widgets/WidgetHighlights.php b/src/Widgets/WidgetHighlights.php deleted file mode 100644 index fa282285..00000000 --- a/src/Widgets/WidgetHighlights.php +++ /dev/null @@ -1,211 +0,0 @@ - esc_html__('大中小尺寸亮点/卖点卡片栅格。', 'aksrt'), - 'classname' => 'widget_aksrt_highlights', - ] - ); - } - - /** - * @param array $args - * @param array $instance - */ - public function widget($args, $instance): void { - $cards = $this->normalize($instance['cards'] ?? []); - if (!$cards) { - if (current_user_can('manage_options')) { - echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo function_exists('aksrt_get_widget_null') - ? aksrt_get_widget_null(__('请添加至少一张亮点卡片', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - : '

' . esc_html__('请添加至少一张亮点卡片', 'aksrt') . '

'; - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - return; - } - $go_link = !empty($instance['go_link']); - $anim = sanitize_key((string) ($instance['obs_animation'] ?? 'slideup')); - $anim_repeat = !empty($instance['animation_repeat']); - - 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 - } - - $large = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'large')); - $medium = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'medium')); - $small = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'small')); - if (!$large && !$medium && !$small) { - $medium = $cards; - } - - echo '
'; - $idx = 0; - foreach (['large' => $large, 'medium' => $medium, 'small' => $small] as $size => $group) { - if (!$group) { - continue; - } - echo '
'; - foreach ($group as $c) { - $pack = function_exists('aksrt_obs_animate_attrs') - ? aksrt_obs_animate_attrs($anim, $anim_repeat, $idx * 0.08) - : ['class' => '', 'attr' => '']; - echo $this->card($c, $size, $go_link, $pack); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - $idx++; - } - echo '
'; - } - echo '
'; - - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - /** - * @param array $c - * @param array{class:string,attr:string} $pack - */ - private function card(array $c, string $size, bool $go_link, array $pack): string { - $color = sanitize_key((string) ($c['color'] ?? 'blue')); - if (!in_array($color, ['blue', 'pink', 'purple', 'green', 'orange', 'cyan'], true)) { - $color = 'blue'; - } - $url = (string) ($c['url'] ?? ''); - if ($url !== '' && $go_link && function_exists('aksrt_go_link')) { - $url = aksrt_go_link($url, true); - } - $tag = $url !== '' ? 'a' : 'div'; - $href = $url !== '' ? ' href="' . esc_url($url) . '"' : ''; - $img = (string) ($c['image'] ?? ''); - $cls = 'aksrt-hl-card size-' . esc_attr($size) . ' color-' . esc_attr($color) . $pack['class']; - $html = '<' . $tag . ' class="' . esc_attr(trim($cls)) . '"' . $href . $pack['attr'] . '>'; - if ($img !== '') { - $placeholder = get_template_directory_uri() . '/assets/img/placeholder.svg'; - $html .= '
'; - } - $html .= '
'; - if (!empty($c['icon'])) { - $html .= '
'; - } - if ($c['title'] !== '') { - $html .= '
' . esc_html($c['title']) . '
'; - } - if ($c['desc'] !== '') { - $html .= '
' . esc_html($c['desc']) . '
'; - } - $html .= '
'; - return $html; - } - - /** - * @param mixed $raw - * @return array> - */ - private function normalize($raw): array { - if (is_string($raw)) { - $decoded = json_decode($raw, true); - $raw = is_array($decoded) ? $decoded : []; - } - if (!is_array($raw)) { - return []; - } - $out = []; - foreach ($raw as $row) { - if (!is_array($row)) { - continue; - } - $title = sanitize_text_field((string) ($row['title'] ?? '')); - $desc = sanitize_text_field((string) ($row['desc'] ?? '')); - if ($title === '' && $desc === '') { - continue; - } - $size = sanitize_key((string) ($row['size'] ?? 'medium')); - if (!in_array($size, ['large', 'medium', 'small'], true)) { - $size = 'medium'; - } - $out[] = [ - 'title' => $title, - 'desc' => $desc, - 'icon' => sanitize_text_field((string) ($row['icon'] ?? '')), - 'image' => esc_url_raw(trim((string) ($row['image'] ?? ''))), - 'url' => esc_url_raw(trim((string) ($row['url'] ?? ''))), - 'color' => sanitize_key((string) ($row['color'] ?? 'blue')), - 'size' => $size, - ]; - if (count($out) >= 12) { - break; - } - } - return $out; - } - - /** - * @param array $instance - */ - public function form($instance): void { - $json = is_string($instance['cards'] ?? null) - ? (string) $instance['cards'] - : wp_json_encode($this->normalize($instance['cards'] ?? []), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - ?> -

- -

-

- - -

-

- -

-

- -

- render_common_form_section($instance); -} - - /** - * @param array $new_instance - * @param array $old_instance - * @return array - */ - public function update($new_instance, $old_instance): array { - $business = [ - 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), - 'cards' => $this->normalize($new_instance['cards'] ?? []), - 'go_link' => !empty($new_instance['go_link']) ? 1 : 0, - 'obs_animation' => sanitize_key((string) ($new_instance['obs_animation'] ?? 'slideup')), - 'animation_repeat' => !empty($new_instance['animation_repeat']) ? 1 : 0, - ]; return $this->update_common_fields($new_instance, $old_instance, $business); - } -} diff --git a/src/Widgets/WidgetTiltCases.php b/src/Widgets/WidgetTiltCases.php deleted file mode 100644 index b767ae28..00000000 --- a/src/Widgets/WidgetTiltCases.php +++ /dev/null @@ -1,272 +0,0 @@ - esc_html__('左文案 + 右侧叠层图片案例展示。', 'aksrt'), - 'classname' => 'widget_aksrt_tilt_cases', - ] - ); - } - - public function widget($args, $instance): void { - $title = trim((string) ($instance['intro_title'] ?? '')); - $subtitle = trim((string) ($instance['intro_subtitle'] ?? '')); - $badge = trim((string) ($instance['intro_badge_text'] ?? '')); - $images = $this->normalize_images($instance['intro_showcase_images'] ?? []); - $features = $this->normalize_features($instance['intro_features'] ?? []); - $buttons = $this->normalize_buttons($instance['intro_buttons'] ?? []); - - if ($title === '' && $subtitle === '' && !$images) { - if (current_user_can('manage_options')) { - echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo function_exists('aksrt_get_widget_null') - ? aksrt_get_widget_null(__('请配置标题或案例图片', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - : '

' . esc_html__('请配置标题或案例图片', 'aksrt') . '

'; - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - return; - } - - echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - - echo '
'; - $pack = function_exists('aksrt_obs_animate_attrs') ? aksrt_obs_animate_attrs('slideup', false, 0) : ['class' => '', 'attr' => '']; - echo '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - if ($badge !== '') { - $icon = sanitize_text_field((string) ($instance['intro_badge_icon'] ?? '')); - echo '
'; - if ($icon !== '') { - echo ' '; - } - echo esc_html($badge) . '
'; - } - if ($title !== '') { - $highlight = trim((string) ($instance['intro_title_highlight'] ?? '')); - $title_html = esc_html($title); - if ($highlight !== '') { - $h = esc_html($highlight); - $title_html = str_replace($h, '' . $h . '', $title_html); - } - echo '

' . $title_html . '

'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - if ($subtitle !== '') { - echo '

' . esc_html($subtitle) . '

'; - } - if ($features) { - echo '
    '; - foreach ($features as $f) { - echo '
  • '; - if ($f['icon'] !== '') { - echo ' '; - } - echo esc_html($f['text']) . '
  • '; - } - echo '
'; - } - if ($buttons) { - echo '
'; - foreach ($buttons as $b) { - $url = $b['url']; - if ($url !== '' && !empty($instance['go_link']) && function_exists('aksrt_go_link')) { - $url = aksrt_go_link($url, true); - } - echo '' . esc_html($b['text']) . ''; - } - echo '
'; - } - echo '
'; - - echo '
'; - if ($images) { - foreach ($images as $i => $img) { - $cls = $i === 0 ? ' is-main' : ''; - $placeholder = get_template_directory_uri() . '/assets/img/placeholder.svg'; - echo '
'; - } - } else { - echo '
'; - } - echo '
'; - - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - /** @param mixed $raw @return array */ - private function normalize_images($raw): array { - if (is_string($raw)) { - $decoded = json_decode($raw, true); - if (is_array($decoded)) { - $raw = $decoded; - } else { - $parts = preg_split('/\r\n|\r|\n|,/', $raw) ?: []; - $raw = $parts; - } - } - if (!is_array($raw)) { - return []; - } - $out = []; - foreach ($raw as $row) { - if (is_array($row)) { - $url = esc_url_raw(trim((string) ($row['image'] ?? $row['url'] ?? ''))); - } else { - $url = esc_url_raw(trim((string) $row)); - } - if ($url !== '') { - $out[] = $url; - } - if (count($out) >= 5) { - break; - } - } - return $out; - } - - /** @param mixed $raw @return array */ - private function normalize_features($raw): array { - if (is_string($raw)) { - $decoded = json_decode($raw, true); - $raw = is_array($decoded) ? $decoded : []; - } - if (!is_array($raw)) { - return []; - } - $out = []; - foreach ($raw as $row) { - if (is_string($row)) { - $text = sanitize_text_field($row); - $icon = ''; - } elseif (is_array($row)) { - $text = sanitize_text_field((string) ($row['text'] ?? '')); - $icon = sanitize_text_field((string) ($row['icon'] ?? '')); - } else { - continue; - } - if ($text === '') { - continue; - } - $out[] = ['text' => $text, 'icon' => $icon]; - if (count($out) >= 8) { - break; - } - } - return $out; - } - - /** @param mixed $raw @return array */ - private function normalize_buttons($raw): array { - if (is_string($raw)) { - $decoded = json_decode($raw, true); - $raw = is_array($decoded) ? $decoded : []; - } - if (!is_array($raw)) { - return []; - } - $out = []; - foreach ($raw as $row) { - if (!is_array($row)) { - continue; - } - $text = sanitize_text_field((string) ($row['text'] ?? $row['btn']['text'] ?? '')); - $url = esc_url_raw(trim((string) ($row['url'] ?? $row['btn']['url'] ?? ''))); - if ($text === '') { - continue; - } - $out[] = ['text' => $text, 'url' => $url]; - if (count($out) >= 4) { - break; - } - } - return $out; - } - - public function form($instance): void { - $images = is_string($instance['intro_showcase_images'] ?? null) - ? (string) $instance['intro_showcase_images'] - : wp_json_encode($this->normalize_images($instance['intro_showcase_images'] ?? []), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - $features = is_string($instance['intro_features'] ?? null) - ? (string) $instance['intro_features'] - : wp_json_encode($this->normalize_features($instance['intro_features'] ?? []), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - $buttons = is_string($instance['intro_buttons'] ?? null) - ? (string) $instance['intro_buttons'] - : wp_json_encode($this->normalize_buttons($instance['intro_buttons'] ?? []), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - ?> -

- -

-

- -

-

- -

-

- -

-

- -

-

- -

-

- -

-

- -

-

- -

- render_common_form_section($instance); -} - - public function update($new_instance, $old_instance): array { - $business = [ - 'intro_badge_text' => sanitize_text_field((string) ($new_instance['intro_badge_text'] ?? '')), - 'intro_badge_icon' => sanitize_text_field((string) ($new_instance['intro_badge_icon'] ?? '')), - 'intro_title' => sanitize_textarea_field((string) ($new_instance['intro_title'] ?? '')), - 'intro_title_highlight' => sanitize_text_field((string) ($new_instance['intro_title_highlight'] ?? '')), - 'intro_subtitle' => sanitize_textarea_field((string) ($new_instance['intro_subtitle'] ?? '')), - 'intro_features' => $this->normalize_features($new_instance['intro_features'] ?? []), - 'intro_buttons' => $this->normalize_buttons($new_instance['intro_buttons'] ?? []), - 'intro_showcase_images' => $this->normalize_images($new_instance['intro_showcase_images'] ?? []), - 'go_link' => !empty($new_instance['go_link']) ? 1 : 0, - ]; return $this->update_common_fields($new_instance, $old_instance, $business); - } -} diff --git a/src/Widgets/WidgetUserLists.php b/src/Widgets/WidgetUserLists.php deleted file mode 100644 index 7776281f..00000000 --- a/src/Widgets/WidgetUserLists.php +++ /dev/null @@ -1,228 +0,0 @@ - esc_html__('展示站点用户迷你名片(头像/身份/关注/简介)。', 'aksrt'), - 'classname' => 'widget_aksrt_user_lists', - ] - ); - } - - /** @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)); - } - - /** - * @param array $instance - */ - public static function render_html(array $instance): string { - $number = max(1, min(50, (int) ($instance['number'] ?? 8))); - $orderby = sanitize_key((string) ($instance['orderby'] ?? 'user_registered')); - $order = strtoupper((string) ($instance['order'] ?? 'DESC')) === 'ASC' ? 'ASC' : 'DESC'; - $include = self::parse_ids_static((string) ($instance['include'] ?? '')); - $exclude = self::parse_ids_static((string) ($instance['exclude'] ?? '')); - $hide_box = !empty($instance['hide_box']); - $blur_bg = !empty($instance['blur_bg']); - - $query = [ - 'number' => $number, - 'order' => $order, - 'fields' => ['ID', 'display_name', 'user_nicename'], - ]; - if ($include) { - $query['include'] = $include; - $query['orderby'] = 'include'; - } else { - switch ($orderby) { - case 'display_name': - $query['orderby'] = 'display_name'; - break; - case 'post_count': - $query['orderby'] = 'post_count'; - break; - case 'last_login': - $query['meta_key'] = 'aksrt_last_login'; - $query['orderby'] = 'meta_value'; - break; - case 'followed-user-count': - $query['meta_key'] = 'aksrt_follower_count'; - $query['orderby'] = 'meta_value_num'; - break; - default: - $query['orderby'] = 'user_registered'; - } - } - if ($exclude) { - $query['exclude'] = $exclude; - } - - $users = get_users($query); - if (!$users) { - return function_exists('aksrt_get_ajax_null') - ? aksrt_get_ajax_null(__('暂无用户', 'aksrt')) - : '

' . esc_html__('暂无用户', 'aksrt') . '

'; - } - - if ($orderby === 'followed-user-count' && !$include && class_exists('\AKSRT\User\Follow')) { - $has_meta = false; - foreach ($users as $u) { - if ((int) get_user_meta($u->ID, 'aksrt_follower_count', true) > 0) { - $has_meta = true; - break; - } - } - if (!$has_meta) { - usort($users, static function ($a, $b) { - $fa = \AKSRT\User\Follow::get_instance()->get_follower_count((int) $a->ID); - $fb = \AKSRT\User\Follow::get_instance()->get_follower_count((int) $b->ID); - return $fb <=> $fa; - }); - } - } - - ob_start(); - // zibll: optional zib-widget + text-center user_lists of author-minicard. - $outer = $hide_box ? 'aksrt-user-lists is-bare ajax-item' : 'aksrt-user-lists zib-widget ajax-item'; - echo '
'; - echo '
'; - foreach ($users as $user) { - $uid = (int) $user->ID; - if (function_exists('aksrt_author_minicard')) { - echo aksrt_author_minicard($uid, 'mb10', $blur_bg); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } else { - $avatar = function_exists('aksrt_get_avatar_url') - ? aksrt_get_avatar_url($uid, ['size' => 96]) - : get_avatar_url($uid, ['size' => 96]); - $home = function_exists('aksrt_get_user_home_url') - ? aksrt_get_user_home_url($uid) - : get_author_posts_url($uid); - $name = $user->display_name ?: $user->user_nicename; - echo ''; - echo ' '; - echo esc_html($name); - echo ''; - } - } - echo '
'; - return (string) ob_get_clean(); - } - - /** - * @param array $args - * @param array $instance - */ - public function widget($args, $instance): void { - $html = self::render_html($instance); - 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 - } - echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - /** - * @param array $instance - */ - public function form($instance): void { - ?> -

- -

-

- -

-

- -

-

- -

-

- -

-

- -

-

-
- -

- render_common_form_section($instance); -} - - /** - * @param array $new_instance - * @param array $old_instance - * @return array - */ - public function update($new_instance, $old_instance): array { - $orderby = sanitize_key((string) ($new_instance['orderby'] ?? 'user_registered')); - $allowed = ['user_registered', 'display_name', 'post_count', 'last_login', 'followed-user-count']; - if (!in_array($orderby, $allowed, true)) { - $orderby = 'user_registered'; - } - $business = [ - 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), - 'number' => max(1, min(50, (int) ($new_instance['number'] ?? 8))), - 'include' => sanitize_text_field((string) ($new_instance['include'] ?? '')), - 'exclude' => sanitize_text_field((string) ($new_instance['exclude'] ?? '')), - 'orderby' => $orderby, - 'order' => strtoupper((string) ($new_instance['order'] ?? 'DESC')) === 'ASC' ? 'ASC' : 'DESC', - 'hide_box' => !empty($new_instance['hide_box']) ? 1 : 0, - 'blur_bg' => !empty($new_instance['blur_bg']) ? 1 : 0, - ]; return $this->update_common_fields($new_instance, $old_instance, $business); - } -} diff --git a/src/Widgets/WidgetUserRanking.php b/src/Widgets/WidgetUserRanking.php deleted file mode 100644 index 54104699..00000000 --- a/src/Widgets/WidgetUserRanking.php +++ /dev/null @@ -1,379 +0,0 @@ - __('按积分、文章数或粉丝数排行的用户列表。', 'aksrt'), - 'classname' => 'widget_aksrt_user_ranking', - ] - ); - } - - public function widget($args, $instance): void { - $title = !empty($instance['title']) ? (string) $instance['title'] : __('排行榜', 'aksrt'); - // Zibll zib_widget_ui_user_ranking: `orderby` (default checkin_all_day) + `number`. - // Accept AKSRT legacy `rank_by`/`count` as aliases. - $rank_by = (string) ($instance['orderby'] ?? $instance['rank_by'] ?? 'checkin_all_day'); - // Map Zibll `points` → AKSRT `credits`; `followed-user-count` → `followers`. - $rank_aliases = [ - 'points' => 'credits', - 'followed-user-count' => 'followers', - 'checkin_all_day' => 'checkin_all_day', - 'checkin_continuous_day' => 'checkin_continuous_day', - 'credits' => 'credits', - 'posts' => 'posts', - 'followers' => 'followers', - ]; - $rank_by = $rank_aliases[$rank_by] ?? 'checkin_all_day'; - $count = max(1, min(20, (int) ($instance['number'] ?? $instance['count'] ?? 6))); - $show_avatar = !isset($instance['show_avatar']) || !empty($instance['show_avatar']); - $desc_mode = sanitize_key((string) ($instance['desc'] ?? 'desc')); - $top_badge = !empty($instance['top_badge']); - $affix = function_exists('aksrt_widget_affix_attrs') ? aksrt_widget_affix_attrs($instance) : ['class' => '', 'attr' => '']; - $users = $this->get_ranking($rank_by, $count, $desc_mode); - - 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 - - $box_cls = 'zib-widget user-ranking-box aksrt-user-ranking-box' . $affix['class']; - echo '
'; - if (!empty($instance['checkin_btn']) && is_user_logged_in() && function_exists('aksrt_header_user_checkin_btn')) { - $cbtn = aksrt_header_user_checkin_btn(get_current_user_id()); - if ($cbtn !== '') { - echo '
' . $cbtn . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - } - - if (empty($users)) { - echo function_exists('aksrt_get_widget_null') - ? aksrt_get_widget_null(__('暂无排行数据', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - : '

' . esc_html__('暂无排行数据', 'aksrt') . '

'; - echo '
'; - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - return; - } - - $ph = get_template_directory_uri() . '/assets/img/placeholder.svg'; - $rank = 0; - foreach ($users as $user) { - $rank++; - $uid = (int) $user['id']; - $user_url = function_exists('aksrt_get_user_home_url') - ? aksrt_get_user_home_url($uid) - : get_author_posts_url($uid); - - $top_bagd = ''; - if ($top_badge && $rank <= 3) { - $tone = $rank === 1 ? 'jb-red' : ($rank === 2 ? 'jb-yellow' : 'b-gray'); - $top_bagd = 'TOP' . (int) $rank . ''; - } - - $name_html = function_exists('aksrt_get_user_name') - ? aksrt_get_user_name([ - 'id' => $uid, - 'class' => 'flex ac flex1', - 'follow' => false, - 'medal' => true, - 'level' => true, - ]) - : '' . esc_html((string) $user['name']) . ''; - - $avatar_html = ''; - if ($show_avatar) { - $avatar_url = function_exists('aksrt_get_avatar_url') - ? aksrt_get_avatar_url($uid, ['size' => 42]) - : get_avatar_url($uid, ['size' => 42]); - $avatar_html = ''; - } - - $desc = (string) ($user['desc'] ?? ''); - $value_label = (string) ($user['value_label'] ?? $user['value'] ?? ''); - $value_icon = (string) ($user['value_icon'] ?? 'fa-trophy'); - $right_badge = '' . esc_html((string) ($user['value_num'] ?? $user['value'] ?? '')) . ''; - - $mt = $rank > 1 ? ' mt20' : ''; - echo '
'; - echo $top_bagd; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo '
'; - } - echo ''; - - echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - - /** - * @return list - */ - private function get_ranking(string $rank_by, int $count, string $desc_mode = 'desc'): array { - $users = []; - - switch ($rank_by) { - case 'credits': - global $wpdb; - $rows = $wpdb->get_results($wpdb->prepare( - "SELECT user_id, meta_value as credits FROM {$wpdb->usermeta} - WHERE meta_key = 'aksrt_credits' - ORDER BY CAST(meta_value AS UNSIGNED) DESC - LIMIT %d", - $count - ), ARRAY_A); - foreach ((array) $rows as $row) { - $user = get_userdata((int) $row['user_id']); - if ($user) { - $num = (int) $row['credits']; - $users[] = [ - 'id' => (int) $row['user_id'], - 'name' => $user->display_name, - 'value' => number_format_i18n($num) . ' 积分', - 'value_num' => (string) number_format_i18n($num), - 'value_label' => sprintf(__('积分:%s', 'aksrt'), number_format_i18n($num)), - 'value_icon' => 'fa-diamond', - 'desc' => $this->user_extra_desc((int) $row['user_id'], $user, $desc_mode), - ]; - } - } - break; - - case 'posts': - $blog_users = get_users([ - 'number' => $count, - 'orderby' => 'post_count', - 'order' => 'DESC', - 'who' => 'authors', - ]); - foreach ($blog_users as $user) { - $post_count = count_user_posts($user->ID, 'post', true); - if ($post_count > 0) { - $users[] = [ - 'id' => $user->ID, - 'name' => $user->display_name, - 'value' => number_format_i18n($post_count) . ' 篇', - 'value_num' => (string) number_format_i18n($post_count), - 'value_label' => sprintf(__('共%d篇文章', 'aksrt'), $post_count), - 'value_icon' => 'fa-file-text-o', - 'desc' => $this->user_extra_desc($user->ID, $user, $desc_mode), - ]; - } - } - break; - - case 'checkin_all_day': - $users = $this->meta_rank('aksrt_checkin_all_day', ['checkin_all_day'], $count, $desc_mode, 'fa-calendar-check-o', __('累计签到%d天', 'aksrt'), ' 天'); - break; - - case 'checkin_continuous_day': - $users = $this->meta_rank('aksrt_checkin_continuous_day', ['checkin_continuous_day'], $count, $desc_mode, 'fa-calendar-check-o', __('连续签到%d天', 'aksrt'), ' 天'); - break; - - case 'followers': - if (class_exists('\AKSRT\User\Follow')) { - global $wpdb; - $follow_table = \AKSRT\Core\DBMigrator::table('follow'); - if ($follow_table) { - $rows = $wpdb->get_results($wpdb->prepare( - "SELECT following_id, COUNT(*) as cnt - FROM {$follow_table} - GROUP BY following_id - ORDER BY cnt DESC - LIMIT %d", - $count - ), ARRAY_A); - foreach ((array) $rows as $row) { - $user = get_userdata((int) $row['following_id']); - if ($user) { - $num = (int) $row['cnt']; - $users[] = [ - 'id' => (int) $row['following_id'], - 'name' => $user->display_name, - 'value' => number_format_i18n($num) . ' 粉丝', - 'value_num' => (string) number_format_i18n($num), - 'value_label' => sprintf(__('共%d个粉丝', 'aksrt'), $num), - 'value_icon' => 'fa-heart', - 'desc' => $this->user_extra_desc((int) $row['following_id'], $user, $desc_mode), - ]; - } - } - } - } - break; - } - - return $users; - } - - /** - * @param list $alt_keys - * @return list - */ - private function meta_rank(string $primary_key, array $alt_keys, int $count, string $desc_mode, string $icon, string $label_tpl, string $suffix): array { - global $wpdb; - $keys = array_merge([$primary_key], $alt_keys); - $in = implode(',', array_fill(0, count($keys), '%s')); - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared - $sql = $wpdb->prepare( - "SELECT user_id, meta_value as val FROM {$wpdb->usermeta} - WHERE meta_key IN ($in) - ORDER BY CAST(meta_value AS UNSIGNED) DESC - LIMIT %d", - ...array_merge($keys, [$count * 2]) - ); - $rows = $wpdb->get_results($sql, ARRAY_A); - $seen = []; - $users = []; - foreach ((array) $rows as $row) { - $uid = (int) $row['user_id']; - if (isset($seen[$uid])) { - continue; - } - $seen[$uid] = true; - $user = get_userdata($uid); - if (!$user) { - continue; - } - $num = (int) $row['val']; - $users[] = [ - 'id' => $uid, - 'name' => $user->display_name, - 'value' => number_format_i18n($num) . $suffix, - 'value_num' => (string) number_format_i18n($num), - 'value_label' => sprintf($label_tpl, $num), - 'value_icon' => $icon, - 'desc' => $this->user_extra_desc($uid, $user, $desc_mode), - ]; - if (count($users) >= $count) { - break; - } - } - return $users; - } - - private function user_extra_desc(int $user_id, $user, string $mode): string { - switch ($mode) { - case 'user_registered': - if ($user && !empty($user->user_registered)) { - $days = max(0, (int) floor((time() - strtotime($user->user_registered)) / DAY_IN_SECONDS)); - return sprintf(__('加入 %d 天', 'aksrt'), $days); - } - return ''; - case 'last_login': - $t = (string) get_user_meta($user_id, 'aksrt_last_login', true); - if ($t === '') { - $t = (string) get_user_meta($user_id, 'last_login', true); - } - return $t !== '' ? sprintf(__('最近登录 %s', 'aksrt'), $t) : ''; - case 'last_checkin': - $t = (string) get_user_meta($user_id, 'aksrt_last_checkin', true); - if ($t === '') { - $t = (string) get_user_meta($user_id, 'last_checkin', true); - } - return $t !== '' ? sprintf(__('最近签到 %s', 'aksrt'), $t) : ''; - case 'desc': - default: - $bio = get_user_meta($user_id, 'description', true); - if (!is_string($bio) || $bio === '') { - $bio = $user ? (string) $user->description : ''; - } - return $bio !== '' ? wp_trim_words($bio, 12) : ''; - } - } - - public function form($instance): void { - $title = !empty($instance['title']) ? $instance['title'] : __('排行榜', 'aksrt'); - // Zibll field is `orderby` (default checkin_all_day); accept legacy `rank_by`. - $rank_by = (string) ($instance['orderby'] ?? $instance['rank_by'] ?? 'checkin_all_day'); - $count = !empty($instance['number']) ? (int) $instance['number'] : (!empty($instance['count']) ? (int) $instance['count'] : 6); - $show_avatar = !isset($instance['show_avatar']) || !empty($instance['show_avatar']); - ?> -

- - -

-

- - -

-

- - -

-

- -

-

- - -

-

- -

-

- -

- render_common_form_section($instance); ?> - update_common_fields($new_instance, $old_instance, [ - 'title' => sanitize_text_field($new_instance['title'] ?? ''), - 'orderby' => $rank_by, - 'rank_by' => $rank_by, // keep alias for any legacy readers. - 'number' => max(1, min(20, (int) ($new_instance['number'] ?? $new_instance['count'] ?? 6))), - 'count' => max(1, min(20, (int) ($new_instance['number'] ?? $new_instance['count'] ?? 6))), - 'show_avatar' => !empty($new_instance['show_avatar']) ? 1 : 0, - 'checkin_btn' => !empty($new_instance['checkin_btn']) ? 1 : 0, - 'top_badge' => !empty($new_instance['top_badge']) ? 1 : 0, - 'desc' => in_array($new_instance['desc'] ?? '', ['desc', 'user_registered', 'last_login', 'last_checkin'], true) ? $new_instance['desc'] : 'desc', - ]); - } -}