feat(identity): author card, per-user tip, comment caps, task status
Author card uses configurable limit/orderby/style and self CTAs. Tip is per-user weixin/alipay QR modal (no site-global image). Comment action permissions honor user_caps matrix. Free points tasks expose done_today/passive status + better comment deep link. audit-admin-contracts errors=0.
This commit is contained in:
@@ -49,10 +49,11 @@ export const pageSchema = {
|
||||
post_article_video_cover_scale: 56,
|
||||
item_heading_bold: false,
|
||||
post_button_toptext: '喜欢就支持一下吧',
|
||||
post_rewards_enabled: false,
|
||||
post_rewards_text: '',
|
||||
post_rewards_image: '',
|
||||
post_rewards_btn_text: '赞赏',
|
||||
post_rewards_s: false,
|
||||
post_rewards_text: '赞赏',
|
||||
post_author_card_limit: 6,
|
||||
post_author_card_orderby: 'views',
|
||||
post_author_card_style: 'card',
|
||||
article_maxheight_kg: false,
|
||||
article_maxheight: 1000,
|
||||
},
|
||||
@@ -71,6 +72,17 @@ export const pageSchema = {
|
||||
{ key: 'breadcrumbs_single_text', label: '末项显示「正文」', type: 'switch', default: true, dependsOn: { key: 'breadcrumbs_single_s', value: true }, help: '关闭后末项显示文章标题' },
|
||||
{ key: 'post_prevnext_s', label: '上一篇/下一篇', type: 'switch', default: true },
|
||||
{ key: 'post_authordesc_s', label: '作者简介', type: 'switch', default: true },
|
||||
{ key: 'post_author_card_limit', label: '作者卡文章数', type: 'number', default: 6, min: 0, max: 12, dependsOn: { key: 'post_authordesc_s', value: true } },
|
||||
{ key: 'post_author_card_orderby', label: '作者卡文章排序', type: 'select', default: 'views', options: [
|
||||
{ label: '浏览量', value: 'views' },
|
||||
{ label: '发布时间', value: 'date' },
|
||||
{ label: '更新时间', value: 'modified' },
|
||||
{ label: '评论数', value: 'comment_count' },
|
||||
], dependsOn: { key: 'post_authordesc_s', value: true } },
|
||||
{ key: 'post_author_card_style', label: '作者卡文章样式', type: 'radio', default: 'card', options: [
|
||||
{ label: '卡片', value: 'card' },
|
||||
{ label: '列表', value: 'list' },
|
||||
], dependsOn: { key: 'post_authordesc_s', value: true } },
|
||||
{ key: 'post_single_hide_time_s', label: '隐藏文章时间', type: 'switch', default: false },
|
||||
],
|
||||
},
|
||||
@@ -137,10 +149,8 @@ export const pageSchema = {
|
||||
{ key: 'post_copyright_enabled', label: '版权信息', type: 'switch', default: true },
|
||||
{ key: 'post_copyright_text', label: '版权默认文案', type: 'textarea', default: '', help: '留空则自动生成"本文由 XX 原创发布"' },
|
||||
{ key: 'post_button_toptext', label: '按钮上方文案', type: 'input', default: '喜欢就支持一下吧', help: '显示在点赞/打赏/分享按钮上方' },
|
||||
{ key: 'post_rewards_enabled', label: '打赏', type: 'switch', default: false },
|
||||
{ key: 'post_rewards_btn_text', label: '打赏按钮文案', type: 'input', default: '赞赏', dependsOn: { key: 'post_rewards_enabled', value: true } },
|
||||
{ key: 'post_rewards_text', label: '打赏说明', type: 'input', default: '', dependsOn: { key: 'post_rewards_enabled', value: true } },
|
||||
{ key: 'post_rewards_image', label: '打赏二维码 URL', type: 'input', default: '', dependsOn: { key: 'post_rewards_enabled', value: true } },
|
||||
{ key: 'post_rewards_s', label: '用户打赏', type: 'switch', default: false, help: '开启后用户可配置微信/支付宝收款码;无码则不显示按钮。' },
|
||||
{ key: 'post_rewards_text', label: '打赏按钮文案', type: 'input', default: '赞赏', dependsOn: { key: 'post_rewards_s', value: true } },
|
||||
{ key: 'article_maxheight_kg', label: '正文限高', type: 'switch', default: false, help: '开启后长文默认折叠,可展开全文' },
|
||||
{ key: 'article_maxheight', label: '限高像素', type: 'number', default: 1000, min: 200, max: 5000, dependsOn: { key: 'article_maxheight_kg', value: true } },
|
||||
],
|
||||
|
||||
+28
-74
@@ -1,8 +1,5 @@
|
||||
/**
|
||||
* Reward (打赏) — dedicated module.
|
||||
*
|
||||
* Handles the reward modal: amount selection, custom amount input,
|
||||
* QR code display, and open/close interaction.
|
||||
* Reward (打赏) — per-user QR modal openers.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
@@ -10,95 +7,52 @@
|
||||
'use strict';
|
||||
|
||||
function initReward() {
|
||||
var btn = document.getElementById('action-reward');
|
||||
if (!btn) return;
|
||||
function closeAll() {
|
||||
document.querySelectorAll('.reward-modal.is-open').forEach(function (m) {
|
||||
m.classList.remove('is-open');
|
||||
m.setAttribute('aria-hidden', 'true');
|
||||
});
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
var modal = document.getElementById('reward-modal');
|
||||
if (!modal) return;
|
||||
|
||||
var closeBtn = modal.querySelector('.reward-modal__close');
|
||||
var overlay = modal.querySelector('.reward-modal__overlay');
|
||||
var amountBtns = modal.querySelectorAll('.reward-amounts__btn');
|
||||
var customWrap = modal.querySelector('.reward-custom');
|
||||
var customInput = modal ? modal.querySelector('.reward-custom__input') : null;
|
||||
var customConfirm = modal ? modal.querySelector('.reward-custom__confirm') : null;
|
||||
var selectedAmount = 0;
|
||||
|
||||
/* ---- open / close ---- */
|
||||
function openReward() {
|
||||
function openForUser(userId) {
|
||||
var id = String(userId || '');
|
||||
var modal = id
|
||||
? document.getElementById('reward-modal-' + id)
|
||||
: document.querySelector('.reward-modal');
|
||||
if (!modal) return;
|
||||
closeAll();
|
||||
modal.classList.add('is-open');
|
||||
modal.setAttribute('aria-hidden', 'false');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeReward() {
|
||||
modal.classList.remove('is-open');
|
||||
document.body.style.overflow = '';
|
||||
// reset selection
|
||||
selectedAmount = 0;
|
||||
amountBtns.forEach(function (b) { b.classList.remove('is-active'); });
|
||||
if (customInput) customInput.value = '';
|
||||
}
|
||||
|
||||
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();
|
||||
openForUser(el.getAttribute('data-user-id') || '');
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-aksrt-reward-close]').forEach(function (el) {
|
||||
el.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
closeAll();
|
||||
});
|
||||
});
|
||||
if (closeBtn) closeBtn.addEventListener('click', closeReward);
|
||||
if (overlay) overlay.addEventListener('click', closeReward);
|
||||
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape' && modal.classList.contains('is-open')) closeReward();
|
||||
if (e.key === 'Escape') closeAll();
|
||||
});
|
||||
|
||||
/* ---- amount selection ---- */
|
||||
amountBtns.forEach(function (b) {
|
||||
b.addEventListener('click', function () {
|
||||
amountBtns.forEach(function (x) { x.classList.remove('is-active'); });
|
||||
b.classList.add('is-active');
|
||||
selectedAmount = parseInt(b.dataset.amount || '0', 10);
|
||||
// clear custom input when preset is chosen
|
||||
if (customInput) customInput.value = '';
|
||||
});
|
||||
});
|
||||
|
||||
/* ---- custom amount ---- */
|
||||
if (customInput) {
|
||||
customInput.addEventListener('focus', function () {
|
||||
amountBtns.forEach(function (x) { x.classList.remove('is-active'); });
|
||||
selectedAmount = 0;
|
||||
});
|
||||
customInput.addEventListener('input', function () {
|
||||
// strip non-digits
|
||||
customInput.value = customInput.value.replace(/[^\d]/g, '');
|
||||
});
|
||||
}
|
||||
|
||||
if (customConfirm) {
|
||||
customConfirm.addEventListener('click', function () {
|
||||
var val = customInput ? parseInt(customInput.value, 10) : 0;
|
||||
if (val > 0) {
|
||||
selectedAmount = val;
|
||||
amountBtns.forEach(function (x) { x.classList.remove('is-active'); });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- register with AksrtFrontend lifecycle ---- */
|
||||
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
|
||||
window.AksrtFrontend.register('aksrt-reward', function () {
|
||||
initReward();
|
||||
});
|
||||
} else if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initReward);
|
||||
} else {
|
||||
// fallback: run on DOMContentLoaded
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initReward);
|
||||
} else {
|
||||
initReward();
|
||||
}
|
||||
initReward();
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -45,6 +45,7 @@ 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/aksrt-rewards.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';
|
||||
|
||||
@@ -75,6 +75,17 @@ class AKSRT_Admin_Schema_Post_List {
|
||||
['key' => 'breadcrumbs_single_text', 'label' => '末项显示「正文」', 'type' => 'switch', 'default' => true, 'depends_on' => 'breadcrumbs_single_s', 'description' => '关闭后末项显示文章标题'],
|
||||
['key' => 'post_prevnext_s', 'label' => '上一篇/下一篇', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'post_authordesc_s', 'label' => '作者简介', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'post_author_card_limit', 'label' => '作者卡文章数', 'type' => 'number', 'default' => 6, 'min' => 0, 'max' => 12],
|
||||
['key' => 'post_author_card_orderby', 'label' => '作者卡文章排序', 'type' => 'select', 'default' => 'views', 'options' => [
|
||||
['label' => '浏览量', 'value' => 'views'],
|
||||
['label' => '发布时间', 'value' => 'date'],
|
||||
['label' => '更新时间', 'value' => 'modified'],
|
||||
['label' => '评论数', 'value' => 'comment_count'],
|
||||
]],
|
||||
['key' => 'post_author_card_style', 'label' => '作者卡文章样式', 'type' => 'radio', 'default' => 'card', 'options' => [
|
||||
['label' => '卡片', 'value' => 'card'],
|
||||
['label' => '列表', 'value' => 'list'],
|
||||
]],
|
||||
['key' => 'post_single_hide_time_s', 'label' => '隐藏文章时间', 'type' => 'switch', 'default' => false],
|
||||
]],
|
||||
['key' => 'cover', 'title' => '封面展示', 'fields' => [
|
||||
@@ -127,8 +138,8 @@ class AKSRT_Admin_Schema_Post_List {
|
||||
['key' => 'post_copyright_enabled', 'label' => '版权信息', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'post_copyright_text', 'label' => '版权默认文案', 'type' => 'textarea', 'default' => '', 'description' => '留空则自动生成"本文由 XX 原创发布"'],
|
||||
['key' => 'post_wechat_share', 'label' => '微信分享', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'post_rewards_enabled', 'label' => '打赏功能', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'post_rewards_text', 'label' => '打赏文案', 'type' => 'input', 'default' => ''],
|
||||
['key' => 'post_rewards_s', 'label' => '用户打赏', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'post_rewards_text', 'label' => '打赏按钮文案', 'type' => 'input', 'default' => '赞赏'],
|
||||
['key' => 'post_button_toptext', 'label' => '按钮上方文案', 'type' => 'input', 'default' => '喜欢就支持一下吧'],
|
||||
]],
|
||||
['key' => 'content', 'title' => '内容处理', 'fields' => [
|
||||
|
||||
@@ -180,9 +180,12 @@ class AKSRT_Points_Free {
|
||||
* @return list<array{key:string,title:string,desc:string,points:int,enabled:bool}>
|
||||
*/
|
||||
public static function task_list_for_user(int $user_id = 0): array {
|
||||
unset($user_id); // reserved for per-user progress later
|
||||
$cfg = self::settings();
|
||||
$list = [];
|
||||
$login_done = false;
|
||||
if ($user_id > 0) {
|
||||
$login_done = (string) get_user_meta($user_id, self::META_LOGIN, true) === self::today_key();
|
||||
}
|
||||
foreach (self::catalog() as $key => $meta) {
|
||||
$pts = (int) ($cfg['tasks'][$key] ?? 0);
|
||||
// Hide sign_up from daily task list (one-time); still grant on register.
|
||||
@@ -192,12 +195,21 @@ class AKSRT_Points_Free {
|
||||
if ($pts <= 0) {
|
||||
continue;
|
||||
}
|
||||
$status = 'todo';
|
||||
if (in_array($key, ['login', 'sign_in'], true) && $login_done) {
|
||||
$status = 'done_today';
|
||||
} elseif (in_array($key, ['post_like', 'post_favorite', 'followed', 'comment_like', 'bbs_essence', 'bbs_adopt', 'bbs_posts_hot', 'bbs_comment_hot', 'bbs_score_extra'], true)) {
|
||||
$status = 'passive';
|
||||
}
|
||||
$list[] = [
|
||||
'key' => $key,
|
||||
'title' => $meta[0],
|
||||
'desc' => $meta[1],
|
||||
'points' => $pts,
|
||||
'enabled' => true,
|
||||
'key' => $key,
|
||||
'title' => $meta[0],
|
||||
'desc' => $meta[1],
|
||||
'points' => $pts,
|
||||
'enabled' => true,
|
||||
'status' => $status,
|
||||
'progress' => null,
|
||||
'target' => null,
|
||||
];
|
||||
}
|
||||
return $list;
|
||||
|
||||
@@ -237,10 +237,20 @@ class AKSRT_Settings_Post_Display {
|
||||
$authordesc = !isset($settings['post_authordesc_s']) || !empty($settings['post_authordesc_s']);
|
||||
$hide_time = !empty($settings['post_single_hide_time_s']);
|
||||
$share_enabled = !isset($settings['share_s']) || !empty($settings['share_s']);
|
||||
$rewards_enabled = !empty($settings['post_rewards_enabled']) || !empty($settings['post_rewards_s']);
|
||||
$rewards_image = (string) ($settings['post_rewards_image'] ?? $settings['post_rewards_qrcode'] ?? $settings['post_rewards_img'] ?? '');
|
||||
$rewards_enabled = !empty($settings['post_rewards_s']) || !empty($settings['post_rewards_enabled']);
|
||||
$rewards_text = sanitize_text_field((string) ($settings['post_rewards_text'] ?? ''));
|
||||
$rewards_btn_text = sanitize_text_field((string) ($settings['post_rewards_btn_text'] ?? '赞赏'));
|
||||
if ($rewards_text === '') {
|
||||
$rewards_text = '赞赏';
|
||||
}
|
||||
$author_card_limit = max(0, min(12, (int) ($settings['post_author_card_limit'] ?? 6)));
|
||||
$author_card_orderby = sanitize_key((string) ($settings['post_author_card_orderby'] ?? 'views'));
|
||||
if (!in_array($author_card_orderby, ['views', 'date', 'modified', 'comment_count'], true)) {
|
||||
$author_card_orderby = 'views';
|
||||
}
|
||||
$author_card_style = sanitize_key((string) ($settings['post_author_card_style'] ?? 'card'));
|
||||
if (!in_array($author_card_style, ['card', 'list'], true)) {
|
||||
$author_card_style = 'card';
|
||||
}
|
||||
$maxheight_enabled = !empty($settings['article_maxheight_kg'])
|
||||
|| !empty($settings['post_article_maxheight_kg'])
|
||||
|| !empty($settings['post_maxheight_kg']);
|
||||
@@ -318,11 +328,15 @@ class AKSRT_Settings_Post_Display {
|
||||
// Canonical + legacy share.
|
||||
'share_enabled' => $share_enabled,
|
||||
'share_s' => $share_enabled,
|
||||
// Rewards (Zibll post_rewards_s).
|
||||
// Author card posts (Zibll user_card_box defaults).
|
||||
'author_card_limit' => $author_card_limit,
|
||||
'author_card_orderby' => $author_card_orderby,
|
||||
'author_card_style' => $author_card_style,
|
||||
// Rewards (Zibll post_rewards_s) — per-user QR only.
|
||||
'rewards_enabled' => $rewards_enabled,
|
||||
'rewards_image' => $rewards_image,
|
||||
'post_rewards_s' => $rewards_enabled,
|
||||
'rewards_text' => $rewards_text,
|
||||
'rewards_btn_text' => $rewards_btn_text !== '' ? $rewards_btn_text : '赞赏',
|
||||
'rewards_btn_text' => $rewards_text,
|
||||
// Content max height (Zibll article_maxheight_kg / article_maxheight).
|
||||
'maxheight_enabled' => $maxheight_enabled,
|
||||
'maxheight' => $maxheight,
|
||||
|
||||
@@ -835,28 +835,59 @@ if (!function_exists('aksrt_comment_action_permissions')) :
|
||||
* @return array{can_edit:bool,can_delete:bool,can_moderate:bool,can_pin:bool}
|
||||
*/
|
||||
function aksrt_comment_action_permissions($comment): array {
|
||||
$comment = $comment instanceof WP_Comment ? $comment : get_comment($comment);
|
||||
$none = ['can_edit' => false, 'can_delete' => false, 'can_moderate' => false, 'can_pin' => false];
|
||||
if (!($comment instanceof WP_Comment) || !is_user_logged_in()) {
|
||||
return $none;
|
||||
$comment = $comment instanceof WP_Comment ? $comment : get_comment($comment);
|
||||
$none = ['can_edit' => false, 'can_delete' => false, 'can_moderate' => false, 'can_pin' => false];
|
||||
if (!($comment instanceof WP_Comment) || !is_user_logged_in()) {
|
||||
return $none;
|
||||
}
|
||||
$uid = get_current_user_id();
|
||||
$is_wp_mod = current_user_can('moderate_comments') || current_user_can('manage_options');
|
||||
$is_owner = (int) $comment->user_id > 0 && (int) $comment->user_id === $uid;
|
||||
$post_id = (int) $comment->comment_post_ID;
|
||||
$post = $post_id > 0 ? get_post($post_id) : null;
|
||||
$is_post_author = $post instanceof WP_Post && (int) $post->post_author === $uid;
|
||||
$ctx = $post_id > 0 ? $post_id : null;
|
||||
|
||||
$can = static function (string $cap) use ($uid, $ctx): bool {
|
||||
if (function_exists('aksrt_user_can')) {
|
||||
return aksrt_user_can($cap, $uid, $ctx);
|
||||
}
|
||||
if (class_exists('AKSRT_Settings_Capabilities')) {
|
||||
return AKSRT_Settings_Capabilities::user_can($cap, $uid, $ctx);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
$edit_window = 10;
|
||||
if (class_exists('AKSRT_Settings')) {
|
||||
$display = AKSRT_Settings::get_comment_display_settings();
|
||||
$edit_window = (int) ($display['edit_window'] ?? 10);
|
||||
}
|
||||
$within_window = $edit_window > 0
|
||||
&& (time() - strtotime((string) $comment->comment_date_gmt)) < ($edit_window * MINUTE_IN_SECONDS);
|
||||
|
||||
$can_edit_own = $is_owner && $within_window && $can('comment_edit');
|
||||
$can_edit_others = (!$is_owner) && (
|
||||
($is_post_author && $can('comment_edit_my_post'))
|
||||
|| $can('comment_edit_other')
|
||||
);
|
||||
$can_delete_own = $is_owner && $can('comment_delete');
|
||||
$can_delete_others = (!$is_owner) && (
|
||||
($is_post_author && $can('comment_delete_my_post'))
|
||||
|| $can('comment_delete_other')
|
||||
);
|
||||
$can_pin = (int) $comment->comment_parent === 0 && (
|
||||
($is_post_author && $can('comment_set_topping_my_post'))
|
||||
|| $can('comment_set_topping_other')
|
||||
);
|
||||
|
||||
return [
|
||||
'can_edit' => $is_wp_mod || $can_edit_own || $can_edit_others,
|
||||
'can_delete' => $is_wp_mod || $can_delete_own || $can_delete_others,
|
||||
'can_moderate' => $is_wp_mod || $can('comment_audit_other') || ($is_post_author && $can('comment_audit_my_post')),
|
||||
'can_pin' => $is_wp_mod || $can_pin,
|
||||
];
|
||||
}
|
||||
$is_moderator = current_user_can('moderate_comments');
|
||||
$is_owner = (int) $comment->user_id > 0 && (int) $comment->user_id === get_current_user_id();
|
||||
// Owner self-edit window (minutes); moderators bypass the window.
|
||||
$edit_window = 10;
|
||||
if (class_exists('AKSRT_Settings')) {
|
||||
$display = AKSRT_Settings::get_comment_display_settings();
|
||||
$edit_window = (int) ($display['edit_window'] ?? 10);
|
||||
}
|
||||
$within_window = $edit_window > 0
|
||||
&& (time() - strtotime((string) $comment->comment_date_gmt)) < ($edit_window * MINUTE_IN_SECONDS);
|
||||
return [
|
||||
'can_edit' => $is_moderator || ($is_owner && $within_window),
|
||||
'can_delete' => $is_moderator || $is_owner,
|
||||
'can_moderate' => $is_moderator,
|
||||
'can_pin' => $is_moderator && (int) $comment->comment_parent === 0,
|
||||
];
|
||||
}
|
||||
endif;
|
||||
if (!function_exists('aksrt_is_comment_pinned')) :
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* Per-user tip (打赏) helpers — Zibll post_rewards_s + user QR parity.
|
||||
*
|
||||
* Meta: aksrt_rewards_weixin, aksrt_rewards_alipay (attachment id or URL).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_rewards_enabled')) {
|
||||
function aksrt_rewards_enabled(): bool {
|
||||
if (!class_exists('AKSRT_Settings') || !method_exists('AKSRT_Settings', 'get_post_page_settings')) {
|
||||
return false;
|
||||
}
|
||||
$s = AKSRT_Settings::get_post_page_settings();
|
||||
return !empty($s['rewards_enabled']) || !empty($s['post_rewards_s']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_get_user_rewards_img_urls')) {
|
||||
/**
|
||||
* @return array{weixin:string,alipay:string}
|
||||
*/
|
||||
function aksrt_get_user_rewards_img_urls(int $user_id): array {
|
||||
$out = ['weixin' => '', 'alipay' => ''];
|
||||
if ($user_id <= 0) {
|
||||
return $out;
|
||||
}
|
||||
foreach (['weixin' => 'aksrt_rewards_weixin', 'alipay' => 'aksrt_rewards_alipay'] as $key => $meta) {
|
||||
$raw = get_user_meta($user_id, $meta, true);
|
||||
if (is_numeric($raw) && (int) $raw > 0) {
|
||||
$url = wp_get_attachment_image_url((int) $raw, 'full');
|
||||
$out[$key] = is_string($url) ? $url : '';
|
||||
} else {
|
||||
$out[$key] = esc_url_raw((string) $raw);
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_user_has_rewards_qr')) {
|
||||
function aksrt_user_has_rewards_qr(int $user_id): bool {
|
||||
$urls = aksrt_get_user_rewards_img_urls($user_id);
|
||||
return $urls['weixin'] !== '' || $urls['alipay'] !== '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_get_rewards_button')) {
|
||||
function aksrt_get_rewards_button(int $user_id, string $class = 'but jb-blue ml10 pw-1em'): string {
|
||||
if ($user_id <= 0 || !aksrt_rewards_enabled() || !aksrt_user_has_rewards_qr($user_id)) {
|
||||
return '';
|
||||
}
|
||||
$label = '赞赏';
|
||||
if (class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_post_page_settings')) {
|
||||
$s = AKSRT_Settings::get_post_page_settings();
|
||||
$label = (string) ($s['rewards_btn_text'] ?? $s['rewards_text'] ?? $label);
|
||||
if ($label === '') {
|
||||
$label = '赞赏';
|
||||
}
|
||||
}
|
||||
return '<button type="button" class="' . esc_attr($class) . ' aksrt-reward-open" data-aksrt-reward-open data-user-id="' . (int) $user_id . '"><i class="fa fa-gift em09" aria-hidden="true"></i> ' . esc_html($label) . '</button>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_render_rewards_modal_for_user')) {
|
||||
function aksrt_render_rewards_modal_for_user(int $user_id): void {
|
||||
static $done = [];
|
||||
if ($user_id <= 0 || isset($done[$user_id])) {
|
||||
return;
|
||||
}
|
||||
if (!aksrt_rewards_enabled() || !aksrt_user_has_rewards_qr($user_id)) {
|
||||
return;
|
||||
}
|
||||
$done[$user_id] = true;
|
||||
$urls = aksrt_get_user_rewards_img_urls($user_id);
|
||||
$label = '赞赏';
|
||||
if (class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_post_page_settings')) {
|
||||
$s = AKSRT_Settings::get_post_page_settings();
|
||||
$label = (string) ($s['rewards_text'] ?? $label);
|
||||
if ($label === '') {
|
||||
$label = __('赞赏', 'aksrt');
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="reward-modal" id="reward-modal-<?php echo (int) $user_id; ?>" data-user-id="<?php echo (int) $user_id; ?>" aria-hidden="true">
|
||||
<div class="reward-modal__overlay" data-aksrt-reward-close></div>
|
||||
<div class="reward-modal__dialog" role="dialog" aria-modal="true">
|
||||
<button type="button" class="reward-modal__close" data-aksrt-reward-close aria-label="<?php esc_attr_e('关闭', 'aksrt'); ?>"><i class="fas fa-times" aria-hidden="true"></i></button>
|
||||
<div class="reward-modal__content">
|
||||
<h3><?php echo esc_html($label); ?></h3>
|
||||
<div class="reward-modal__qrcodes flex jc ac hh">
|
||||
<?php if ($urls['weixin'] !== '') : ?>
|
||||
<div class="reward-modal__qrcode text-center mr10">
|
||||
<img src="<?php echo esc_url($urls['weixin']); ?>" alt="<?php esc_attr_e('微信收款码', 'aksrt'); ?>" loading="lazy" decoding="async" />
|
||||
<div class="em09 muted-2-color mt6"><?php esc_html_e('微信', 'aksrt'); ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($urls['alipay'] !== '') : ?>
|
||||
<div class="reward-modal__qrcode text-center">
|
||||
<img src="<?php echo esc_url($urls['alipay']); ?>" alt="<?php esc_attr_e('支付宝收款码', 'aksrt'); ?>" loading="lazy" decoding="async" />
|
||||
<div class="em09 muted-2-color mt6"><?php esc_html_e('支付宝', 'aksrt'); ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -240,7 +240,23 @@ if (!function_exists('aksrt_single_render_actions')) :
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($settings['rewards_enabled']) && !empty($settings['rewards_image'])) : ?>
|
||||
<?php
|
||||
$reward_author = (int) get_the_author_meta('ID');
|
||||
$reward_btn = ($reward_author > 0 && function_exists('aksrt_get_rewards_button'))
|
||||
? aksrt_get_rewards_button($reward_author, 'action action-rewards')
|
||||
: '';
|
||||
if ($reward_btn === '' && !empty($settings['rewards_enabled']) && function_exists('aksrt_user_has_rewards_qr') && $reward_author > 0 && aksrt_user_has_rewards_qr($reward_author)) {
|
||||
$label = esc_html((string) ($settings['rewards_btn_text'] ?? __('赞赏', 'aksrt')));
|
||||
$reward_btn = '<button type="button" class="action action-rewards" data-aksrt-reward-open data-user-id="' . (int) $reward_author . '"><i class="fas fa-gift" aria-hidden="true"></i><span class="action-btn__label">' . $label . '</span></button>';
|
||||
}
|
||||
if ($reward_btn !== '') :
|
||||
echo $reward_btn; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
if (function_exists('aksrt_render_rewards_modal_for_user')) {
|
||||
aksrt_render_rewards_modal_for_user($reward_author);
|
||||
}
|
||||
endif;
|
||||
// legacy placeholder to keep structure; actual button echoed above
|
||||
if (false) : ?>
|
||||
<button type="button" class="action action-rewards" id="action-reward">
|
||||
<i class="fas fa-gift" aria-hidden="true"></i>
|
||||
<span class="action-btn__label"><?php echo esc_html($settings['rewards_btn_text'] ?? __('赞赏', 'aksrt')); ?></span>
|
||||
@@ -348,15 +364,42 @@ if (!function_exists('aksrt_single_render_author_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']);
|
||||
$recent = get_posts([
|
||||
'author' => $author_id,
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => 6,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'no_found_rows' => true,
|
||||
]);
|
||||
$page_s = class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_post_page_settings')
|
||||
? AKSRT_Settings::get_post_page_settings()
|
||||
: [];
|
||||
$card_limit = max(0, min(12, (int) ($page_s['author_card_limit'] ?? 6)));
|
||||
$card_orderby = sanitize_key((string) ($page_s['author_card_orderby'] ?? 'views'));
|
||||
$card_style = sanitize_key((string) ($page_s['author_card_style'] ?? 'card'));
|
||||
$recent = [];
|
||||
if ($card_limit > 0) {
|
||||
$q = [
|
||||
'author' => $author_id,
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => $card_limit,
|
||||
'ignore_sticky_posts' => true,
|
||||
'no_found_rows' => true,
|
||||
];
|
||||
$cur = get_the_ID();
|
||||
if ($cur) {
|
||||
$q['post__not_in'] = [(int) $cur];
|
||||
}
|
||||
if ($card_orderby === 'views') {
|
||||
$q['meta_key'] = 'views';
|
||||
$q['orderby'] = 'meta_value_num';
|
||||
$q['order'] = 'DESC';
|
||||
} elseif ($card_orderby === 'comment_count') {
|
||||
$q['orderby'] = 'comment_count';
|
||||
$q['order'] = 'DESC';
|
||||
} elseif ($card_orderby === 'modified') {
|
||||
$q['orderby'] = 'modified';
|
||||
$q['order'] = 'DESC';
|
||||
} else {
|
||||
$q['orderby'] = 'date';
|
||||
$q['order'] = 'DESC';
|
||||
}
|
||||
$recent = get_posts($q);
|
||||
}
|
||||
$is_self = is_user_logged_in() && get_current_user_id() === $author_id;
|
||||
$login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url(get_permalink());
|
||||
$aksrt_pm_on = class_exists('AKSRT_Settings') && !empty(AKSRT_Settings::private_message_settings()['enabled']);
|
||||
@@ -387,7 +430,20 @@ if (!function_exists('aksrt_single_render_author_card')) :
|
||||
<div class="user-desc mt10 muted-2-color em09"><?php echo esc_html($bio); ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="user-btns mt20">
|
||||
<?php if (!$is_self) : ?>
|
||||
<?php if ($is_self) : ?>
|
||||
<?php
|
||||
$submit = function_exists('aksrt_get_page_url_by_template')
|
||||
? (string) aksrt_get_page_url_by_template('templates/pages/page-submit.php')
|
||||
: '';
|
||||
$center = function_exists('aksrt_get_user_center_url')
|
||||
? (string) aksrt_get_user_center_url()
|
||||
: $author_url;
|
||||
if ($submit !== '') :
|
||||
?>
|
||||
<a class="but pw-1em mr6 jb-pink" href="<?php echo esc_url($submit); ?>"><?php esc_html_e('发布文章', 'aksrt'); ?></a>
|
||||
<?php endif; ?>
|
||||
<a class="but pw-1em mr6 jb-blue" href="<?php echo esc_url($center); ?>"><?php esc_html_e('用户中心', 'aksrt'); ?></a>
|
||||
<?php else : ?>
|
||||
<?php if (is_user_logged_in()) : ?>
|
||||
<button type="button" class="but pw-1em mr6 c-red follow" data-aksrt-follow="<?php echo (int) $author_id; ?>">
|
||||
<i class="fa fa-heart em09" aria-hidden="true"></i> <span><?php esc_html_e('关注', 'aksrt'); ?></span>
|
||||
@@ -397,34 +453,56 @@ if (!function_exists('aksrt_single_render_author_card')) :
|
||||
<i class="fa fa-heart em09" aria-hidden="true"></i> <span><?php esc_html_e('关注', 'aksrt'); ?></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if (is_user_logged_in() && $aksrt_pm_on && $aksrt_msg_url !== '') : ?>
|
||||
<a class="but pw-1em mr6 c-blue" href="<?php echo esc_url(add_query_arg('msg_type', 'conversation', $aksrt_msg_url)); ?>">
|
||||
<i class="fa fa-comment em09" aria-hidden="true"></i> <?php esc_html_e('私信', 'aksrt'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
$tip = function_exists('aksrt_get_rewards_button') ? aksrt_get_rewards_button($author_id, 'but pw-1em mr6 c-yellow') : '';
|
||||
if ($tip !== '') {
|
||||
echo $tip; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
if (function_exists('aksrt_render_rewards_modal_for_user')) {
|
||||
aksrt_render_rewards_modal_for_user($author_id);
|
||||
}
|
||||
}
|
||||
?>
|
||||
<a class="but pw-1em mr6 jb-blue" href="<?php echo esc_url($author_url); ?>"><?php esc_html_e('个人主页', 'aksrt'); ?></a>
|
||||
<?php endif; ?>
|
||||
<?php if (!$is_self && is_user_logged_in() && $aksrt_pm_on && $aksrt_msg_url !== '') : ?>
|
||||
<a class="but pw-1em mr6 c-blue" href="<?php echo esc_url(add_query_arg('msg_type', 'conversation', $aksrt_msg_url)); ?>">
|
||||
<i class="fa fa-comment em09" aria-hidden="true"></i> <?php esc_html_e('私信', 'aksrt'); ?>
|
||||
</a>
|
||||
<?php elseif (!$is_self && $rewards_on) : ?>
|
||||
<button type="button" class="but pw-1em mr6 c-yellow" data-aksrt-reward-open>
|
||||
<i class="fa fa-gift em09" aria-hidden="true"></i> <?php esc_html_e('赞赏', 'aksrt'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<a class="but pw-1em mr6 jb-blue" href="<?php echo esc_url($author_url); ?>"><?php esc_html_e('个人主页', 'aksrt'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!empty($recent)) : ?>
|
||||
<div class="user-card-posts mt10">
|
||||
<ul class="no-thumb">
|
||||
<?php foreach ($recent as $rp) : ?>
|
||||
<?php if ($rp instanceof WP_Post) : ?>
|
||||
<li><a class="icon-circle" href="<?php echo esc_url(get_permalink($rp)); ?>"><?php echo esc_html(get_the_title($rp)); ?></a></li>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php if ($card_style === 'card') : ?>
|
||||
<div class="more-posts-mini flex hh">
|
||||
<?php foreach ($recent as $rp) : ?>
|
||||
<?php if ($rp instanceof WP_Post) :
|
||||
$thumb = get_the_post_thumbnail_url($rp, 'medium');
|
||||
?>
|
||||
<a class="item mr10 mb10" href="<?php echo esc_url(get_permalink($rp)); ?>" style="display:block;width:46%;">
|
||||
<?php if ($thumb) : ?>
|
||||
<img class="fit-cover radius8" src="<?php echo esc_url($thumb); ?>" alt="" loading="lazy" decoding="async" style="width:100%;aspect-ratio:16/10;object-fit:cover;" />
|
||||
<?php endif; ?>
|
||||
<div class="em09 mt6 text-ellipsis"><?php echo esc_html(get_the_title($rp)); ?></div>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<ul class="no-thumb">
|
||||
<?php foreach ($recent as $rp) : ?>
|
||||
<?php if ($rp instanceof WP_Post) : ?>
|
||||
<li><a class="icon-circle" href="<?php echo esc_url(get_permalink($rp)); ?>"><?php echo esc_html(get_the_title($rp)); ?></a></li>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="user-card-posts mt10 muted-2-color em09 text-center"><?php esc_html_e('暂无更多文章', 'aksrt'); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif;
|
||||
?> </div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
@@ -167,8 +167,10 @@ $pane = isset($points_tasks_pane) ? sanitize_key((string) $points_tasks_pane)
|
||||
<?php
|
||||
$task_key = sanitize_key((string) ($task['key'] ?? ''));
|
||||
$action = $aksrt_points_task_action($task_key);
|
||||
$status = sanitize_key((string) ($task['status'] ?? 'todo'));
|
||||
$done = in_array($status, ['done_today', 'done'], true);
|
||||
?>
|
||||
<div class="border-bottom padding-h10 uc-points-tasks__row" data-task-key="<?php echo esc_attr($task_key); ?>">
|
||||
<div class="border-bottom padding-h10 uc-points-tasks__row<?php echo $done ? ' is-done' : ''; ?>" data-task-key="<?php echo esc_attr($task_key); ?>" data-status="<?php echo esc_attr($status); ?>">
|
||||
<div class="flex jsb ac">
|
||||
<div class="flex1 mr20">
|
||||
<div class="font-bold mb6"><?php echo esc_html((string) $task['title']); ?></div>
|
||||
|
||||
Reference in New Issue
Block a user