From defb64fd89574b0bf3e872afa44236cecb697595 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 16 Jul 2026 20:32:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(single):=20identity=20chips,=20comment=20?= =?UTF-8?q?=E7=A5=9E=E8=AF=84,=20reward=20open=20from=20author=20bar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Share VIP/verify/level/badge chrome via aksrt-identity helpers on author bar, author card, and comments; mark hot comments; open reward modal from author actions; admin threshold for 神评; task list go-to actions. --- .../src/schema/sections/post-list/comment.js | 2 + assets/css/frontend/comments.css | 31 ++++++ assets/js/reward.js | 7 ++ inc/bootstrap.php | 1 + .../class-aksrt-admin-schema-post-list.php | 1 + inc/helpers/aksrt-frontend-tags.php | 9 ++ inc/helpers/aksrt-identity.php | 103 ++++++++++++++++++ inc/helpers/aksrt-single-render.php | 18 +-- templates/parts/single-author-bar.php | 20 +--- 9 files changed, 166 insertions(+), 26 deletions(-) create mode 100644 inc/helpers/aksrt-identity.php diff --git a/assets/admin/src/schema/sections/post-list/comment.js b/assets/admin/src/schema/sections/post-list/comment.js index 721f3786..bf672280 100644 --- a/assets/admin/src/schema/sections/post-list/comment.js +++ b/assets/admin/src/schema/sections/post-list/comment.js @@ -20,6 +20,7 @@ export const commentSchema = { comment_img: true, comment_upload_img: false, comment_like_s: true, + comment_hot_threshold: 10, comment_quick_s: true, comment_city_s: true, comment_author_tag: true, @@ -78,6 +79,7 @@ export const commentSchema = { title: '互动功能', icon: 'fas fa-heart', fields: [ + { key: 'comment_hot_threshold', label: '神评点赞阈值', type: 'number', default: 10, min: 1, max: 999, help: '点赞数达到该值后显示「神评」徽章', dependsOn: { key: 'comment_like_s', value: true } }, { key: 'comment_like_s', label: '评论点赞', type: 'switch', default: true }, { key: 'comment_quick_s', label: '快捷回复', type: 'switch', default: true }, { key: 'comment_city_s', label: '评论城市', type: 'switch', default: true }, diff --git a/assets/css/frontend/comments.css b/assets/css/frontend/comments.css index 3520487e..783dfbd6 100644 --- a/assets/css/frontend/comments.css +++ b/assets/css/frontend/comments.css @@ -671,3 +671,34 @@ body.dark-theme .comment-login-prompt__inner { margin-bottom: 0; opacity: 0.9; } + + +/* Identity chips + 神评 */ +.aksrt-identity-chip { + display: inline-flex; + align-items: center; + gap: 3px; + vertical-align: middle; + max-width: 9em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.aksrt-identity-chip--comment { + font-size: 11px; + padding: 0 6px; +} +.aksrt-comment__badge--hot { + color: #ea580c; + background: rgba(234, 88, 12, 0.1); + border-radius: 999px; + padding: 0 6px; + margin-left: 4px; + font-size: 11px; +} +.aksrt-comment__header .author-box { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 4px; +} diff --git a/assets/js/reward.js b/assets/js/reward.js index 6090367f..d6455f7c 100644 --- a/assets/js/reward.js +++ b/assets/js/reward.js @@ -40,6 +40,13 @@ } btn.addEventListener('click', openReward); + document.querySelectorAll('[data-aksrt-reward-open]').forEach(function (el) { + if (el === btn) return; + el.addEventListener('click', function (e) { + e.preventDefault(); + openReward(); + }); + }); if (closeBtn) closeBtn.addEventListener('click', closeReward); if (overlay) overlay.addEventListener('click', closeReward); diff --git a/inc/bootstrap.php b/inc/bootstrap.php index 2b383295..9be8898c 100644 --- a/inc/bootstrap.php +++ b/inc/bootstrap.php @@ -44,6 +44,7 @@ require_once AKSRT_DIR . '/inc/helpers/aksrt-pay.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-coupon-order.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-credits.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-null.php'; +require_once AKSRT_DIR . '/inc/helpers/aksrt-identity.php'; require_once AKSRT_DIR . '/inc/helpers/menu-decoration.php'; require_once AKSRT_DIR . '/inc/helpers/class-aksrt-nav-walker.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-transactions.php'; diff --git a/inc/classes/admin/schema/class-aksrt-admin-schema-post-list.php b/inc/classes/admin/schema/class-aksrt-admin-schema-post-list.php index 2ca5ce6b..57febfbf 100644 --- a/inc/classes/admin/schema/class-aksrt-admin-schema-post-list.php +++ b/inc/classes/admin/schema/class-aksrt-admin-schema-post-list.php @@ -250,6 +250,7 @@ class AKSRT_Admin_Schema_Post_List { ['key' => 'comment_upload_img', 'label' => '评论图片上传', 'type' => 'switch', 'default' => false], ]], ['key' => 'interaction', 'title' => '互动功能', 'fields' => [ + ['key' => 'comment_hot_threshold', 'label' => '神评点赞阈值', 'type' => 'number', 'default' => 10, 'min' => 1, 'max' => 999], ['key' => 'comment_like_s', 'label' => '评论点赞', 'type' => 'switch', 'default' => true], ['key' => 'comment_quick_s', 'label' => '快捷回复', 'type' => 'switch', 'default' => true], ['key' => 'comment_city_s', 'label' => '评论城市', 'type' => 'switch', 'default' => true], diff --git a/inc/helpers/aksrt-frontend-tags.php b/inc/helpers/aksrt-frontend-tags.php index 1a3e94d1..065211d3 100644 --- a/inc/helpers/aksrt-frontend-tags.php +++ b/inc/helpers/aksrt-frontend-tags.php @@ -1055,9 +1055,18 @@ if (!function_exists('aksrt_comment_callback')) :
'avatar-img comt-avatar']); ?> + user_id; + if ($comment_user_id > 0 && function_exists('aksrt_render_user_identity_chips')) { + echo aksrt_render_user_identity_chips($comment_user_id, 'comment'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + ?> + + + diff --git a/inc/helpers/aksrt-identity.php b/inc/helpers/aksrt-identity.php new file mode 100644 index 00000000..3c9ac91c --- /dev/null +++ b/inc/helpers/aksrt-identity.php @@ -0,0 +1,103 @@ + + */ + function aksrt_get_user_identity_signals(int $user_id): array { + if ($user_id <= 0) { + return []; + } + if (class_exists('AKSRT_User_Home')) { + $signals = AKSRT_User_Home::get_instance()->get_profile_signals($user_id); + return is_array($signals) ? array_values($signals) : []; + } + return []; + } +} + +if (!function_exists('aksrt_render_user_identity_chips')) { + /** + * Render compact identity chips (verify / level / badges). + * + * @param int $user_id + * @param string $context author|comment|card + */ + function aksrt_render_user_identity_chips(int $user_id, string $context = 'author'): string { + if ($user_id <= 0) { + return ''; + } + $html = ''; + if (function_exists('aksrt_render_vip_badge')) { + $vip = aksrt_render_vip_badge($user_id, 'sm'); + if (is_string($vip) && $vip !== '') { + $html .= $vip; + } + } + $signals = aksrt_get_user_identity_signals($user_id); + $limit = $context === 'comment' ? 3 : 6; + $n = 0; + foreach ($signals as $signal) { + if ($n >= $limit) { + break; + } + $label = trim((string) ($signal['label'] ?? '')); + if ($label === '') { + continue; + } + $tone = sanitize_html_class((string) ($signal['tone'] ?? 'info')); + $icon = sanitize_html_class((string) ($signal['icon'] ?? 'check')); + // Font Awesome: map short names to fa-* if needed. + if ($icon !== '' && !str_contains($icon, 'fa-')) { + $icon = 'fa-' . $icon; + } + $title = (string) ($signal['title'] ?? $label); + $html .= ''; + if ($icon !== '') { + $html .= ' '; + } + $html .= esc_html($label) . ''; + $n++; + } + return $html; + } +} + +if (!function_exists('aksrt_is_blog_comment_hot')) { + /** + * "神评" for ordinary post comments when likes cross threshold. + */ + function aksrt_is_blog_comment_hot($comment): bool { + $comment_id = $comment instanceof WP_Comment ? (int) $comment->comment_ID : (int) $comment; + if ($comment_id <= 0) { + return false; + } + if ('1' === (string) get_comment_meta($comment_id, '_aksrt_comment_hot', true)) { + return true; + } + $threshold = 10; + if (class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_comment_display_settings')) { + $display = AKSRT_Settings::get_comment_display_settings(); + if (isset($display['hot_threshold'])) { + $threshold = max(1, (int) $display['hot_threshold']); + } + } + $all = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_all() : []; + if (isset($all['comment_hot_threshold'])) { + $threshold = max(1, (int) $all['comment_hot_threshold']); + } + $likes = function_exists('aksrt_get_comment_likes') ? aksrt_get_comment_likes($comment_id) : (int) get_comment_meta($comment_id, 'aksrt_comment_likes', true); + if ($likes < $threshold) { + return false; + } + update_comment_meta($comment_id, '_aksrt_comment_hot', '1'); + return true; + } +} diff --git a/inc/helpers/aksrt-single-render.php b/inc/helpers/aksrt-single-render.php index 5996da6b..8a57a170 100644 --- a/inc/helpers/aksrt-single-render.php +++ b/inc/helpers/aksrt-single-render.php @@ -306,11 +306,9 @@ if (!function_exists('aksrt_single_render_author_card')) : $author_url = get_author_posts_url($author_id); $author_name = get_the_author(); $bio = trim((string) get_the_author_meta('description')); - $vip_badge = function_exists('aksrt_render_vip_badge') ? aksrt_render_vip_badge($author_id, 'sm') : ''; - $signals = []; - if (class_exists('AKSRT_User_Home')) { - $signals = AKSRT_User_Home::get_instance()->get_profile_signals($author_id); - } + $identity_chips = function_exists('aksrt_render_user_identity_chips') + ? aksrt_render_user_identity_chips($author_id, 'card') + : ''; $avatar = function_exists('aksrt_get_avatar_html') ? aksrt_get_avatar_html($author_id, 80, ['class' => 'avatar avatar-lg']) : get_avatar($author_id, 80, '', esc_attr($author_name), ['class' => 'avatar avatar-lg']); @@ -331,13 +329,9 @@ if (!function_exists('aksrt_single_render_author_card')) :