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:
2026-07-17 01:21:35 +08:00
parent b4d04ae346
commit 8d4e94a02c
10 changed files with 374 additions and 148 deletions
+108 -30
View File
@@ -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
}