From b1731f7a8d41fde3a74f742037af249eb05244e6 Mon Sep 17 00:00:00 2001
From: unknown
Date: Thu, 16 Jul 2026 17:46:51 +0800
Subject: [PATCH 1/3] feat(assets): forum free-task depth, withdraw notices,
share poster
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Route forum essence/adopt/hot/score rewards through free-points day cap,
notify users on withdraw complete/reject, surface 海报分享 on single
share grid, and extend admin free-task keys for the remaining matrix.
---
.../src/schema/sections/users/credits.js | 8 ++++
.../frontend/single-post/author-actions.css | 2 +
.../schema/class-aksrt-admin-schema-users.php | 4 ++
inc/classes/class-aksrt-credits-earn.php | 26 ++++-------
inc/classes/class-aksrt-points-free.php | 34 +++++++++++++++
inc/classes/class-aksrt-withdrawal.php | 26 ++++++++++-
.../class-aksrt-forum-comment-service.php | 43 +++++++++++++------
.../forum/class-aksrt-forum-score-service.php | 38 ++++++++++------
...trait-aksrt-forum-topic-service-part-1.php | 34 +++++++++------
inc/helpers/aksrt-credits.php | 4 ++
inc/helpers/aksrt-single-render.php | 1 +
11 files changed, 165 insertions(+), 55 deletions(-)
diff --git a/assets/admin/src/schema/sections/users/credits.js b/assets/admin/src/schema/sections/users/credits.js
index 0199f2ca..09ff0727 100644
--- a/assets/admin/src/schema/sections/users/credits.js
+++ b/assets/admin/src/schema/sections/users/credits.js
@@ -22,6 +22,10 @@ export const creditsSchema = {
points_free_bbs_posts_new: 5,
points_free_bbs_reply: 2,
points_free_bbs_essence: 10,
+ points_free_bbs_adopt: 20,
+ points_free_bbs_posts_hot: 5,
+ points_free_bbs_comment_hot: 5,
+ points_free_bbs_score_extra: 3,
points_earn_invite: 10,
points_spend_comment: 0,
points_spend_download: 0,
@@ -73,6 +77,10 @@ export const creditsSchema = {
{ key: 'points_free_bbs_posts_new', label: '论坛发帖', type: 'number', default: 5, min: 0, max: 1000 },
{ key: 'points_free_bbs_reply', label: '论坛回复', type: 'number', default: 2, min: 0, max: 1000 },
{ key: 'points_free_bbs_essence', label: '帖子加精', type: 'number', default: 10, min: 0, max: 1000 },
+ { key: 'points_free_bbs_adopt', label: '回复被采纳', type: 'number', default: 20, min: 0, max: 1000 },
+ { key: 'points_free_bbs_posts_hot', label: '热帖奖励', type: 'number', default: 5, min: 0, max: 1000 },
+ { key: 'points_free_bbs_comment_hot', label: '神评奖励', type: 'number', default: 5, min: 0, max: 1000 },
+ { key: 'points_free_bbs_score_extra', label: '帖子加分', type: 'number', default: 3, min: 0, max: 1000 },
{ key: 'points_earn_invite', label: '邀请注册奖励', type: 'number', default: 10, min: 0, max: 1000, help: '邀请不计入免费日上限' },
],
},
diff --git a/assets/css/frontend/single-post/author-actions.css b/assets/css/frontend/single-post/author-actions.css
index b9674b1a..50f919fc 100644
--- a/assets/css/frontend/single-post/author-actions.css
+++ b/assets/css/frontend/single-post/author-actions.css
@@ -278,6 +278,7 @@
.share-item[data-platform="twitter"]:hover { background: #f0f0f0; color: #000; }
.share-item[data-platform="wechat"]:hover { background: #e6f7ec; color: #07c160; }
.share-item[data-platform="copy"]:hover { background: #f0f2f5; color: #555; }
+.share-item[data-platform="poster"]:hover { background: #fff4e8; color: #f59e0b; }
/* 微信二维码浮层 */
#share-qrcode-box {
@@ -332,6 +333,7 @@ html.dark .share-item {
.theme-dark .share-item[data-platform="twitter"]:hover { background: rgba(255,255,255,0.08); color: #fff; }
.theme-dark .share-item[data-platform="wechat"]:hover { background: rgba(7,193,96,0.12); color: #07c160; }
.theme-dark .share-item[data-platform="copy"]:hover { background: rgba(255,255,255,0.06); color: #ccc; }
+.theme-dark .share-item[data-platform="poster"]:hover { background: rgba(245,158,11,0.12); color: #f59e0b; }
.theme-dark .post-drop-meta__menu,
html.dark .post-drop-meta__menu {
diff --git a/inc/classes/admin/schema/class-aksrt-admin-schema-users.php b/inc/classes/admin/schema/class-aksrt-admin-schema-users.php
index 86055c6a..6edd2ed8 100644
--- a/inc/classes/admin/schema/class-aksrt-admin-schema-users.php
+++ b/inc/classes/admin/schema/class-aksrt-admin-schema-users.php
@@ -428,6 +428,10 @@ class AKSRT_Admin_Schema_Users {
['key' => 'points_free_bbs_posts_new', 'label' => '论坛发帖', 'type' => 'number', 'default' => 5, 'min' => 0, 'max' => 1000],
['key' => 'points_free_bbs_reply', 'label' => '论坛回复', 'type' => 'number', 'default' => 2, 'min' => 0, 'max' => 1000],
['key' => 'points_free_bbs_essence', 'label' => '帖子加精', 'type' => 'number', 'default' => 10, 'min' => 0, 'max' => 1000],
+ ['key' => 'points_free_bbs_adopt', 'label' => '回复被采纳', 'type' => 'number', 'default' => 20, 'min' => 0, 'max' => 1000],
+ ['key' => 'points_free_bbs_posts_hot', 'label' => '热帖奖励', 'type' => 'number', 'default' => 5, 'min' => 0, 'max' => 1000],
+ ['key' => 'points_free_bbs_comment_hot', 'label' => '神评奖励', 'type' => 'number', 'default' => 5, 'min' => 0, 'max' => 1000],
+ ['key' => 'points_free_bbs_score_extra', 'label' => '帖子加分', 'type' => 'number', 'default' => 3, 'min' => 0, 'max' => 1000],
['key' => 'points_earn_invite', 'label' => '邀请注册奖励', 'type' => 'number', 'default' => 10, 'min' => 0, 'max' => 1000, 'help' => '邀请奖励不走免费日上限'],
]],
['key' => 'spend', 'title' => '积分消费', 'fields' => [
diff --git a/inc/classes/class-aksrt-credits-earn.php b/inc/classes/class-aksrt-credits-earn.php
index 877bafe9..b872857f 100644
--- a/inc/classes/class-aksrt-credits-earn.php
+++ b/inc/classes/class-aksrt-credits-earn.php
@@ -234,22 +234,14 @@ class AKSRT_Credits_Earn {
}
}
- public function on_forum_topic_featured(int $topic_id, int $operator_id): void {
- unset($operator_id);
- $post = get_post($topic_id);
- if (!$post || $post->post_type !== 'aksrt_forum_topic') {
- return;
- }
- $user_id = (int) $post->post_author;
- if ($user_id <= 0 || !class_exists('AKSRT_Points_Free')) {
- return;
- }
- if (get_post_meta($topic_id, 'aksrt_credit_essence_rewarded', true)) {
- return;
- }
- $granted = AKSRT_Points_Free::grant($user_id, 'bbs_essence', 0, ['type' => 'post', 'id' => $topic_id]);
- if (!is_wp_error($granted) && $granted > 0) {
- update_post_meta($topic_id, 'aksrt_credit_essence_rewarded', 1);
- }
+ /**
+ * Essence reward is owned by AKSRT_Forum::reward_essence() (free-day-cap).
+ * Keep hook for external integrations only — do not double-grant.
+ *
+ * @param int $topic_id
+ * @param int $author_or_operator Author id from forum (2nd arg) or operator.
+ */
+ public function on_forum_topic_featured(int $topic_id, int $author_or_operator = 0): void {
+ unset($topic_id, $author_or_operator);
}
}
diff --git a/inc/classes/class-aksrt-points-free.php b/inc/classes/class-aksrt-points-free.php
index b4d1bae7..6bdf767b 100644
--- a/inc/classes/class-aksrt-points-free.php
+++ b/inc/classes/class-aksrt-points-free.php
@@ -33,6 +33,10 @@ class AKSRT_Points_Free {
'bbs_posts_new' => [__('论坛发帖', 'aksrt'), __('发布论坛主题', 'aksrt'), 5],
'bbs_reply' => [__('论坛回复', 'aksrt'), __('回复论坛主题', 'aksrt'), 2],
'bbs_essence' => [__('帖子加精', 'aksrt'), __('主题被设为精华', 'aksrt'), 10],
+ 'bbs_adopt' => [__('回复被采纳', 'aksrt'), __('问答帖回复被采纳', 'aksrt'), 20],
+ 'bbs_posts_hot' => [__('热帖奖励', 'aksrt'), __('主题成为热帖', 'aksrt'), 5],
+ 'bbs_comment_hot'=> [__('神评奖励', 'aksrt'), __('回复成为神评', 'aksrt'), 5],
+ 'bbs_score_extra'=> [__('帖子加分', 'aksrt'), __('主题被加分时奖励', 'aksrt'), 3],
];
}
@@ -276,6 +280,36 @@ class AKSRT_Points_Free {
return max(0, (int) ($f['credits']['comment_new'] ?? $default));
}
return $default;
+ case 'bbs_essence':
+ if (class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_forum_settings')) {
+ $f = AKSRT_Settings::get_forum_settings();
+ return max(0, (int) ($f['credits']['essence'] ?? $default));
+ }
+ return $default;
+ case 'bbs_adopt':
+ if (class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_forum_settings')) {
+ $f = AKSRT_Settings::get_forum_settings();
+ return max(0, (int) ($f['credits']['adopted'] ?? $default));
+ }
+ return $default;
+ case 'bbs_posts_hot':
+ if (class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_forum_settings')) {
+ $f = AKSRT_Settings::get_forum_settings();
+ return max(0, (int) ($f['credits']['posts_hot'] ?? $default));
+ }
+ return $default;
+ case 'bbs_comment_hot':
+ if (class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_forum_settings')) {
+ $f = AKSRT_Settings::get_forum_settings();
+ return max(0, (int) ($f['credits']['comment_hot'] ?? $f['credits']['comment_like'] ?? $default));
+ }
+ return $default;
+ case 'bbs_score_extra':
+ if (class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_forum_settings')) {
+ $f = AKSRT_Settings::get_forum_settings();
+ return max(0, (int) ($f['credits']['score_extra'] ?? $default));
+ }
+ return $default;
default:
return $default;
}
diff --git a/inc/classes/class-aksrt-withdrawal.php b/inc/classes/class-aksrt-withdrawal.php
index 8c8a363c..ac5b8c87 100644
--- a/inc/classes/class-aksrt-withdrawal.php
+++ b/inc/classes/class-aksrt-withdrawal.php
@@ -167,7 +167,31 @@ class AKSRT_Withdrawal {
}
$ok = $wpdb->update($this->table(), $update, ['id' => $withdrawal_id], $format, ['%d']) !== false;
- return $ok ? true : new WP_Error('aksrt_withdraw_update', __('提现状态更新失败', 'aksrt'));
+ if (!$ok) {
+ return new WP_Error('aksrt_withdraw_update', __('提现状态更新失败', 'aksrt'));
+ }
+
+ // Notify user on terminal status (Zibll withdraw_reply parity).
+ if (class_exists('AKSRT_Message') && $user_id > 0 && in_array($new_status, [self::STATUS_COMPLETED, self::STATUS_REJECTED], true)) {
+ $gross = $this->resolve_gross_amount($row, $meta);
+ $amount_txt = class_exists('AKSRT_Balance') ? AKSRT_Balance::format($gross) : number_format($gross, 2);
+ if ($new_status === self::STATUS_REJECTED) {
+ $title = __('提现已拒绝', 'aksrt');
+ $body = sprintf(__('您申请提现 %s 元已被拒绝,冻结金额已退回钱包。', 'aksrt'), $amount_txt);
+ if ($note !== '') {
+ $body .= ' ' . sprintf(__('备注:%s', 'aksrt'), $note);
+ }
+ } else {
+ $title = __('提现已完成', 'aksrt');
+ $body = sprintf(__('您申请提现 %s 元已处理完成。', 'aksrt'), $amount_txt);
+ }
+ AKSRT_Message::get_instance()->send($user_id, 'withdraw', $body, [
+ 'title' => $title,
+ 'target_url' => function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url('credits') : '',
+ ]);
+ }
+
+ return true;
}
/**
diff --git a/inc/classes/forum/class-aksrt-forum-comment-service.php b/inc/classes/forum/class-aksrt-forum-comment-service.php
index 5a76d038..a934762e 100644
--- a/inc/classes/forum/class-aksrt-forum-comment-service.php
+++ b/inc/classes/forum/class-aksrt-forum-comment-service.php
@@ -312,17 +312,27 @@ class AKSRT_Forum_Comment_Service {
update_post_meta($topic_id, '_aksrt_question_status', 1); // QUESTION_SOLVED
$adoptee_id = (int) $comment->user_id;
- if ($adoptee_id > 0 && class_exists('AKSRT_Credits')) {
+ if ($adoptee_id > 0) {
$config = $this->forum->get_config();
$amount = (int) ($config['credits']['adopted'] ?? 20);
if ($amount > 0) {
$already = get_comment_meta($comment_id, '_aksrt_adopt_credited', true);
if (!$already) {
- \AKSRT_Credits::add($adoptee_id, $amount, 'forum_adopted', [
- 'type' => 'comment',
- 'id' => $comment_id,
- ]);
- update_comment_meta($comment_id, '_aksrt_adopt_credited', '1');
+ if (class_exists('AKSRT_Points_Free')) {
+ $granted = \AKSRT_Points_Free::grant($adoptee_id, 'bbs_adopt', $amount, [
+ 'type' => 'comment',
+ 'id' => $comment_id,
+ ]);
+ if (!is_wp_error($granted) && (int) $granted > 0) {
+ update_comment_meta($comment_id, '_aksrt_adopt_credited', '1');
+ }
+ } elseif (class_exists('AKSRT_Credits')) {
+ \AKSRT_Credits::add($adoptee_id, $amount, 'forum_adopted', [
+ 'type' => 'comment',
+ 'id' => $comment_id,
+ ]);
+ update_comment_meta($comment_id, '_aksrt_adopt_credited', '1');
+ }
}
}
@@ -498,15 +508,22 @@ class AKSRT_Forum_Comment_Service {
update_comment_meta($comment_id, '_aksrt_is_hot', '1');
- // Credit the comment author
+ // Credit the comment author (free-task day cap).
$author_id = (int) $comment->user_id;
- if ($author_id > 0 && class_exists('AKSRT_Credits')) {
- $amount = (int) ($config['credits']['comment_like'] ?? 1);
+ if ($author_id > 0) {
+ $amount = (int) ($config['credits']['comment_hot'] ?? $config['credits']['comment_like'] ?? 5);
if ($amount > 0) {
- \AKSRT_Credits::add($author_id, $amount, 'forum_hot_comment', [
- 'type' => 'comment',
- 'id' => $comment_id,
- ]);
+ if (class_exists('AKSRT_Points_Free')) {
+ \AKSRT_Points_Free::grant($author_id, 'bbs_comment_hot', $amount, [
+ 'type' => 'comment',
+ 'id' => $comment_id,
+ ]);
+ } elseif (class_exists('AKSRT_Credits')) {
+ \AKSRT_Credits::add($author_id, $amount, 'forum_hot_comment', [
+ 'type' => 'comment',
+ 'id' => $comment_id,
+ ]);
+ }
}
}
diff --git a/inc/classes/forum/class-aksrt-forum-score-service.php b/inc/classes/forum/class-aksrt-forum-score-service.php
index 5cd648e0..46a6dddf 100644
--- a/inc/classes/forum/class-aksrt-forum-score-service.php
+++ b/inc/classes/forum/class-aksrt-forum-score-service.php
@@ -126,16 +126,23 @@ class AKSRT_Forum_Score_Service {
$reputation += $amount;
update_user_meta($author_id, 'aksrt_reputation', $reputation);
- if ($amount > 0 && class_exists('AKSRT_Credits')) {
+ if ($amount > 0) {
$credits_amount = (int) ($config['credits']['score_extra'] ?? 3);
if ($credits_amount > 0) {
- $daily = $this->today_credits_count($author_id, 'forum_score_extra');
- $daily_max = (int) ($config['credits']['daily_max'] ?? 50);
- if ($daily < $daily_max) {
- AKSRT_Credits::add($author_id, $credits_amount, 'forum_score_extra', sprintf(
- __('帖子「%s」被加分', 'aksrt'),
- get_the_title($topic_id)
- ));
+ if (class_exists('AKSRT_Points_Free')) {
+ AKSRT_Points_Free::grant($author_id, 'bbs_score_extra', $credits_amount, [
+ 'type' => 'post',
+ 'id' => $topic_id,
+ ]);
+ } elseif (class_exists('AKSRT_Credits')) {
+ $daily = $this->today_credits_count($author_id, 'forum_score_extra');
+ $daily_max = (int) ($config['credits']['daily_max'] ?? 50);
+ if ($daily < $daily_max) {
+ AKSRT_Credits::add($author_id, $credits_amount, 'forum_score_extra', sprintf(
+ __('帖子「%s」被加分', 'aksrt'),
+ get_the_title($topic_id)
+ ));
+ }
}
}
}
@@ -232,10 +239,17 @@ class AKSRT_Forum_Score_Service {
update_post_meta($topic_id, '_aksrt_hot_rewarded', '1');
$config = $this->forum->get_config();
$amount = (int) ($config['credits']['posts_hot'] ?? 5);
- if ($amount > 0 && class_exists('AKSRT_Credits')) {
- AKSRT_Credits::add($author_id, $amount, 'forum_hot_topic', [
- 'type' => 'post', 'id' => $topic_id,
- ]);
+ if ($amount > 0) {
+ if (class_exists('AKSRT_Points_Free')) {
+ AKSRT_Points_Free::grant($author_id, 'bbs_posts_hot', $amount, [
+ 'type' => 'post',
+ 'id' => $topic_id,
+ ]);
+ } elseif (class_exists('AKSRT_Credits')) {
+ AKSRT_Credits::add($author_id, $amount, 'forum_hot_topic', [
+ 'type' => 'post', 'id' => $topic_id,
+ ]);
+ }
}
$this->notify($author_id, 'hot', sprintf(
__('你的帖子「%s」成为热帖!', 'aksrt'), get_the_title($topic_id)
diff --git a/inc/classes/forum/topic-service-traits/trait-aksrt-forum-topic-service-part-1.php b/inc/classes/forum/topic-service-traits/trait-aksrt-forum-topic-service-part-1.php
index 96c92fe2..29c4715b 100644
--- a/inc/classes/forum/topic-service-traits/trait-aksrt-forum-topic-service-part-1.php
+++ b/inc/classes/forum/topic-service-traits/trait-aksrt-forum-topic-service-part-1.php
@@ -245,22 +245,32 @@ trait AKSRT_Forum_Topic_Service_Part_1 {
return;
}
- // 积分奖励(§7.7):读 `credits.essence`,带每日上限。
- if (class_exists('AKSRT_Credits') && class_exists('AKSRT_Settings')) {
+ // 积分奖励(§7.7):统一走免费积分日上限。
+ if (class_exists('AKSRT_Settings')) {
$cfg = AKSRT_Settings::get_forum_settings();
$amount = (int) ($cfg['credits']['essence'] ?? 0);
if ($amount > 0) {
- $daily_max = (int) ($cfg['credits']['daily_max'] ?? 50);
- if ($daily_max > 0 && $this->today_credits_count($author_id, 'forum_essence') >= $daily_max) {
- $amount = 0;
- }
-
- if ($amount > 0) {
- AKSRT_Credits::add($author_id, $amount, 'forum_essence', [
+ $granted = 0;
+ if (class_exists('AKSRT_Points_Free')) {
+ $result = AKSRT_Points_Free::grant($author_id, 'bbs_essence', $amount, [
'type' => 'post',
- 'id' => $topic_id,
- ], __('主题被设为精华', 'aksrt'));
-
+ 'id' => $topic_id,
+ ]);
+ $granted = is_wp_error($result) ? 0 : (int) $result;
+ } elseif (class_exists('AKSRT_Credits')) {
+ $daily_max = (int) ($cfg['credits']['daily_max'] ?? 50);
+ if ($daily_max > 0 && $this->today_credits_count($author_id, 'forum_essence') >= $daily_max) {
+ $amount = 0;
+ }
+ if ($amount > 0) {
+ AKSRT_Credits::add($author_id, $amount, 'forum_essence', [
+ 'type' => 'post',
+ 'id' => $topic_id,
+ ], __('主题被设为精华', 'aksrt'));
+ $granted = $amount;
+ }
+ }
+ if ($granted > 0) {
update_post_meta($topic_id, '_aksrt_essence_rewarded', '1');
update_post_meta($topic_id, '_aksrt_essence_rewarded_at', current_time('mysql'));
}
diff --git a/inc/helpers/aksrt-credits.php b/inc/helpers/aksrt-credits.php
index f5919a1f..afd0d287 100644
--- a/inc/helpers/aksrt-credits.php
+++ b/inc/helpers/aksrt-credits.php
@@ -61,6 +61,10 @@ if (!function_exists('aksrt_credits_label')) {
'free_bbs_posts_new'=> __('论坛发帖', 'aksrt'),
'free_bbs_reply'=> __('论坛回复', 'aksrt'),
'free_bbs_essence'=> __('帖子加精', 'aksrt'),
+ 'free_bbs_adopt'=> __('回复被采纳', 'aksrt'),
+ 'free_bbs_posts_hot'=> __('热帖奖励', 'aksrt'),
+ 'free_bbs_comment_hot'=> __('神评奖励', 'aksrt'),
+ 'free_bbs_score_extra'=> __('帖子加分', 'aksrt'),
];
if (isset($map[$reason])) {
return $map[$reason];
diff --git a/inc/helpers/aksrt-single-render.php b/inc/helpers/aksrt-single-render.php
index 3de983cf..2b5b04b7 100644
--- a/inc/helpers/aksrt-single-render.php
+++ b/inc/helpers/aksrt-single-render.php
@@ -236,6 +236,7 @@ if (!function_exists('aksrt_single_render_actions')) :
+
![QR Code]()
From a0748c08fe732164e2e366d17343136d4668ae1c Mon Sep 17 00:00:00 2001
From: unknown
Date: Thu, 16 Jul 2026 19:33:57 +0800
Subject: [PATCH 2/3] feat(frontend): illustrated null states and author
rewards fallback
Add aksrt_get_null / widget null helpers with null.svg, use them in
sidebar widgets, comments empty, and related posts; when PM is off show
post rewards entry on the single author bar.
---
assets/css/frontend/widgets/part-2.css | 12 +++
assets/img/null.svg | 9 +++
inc/bootstrap.php | 1 +
inc/classes/class-aksrt-widgets-batch1.php | 4 +-
inc/classes/class-aksrt-widgets-new.php | 4 +-
.../widgets/class-aksrt-home-widgets.php | 6 +-
inc/helpers/aksrt-comments.php | 8 +-
inc/helpers/aksrt-null.php | 78 +++++++++++++++++++
inc/helpers/aksrt-single-render.php | 11 +++
templates/parts/single-author-bar.php | 16 +++-
10 files changed, 140 insertions(+), 9 deletions(-)
create mode 100644 assets/img/null.svg
create mode 100644 inc/helpers/aksrt-null.php
diff --git a/assets/css/frontend/widgets/part-2.css b/assets/css/frontend/widgets/part-2.css
index 14337910..9cc4840d 100644
--- a/assets/css/frontend/widgets/part-2.css
+++ b/assets/css/frontend/widgets/part-2.css
@@ -298,3 +298,15 @@
}
/* ============================================================
+
+
+.aksrt-null--widget {
+ padding: 12px 0 !important;
+}
+.aksrt-null--widget .aksrt-null__img {
+ margin: 0 auto;
+ display: block;
+}
+.aksrt-null .separator {
+ border: 0;
+}
diff --git a/assets/img/null.svg b/assets/img/null.svg
new file mode 100644
index 00000000..d6dd55b1
--- /dev/null
+++ b/assets/img/null.svg
@@ -0,0 +1,9 @@
+
diff --git a/inc/bootstrap.php b/inc/bootstrap.php
index e5573087..2b383295 100644
--- a/inc/bootstrap.php
+++ b/inc/bootstrap.php
@@ -43,6 +43,7 @@ require_once AKSRT_DIR . '/inc/helpers/aksrt-resource.php';
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/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/class-aksrt-widgets-batch1.php b/inc/classes/class-aksrt-widgets-batch1.php
index 22e558c8..50e6d6f4 100644
--- a/inc/classes/class-aksrt-widgets-batch1.php
+++ b/inc/classes/class-aksrt-widgets-batch1.php
@@ -192,7 +192,7 @@ class AKSRT_Recent_Comments_Widget extends WP_Widget {
-
+ ' . esc_html__('暂无评论', 'aksrt') . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
-
+ ' . esc_html__('暂无友情链接', 'aksrt') . ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
';
wp_reset_postdata();
} else {
- echo '' . esc_html__('暂无热门文章', 'aksrt') . '
';
+ echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('暂无热门文章', 'aksrt')) : '' . esc_html__('暂无热门文章', 'aksrt') . '
';
}
echo $args['after_widget'];
@@ -360,7 +360,7 @@ class AKSRT_Tab_Posts_Widget extends WP_Widget {
-
+ ' . esc_html__('暂无文章', 'aksrt') . ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
diff --git a/inc/classes/widgets/class-aksrt-home-widgets.php b/inc/classes/widgets/class-aksrt-home-widgets.php
index aaf55950..78a9e722 100644
--- a/inc/classes/widgets/class-aksrt-home-widgets.php
+++ b/inc/classes/widgets/class-aksrt-home-widgets.php
@@ -189,7 +189,7 @@ if (!function_exists('aksrt_home_widget_render_post_grid')) {
*/
function aksrt_home_widget_render_post_grid(WP_Query $query, string $layout = 'card', int $columns = 3, string $context = 'homepage'): void {
if (!$query->have_posts()) {
- echo '' . esc_html__('暂无内容', 'aksrt') . '
';
+ echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('暂无内容', 'aksrt')) : '' . esc_html__('暂无内容', 'aksrt') . '
';
wp_reset_postdata();
return;
}
@@ -464,7 +464,7 @@ class AKSRT_Category_Tabs_Widget extends WP_Widget {
echo '';
if (empty($tabs)) {
- echo '' . esc_html__('暂无可用分类', 'aksrt') . '
';
+ echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('暂无可用分类', 'aksrt')) : '' . esc_html__('暂无可用分类', 'aksrt') . '
';
echo '';
echo $args['after_widget'];
return;
@@ -649,7 +649,7 @@ class AKSRT_Category_Recommend_Widget extends WP_Widget {
aksrt_home_widget_render_header($title);
if (empty($cards)) {
- echo '' . esc_html__('暂无推荐分类', 'aksrt') . '
';
+ echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('暂无推荐分类', 'aksrt')) : '' . esc_html__('暂无推荐分类', 'aksrt') . '
';
echo '';
echo $args['after_widget'];
return;
diff --git a/inc/helpers/aksrt-comments.php b/inc/helpers/aksrt-comments.php
index de3de7eb..cb94a64c 100644
--- a/inc/helpers/aksrt-comments.php
+++ b/inc/helpers/aksrt-comments.php
@@ -571,12 +571,18 @@ if (!function_exists('aksrt_comments_render_empty')) :
* @param array $ctx Comments context.
*/
function aksrt_comments_render_empty(array $ctx): void {
+ $text = (string) ($ctx['empty_text'] ?? __('暂无评论内容', 'aksrt'));
+ if (function_exists('aksrt_get_null')) {
+ echo aksrt_get_null($text, 40, 'null.svg', 'comment comment-null comments-empty', 220); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ echo '';
+ return;
+ }
?>
' . esc_html((string) $text) . ''
+ : '';
+ if ($height > 0) {
+ $style = $width > 0 ? 'max-width:' . (int) $width . 'px;' : '';
+ $style .= 'height:' . (int) $height . 'px;';
+ } else {
+ $style = $width > 0 ? 'width:' . (int) $width . 'px;' : '';
+ }
+ $style .= 'opacity:.7;';
+ $src = aksrt_null_image_url($img);
+ return ''
+ . '
 . ')
'
+ . $caption
+ . '
';
+ }
+}
+
+if (!function_exists('aksrt_get_widget_null')) {
+ /**
+ * Compact null for sidebar widgets.
+ */
+ function aksrt_get_widget_null(string $text = '', int $margin = 24, int $width = 140): string {
+ if ($text === '') {
+ $text = __('暂无内容', 'aksrt');
+ }
+ return aksrt_get_null($text, $margin, 'null.svg', 'widget-empty aksrt-null--widget', $width);
+ }
+}
diff --git a/inc/helpers/aksrt-single-render.php b/inc/helpers/aksrt-single-render.php
index 2b5b04b7..5996da6b 100644
--- a/inc/helpers/aksrt-single-render.php
+++ b/inc/helpers/aksrt-single-render.php
@@ -555,6 +555,17 @@ if (!function_exists('aksrt_single_render_related')) :
$query = new WP_Query($args);
if (!$query->have_posts()) {
wp_reset_postdata();
+ $empty_wrap = 'theme-box relates' . ($style === 'img' ? ' relates-thumb' : '');
+ ?>
+
+ ">
-
+
+
+
+
+
+
From defb64fd89574b0bf3e872afa44236cecb697595 Mon Sep 17 00:00:00 2001
From: unknown
Date: Thu, 16 Jul 2026 20:32:46 +0800
Subject: [PATCH 3/3] =?UTF-8?q?feat(single):=20identity=20chips,=20comment?=
=?UTF-8?q?=20=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')) :
diff --git a/templates/parts/single-author-bar.php b/templates/parts/single-author-bar.php
index 8371b322..6f706d83 100644
--- a/templates/parts/single-author-bar.php
+++ b/templates/parts/single-author-bar.php
@@ -48,12 +48,10 @@ $aksrt_msg_url = function_exists('aksrt_get_messages_page_url') ? aksrt_get_mess
$login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url(get_permalink());
$is_self = is_user_logged_in() && get_current_user_id() === $author_id;
-// Identity chips: VIP + verify/level/badges.
-$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: VIP + verify/level/badges (shared helper).
+$identity_chips = function_exists('aksrt_render_user_identity_chips')
+ ? aksrt_render_user_identity_chips($author_id, 'author')
+ : '';
?>
@@ -71,15 +69,9 @@ if (class_exists('AKSRT_User_Home')) {