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
@@ -149,8 +149,12 @@ 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_s', label: '用户打赏', type: 'switch', default: false, help: '开启后用户可配置微信/支付宝收款码;无码则不显示按钮。' },
{ 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: 'post_rewards_amounts', label: '快捷金额', type: 'input', default: '5,10,20,50,100', help: '使用英文逗号分隔', dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'post_rewards_custom', label: '允许自定义金额', type: 'switch', default: true, dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'post_rewards_min', label: '最低金额', type: 'number', default: 1, min: 0.01, max: 1000, step: 0.01, dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'post_rewards_max', label: '最高金额', type: 'number', default: 1000, min: 1, max: 100000, step: 0.01, 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 } },
],
@@ -197,3 +197,64 @@
background: var(--surface-3, #ECEEF1);
}
.reward-modal__content > p {
margin: -4px 0 18px;
}
.reward-amounts {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 10px;
margin: 18px 0;
}
.reward-amount {
min-height: 42px;
border: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.1));
border-radius: 10px;
background: var(--surface-2);
color: var(--color-ink-2);
cursor: pointer;
font-weight: 700;
}
.reward-amount.is-active {
border-color: var(--color-primary);
background: var(--color-primary-soft);
color: var(--color-primary);
}
.reward-custom {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 16px;
color: var(--color-ink-3);
font-size: 13px;
}
.reward-custom input {
width: 140px;
min-height: 40px;
border: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.1));
border-radius: 9px;
background: var(--surface-1);
color: var(--color-ink);
padding: 0 12px;
}
.reward-modal__submit {
width: 100%;
min-height: 42px;
}
.reward-modal__message {
min-height: 20px;
margin-top: 10px;
color: var(--color-primary);
font-size: 12px;
text-align: center;
}
+258
View File
@@ -380,3 +380,261 @@ body.aksrt-user-center .uc-content,
padding-top: 18px;
border-top: 1px solid var(--color-line-soft, rgba(0,0,0,0.06));
}
/* ==================== 侧栏账户仪表盘 ==================== */
.uc-sidebar__section--stats {
padding: 8px 10px;
}
.uc-sidebar__heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 14px;
color: var(--color-ink, #172033);
font-size: 14px;
font-weight: 700;
}
.uc-sidebar__heading > a {
display: inline-flex;
align-items: center;
gap: 5px;
color: var(--color-ink-4);
font-size: 12px;
font-weight: 500;
text-decoration: none;
}
.uc-sidebar__heading > a:hover {
color: var(--color-primary);
}
.uc-stats {
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 0;
}
.uc-stats__item {
position: relative;
gap: 2px;
padding: 8px 2px;
background: transparent;
}
.uc-stats__item + .uc-stats__item::before {
content: '';
position: absolute;
top: 12px;
bottom: 12px;
left: 0;
width: 1px;
background: var(--color-line-soft, rgba(15, 23, 42, 0.07));
}
.uc-stats__item:hover {
background: var(--surface-2);
box-shadow: none;
}
.uc-stats__value {
color: var(--color-ink, #172033);
font-size: 17px;
letter-spacing: -0.02em;
}
.uc-stats__label {
margin: 0;
font-size: 11px;
}
.uc-order-grid {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 4px;
}
.uc-order-grid__item {
display: flex;
flex-direction: column;
align-items: center;
gap: 7px;
min-width: 0;
padding: 5px 0 2px;
color: var(--color-ink-3);
font-size: 11px;
text-align: center;
text-decoration: none;
}
.uc-order-grid__item:hover {
color: var(--color-primary);
}
.uc-order-grid__icon {
position: relative;
display: grid;
place-items: center;
width: 38px;
height: 38px;
border-radius: 13px;
background: color-mix(in srgb, var(--color-primary) 9%, var(--surface-2));
color: var(--color-primary);
font-size: 16px;
transition: transform 0.2s ease, background-color 0.2s ease;
}
.uc-order-grid__item:nth-child(2) .uc-order-grid__icon { color: #a56b10; background: rgba(245, 158, 11, 0.12); }
.uc-order-grid__item:nth-child(3) .uc-order-grid__icon { color: #15806c; background: rgba(16, 185, 129, 0.12); }
.uc-order-grid__item:nth-child(4) .uc-order-grid__icon { color: #7c4ed8; background: rgba(139, 92, 246, 0.12); }
.uc-order-grid__item:nth-child(5) .uc-order-grid__icon { color: #d04b65; background: rgba(244, 63, 94, 0.11); }
.uc-order-grid__item:hover .uc-order-grid__icon {
transform: translateY(-2px);
}
.uc-order-grid__icon small,
.uc-service-grid__icon small {
position: absolute;
top: -5px;
right: -7px;
display: grid;
place-items: center;
min-width: 17px;
height: 17px;
padding: 0 4px;
border: 2px solid var(--surface-1);
border-radius: 99px;
background: var(--color-error, #ef4444);
color: #fff;
font-size: 9px;
font-style: normal;
font-weight: 700;
line-height: 1;
}
.uc-sidebar__pair {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.uc-summary-card,
.uc-center-card {
min-width: 0;
border: 1px solid var(--color-line-soft, rgba(15, 23, 42, 0.06));
border-radius: var(--main-radius, var(--radius, 8px));
background: var(--surface-1);
box-shadow: 0 1px 4px rgba(15, 23, 42, 0.04);
color: var(--color-ink-2);
text-decoration: none;
}
.uc-summary-card {
padding: 14px;
}
.uc-summary-card__head,
.uc-summary-card__body {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.uc-summary-card__head {
margin-bottom: 10px;
color: var(--color-ink-4);
font-size: 12px;
}
.uc-summary-card__body strong {
overflow: hidden;
font-size: 18px;
font-variant-numeric: tabular-nums;
letter-spacing: -0.02em;
text-overflow: ellipsis;
}
.uc-summary-card__body > i {
font-size: 18px;
}
.uc-summary-card--wallet .uc-summary-card__body { color: #3978d6; }
.uc-summary-card--points .uc-summary-card__body { color: #ba7a0a; }
.uc-center-card {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 9px;
padding: 13px 12px;
}
.uc-center-card__icon {
display: grid;
place-items: center;
width: 34px;
height: 34px;
border-radius: 12px;
font-size: 15px;
}
.uc-center-card strong,
.uc-center-card small {
display: block;
white-space: nowrap;
}
.uc-center-card strong { font-size: 13px; }
.uc-center-card small { margin-top: 3px; color: var(--color-ink-4); font-size: 10px; }
.uc-center-card > i { color: var(--color-ink-4); font-size: 11px; }
.uc-center-card--creation .uc-center-card__icon { color: #6650c7; background: rgba(124, 92, 220, 0.12); }
.uc-center-card--promotion .uc-center-card__icon { color: #ce6b35; background: rgba(234, 112, 55, 0.12); }
.uc-service-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
}
.uc-service-grid__item {
display: flex;
flex-direction: column;
align-items: center;
gap: 7px;
min-width: 0;
padding: 4px 2px;
color: var(--color-ink-3);
font-size: 11px;
text-align: center;
text-decoration: none;
}
.uc-service-grid__icon {
position: relative;
display: grid;
place-items: center;
width: 38px;
height: 38px;
border-radius: 14px;
background: var(--surface-2);
font-size: 16px;
}
.uc-service-grid__item--cart .uc-service-grid__icon { color: #dd6941; background: rgba(238, 109, 61, 0.12); }
.uc-service-grid__item--level .uc-service-grid__icon { color: #9b6b0a; background: rgba(234, 179, 8, 0.13); }
.uc-service-grid__item--auth .uc-service-grid__icon { color: #287bc4; background: rgba(14, 165, 233, 0.12); }
.uc-service-grid__item--notice .uc-service-grid__icon { color: #d04b65; background: rgba(244, 63, 94, 0.11); }
.uc-service-grid__item--profile .uc-service-grid__icon { color: #6550c7; background: rgba(124, 92, 220, 0.12); }
.uc-service-grid__item--security .uc-service-grid__icon { color: #16816c; background: rgba(16, 185, 129, 0.12); }
.uc-service-grid__item:hover {
color: var(--color-primary);
}
@media (prefers-reduced-motion: reduce) {
.uc-order-grid__icon { transition: none; }
}
+82 -23
View File
@@ -1,55 +1,114 @@
/**
* Reward (打赏) — per-user QR modal openers.
* On-site wallet tipping modal.
*
* @package AKSRT
*/
;(function () {
'use strict';
var cfg = window.aksrtData || {};
function initReward() {
var activeTrigger = null;
function closeAll() {
document.querySelectorAll('.reward-modal.is-open').forEach(function (m) {
m.classList.remove('is-open');
m.setAttribute('aria-hidden', 'true');
document.querySelectorAll('.reward-modal.is-open').forEach(function (modal) {
modal.classList.remove('is-open');
modal.setAttribute('aria-hidden', 'true');
});
document.body.style.overflow = '';
if (activeTrigger) activeTrigger.focus();
activeTrigger = null;
}
function openForUser(userId) {
var id = String(userId || '');
var modal = id
? document.getElementById('reward-modal-' + id)
: document.querySelector('.reward-modal');
function open(trigger) {
var userId = trigger.getAttribute('data-user-id') || '';
var modal = document.getElementById('reward-modal-' + userId);
if (!modal) return;
closeAll();
activeTrigger = trigger;
modal.dataset.postId = trigger.getAttribute('data-post-id') || modal.dataset.postId || '0';
modal.classList.add('is-open');
modal.setAttribute('aria-hidden', 'false');
document.body.style.overflow = 'hidden';
var first = modal.querySelector('[data-reward-amount], [data-aksrt-reward-custom]');
if (first) first.focus();
}
document.querySelectorAll('[data-aksrt-reward-open]').forEach(function (el) {
el.addEventListener('click', function (e) {
e.preventDefault();
openForUser(el.getAttribute('data-user-id') || '');
});
});
document.addEventListener('click', function (event) {
var opener = event.target.closest('[data-aksrt-reward-open]');
if (opener) {
event.preventDefault();
open(opener);
return;
}
document.querySelectorAll('[data-aksrt-reward-close]').forEach(function (el) {
el.addEventListener('click', function (e) {
e.preventDefault();
if (event.target.closest('[data-aksrt-reward-close]')) {
event.preventDefault();
closeAll();
return;
}
var amountButton = event.target.closest('[data-reward-amount]');
if (amountButton) {
var modal = amountButton.closest('.reward-modal');
modal.querySelectorAll('[data-reward-amount]').forEach(function (button) {
button.classList.toggle('is-active', button === amountButton);
});
var custom = modal.querySelector('[data-aksrt-reward-custom]');
if (custom) custom.value = '';
return;
}
var submit = event.target.closest('[data-aksrt-reward-submit]');
if (!submit || submit.disabled) return;
var tipModal = submit.closest('.reward-modal');
var message = tipModal.querySelector('[data-aksrt-reward-message]');
var customInput = tipModal.querySelector('[data-aksrt-reward-custom]');
var selected = tipModal.querySelector('[data-reward-amount].is-active');
var amount = customInput && customInput.value ? customInput.value : (selected ? selected.dataset.rewardAmount : '');
submit.disabled = true;
submit.textContent = '赞赏中…';
if (message) message.textContent = '';
var body = new URLSearchParams();
body.set('action', 'aksrt_submit_tip');
body.set('nonce', cfg.nonce || '');
body.set('recipient_id', tipModal.dataset.userId || '');
body.set('post_id', tipModal.dataset.postId || '0');
body.set('amount', amount);
fetch(cfg.ajaxUrl || '/wp-admin/admin-ajax.php', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
body: body.toString()
}).then(function (response) {
return response.json();
}).then(function (response) {
var text = response && response.data && response.data.message ? response.data.message : '赞赏失败';
if (response && response.success) {
if (message) message.textContent = text;
setTimeout(closeAll, 900);
} else if (message) {
message.textContent = text;
}
}).catch(function () {
if (message) message.textContent = '网络错误,请稍后重试';
}).finally(function () {
submit.disabled = false;
submit.textContent = '余额赞赏';
});
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') closeAll();
document.addEventListener('keydown', function (event) {
if (event.key === 'Escape') closeAll();
});
}
if (window.AksrtFrontend && typeof window.AksrtFrontend.register === 'function') {
window.AksrtFrontend.register('aksrt-reward', function () {
initReward();
});
window.AksrtFrontend.register('aksrt-reward', initReward);
} else if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initReward);
} else {
-76
View File
@@ -121,80 +121,6 @@
/* ==================== 个人信息保存 ==================== */
/* ==================== 打赏收款码上传 ==================== */
function initRewardQrUpload() {
var form = document.getElementById('profile-form');
if (!form) return;
var nonceInput = form.querySelector('input[name="_profile_nonce"]');
var nonce = nonceInput ? nonceInput.value : '';
function setPreview(kind, url) {
var box = form.querySelector('[data-reward-preview="' + kind + '"]');
if (!box) return;
if (url) {
box.innerHTML = '<img src="' + url + '" alt="" />';
} else {
box.innerHTML = '<span class="muted-2-color em09">未上传</span>';
}
}
form.querySelectorAll('[data-reward-upload]').forEach(function (btn) {
btn.addEventListener('click', function () {
var kind = btn.getAttribute('data-reward-upload');
var fileInput = form.querySelector('input[data-reward-kind="' + kind + '"]');
if (fileInput) fileInput.click();
});
});
form.querySelectorAll('[data-reward-clear]').forEach(function (btn) {
btn.addEventListener('click', function () {
var kind = btn.getAttribute('data-reward-clear');
var hidden = form.querySelector('#rewards-' + kind);
var fileInput = form.querySelector('input[data-reward-kind="' + kind + '"]');
if (hidden) hidden.value = '';
if (fileInput) fileInput.value = '';
setPreview(kind, '');
});
});
form.querySelectorAll('input[data-reward-kind]').forEach(function (input) {
input.addEventListener('change', function () {
var kind = input.getAttribute('data-reward-kind');
var file = input.files && input.files[0];
if (!file || !kind) return;
if (file.size > 2 * 1024 * 1024) {
showToast('图片不能超过 2MB');
input.value = '';
return;
}
var body = new FormData();
body.append('action', 'aksrt_upload_reward_qr');
body.append('_profile_nonce', nonce);
body.append('kind', kind);
body.append('file', file);
showToast(i18n.saving || '上传中…');
fetch(ajaxUrl, { method: 'POST', body: body, credentials: 'same-origin' })
.then(function (r) { return r.json(); })
.then(function (res) {
if (res && res.success && res.data) {
var hidden = form.querySelector('#rewards-' + kind);
if (hidden) hidden.value = String(res.data.id || '');
setPreview(kind, res.data.url || '');
showToast(res.data.message || '上传成功');
} else {
showToast((res && res.data && res.data.message) || '上传失败');
}
})
.catch(function () {
showToast(i18n.networkError || '网络错误');
})
.finally(function () {
input.value = '';
});
});
});
}
function initProfileForm() {
var form = document.getElementById('profile-form');
@@ -752,7 +678,6 @@
document.addEventListener('DOMContentLoaded', function() {
initDashboardNavigation();
initProfileForm();
initRewardQrUpload();
initUnfavorite();
initNotifications();
initSettings();
@@ -760,7 +685,6 @@
} else {
initDashboardNavigation();
initProfileForm();
initRewardQrUpload();
initUnfavorite();
initNotifications();
initSettings();
+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: 发送邮箱验证码(修改密码/更改邮箱通用)
// ============================================================
@@ -140,6 +140,10 @@ class SchemaPostList {
['key' => 'post_wechat_share', 'label' => '微信分享', 'type' => 'switch', 'default' => false],
['key' => 'post_rewards_s', 'label' => '用户打赏', 'type' => 'switch', 'default' => false],
['key' => 'post_rewards_text', 'label' => '打赏按钮文案', 'type' => 'input', 'default' => '赞赏'],
['key' => 'post_rewards_amounts', 'label' => '快捷金额', 'type' => 'input', 'default' => '5,10,20,50,100', 'description' => '英文逗号分隔,赞赏直接进入作者站内余额'],
['key' => 'post_rewards_custom', 'label' => '允许自定义金额', 'type' => 'switch', 'default' => true],
['key' => 'post_rewards_min', 'label' => '最低金额', 'type' => 'number', 'default' => 1, 'min' => 0.01, 'max' => 1000, 'step' => 0.01],
['key' => 'post_rewards_max', 'label' => '最高金额', 'type' => 'number', 'default' => 1000, 'min' => 1, 'max' => 100000, 'step' => 0.01],
['key' => 'post_button_toptext', 'label' => '按钮上方文案', 'type' => 'input', 'default' => '喜欢就支持一下吧'],
]],
['key' => 'content', 'title' => '内容处理', 'fields' => [
+1 -8
View File
@@ -585,14 +585,7 @@ class SchemaUsers {
['key' => 'user_privacy_ip', 'label' => '隐藏IP归属地', 'type' => 'switch', 'default' => false],
['key' => 'user_privacy_location', 'label' => '隐藏位置', 'type' => 'switch', 'default' => false],
]],
['key' => 'rewards', 'title' => '打赏设置', 'fields' => [
['key' => 'post_rewards_s', 'label' => '启用文章打赏', 'type' => 'switch', 'default' => true],
['key' => 'post_rewards_text', 'label' => '打赏文案', 'type' => 'input', 'default' => ''],
['key' => 'post_rewards_img', 'label' => '打赏二维码', 'type' => 'media', 'default' => ''],
['key' => 'post_rewards_btn_text', 'label' => '打赏按钮文案', 'type' => 'input', 'default' => '赞赏'],
['key' => 'post_rewards_amounts', 'label' => '打赏金额', 'type' => 'input', 'default' => '5,10,20,50,100'],
['key' => 'post_rewards_custom', 'label' => '自定义金额', 'type' => 'switch', 'default' => true],
]],
],
],
'verify' => [
+101
View File
@@ -244,6 +244,105 @@ class Balance {
return !empty(\AKSRT\Settings\Settings::get_all()['pay_balance_s']);
}
/**
* Atomically transfer cash balance between two users.
*
* @param array<string,mixed> $ref
* @return array{sender_balance:float,recipient_balance:float}|\WP_Error
*/
public static function transfer(int $sender_id, int $recipient_id, float $amount, string $reason_out = 'tip_sent', string $reason_in = 'tip_received', array $ref = [], string $remark = '') {
global $wpdb;
$amount = round($amount, 2);
if ($sender_id <= 0 || $recipient_id <= 0 || $sender_id === $recipient_id) {
return new \WP_Error('aksrt_balance_transfer_user', __('转账用户无效', 'aksrt'));
}
if ($amount <= 0) {
return new \WP_Error('aksrt_balance_transfer_amount', __('转账金额必须大于零', 'aksrt'));
}
if (!class_exists('\AKSRT\Core\DBMigrator')) {
return new \WP_Error('aksrt_balance_transfer_unavailable', __('余额服务不可用', 'aksrt'));
}
foreach ([$sender_id, $recipient_id] as $user_id) {
if (!metadata_exists('user', $user_id, self::META_KEY)) {
add_user_meta($user_id, self::META_KEY, '0', true);
}
}
$meta_table = $wpdb->usermeta;
$log_table = \AKSRT\Core\DBMigrator::table('balance_log');
$locked_ids = [$sender_id, $recipient_id];
sort($locked_ids, SORT_NUMERIC);
$wpdb->query('START TRANSACTION');
try {
foreach ($locked_ids as $user_id) {
$wpdb->get_var($wpdb->prepare(
"SELECT umeta_id FROM {$meta_table} WHERE user_id = %d AND meta_key = %s FOR UPDATE",
$user_id,
self::META_KEY
));
}
$sender_before = (float) $wpdb->get_var($wpdb->prepare(
"SELECT meta_value FROM {$meta_table} WHERE user_id = %d AND meta_key = %s LIMIT 1",
$sender_id,
self::META_KEY
));
if ($sender_before < $amount) {
$wpdb->query('ROLLBACK');
return new \WP_Error('aksrt_balance_insufficient', __('余额不足', 'aksrt'));
}
$sender_after = round($sender_before - $amount, 2);
$recipient_before = (float) $wpdb->get_var($wpdb->prepare(
"SELECT meta_value FROM {$meta_table} WHERE user_id = %d AND meta_key = %s LIMIT 1",
$recipient_id,
self::META_KEY
));
$recipient_after = round($recipient_before + $amount, 2);
$sender_updated = $wpdb->update($meta_table, ['meta_value' => (string) $sender_after], ['user_id' => $sender_id, 'meta_key' => self::META_KEY], ['%s'], ['%d', '%s']);
$recipient_updated = $wpdb->update($meta_table, ['meta_value' => (string) $recipient_after], ['user_id' => $recipient_id, 'meta_key' => self::META_KEY], ['%s'], ['%d', '%s']);
if ($sender_updated !== 1 || $recipient_updated !== 1) {
throw new \RuntimeException('balance_update_failed');
}
$ref_type = isset($ref['type']) ? sanitize_key((string) $ref['type']) : 'tip';
$ref_id = isset($ref['id']) ? (int) $ref['id'] : null;
$created_at = current_time('mysql', true);
$log_rows = [
[$sender_id, -$amount, $sender_after, $reason_out],
[$recipient_id, $amount, $recipient_after, $reason_in],
];
foreach ($log_rows as [$user_id, $delta, $balance_after, $reason]) {
$inserted = $wpdb->insert($log_table, [
'user_id' => $user_id,
'delta' => $delta,
'balance_after' => $balance_after,
'reason' => sanitize_key($reason),
'remark' => $remark !== '' ? sanitize_text_field(substr($remark, 0, 255)) : null,
'ref_type' => $ref_type,
'ref_id' => $ref_id,
'created_at' => $created_at,
], ['%d', '%f', '%f', '%s', '%s', '%s', '%d', '%s']);
if ($inserted !== 1) {
throw new \RuntimeException('balance_log_failed');
}
}
$wpdb->query('COMMIT');
wp_cache_delete($sender_id, 'user_meta');
wp_cache_delete($recipient_id, 'user_meta');
do_action('aksrt_balance_transferred', $sender_id, $recipient_id, $amount, $ref);
return ['sender_balance' => $sender_after, 'recipient_balance' => $recipient_after];
} catch (\Throwable $e) {
$wpdb->query('ROLLBACK');
return new \WP_Error('aksrt_balance_transfer_failed', __('打赏入账失败,请稍后重试', 'aksrt'));
}
}
/**
* Format yuan for display.
*/
@@ -262,6 +361,8 @@ class Balance {
'recharge' => __('余额充值', 'aksrt'),
'transfer_in' => __('转入', 'aksrt'),
'transfer_out' => __('转出', 'aksrt'),
'tip_sent' => __('打赏支出', 'aksrt'),
'tip_received' => __('收到打赏', 'aksrt'),
'admin' => __('管理员调整', 'aksrt'),
'exchange_from_credits' => __('积分兑换', 'aksrt'),
'withdraw_hold' => __('提现冻结', 'aksrt'),
+8 -4
View File
@@ -391,9 +391,11 @@ trait OrderRepositoryCore {
SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END) as paid,
SUM(CASE WHEN status = 'delivered' THEN 1 ELSE 0 END) as delivered,
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
SUM(CASE WHEN status = 'pending_review' THEN 1 ELSE 0 END) as pending_review,
SUM(CASE WHEN status = 'refunding' THEN 1 ELSE 0 END) as refunding,
SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) as cancelled,
SUM(CASE WHEN status = 'refunded' THEN 1 ELSE 0 END) as refunded,
SUM(CASE WHEN status IN ('paid','delivered','completed') THEN amount ELSE 0 END) as revenue
SUM(CASE WHEN status IN ('paid','delivered','completed','pending_review') THEN amount ELSE 0 END) as revenue
FROM {$this->table()} {$where}";
if (!empty($params)) {
@@ -406,9 +408,11 @@ trait OrderRepositoryCore {
'total' => (int) ($row['total'] ?? 0),
'pending' => (int) ($row['pending'] ?? 0),
'paid' => (int) ($row['paid'] ?? 0),
'delivered' => (int) ($row['delivered'] ?? 0),
'completed' => (int) ($row['completed'] ?? 0),
'cancelled' => (int) ($row['cancelled'] ?? 0),
'delivered' => (int) ($row['delivered'] ?? 0),
'completed' => (int) ($row['completed'] ?? 0),
'pending_review' => (int) ($row['pending_review'] ?? 0),
'refunding' => (int) ($row['refunding'] ?? 0),
'cancelled' => (int) ($row['cancelled'] ?? 0),
'refunded' => (int) ($row['refunded'] ?? 0),
'revenue' => (float) ($row['revenue'] ?? 0),
];
+14 -2
View File
@@ -237,11 +237,19 @@ class PostDisplay {
$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_s']) || !empty($settings['post_rewards_enabled']);
$rewards_enabled = !empty($settings['post_rewards_s']);
$rewards_text = sanitize_text_field((string) ($settings['post_rewards_text'] ?? ''));
if ($rewards_text === '') {
$rewards_text = '赞赏';
}
$rewards_amounts = array_values(array_filter(array_map(static function ($value): float {
return round((float) $value, 2);
}, explode(',', (string) ($settings['post_rewards_amounts'] ?? '5,10,20,50,100'))), static fn(float $value): bool => $value > 0));
if ($rewards_amounts === []) {
$rewards_amounts = [5, 10, 20, 50, 100];
}
$rewards_min = max(0.01, round((float) ($settings['post_rewards_min'] ?? 1), 2));
$rewards_max = max($rewards_min, round((float) ($settings['post_rewards_max'] ?? 1000), 2));
$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)) {
@@ -332,11 +340,15 @@ class PostDisplay {
'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.
// On-site wallet tipping.
'rewards_enabled' => $rewards_enabled,
'post_rewards_s' => $rewards_enabled,
'rewards_text' => $rewards_text,
'rewards_btn_text' => $rewards_text,
'rewards_amounts' => $rewards_amounts,
'rewards_custom' => !isset($settings['post_rewards_custom']) || !empty($settings['post_rewards_custom']),
'rewards_min' => $rewards_min,
'rewards_max' => $rewards_max,
// Content max height (Zibll article_maxheight_kg / article_maxheight).
'maxheight_enabled' => $maxheight_enabled,
'maxheight' => $maxheight,
+9 -14
View File
@@ -122,21 +122,16 @@ $is_self = is_user_logged_in() && get_current_user_id() === $author_id;
<a href="<?php echo esc_url(add_query_arg('msg_type', 'conversation', $aksrt_msg_url)); ?>" class="ml6 but c-blue px12-sm">
<i class="fa fa-comment em09" aria-hidden="true"></i> <?php esc_html_e('私信', 'aksrt'); ?>
</a>
<?php else : ?>
<?php
$aksrt_post_settings = class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_post_page_settings')
? \AKSRT\Settings\Settings::get_post_page_settings()
: [];
$rewards_on = !empty($aksrt_post_settings['rewards_enabled'])
|| !empty($aksrt_post_settings['post_rewards_enabled'])
|| !empty($aksrt_post_settings['post_rewards_s']);
?>
<?php if ($rewards_on) : ?>
<button type="button" class="ml6 but c-yellow px12-sm" data-aksrt-reward-open>
<i class="fa fa-gift em09" aria-hidden="true"></i> <?php esc_html_e('赞赏', 'aksrt'); ?>
</button>
<?php endif; ?>
<?php endif; ?>
<?php
$reward_button = function_exists('aksrt_get_rewards_button')
? aksrt_get_rewards_button($author_id, 'ml6 but c-yellow px12-sm', get_the_ID())
: '';
if ($reward_button !== '') {
echo $reward_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
aksrt_render_rewards_modal_for_user($author_id, get_the_ID());
}
?>
<?php else : ?>
<a href="<?php echo esc_url($login_url); ?>" class="px12-sm ml10 follow but c-red">
<i class="fa fa-heart em09" aria-hidden="true"></i> <?php esc_html_e('关注', 'aksrt'); ?>