From 7a91eb7321d49bc98f672f8c39b3a16348a06106 Mon Sep 17 00:00:00 2001
From: unknown
Date: Sun, 19 Jul 2026 01:06:20 +0800
Subject: [PATCH] feat(widgets): user-card guest/login depth, main posts, term
aggregation
1:1 zibll user widget guest shell + checkin/actions, main post list
styles, term aggregation cards, and ranking by check-in days.
---
assets/css/frontend/widget-batch5.css | 229 +++++++++++++++
assets/css/frontend/widgets.css | 1 +
inc/modules/widgets-register.php | 2 +
src/AKSRT/Widgets/WidgetMainPosts.php | 207 +++++++++++++
src/AKSRT/Widgets/WidgetTermAggregation.php | 197 +++++++++++++
src/AKSRT/Widgets/WidgetUserCard.php | 304 ++++++++++++--------
src/AKSRT/Widgets/WidgetUserRanking.php | 70 ++++-
7 files changed, 884 insertions(+), 126 deletions(-)
create mode 100644 assets/css/frontend/widget-batch5.css
create mode 100644 src/AKSRT/Widgets/WidgetMainPosts.php
create mode 100644 src/AKSRT/Widgets/WidgetTermAggregation.php
diff --git a/assets/css/frontend/widget-batch5.css b/assets/css/frontend/widget-batch5.css
new file mode 100644
index 00000000..63f5d4e2
--- /dev/null
+++ b/assets/css/frontend/widget-batch5.css
@@ -0,0 +1,229 @@
+/**
+ * Batch5: user card guest/login depth, main posts, term aggregation.
+ */
+
+.aksrt-user-card {
+ border-radius: 12px;
+ overflow: hidden;
+ border: 1px solid var(--color-line, #e5e7eb);
+ background: var(--surface-1, #fff);
+ text-align: center;
+ margin-bottom: 12px;
+}
+.aksrt-user-card__cover {
+ height: 90px;
+ background: linear-gradient(135deg, #93c5fd, #c4b5fd) center/cover no-repeat;
+}
+.aksrt-user-card__cover.is-empty {
+ background: linear-gradient(135deg, #e2e8f0, #f8fafc);
+}
+.aksrt-user-card__body { padding: 0 14px 16px; position: relative; }
+.aksrt-user-card__checkin {
+ position: absolute;
+ right: 10px;
+ top: 8px;
+ z-index: 2;
+ max-width: 48%;
+}
+.aksrt-user-card__checkin .but {
+ padding: 4px 8px !important;
+ font-size: 12px !important;
+ line-height: 1.2;
+}
+.aksrt-user-card__checkin .aksrt-header-checkin-details { display: none; }
+.aksrt-user-card__avatar {
+ display: inline-block;
+ margin-top: -36px;
+ width: 72px;
+ height: 72px;
+ border-radius: 50%;
+ overflow: hidden;
+ border: 3px solid var(--surface-1, #fff);
+ background: var(--surface-2, #eee);
+}
+.aksrt-user-card__avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
+.aksrt-user-card__name {
+ margin: 10px 0 0;
+ font-size: 16px;
+ font-weight: 700;
+}
+.aksrt-user-card__name a { color: inherit; text-decoration: none; }
+.aksrt-user-card__bio,
+.aksrt-user-card__guest-title {
+ margin: 8px 0 0;
+ font-size: 12px;
+ color: var(--muted-2-color, #888);
+ line-height: 1.5;
+}
+.aksrt-user-card__guest-title { font-size: 14px; font-weight: 600; color: inherit; }
+.aksrt-user-card__stats {
+ display: flex;
+ justify-content: center;
+ gap: 18px;
+ margin-top: 12px;
+}
+.aksrt-user-card__stat-value {
+ display: block;
+ font-size: 16px;
+ font-weight: 700;
+}
+.aksrt-user-card__stat-label {
+ font-size: 11px;
+ color: var(--muted-2-color, #999);
+}
+.aksrt-user-card__actions {
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-top: 14px;
+}
+.aksrt-user-card__btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 96px;
+ padding: 7px 14px;
+ border-radius: 999px;
+ font-size: 13px;
+ text-decoration: none;
+ font-weight: 600;
+}
+.aksrt-user-card__btn--primary {
+ background: var(--color-primary, #3b82f6);
+ color: #fff !important;
+}
+.aksrt-user-card__btn--ghost {
+ background: var(--surface-2, #f3f4f6);
+ color: inherit !important;
+}
+
+/* Main posts */
+.aksrt-main-posts { display: flex; flex-direction: column; gap: 10px; }
+.aksrt-main-posts.style-card {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 12px;
+}
+@media (max-width: 575.98px) {
+ .aksrt-main-posts.style-card { grid-template-columns: 1fr; }
+}
+.aksrt-main-posts__card {
+ display: block;
+ border-radius: 12px;
+ overflow: hidden;
+ border: 1px solid var(--color-line, #e5e7eb);
+ background: var(--surface-1, #fff);
+ text-decoration: none;
+ color: inherit;
+}
+.aksrt-main-posts__thumb {
+ height: 110px;
+ background: var(--surface-2, #f3f4f6);
+ overflow: hidden;
+}
+.aksrt-main-posts__thumb.mini {
+ width: 56px;
+ height: 56px;
+ border-radius: 8px;
+ flex-shrink: 0;
+}
+.aksrt-main-posts__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
+.aksrt-main-posts__thumb.is-empty { background: linear-gradient(135deg, #e2e8f0, #f8fafc); }
+.aksrt-main-posts__body { padding: 10px 12px 12px; min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 4px; }
+.aksrt-main-posts__title {
+ font-size: 13px;
+ font-weight: 600;
+ line-height: 1.4;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+.aksrt-main-posts__meta {
+ display: flex;
+ gap: 10px;
+ font-size: 11px;
+ color: var(--muted-2-color, #999);
+}
+.aksrt-main-posts__row {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ text-decoration: none;
+ color: inherit;
+ padding: 4px 0;
+ border-bottom: 1px dashed var(--color-line, #e5e7eb);
+}
+.aksrt-main-posts__row:last-child { border-bottom: 0; }
+.aksrt-main-posts__num {
+ width: 20px;
+ flex-shrink: 0;
+ font-size: 12px;
+ font-weight: 700;
+ color: var(--color-primary, #3b82f6);
+ text-align: center;
+}
+
+/* Term aggregation */
+.aksrt-term-agg {
+ display: grid;
+ grid-template-columns: repeat(var(--aksrt-ta-cols, 1), minmax(0, 1fr));
+ gap: 12px;
+}
+.aksrt-term-agg__card {
+ border: 1px solid var(--color-line, #e5e7eb);
+ border-radius: 12px;
+ overflow: hidden;
+ background: var(--surface-1, #fff);
+}
+.aksrt-term-agg__head {
+ display: block;
+ text-decoration: none;
+ color: inherit;
+ position: relative;
+}
+.aksrt-term-agg__cover {
+ height: 96px;
+ background: var(--surface-2, #f3f4f6) center/cover no-repeat;
+}
+.aksrt-term-agg__cover.is-empty {
+ background: linear-gradient(135deg, #dbeafe, #eff6ff);
+}
+.aksrt-term-agg__name {
+ position: absolute;
+ left: 12px;
+ bottom: 10px;
+ font-weight: 700;
+ color: #fff;
+ text-shadow: 0 1px 3px rgba(0,0,0,.45);
+}
+.aksrt-term-agg__count {
+ position: absolute;
+ right: 10px;
+ top: 10px;
+ font-size: 11px;
+ padding: 2px 8px;
+ border-radius: 999px;
+ background: rgba(0,0,0,.45);
+ color: #fff;
+}
+.aksrt-term-agg__posts {
+ list-style: none;
+ margin: 0;
+ padding: 8px 12px 10px;
+}
+.aksrt-term-agg__posts li {
+ padding: 6px 0;
+ border-bottom: 1px dashed var(--color-line, #eee);
+}
+.aksrt-term-agg__posts li:last-child { border-bottom: 0; }
+.aksrt-term-agg__posts a {
+ color: inherit;
+ text-decoration: none;
+ font-size: 13px;
+ display: block;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
diff --git a/assets/css/frontend/widgets.css b/assets/css/frontend/widgets.css
index 69e0c933..69820df2 100644
--- a/assets/css/frontend/widgets.css
+++ b/assets/css/frontend/widgets.css
@@ -8,3 +8,4 @@
@import url("widget-batch3d.css");
@import url("widget-batch3e.css");
@import url("widget-batch3f.css");
+@import url("widget-batch5.css");
diff --git a/inc/modules/widgets-register.php b/inc/modules/widgets-register.php
index 8ba39126..b0390149 100644
--- a/inc/modules/widgets-register.php
+++ b/inc/modules/widgets-register.php
@@ -74,6 +74,8 @@ function aksrt_register_widgets() {
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');
// Forum widgets
diff --git a/src/AKSRT/Widgets/WidgetMainPosts.php b/src/AKSRT/Widgets/WidgetMainPosts.php
new file mode 100644
index 00000000..f2ce4ff8
--- /dev/null
+++ b/src/AKSRT/Widgets/WidgetMainPosts.php
@@ -0,0 +1,207 @@
+ esc_html__('卡片/迷你/列表样式的文章模块。', 'aksrt'),
+ 'classname' => 'widget_aksrt_main_posts',
+ ]
+ );
+ }
+
+ public function widget($args, $instance): void {
+ $count = max(1, min(30, (int) ($instance['count'] ?? 6)));
+ $style = sanitize_key((string) ($instance['style'] ?? 'list'));
+ if (!in_array($style, ['list', 'card', 'mini'], true)) {
+ $style = 'list';
+ }
+ $orderby = sanitize_key((string) ($instance['orderby'] ?? 'date'));
+ $cat = (int) ($instance['cat'] ?? 0);
+ $limit_day = max(0, (int) ($instance['limit_day'] ?? 0));
+ $show_thumb = !isset($instance['show_thumb']) || !empty($instance['show_thumb']);
+ $show_meta = !isset($instance['show_meta']) || !empty($instance['show_meta']);
+ $show_number = !empty($instance['show_number']);
+
+ $query = [
+ 'post_type' => 'post',
+ 'post_status' => 'publish',
+ 'posts_per_page' => $count,
+ 'ignore_sticky_posts' => true,
+ 'no_found_rows' => true,
+ ];
+ if ($cat > 0) {
+ $query['cat'] = $cat;
+ }
+ if ($limit_day > 0) {
+ $query['date_query'] = [['after' => $limit_day . ' days ago']];
+ }
+ switch ($orderby) {
+ case 'views':
+ $query['meta_key'] = 'aksrt_post_views';
+ $query['orderby'] = 'meta_value_num';
+ $query['order'] = 'DESC';
+ break;
+ case 'comments':
+ $query['orderby'] = 'comment_count';
+ $query['order'] = 'DESC';
+ break;
+ case 'rand':
+ $query['orderby'] = 'rand';
+ break;
+ case 'modified':
+ $query['orderby'] = 'modified';
+ $query['order'] = 'DESC';
+ break;
+ default:
+ $query['orderby'] = 'date';
+ $query['order'] = 'DESC';
+ }
+
+ $q = new \WP_Query($query);
+ if (!$q->have_posts()) {
+ wp_reset_postdata();
+ 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
+ }
+
+ echo '';
+ wp_reset_postdata();
+
+ echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ }
+
+ public function form($instance): void {
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sanitize_text_field((string) ($new_instance['title'] ?? '')),
+ 'count' => max(1, min(30, (int) ($new_instance['count'] ?? 6))),
+ 'style' => $style,
+ 'orderby' => $orderby,
+ 'cat' => max(0, (int) ($new_instance['cat'] ?? 0)),
+ 'limit_day' => max(0, (int) ($new_instance['limit_day'] ?? 0)),
+ 'show_thumb' => !empty($new_instance['show_thumb']) ? 1 : 0,
+ 'show_meta' => !empty($new_instance['show_meta']) ? 1 : 0,
+ 'show_number' => !empty($new_instance['show_number']) ? 1 : 0,
+ ];
+ }
+}
diff --git a/src/AKSRT/Widgets/WidgetTermAggregation.php b/src/AKSRT/Widgets/WidgetTermAggregation.php
new file mode 100644
index 00000000..be75dcff
--- /dev/null
+++ b/src/AKSRT/Widgets/WidgetTermAggregation.php
@@ -0,0 +1,197 @@
+ esc_html__('分类封面 + 最新文章列表聚合卡。', 'aksrt'),
+ 'classname' => 'widget_aksrt_term_aggregation',
+ ]
+ );
+ }
+
+ public function widget($args, $instance): void {
+ $taxonomy = sanitize_key((string) ($instance['taxonomy'] ?? 'category'));
+ if (!taxonomy_exists($taxonomy)) {
+ $taxonomy = 'category';
+ }
+ $term_ids = $this->parse_ids((string) ($instance['term_ids'] ?? ''));
+ $count = max(1, min(12, (int) ($instance['count'] ?? 4)));
+ $orderby = sanitize_key((string) ($instance['orderby'] ?? 'date'));
+ $columns = max(1, min(3, (int) ($instance['columns'] ?? 1)));
+
+ if (!$term_ids) {
+ // Fallback: top terms by count.
+ $terms = get_terms([
+ 'taxonomy' => $taxonomy,
+ 'number' => max(1, min(4, (int) ($instance['auto_terms'] ?? 2))),
+ 'orderby' => 'count',
+ 'order' => 'DESC',
+ 'hide_empty' => true,
+ ]);
+ if (is_wp_error($terms) || !$terms) {
+ return;
+ }
+ $term_ids = array_map(static fn($t) => (int) $t->term_id, $terms);
+ }
+
+ 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 '';
+ foreach ($term_ids as $term_id) {
+ $term = get_term($term_id, $taxonomy);
+ if (!$term || is_wp_error($term)) {
+ continue;
+ }
+ $link = get_term_link($term);
+ if (is_wp_error($link)) {
+ continue;
+ }
+ $cover = '';
+ $img_id = (int) get_term_meta($term_id, 'thumbnail_id', true);
+ if (!$img_id) {
+ $img_id = (int) get_term_meta($term_id, '_aksrt_cover', true);
+ }
+ if ($img_id) {
+ $cover = wp_get_attachment_image_url($img_id, 'medium') ?: '';
+ }
+ if ($cover === '') {
+ $cover = (string) get_term_meta($term_id, '_aksrt_cover_url', true);
+ }
+
+ $posts_q = [
+ 'post_type' => 'post',
+ 'post_status' => 'publish',
+ 'posts_per_page' => $count,
+ 'ignore_sticky_posts' => true,
+ 'no_found_rows' => true,
+ 'tax_query' => [[
+ 'taxonomy' => $taxonomy,
+ 'field' => 'term_id',
+ 'terms' => $term_id,
+ ]],
+ ];
+ if ($orderby === 'views') {
+ $posts_q['meta_key'] = 'aksrt_post_views';
+ $posts_q['orderby'] = 'meta_value_num';
+ $posts_q['order'] = 'DESC';
+ } elseif ($orderby === 'modified') {
+ $posts_q['orderby'] = 'modified';
+ $posts_q['order'] = 'DESC';
+ } else {
+ $posts_q['orderby'] = 'date';
+ $posts_q['order'] = 'DESC';
+ }
+ $q = new \WP_Query($posts_q);
+
+ echo '
';
+ }
+ 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));
+ }
+
+ public function form($instance): void {
+ $taxs = get_taxonomies(['public' => true], 'objects');
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sanitize_text_field((string) ($new_instance['title'] ?? '')),
+ 'taxonomy' => sanitize_key((string) ($new_instance['taxonomy'] ?? 'category')),
+ 'term_ids' => sanitize_text_field((string) ($new_instance['term_ids'] ?? '')),
+ 'count' => max(1, min(12, (int) ($new_instance['count'] ?? 4))),
+ 'columns' => max(1, min(3, (int) ($new_instance['columns'] ?? 1))),
+ 'orderby' => $orderby,
+ 'auto_terms' => max(1, min(4, (int) ($new_instance['auto_terms'] ?? 2))),
+ ];
+ }
+}
diff --git a/src/AKSRT/Widgets/WidgetUserCard.php b/src/AKSRT/Widgets/WidgetUserCard.php
index 4810a259..5be7120f 100644
--- a/src/AKSRT/Widgets/WidgetUserCard.php
+++ b/src/AKSRT/Widgets/WidgetUserCard.php
@@ -1,5 +1,7 @@
__('在侧栏显示当前登录用户或指定用户的信息卡片。', 'aksrt')]
- );
- }
+ public function __construct() {
+ parent::__construct(
+ 'aksrt_user_card',
+ __('用户卡片', 'aksrt'),
+ ['description' => __('未登录显示登录入口;登录后显示当前用户卡片、签到与快捷按钮。', 'aksrt')]
+ );
+ }
- public function widget($args, $instance): void {
- $title = !empty($instance['title']) ? $instance['title'] : '';
- $show_stats = !empty($instance['show_stats']);
- $show_actions = !empty($instance['show_actions']);
+ public function widget($args, $instance): void {
+ $show_cover = !isset($instance['show_img_bg']) || !empty($instance['show_img_bg']);
+ $show_stats = !empty($instance['show_stats']) || !isset($instance['show_stats']);
+ $show_actions = !empty($instance['show_button']) || !isset($instance['show_button']);
+ $show_checkin = !empty($instance['show_checkin']) || !isset($instance['show_checkin']);
+ $loged_title = (string) ($instance['loged_title'] ?? __('Hi!请登录', 'aksrt'));
+ $btn1_text = (string) ($instance['button_1_text'] ?? __('发布文章', 'aksrt'));
+ $btn2_text = (string) ($instance['button_2_text'] ?? __('用户中心', 'aksrt'));
- // 获取目标用户
- $user_id = !empty($instance['user_id']) ? (int) $instance['user_id'] : 0;
- if ($user_id <= 0 && is_user_logged_in()) {
- $user_id = get_current_user_id();
- }
+ // Fixed user id wins; else current user.
+ $user_id = !empty($instance['user_id']) ? (int) $instance['user_id'] : 0;
+ if ($user_id <= 0 && is_user_logged_in()) {
+ $user_id = get_current_user_id();
+ }
- if ($user_id <= 0) 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
+ }
- $user = get_userdata($user_id);
- if (!$user) return;
+ if ($user_id <= 0) {
+ $this->render_guest($show_cover, $loged_title);
+ echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ return;
+ }
- // 获取用户统计
- $post_count = count_user_posts($user_id, 'post', true);
- $comment_count = get_comments(['user_id' => $user_id, 'count' => true]);
- $follower_count = 0;
- $following_count = 0;
- if (class_exists('\AKSRT\User\Follow')) {
- $follower_count = \AKSRT\User\Follow::get_instance()->get_follower_count($user_id);
- $following_count = \AKSRT\User\Follow::get_instance()->get_following_count($user_id);
- }
+ $user = get_userdata($user_id);
+ if (!$user) {
+ echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ return;
+ }
- // 头像
- $avatar_url = function_exists('aksrt_get_avatar_url')
- ? aksrt_get_avatar_url($user_id, ['size' => 144])
- : get_avatar_url($user_id, ['size' => 144]);
+ $is_self = is_user_logged_in() && (int) get_current_user_id() === $user_id;
+ $avatar_url = function_exists('aksrt_get_avatar_url')
+ ? aksrt_get_avatar_url($user_id, ['size' => 144])
+ : get_avatar_url($user_id, ['size' => 144]);
+ $profile_url = function_exists('aksrt_get_user_home_url')
+ ? aksrt_get_user_home_url($user_id)
+ : get_author_posts_url($user_id);
+ $center_url = function_exists('aksrt_get_user_center_url')
+ ? aksrt_get_user_center_url()
+ : $profile_url;
+ $compose_url = home_url('/');
+ // Prefer front submit / write page when available.
+ if (function_exists('get_pages')) {
+ $pages = get_pages(['meta_key' => '_wp_page_template', 'meta_value' => 'templates/pages/page-submit.php', 'number' => 1]);
+ if (!empty($pages[0])) {
+ $compose_url = get_permalink($pages[0]);
+ }
+ }
+ if ($compose_url === home_url('/') && function_exists('aksrt_get_user_center_url')) {
+ $compose_url = aksrt_get_user_center_url('posts');
+ }
+ $bio = get_user_meta($user_id, 'description', true);
+ if (!is_string($bio) || $bio === '') {
+ $bio = (string) $user->description;
+ }
+ $cover = (string) get_user_meta($user_id, 'aksrt_cover', true);
+ if ($cover === '') {
+ $cover = (string) get_user_meta($user_id, 'custom_avatar_cover', true);
+ }
- // 用户主页链接
- $profile_url = function_exists('aksrt_get_user_home_url')
- ? aksrt_get_user_home_url($user_id)
- : get_author_posts_url($user_id);
+ $post_count = count_user_posts($user_id, 'post', true);
+ $follower_count = 0;
+ $following_count = 0;
+ if (class_exists('\AKSRT\User\Follow')) {
+ $follower_count = \AKSRT\User\Follow::get_instance()->get_follower_count($user_id);
+ $following_count = \AKSRT\User\Follow::get_instance()->get_following_count($user_id);
+ }
- // 简介
- $bio = get_user_meta($user_id, 'description', true);
- if (!$bio) $bio = $user->description ?: '';
+ echo '';
- echo $args['before_widget'];
+ echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ }
- if ($title) {
- echo $args['before_title'] . esc_html($title) . $args['after_title'];
- }
+ private function render_guest(bool $show_cover, string $loged_title): void {
+ $login = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url();
+ $register = function_exists('aksrt_get_register_url') ? aksrt_get_register_url() : wp_registration_url();
+ $default_avatar = function_exists('get_avatar_url')
+ ? get_avatar_url(0, ['size' => 144, 'force_default' => true])
+ : includes_url('images/blank.gif');
- echo '';
+ echo '
';
+ }
- // 头像
- echo '
';
+ public function form($instance): void {
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
- echo '
' . esc_html($user->display_name) . '';
- echo '';
-
- // 简介
- if ($bio) {
- echo '
' . esc_html(wp_trim_words($bio, 20)) . '
';
- }
-
- // 统计
- if ($show_stats) {
- echo '
';
- echo '
' . number_format_i18n($post_count) . '' . esc_html__('文章', 'aksrt') . '
';
- echo '
' . number_format_i18n($follower_count) . '' . esc_html__('粉丝', 'aksrt') . '
';
- echo '
' . number_format_i18n($following_count) . '' . esc_html__('关注', 'aksrt') . '
';
- echo '
';
- }
-
- // 操作按钮
- if ($show_actions) {
- echo '
';
- }
-
- echo '
';
-
- echo $args['after_widget'];
- }
-
- public function form($instance): void {
- $title = !empty($instance['title']) ? $instance['title'] : '';
- $user_id = !empty($instance['user_id']) ? (int) $instance['user_id'] : 0;
- $show_stats = !empty($instance['show_stats']);
- $show_actions = !empty($instance['show_actions']);
- ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- sanitize_text_field((string) ($new_instance['title'] ?? '')),
+ 'user_id' => max(0, (int) ($new_instance['user_id'] ?? 0)),
+ 'loged_title' => sanitize_text_field((string) ($new_instance['loged_title'] ?? '')),
+ 'button_1_text' => sanitize_text_field((string) ($new_instance['button_1_text'] ?? '')),
+ 'button_2_text' => sanitize_text_field((string) ($new_instance['button_2_text'] ?? '')),
+ 'show_img_bg' => !empty($new_instance['show_img_bg']) ? 1 : 0,
+ 'show_stats' => !empty($new_instance['show_stats']) ? 1 : 0,
+ 'show_button' => !empty($new_instance['show_button']) ? 1 : 0,
+ 'show_checkin' => !empty($new_instance['show_checkin']) ? 1 : 0,
+ ];
+ }
}
diff --git a/src/AKSRT/Widgets/WidgetUserRanking.php b/src/AKSRT/Widgets/WidgetUserRanking.php
index 4094f7a5..c64dd3c2 100644
--- a/src/AKSRT/Widgets/WidgetUserRanking.php
+++ b/src/AKSRT/Widgets/WidgetUserRanking.php
@@ -29,6 +29,13 @@ class WidgetUserRanking extends \WP_Widget {
echo $args['before_widget'];
echo $args['before_title'] . esc_html($title) . $args['after_title'];
+ 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
+ }
+ }
+
echo '';
$rank = 0;
foreach ($users as $user) {
@@ -110,6 +117,58 @@ class WidgetUserRanking extends \WP_Widget {
}
break;
+ case 'checkin_all_day':
+ global $wpdb;
+ $rows = $wpdb->get_results($wpdb->prepare(
+ "SELECT user_id, meta_value as val FROM {$wpdb->usermeta}
+ WHERE meta_key IN ('aksrt_checkin_all_day','checkin_all_day')
+ ORDER BY CAST(meta_value AS UNSIGNED) DESC
+ LIMIT %d",
+ $count * 2
+ ), ARRAY_A);
+ $seen = [];
+ foreach ((array) $rows as $row) {
+ $uid = (int) $row['user_id'];
+ if (isset($seen[$uid])) continue;
+ $seen[$uid] = true;
+ $user = get_userdata($uid);
+ if ($user) {
+ $users[] = [
+ 'id' => $uid,
+ 'name' => $user->display_name,
+ 'value' => number_format_i18n((int) $row['val']) . ' 天',
+ ];
+ }
+ if (count($users) >= $count) break;
+ }
+ break;
+
+ case 'checkin_continuous_day':
+ global $wpdb;
+ $rows = $wpdb->get_results($wpdb->prepare(
+ "SELECT user_id, meta_value as val FROM {$wpdb->usermeta}
+ WHERE meta_key IN ('aksrt_checkin_continuous_day','checkin_continuous_day')
+ ORDER BY CAST(meta_value AS UNSIGNED) DESC
+ LIMIT %d",
+ $count * 2
+ ), ARRAY_A);
+ $seen = [];
+ foreach ((array) $rows as $row) {
+ $uid = (int) $row['user_id'];
+ if (isset($seen[$uid])) continue;
+ $seen[$uid] = true;
+ $user = get_userdata($uid);
+ if ($user) {
+ $users[] = [
+ 'id' => $uid,
+ 'name' => $user->display_name,
+ 'value' => number_format_i18n((int) $row['val']) . ' 天',
+ ];
+ }
+ if (count($users) >= $count) break;
+ }
+ break;
+
case 'followers':
if (class_exists('\AKSRT\User\Follow')) {
global $wpdb;
@@ -157,6 +216,8 @@ class WidgetUserRanking extends \WP_Widget {
+
+
@@ -169,15 +230,22 @@ class WidgetUserRanking extends \WP_Widget {
+
+
+