feat(user-center): redesign sidebar and wallet tips

This commit is contained in:
2026-07-28 13:41:00 +08:00
parent 82e71d1bf9
commit a7f3caec59
24 changed files with 895 additions and 528 deletions
+4 -1
View File
@@ -91,9 +91,12 @@ if (!function_exists('aksrt_resolve_single_post_display_settings')) :
'authordesc' => true,
'hide_time' => false,
'rewards_enabled' => false,
'rewards_image' => '',
'rewards_text' => '',
'rewards_btn_text' => '赞赏',
'rewards_amounts' => [5, 10, 20, 50, 100],
'rewards_custom' => true,
'rewards_min' => 1,
'rewards_max' => 1000,
'maxheight_enabled' => false,
'maxheight' => 1000,
'copyright_enabled' => true,
+97 -77
View File
@@ -1,8 +1,6 @@
<?php
/**
* Per-user tip (打赏) helpers — Zibll post_rewards_s + user QR parity.
*
* Meta: aksrt_rewards_weixin, aksrt_rewards_alipay (attachment id or URL).
* On-site wallet tipping helpers.
*
* @package AKSRT
*/
@@ -11,103 +9,125 @@ defined('ABSPATH') || exit;
if (!function_exists('aksrt_rewards_enabled')) {
function aksrt_rewards_enabled(): bool {
if (!class_exists('\AKSRT\Settings\Settings') || !method_exists('\AKSRT\Settings\Settings', 'get_post_page_settings')) {
if (!class_exists('\AKSRT\Settings\Settings')) {
return false;
}
$s = \AKSRT\Settings\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'] !== '';
$settings = \AKSRT\Settings\Settings::get_post_page_settings();
return !empty($settings['rewards_enabled']);
}
}
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)) {
function aksrt_get_rewards_button(int $user_id, string $class = 'but jb-blue ml10 pw-1em', int $post_id = 0): string {
if ($user_id <= 0 || !aksrt_rewards_enabled()) {
return '';
}
$label = '赞赏';
if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_post_page_settings')) {
$s = \AKSRT\Settings\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>';
$settings = \AKSRT\Settings\Settings::get_post_page_settings();
$label = (string) ($settings['rewards_btn_text'] ?? __('赞赏', 'aksrt'));
return sprintf(
'<button type="button" class="%1$s aksrt-reward-open" data-aksrt-reward-open data-user-id="%2$d" data-post-id="%3$d"><i class="fa fa-gift em09" aria-hidden="true"></i> <span class="action-btn__label">%4$s</span></button>',
esc_attr($class),
$user_id,
$post_id,
esc_html($label)
);
}
}
if (!function_exists('aksrt_render_rewards_modal_for_user')) {
function aksrt_render_rewards_modal_for_user(int $user_id): void {
function aksrt_render_rewards_modal_for_user(int $user_id, int $post_id = 0): void {
static $done = [];
if ($user_id <= 0 || isset($done[$user_id])) {
$key = $user_id . ':' . $post_id;
if ($user_id <= 0 || isset($done[$key]) || !aksrt_rewards_enabled()) {
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\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_post_page_settings')) {
$s = \AKSRT\Settings\Settings::get_post_page_settings();
$label = (string) ($s['rewards_text'] ?? $label);
if ($label === '') {
$label = __('赞赏', 'aksrt');
}
}
$done[$key] = true;
$settings = \AKSRT\Settings\Settings::get_post_page_settings();
$amounts = (array) ($settings['rewards_amounts'] ?? [5, 10, 20, 50, 100]);
$recipient = get_userdata($user_id);
?>
<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" id="reward-modal-<?php echo (int) $user_id; ?>" data-user-id="<?php echo (int) $user_id; ?>" data-post-id="<?php echo (int) $post_id; ?>" aria-hidden="true">
<div class="reward-modal__overlay" data-aksrt-reward-close></div>
<div class="reward-modal__dialog" role="dialog" aria-modal="true">
<div class="reward-modal__dialog" role="dialog" aria-modal="true" aria-labelledby="reward-title-<?php echo (int) $user_id; ?>">
<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; ?>
<h3 id="reward-title-<?php echo (int) $user_id; ?>"><?php echo esc_html((string) ($settings['rewards_text'] ?? __('赞赏', 'aksrt'))); ?></h3>
<p class="muted-2-color em09"><?php printf(esc_html__('赞赏将直接进入 %s 的站内余额', 'aksrt'), esc_html($recipient ? $recipient->display_name : __('作者', 'aksrt'))); ?></p>
<div class="reward-amounts" data-aksrt-reward-amounts>
<?php foreach ($amounts as $index => $amount) : ?>
<button type="button" class="reward-amount<?php echo $index === 0 ? ' is-active' : ''; ?>" data-reward-amount="<?php echo esc_attr(number_format((float) $amount, 2, '.', '')); ?>">¥<?php echo esc_html(number_format_i18n((float) $amount, 2)); ?></button>
<?php endforeach; ?>
</div>
<?php if (!empty($settings['rewards_custom'])) : ?>
<label class="reward-custom"><span><?php esc_html_e('自定义金额', 'aksrt'); ?></span><input type="number" min="<?php echo esc_attr((string) ($settings['rewards_min'] ?? 1)); ?>" max="<?php echo esc_attr((string) ($settings['rewards_max'] ?? 1000)); ?>" step="0.01" data-aksrt-reward-custom placeholder="<?php esc_attr_e('输入金额', 'aksrt'); ?>"></label>
<?php endif; ?>
<button type="button" class="btn-primary reward-modal__submit" data-aksrt-reward-submit><?php esc_html_e('余额赞赏', 'aksrt'); ?></button>
<div class="reward-modal__message" data-aksrt-reward-message role="status"></div>
</div>
</div>
</div>
<?php
}
}
add_action('wp_ajax_aksrt_submit_tip', function (): void {
check_ajax_referer('aksrt_public_nonce', 'nonce');
if (!is_user_logged_in()) {
wp_send_json_error(['message' => __('请先登录后赞赏', 'aksrt')], 401);
}
if (!aksrt_rewards_enabled() || !class_exists('\AKSRT\Credits\Balance') || !\AKSRT\Credits\Balance::enabled()) {
wp_send_json_error(['message' => __('赞赏功能当前不可用', 'aksrt')], 400);
}
$sender_id = get_current_user_id();
$post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
$recipient_id = isset($_POST['recipient_id']) ? absint($_POST['recipient_id']) : 0;
if ($post_id > 0) {
$post = get_post($post_id);
if (!$post instanceof WP_Post || $post->post_status !== 'publish') {
wp_send_json_error(['message' => __('赞赏内容不存在', 'aksrt')], 404);
}
$recipient_id = (int) $post->post_author;
}
if ($recipient_id <= 0 || !get_userdata($recipient_id) || $recipient_id === $sender_id) {
wp_send_json_error(['message' => __('不能赞赏该用户', 'aksrt')], 400);
}
$settings = \AKSRT\Settings\Settings::get_post_page_settings();
$amount = isset($_POST['amount']) ? round((float) wp_unslash($_POST['amount']), 2) : 0.0;
$minimum = (float) ($settings['rewards_min'] ?? 1);
$maximum = (float) ($settings['rewards_max'] ?? 1000);
if (!is_finite($amount) || $amount < $minimum || $amount > $maximum) {
wp_send_json_error(['message' => sprintf(__('赞赏金额需在 ¥%1$s 至 ¥%2$s 之间', 'aksrt'), number_format_i18n($minimum, 2), number_format_i18n($maximum, 2))], 400);
}
if (empty($settings['rewards_custom'])) {
$allowed_amounts = array_map(static fn($value): float => round((float) $value, 2), (array) ($settings['rewards_amounts'] ?? []));
if (!in_array($amount, $allowed_amounts, true)) {
wp_send_json_error(['message' => __('请选择预设的赞赏金额', 'aksrt')], 400);
}
}
$rate_key = 'aksrt_tip_rate_' . $sender_id;
if (get_transient($rate_key)) {
wp_send_json_error(['message' => __('操作太频繁,请稍后再试', 'aksrt')], 429);
}
set_transient($rate_key, 1, 3);
$result = \AKSRT\Credits\Balance::transfer(
$sender_id,
$recipient_id,
$amount,
'tip_sent',
'tip_received',
['type' => 'tip', 'id' => $post_id],
$post_id > 0 ? sprintf(__('赞赏文章 #%d', 'aksrt'), $post_id) : __('用户赞赏', 'aksrt')
);
if (is_wp_error($result)) {
wp_send_json_error(['message' => $result->get_error_message()], 400);
}
wp_send_json_success([
'message' => __('赞赏成功,金额已进入对方余额', 'aksrt'),
'balance' => \AKSRT\Credits\Balance::format((float) $result['sender_balance']),
]);
});
+8 -34
View File
@@ -251,26 +251,14 @@ if (!function_exists('aksrt_single_render_actions')) :
<?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')
$reward_btn = ($reward_author > 0 && !empty($settings['rewards_enabled']) && function_exists('aksrt_get_rewards_button'))
? aksrt_get_rewards_button($reward_author, 'action action-rewards', $post_id)
: '';
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 !== '') :
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>
</button>
<?php endif; ?>
aksrt_render_rewards_modal_for_user($reward_author, $post_id);
}
?>
<?php if (!empty($settings['share_enabled'])) : ?>
<button type="button" class="action action-share" id="action-share-trigger" aria-haspopup="true" aria-expanded="false">
@@ -293,20 +281,6 @@ if (!function_exists('aksrt_single_render_actions')) :
<?php endif; ?>
</div>
<?php if (!empty($settings['rewards_enabled']) && !empty($settings['rewards_image'])) : ?>
<div class="reward-modal" id="reward-modal" aria-hidden="true">
<div class="reward-modal__overlay"></div>
<div class="reward-modal__dialog">
<button type="button" class="reward-modal__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((string) ($settings['rewards_text'] ?? '')); ?></h3>
<div class="reward-modal__qrcode">
<img src="<?php echo esc_url((string) $settings['rewards_image']); ?>" alt="<?php esc_attr_e('打赏二维码', 'aksrt'); ?>">
</div>
</div>
</div>
</div>
<?php endif; ?>
<?php
}
endif;
@@ -484,11 +458,11 @@ if (!function_exists('aksrt_single_render_author_card')) :
</a>
<?php endif; ?>
<?php
$tip = function_exists('aksrt_get_rewards_button') ? aksrt_get_rewards_button($author_id, 'but pw-1em mr6 c-yellow') : '';
$tip = function_exists('aksrt_get_rewards_button') ? aksrt_get_rewards_button($author_id, 'but pw-1em mr6 c-yellow', get_the_ID()) : '';
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);
aksrt_render_rewards_modal_for_user($author_id, get_the_ID());
}
}
?>
+4 -24
View File
@@ -92,30 +92,6 @@ if (!function_exists('aksrt_save_user_center_profile')) {
update_user_meta($user_id, 'aksrt_user_contacts', aksrt_normalize_user_contacts($input['contacts'] ?? []));
// Tip QR images (attachment id or URL). Empty clears.
if (array_key_exists('rewards_weixin', $input) || array_key_exists('rewards_alipay', $input)) {
foreach (['rewards_weixin' => 'aksrt_rewards_weixin', 'rewards_alipay' => 'aksrt_rewards_alipay'] as $field => $meta) {
if (!array_key_exists($field, $input)) {
continue;
}
$raw = is_string($input[$field]) ? trim(wp_unslash($input[$field])) : '';
if ($raw === '' || $raw === '0') {
delete_user_meta($user_id, $meta);
continue;
}
if (ctype_digit($raw)) {
$att = (int) $raw;
if ($att > 0 && wp_attachment_is_image($att)) {
update_user_meta($user_id, $meta, $att);
}
continue;
}
$url = esc_url_raw($raw);
if ($url !== '') {
update_user_meta($user_id, $meta, $url);
}
}
}
return true;
}
@@ -479,6 +455,9 @@ if (!function_exists('aksrt_get_user_center_render_context')) {
$allow_avatar_upload = !empty($user_center_settings['avatar_upload']);
$allow_bg_upload = !empty($user_center_settings['cover_upload']) && class_exists('\AKSRT\Settings\Settings') && aksrt_get_setting('allow_background_upload', false);
$messages_enabled = !class_exists('\AKSRT\Settings\Settings') || \AKSRT\Settings\Settings::message_enabled();
$follower_count = class_exists('\AKSRT\User\Follow')
? \AKSRT\User\Follow::get_instance()->get_follower_count($user_id)
: 0;
$post_status_filter = isset($_GET['post_status']) ? sanitize_key(wp_unslash($_GET['post_status'])) : 'publish';
if (!in_array($post_status_filter, ['all', 'publish', 'draft', 'pending', 'private'], true)) {
@@ -531,6 +510,7 @@ if (!function_exists('aksrt_get_user_center_render_context')) {
'comment_count' => $comment_count,
'favorite_post_ids' => $favorite_post_ids,
'favorite_count' => $favorite_count,
'follower_count' => $follower_count,
'user_contacts' => $user_contacts,
'profile_signals' => $dashboard['profile_signals'] ?? [],
'user_background_url' => $user_background_url,
@@ -32,55 +32,6 @@ extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_
<?php require __DIR__ . '/form-contacts.php'; ?>
<?php
$rewards_on = function_exists('aksrt_rewards_enabled') ? aksrt_rewards_enabled() : false;
$rw = (string) get_user_meta((int) $user_id, 'aksrt_rewards_weixin', true);
$ra = (string) get_user_meta((int) $user_id, 'aksrt_rewards_alipay', true);
$rw_url = '';
$ra_url = '';
if (function_exists('aksrt_get_user_rewards_img_urls')) {
$urls = aksrt_get_user_rewards_img_urls((int) $user_id);
$rw_url = (string) ($urls['weixin'] ?? '');
$ra_url = (string) ($urls['alipay'] ?? '');
}
?>
<?php if ($rewards_on) : ?>
<div class="widget-card">
<h3 class="widget-title"><?php esc_html_e('打赏收款码', 'aksrt'); ?></h3>
<p class="profile-hint"><?php esc_html_e('上传微信/支付宝收款码后,读者可在文章与作者卡赞赏你。留空则不显示赞赏按钮。', 'aksrt'); ?></p>
<div class="aksrt-reward-upload-grid">
<div class="aksrt-reward-upload">
<label class="aksrt-reward-upload__label"><?php esc_html_e('微信收款码', 'aksrt'); ?></label>
<div class="aksrt-reward-upload__preview" data-reward-preview="weixin">
<?php if ($rw_url !== '') : ?>
<img src="<?php echo esc_url($rw_url); ?>" alt="" />
<?php else : ?>
<span class="muted-2-color em09"><?php esc_html_e('未上传', 'aksrt'); ?></span>
<?php endif; ?>
</div>
<input type="hidden" name="rewards_weixin" id="rewards-weixin" value="<?php echo esc_attr($rw); ?>" />
<input type="file" id="rewards-weixin-file" accept="image/*" class="aksrt-reward-upload__file" data-reward-kind="weixin" />
<button type="button" class="btn-primary btn-sm" data-reward-upload="weixin"><?php esc_html_e('选择图片', 'aksrt'); ?></button>
<button type="button" class="btn-sm" data-reward-clear="weixin"><?php esc_html_e('清除', 'aksrt'); ?></button>
</div>
<div class="aksrt-reward-upload">
<label class="aksrt-reward-upload__label"><?php esc_html_e('支付宝收款码', 'aksrt'); ?></label>
<div class="aksrt-reward-upload__preview" data-reward-preview="alipay">
<?php if ($ra_url !== '') : ?>
<img src="<?php echo esc_url($ra_url); ?>" alt="" />
<?php else : ?>
<span class="muted-2-color em09"><?php esc_html_e('未上传', 'aksrt'); ?></span>
<?php endif; ?>
</div>
<input type="hidden" name="rewards_alipay" id="rewards-alipay" value="<?php echo esc_attr($ra); ?>" />
<input type="file" id="rewards-alipay-file" accept="image/*" class="aksrt-reward-upload__file" data-reward-kind="alipay" />
<button type="button" class="btn-primary btn-sm" data-reward-upload="alipay"><?php esc_html_e('选择图片', 'aksrt'); ?></button>
<button type="button" class="btn-sm" data-reward-clear="alipay"><?php esc_html_e('清除', 'aksrt'); ?></button>
</div>
</div>
</div>
<?php endif; ?>
<div class="profile-form__submit">
<button type="submit" class="btn-primary btn-lg" id="profile-save-btn">
@@ -25,27 +25,20 @@ $section = sanitize_key((string) ($_GET['section'] ?? ''));
if ($tab === '' && isset($_GET['tab']) && sanitize_key((string) $_GET['tab']) !== 'orders') {
// When rendered as standalone legacy include, outer tab may be status.
$maybe = sanitize_key((string) $_GET['tab']);
if (in_array($maybe, ['pending', 'shipped', 'received', 'review', 'after', 'wait-pay', 'wait-shipped', 'wait-receive', 'wait-evaluate', 'after-sale', 'all'], true)) {
if (in_array($maybe, ['pending', 'to-ship', 'shipped', 'received', 'review', 'after'], true)) {
$tab = $maybe;
}
}
$tab_aliases = [
'wait-pay' => 'pending',
'wait-shipped' => 'shipped',
'wait-receive' => 'shipped',
'wait-evaluate' => 'review',
'after-sale' => 'after',
'all' => '',
];
$tab_aliases = [];
if (isset($tab_aliases[$tab])) {
$tab = $tab_aliases[$tab];
}
$tab_status_map = [
'pending' => \AKSRT\Payment\Order::STATUS_PENDING,
'to-ship' => \AKSRT\Payment\Order::STATUS_PAID,
'shipped' => \AKSRT\Payment\Order::STATUS_DELIVERED,
'received' => \AKSRT\Payment\Order::STATUS_COMPLETED,
'review' => \AKSRT\Payment\Order::STATUS_PENDING_REVIEW,
'after' => \AKSRT\Payment\Order::STATUS_REFUNDING,
];
@@ -70,6 +63,7 @@ $shop = class_exists('\AKSRT\Shop\Shop') ? \AKSRT\Shop\Shop::get_instance() : nu
$tabs = [
'' => __('全部', 'aksrt'),
'pending' => __('待支付', 'aksrt'),
'to-ship' => __('待发货', 'aksrt'),
'shipped' => __('待收货', 'aksrt'),
'review' => __('待评价', 'aksrt'),
'after' => __('售后', 'aksrt'),
@@ -1,6 +1,6 @@
<?php
/**
* User center profile sidebar part (orchestrator).
* User center profile sidebar orchestrator.
*
* @package AKSRT
*/
@@ -11,10 +11,11 @@ $context = is_array($args['context'] ?? null) ? $args['context'] : [];
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
require __DIR__ . '/sidebar-stats.php';
require __DIR__ . '/sidebar-nav.php';
require __DIR__ . '/sidebar-creator.php';
require __DIR__ . '/sidebar-orders.php';
require __DIR__ . '/sidebar-commerce.php';
require __DIR__ . '/sidebar-creator.php';
require __DIR__ . '/sidebar-nav.php';
?>
<button type="button" class="uc-sidebar__drawer-trigger" id="uc-drawer-trigger" aria-label="<?php esc_attr_e('打开导航', 'aksrt'); ?>">
<i class="fas fa-bars" aria-hidden="true"></i>
<i class="fas fa-th-large" aria-hidden="true"></i>
</button>
@@ -1,6 +1,6 @@
<?php
/**
* User center sidebar: Zibll dual asset mini cards + commerce shortcuts.
* User center sidebar: balance and points pair.
*
* @package AKSRT
*/
@@ -8,73 +8,32 @@
defined('ABSPATH') || exit;
$show_wallet = !empty($balance_enabled);
$show_credits = !empty($show_credit_tabs) || !empty($credits_enabled);
$wallet = (float) ($wallet_balance ?? 0.0);
$points = (float) ($credit_balance ?? 0.0);
$currency = (string) ($currency_name ?? __('积分', 'aksrt'));
if ($show_wallet || $show_credits) :
$assets_url = function_exists('aksrt_get_user_center_tab_url')
? aksrt_get_user_center_tab_url('credits')
: '#';
?>
<div class="uc-sidebar__section">
<div class="uc-sidebar__title"><?php esc_html_e('我的资产', 'aksrt'); ?></div>
<div class="uc-asset-mini flex ab jsb col-ml6">
<?php if ($show_wallet) : ?>
<a class="uc-asset-mini__card flex1" href="<?php echo esc_url($assets_url); ?>">
<div class="uc-asset-mini__label muted-2-color em09"><?php esc_html_e('余额', 'aksrt'); ?><i class="ml6 fa fa-angle-right em12" aria-hidden="true"></i></div>
<div class="flex jsb ac">
<span class="font-bold c-blue-2"><?php echo esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format($wallet) : number_format_i18n($wallet, 2)); ?></span>
<i class="fas fa-wallet em14 c-blue-2" aria-hidden="true"></i>
</div>
</a>
<?php endif; ?>
<?php if ($show_credits) : ?>
<a class="uc-asset-mini__card flex1" href="<?php echo esc_url($assets_url); ?>">
<div class="uc-asset-mini__label muted-2-color em09"><?php echo esc_html($currency); ?><i class="ml6 fa fa-angle-right em12" aria-hidden="true"></i></div>
<div class="flex jsb ac">
<span class="font-bold c-yellow"><?php echo esc_html(function_exists('aksrt_format_credits') ? aksrt_format_credits((int) $points) : (string) (int) $points); ?></span>
<i class="fas fa-coins em14 c-yellow" aria-hidden="true"></i>
</div>
</a>
<?php endif; ?>
</div>
</div>
<?php
endif;
if (empty($orders_url) && empty($show_vip) && empty($show_credit_tabs) && empty($balance_enabled) && empty($affiliate_enabled)) {
$show_credits = !empty($credits_enabled) || !empty($show_credit_tabs);
if (!$show_wallet && !$show_credits) {
return;
}
$assets_url = aksrt_get_user_center_tab_url('credits');
$wallet = (float) ($wallet_balance ?? 0);
$points = (float) ($credit_balance ?? 0);
?>
<div class="uc-sidebar__section">
<div class="uc-sidebar__title"><?php esc_html_e('权益与消费', 'aksrt'); ?></div>
<div class="uc-sidebar__buttons">
<?php $revenue_url = function_exists('aksrt_get_revenue_page_url') ? aksrt_get_revenue_page_url() : ''; ?>
<?php
$orders_href = !empty($orders_url)
? (string) $orders_url
: (function_exists('aksrt_get_user_center_tab_url') ? aksrt_get_user_center_tab_url('orders') : '');
if ($orders_href !== '') :
$orders_active = !empty($active_tab) && $active_tab === 'orders';
?>
<a href="<?php echo esc_url($orders_href); ?>" class="uc-sidebar__btn<?php echo $orders_active ? ' is-active' : ''; ?>" data-tab="orders">
<i class="fas fa-receipt" aria-hidden="true"></i>
<span><?php esc_html_e('我的订单', 'aksrt'); ?></span>
</a>
<?php endif; ?>
<?php if (!empty($show_vip)) : ?>
<a class="uc-sidebar__btn payvip-icon<?php echo (!empty($active_tab) && $active_tab === 'vip') ? ' is-active' : ''; ?>" href="<?php echo esc_url(aksrt_get_user_center_tab_url('vip')); ?>" data-tab="vip">
<i class="fas fa-crown" aria-hidden="true"></i>
<span><?php esc_html_e('VIP 会员', 'aksrt'); ?></span>
</a>
<?php endif; ?>
<?php if (!empty($affiliate_enabled) && $revenue_url) : ?>
<a href="<?php echo esc_url($revenue_url); ?>" class="uc-sidebar__btn">
<i class="fas fa-share-alt" aria-hidden="true"></i>
<span><?php esc_html_e('推广返佣', 'aksrt'); ?></span>
</a>
<?php endif; ?>
</div>
<div class="uc-sidebar__pair uc-sidebar__pair--assets">
<?php if ($show_wallet) : ?>
<a class="uc-summary-card uc-summary-card--wallet" href="<?php echo esc_url($assets_url); ?>">
<span class="uc-summary-card__head"><?php esc_html_e('账户余额', 'aksrt'); ?><i class="fas fa-angle-right" aria-hidden="true"></i></span>
<span class="uc-summary-card__body">
<strong><?php echo esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format($wallet) : number_format_i18n($wallet, 2)); ?></strong>
<i class="fas fa-wallet" aria-hidden="true"></i>
</span>
</a>
<?php endif; ?>
<?php if ($show_credits) : ?>
<a class="uc-summary-card uc-summary-card--points" href="<?php echo esc_url(add_query_arg('asset_tab', 'points', $assets_url)); ?>">
<span class="uc-summary-card__head"><?php echo esc_html((string) ($currency_name ?? __('积分', 'aksrt'))); ?><i class="fas fa-angle-right" aria-hidden="true"></i></span>
<span class="uc-summary-card__body">
<strong><?php echo esc_html(function_exists('aksrt_format_credits') ? aksrt_format_credits((int) $points) : number_format_i18n((int) $points)); ?></strong>
<i class="fas fa-coins" aria-hidden="true"></i>
</span>
</a>
<?php endif; ?>
</div>
@@ -1,47 +1,35 @@
<?php
/**
* User center sidebar: creator and community shortcuts.
* User center sidebar: creation and promotion center pair.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
$creator_links = array_filter([
[
'url' => (string) ($new_post_url ?? ''),
'icon' => 'pen',
'label' => __('发布文章', 'aksrt'),
],
[
'url' => (string) ($new_product_url ?? ''),
'icon' => 'store',
'label' => __('发布商品', 'aksrt'),
],
[
'url' => (string) ($forum_compose_url ?? ''),
'icon' => 'comments',
'label' => __('论坛发帖', 'aksrt'),
],
[
'url' => (string) ($revenue_url ?? ''),
'icon' => 'chart-line',
'label' => __('创作收益', 'aksrt'),
],
], static fn(array $item): bool => $item['url'] !== '');
$creation_url = (string) ($new_post_url ?? '');
if ($creation_url === '') {
$creation_url = isset($dashboard_tabs['posts']) ? aksrt_get_user_center_tab_url('posts') : '';
}
$promotion_url = (string) ($revenue_url ?? '');
if (!$creator_links) {
return;
if ($creation_url === '' && $promotion_url === '') {
return;
}
?>
<div class="uc-sidebar__section">
<div class="uc-sidebar__title"><?php esc_html_e('创作服务', 'aksrt'); ?></div>
<div class="uc-sidebar__buttons">
<?php foreach ($creator_links as $item) : ?>
<a class="uc-sidebar__btn" href="<?php echo esc_url($item['url']); ?>">
<i class="fas fa-<?php echo esc_attr($item['icon']); ?>" aria-hidden="true"></i>
<span><?php echo esc_html($item['label']); ?></span>
</a>
<?php endforeach; ?>
</div>
<div class="uc-sidebar__pair uc-sidebar__pair--centers">
<?php if ($creation_url !== '') : ?>
<a class="uc-center-card uc-center-card--creation" href="<?php echo esc_url($creation_url); ?>">
<span class="uc-center-card__icon"><i class="fas fa-feather-alt" aria-hidden="true"></i></span>
<span><strong><?php esc_html_e('创作中心', 'aksrt'); ?></strong><small><?php esc_html_e('发布与管理内容', 'aksrt'); ?></small></span>
<i class="fas fa-angle-right" aria-hidden="true"></i>
</a>
<?php endif; ?>
<?php if ($promotion_url !== '') : ?>
<a class="uc-center-card uc-center-card--promotion" href="<?php echo esc_url($promotion_url); ?>">
<span class="uc-center-card__icon"><i class="fas fa-bullhorn" aria-hidden="true"></i></span>
<span><strong><?php esc_html_e('推广中心', 'aksrt'); ?></strong><small><?php esc_html_e('返佣与收益', 'aksrt'); ?></small></span>
<i class="fas fa-angle-right" aria-hidden="true"></i>
</a>
<?php endif; ?>
</div>
@@ -1,36 +1,89 @@
<?php
/**
* User center sidebar: main service navigation.
*
* Expects extracted $context vars.
* User center sidebar: services and account settings.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
?>
<div class="uc-sidebar__section">
<div class="uc-sidebar__title"><?php esc_html_e('我的服务', 'aksrt'); ?></div>
<div class="uc-sidebar__buttons">
<?php foreach ($dashboard_tabs as $tab_key => $tab) :
// VIP / 订单 only under 权益与消费 (sidebar-commerce), not duplicated here.
if (in_array((string) $tab_key, ['vip', 'orders'], true)) {
continue;
}
?>
<a class="uc-sidebar__btn<?php echo $active_tab === $tab_key ? ' is-active' : ''; ?>" href="<?php echo esc_url(aksrt_get_user_center_tab_url($tab_key)); ?>" data-tab="<?php echo esc_attr($tab_key); ?>">
<i class="fas fa-<?php echo esc_attr($tab['icon']); ?>" aria-hidden="true"></i>
<span><?php echo esc_html($tab['label']); ?></span>
$cart_url = function_exists('aksrt_get_cart_page_url') ? aksrt_get_cart_page_url() : '';
$level_url = isset($dashboard_tabs['credits'])
? add_query_arg('asset_tab', 'points', aksrt_get_user_center_tab_url('credits'))
: '';
$auth_url = function_exists('aksrt_get_page_url_by_template')
? aksrt_get_page_url_by_template('templates/pages/page-user-auth.php')
: '';
$services = array_values(array_filter([
[
'label' => __('购物车', 'aksrt'),
'icon' => 'shopping-cart',
'tone' => 'cart',
'url' => $cart_url,
],
[
'label' => __('我的等级', 'aksrt'),
'icon' => 'chart-line',
'tone' => 'level',
'url' => $level_url,
],
[
'label' => __('官方认证', 'aksrt'),
'icon' => 'id-badge',
'tone' => 'auth',
'url' => $auth_url,
],
], static fn(array $item): bool => (string) $item['url'] !== ''));
$settings = array_values(array_filter([
[
'label' => __('消息通知', 'aksrt'),
'icon' => 'bell',
'tone' => 'notice',
'url' => (string) ($messages_url ?? ''),
'count' => (int) ($notification_unread_count ?? 0),
],
[
'label' => __('个人资料', 'aksrt'),
'icon' => 'user-edit',
'tone' => 'profile',
'url' => isset($dashboard_tabs['profile']) ? aksrt_get_user_center_tab_url('profile') : '',
],
[
'label' => __('账户安全', 'aksrt'),
'icon' => 'shield-alt',
'tone' => 'security',
'url' => isset($dashboard_tabs['settings']) ? aksrt_get_user_center_tab_url('settings') : '',
],
], static fn(array $item): bool => (string) $item['url'] !== ''));
$render_grid = static function (array $items): void {
?>
<div class="uc-service-grid">
<?php foreach ($items as $item) : ?>
<a class="uc-service-grid__item uc-service-grid__item--<?php echo esc_attr((string) $item['tone']); ?>" href="<?php echo esc_url((string) $item['url']); ?>">
<span class="uc-service-grid__icon">
<i class="fas fa-<?php echo esc_attr((string) $item['icon']); ?>" aria-hidden="true"></i>
<?php if (!empty($item['count'])) : ?><small><?php echo esc_html((string) $item['count']); ?></small><?php endif; ?>
</span>
<span><?php echo esc_html((string) $item['label']); ?></span>
</a>
<?php endforeach; ?>
<?php if (!empty($messages_url)) : ?>
<a href="<?php echo esc_url($messages_url); ?>" class="uc-sidebar__btn">
<i class="fas fa-bell" aria-hidden="true"></i>
<span><?php esc_html_e('消息通知', 'aksrt'); ?></span>
<?php if ($notification_unread_count > 0) : ?>
<span class="uc-sidebar__badge"><?php echo esc_html((string) $notification_unread_count); ?></span>
<?php endif; ?>
</a>
<?php endif; ?>
</div>
<?php
};
?>
<?php if ($services) : ?>
<div class="uc-sidebar__section">
<div class="uc-sidebar__heading"><span><?php esc_html_e('我的服务', 'aksrt'); ?></span></div>
<?php $render_grid($services); ?>
</div>
<?php endif; ?>
<?php if ($settings) : ?>
<div class="uc-sidebar__section">
<div class="uc-sidebar__heading"><span><?php esc_html_e('功能设置', 'aksrt'); ?></span></div>
<?php $render_grid($settings); ?>
</div>
<?php endif; ?>
@@ -0,0 +1,73 @@
<?php
/**
* User center sidebar: task-oriented order shortcuts.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
$orders_base_url = (string) ($orders_url ?? '');
if ($orders_base_url === '') {
return;
}
$order_stats = class_exists('\AKSRT\Payment\Order')
? \AKSRT\Payment\Order::get_instance()->get_stats((int) ($user_id ?? 0))
: [];
$order_items = [
[
'label' => __('待支付', 'aksrt'),
'icon' => 'wallet',
'tab' => 'pending',
'count' => (int) ($order_stats['pending'] ?? 0),
],
[
'label' => __('待发货', 'aksrt'),
'icon' => 'gift',
'tab' => 'to-ship',
'count' => (int) ($order_stats['paid'] ?? 0),
],
[
'label' => __('待收货', 'aksrt'),
'icon' => 'truck',
'tab' => 'shipped',
'count' => (int) ($order_stats['delivered'] ?? 0),
],
[
'label' => __('待评价', 'aksrt'),
'icon' => 'comment-dots',
'tab' => 'review',
'count' => (int) ($order_stats['pending_review'] ?? 0),
],
[
'label' => __('售后', 'aksrt'),
'icon' => 'undo-alt',
'tab' => 'after',
'count' => (int) ($order_stats['refunding'] ?? 0),
],
];
?>
<div class="uc-sidebar__section uc-order-card">
<div class="uc-sidebar__heading">
<span><?php esc_html_e('我的订单', 'aksrt'); ?></span>
<a href="<?php echo esc_url($orders_base_url); ?>">
<?php esc_html_e('全部', 'aksrt'); ?><i class="fas fa-angle-right" aria-hidden="true"></i>
</a>
</div>
<div class="uc-order-grid">
<?php foreach ($order_items as $item) :
$item_url = add_query_arg('order_tab', $item['tab'], $orders_base_url);
?>
<a class="uc-order-grid__item" href="<?php echo esc_url($item_url); ?>">
<span class="uc-order-grid__icon">
<i class="fas fa-<?php echo esc_attr((string) $item['icon']); ?>" aria-hidden="true"></i>
<?php if ($item['count'] > 0) : ?>
<small><?php echo esc_html($item['count'] > 99 ? '99+' : (string) $item['count']); ?></small>
<?php endif; ?>
</span>
<span><?php echo esc_html((string) $item['label']); ?></span>
</a>
<?php endforeach; ?>
</div>
</div>
@@ -1,34 +1,43 @@
<?php
/**
* User center sidebar: stats section.
*
* Expects extracted $context vars.
* User center sidebar: one-line account statistics.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
$public_home_url = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url($target_user ?? null) : '';
$stats = [
[
'label' => __('文章', 'aksrt'),
'value' => (int) ($post_count ?? 0),
'url' => isset($dashboard_tabs['posts']) ? aksrt_get_user_center_tab_url('posts') : $public_home_url,
],
[
'label' => __('评论', 'aksrt'),
'value' => (int) ($comment_count ?? 0),
'url' => isset($dashboard_tabs['comments']) ? aksrt_get_user_center_tab_url('comments') : $public_home_url,
],
[
'label' => __('收藏', 'aksrt'),
'value' => (int) ($favorite_count ?? 0),
'url' => isset($dashboard_tabs['favorites']) ? aksrt_get_user_center_tab_url('favorites') : $public_home_url,
],
[
'label' => __('粉丝', 'aksrt'),
'value' => (int) ($follower_count ?? 0),
'url' => $public_home_url !== '' ? add_query_arg(['tab' => 'follow', 'follow_sub' => 'followers'], $public_home_url) : '',
],
];
?>
<div class="uc-sidebar__section">
<div class="uc-sidebar__title"><?php esc_html_e('数据统计', 'aksrt'); ?></div>
<div class="uc-sidebar__section uc-sidebar__section--stats" aria-label="<?php esc_attr_e('账号统计', 'aksrt'); ?>">
<div class="uc-stats">
<?php foreach (['posts', 'comments', 'favorites'] as $stat_tab) : ?>
<?php if (!isset($dashboard_tabs[$stat_tab])) { continue; } ?>
<?php
$stat_count = 'posts' === $stat_tab
? $post_count
: ('comments' === $stat_tab ? $comment_count : $favorite_count);
?>
<a class="uc-stats__item" href="<?php echo esc_url(add_query_arg('tab', $stat_tab, remove_query_arg('tab'))); ?>">
<span class="uc-stats__value"><?php echo esc_html((string) $stat_count); ?></span>
<span class="uc-stats__label"><?php echo esc_html($dashboard_tabs[$stat_tab]['label']); ?></span>
<?php foreach ($stats as $stat) : ?>
<a class="uc-stats__item" href="<?php echo esc_url((string) $stat['url']); ?>">
<span class="uc-stats__value"><?php echo esc_html(number_format_i18n((int) $stat['value'])); ?></span>
<span class="uc-stats__label"><?php echo esc_html((string) $stat['label']); ?></span>
</a>
<?php endforeach; ?>
<?php if (!empty($messages_url)) : ?>
<a class="uc-stats__item" href="<?php echo esc_url($messages_url); ?>">
<span class="uc-stats__value"><?php echo esc_html((string) $notification_unread_count); ?></span>
<span class="uc-stats__label"><?php esc_html_e('通知', 'aksrt'); ?></span>
</a>
<?php endif; ?>
</div>
</div>
-53
View File
@@ -25,59 +25,6 @@ add_action('wp_ajax_aksrt_save_profile', function () {
wp_send_json_success(['message' => __('保存成功!', 'aksrt')]);
});
// ============================================================
// AJAX: 上传打赏收款码
// ============================================================
add_action('wp_ajax_aksrt_upload_reward_qr', function () {
if (!isset($_POST['_profile_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_profile_nonce'])), 'aksrt_profile_save')) {
wp_send_json_error(['message' => __('安全验证失败,请刷新页面重试', 'aksrt')]);
}
$user_id = get_current_user_id();
if ($user_id <= 0) {
wp_send_json_error(['message' => __('请先登录', 'aksrt')]);
}
if (function_exists('aksrt_rewards_enabled') && !aksrt_rewards_enabled()) {
wp_send_json_error(['message' => __('打赏功能未启用', 'aksrt')]);
}
$kind = isset($_POST['kind']) ? sanitize_key((string) $_POST['kind']) : '';
if (!in_array($kind, ['weixin', 'alipay'], true)) {
wp_send_json_error(['message' => __('无效类型', 'aksrt')]);
}
if (empty($_FILES['file']['name'])) {
wp_send_json_error(['message' => __('请选择图片', 'aksrt')]);
}
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
$file = $_FILES['file'];
$check = wp_check_filetype_and_ext($file['tmp_name'], $file['name']);
$allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$mime = (string) ($check['type'] ?? $file['type'] ?? '');
if ($mime === '' || !in_array($mime, $allowed, true)) {
wp_send_json_error(['message' => __('仅支持 JPG/PNG/GIF/WebP 图片', 'aksrt')]);
}
if (!empty($file['size']) && (int) $file['size'] > 2 * 1024 * 1024) {
wp_send_json_error(['message' => __('图片不能超过 2MB', 'aksrt')]);
}
$attachment_id = media_handle_upload('file', 0);
if (is_wp_error($attachment_id)) {
wp_send_json_error(['message' => $attachment_id->get_error_message()]);
}
$meta = $kind === 'weixin' ? 'aksrt_rewards_weixin' : 'aksrt_rewards_alipay';
update_user_meta($user_id, $meta, (int) $attachment_id);
$url = wp_get_attachment_image_url((int) $attachment_id, 'full');
wp_send_json_success([
'message' => __('上传成功', 'aksrt'),
'id' => (int) $attachment_id,
'url' => is_string($url) ? $url : '',
'kind' => $kind,
]);
});
// ============================================================
// AJAX: 发送邮箱验证码(修改密码/更改邮箱通用)
// ============================================================