The old 售后 flow was an order-refund appendage: tickets were hard-bound to an order number, users could only file them from 「我的订单」against a paid order, and the admin action bottomed out at 「标记订单已退款」. It could not carry account questions or feature requests that have nothing to do with an order. Replace it with a general ticket system modelled on 魔方财务云's idcsmart_ticket: title + department + description are required, linking an order is optional (user's own paid orders only). Add departments, custom statuses, preset replies and internal admin notes as four configuration surfaces. Conversation history moves off the ticket row's JSON log into dedicated ticket_reply rows, which unlocks quoted replies. Front end gets a 工单中心 panel under 我的服务; back end moves from 支付中心 → 售后服务 to users.php → 工单管理. Per CLAUDE.md's rewrite-over-compatibility rule: drop the old table, build new ones, delete the old code. No dual paths, no data migration. The upstream plugin's upstream/downstream delivery and internal-ticket conversion are deliberately left out — both are multi-provider platform concerns with no meaning on a single WordPress site. Data: order_aftersale becomes six aksrt_ticket* tables (ticket, ticket_reply, ticket_status, ticket_type, ticket_prereply, ticket_note). SCHEMA_VERSION 2.6.0 -> 3.0.0. Status and department seeds are idempotent; the default status 「待接单」is flagged as non-editable. Domain: new src/Ticket/ (13 files, all under 460 lines). Attachments reuse UserController::rest_upload_comment_image with a ticket-specific permission callback, mirroring the existing /report/upload-image route rather than growing a second upload path. Notifications go through AKSRT\Messages\Message::send() and deep-link to the right surface; email/SMS stay out of scope since the theme's mail and SMS stacks are separate implementations. Refund gate opens up: marking an order refunded no longer requires an in-flight ticket, only that the order is paid. Also generalise a hardcoded special case in tools/audit-admin-contracts.php — schema domain inference now reads the parent directory instead of matching "PostList" by name, so new leaf schema files need no per-name exception. Verification: php tools/audit-admin-contracts.php exit 0, errors=0 node --test (widget-system + admin) 664 pass / 0 fail php -l over all new/changed files clean node --check over all JS clean npm run build + build:public clean Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
577 lines
23 KiB
PHP
577 lines
23 KiB
PHP
<?php
|
|
/**
|
|
* User center helpers.
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
if (!function_exists('aksrt_get_user_profile_details')) {
|
|
/**
|
|
* Read the fixed profile details. Social fields are deliberately kept in one
|
|
* structured meta value so public rendering can filter them server-side.
|
|
*
|
|
* @return array{privacy:string,gender:string,website:string,qq:string,wechat:string,weibo:string,github:string,address:string}
|
|
*/
|
|
function aksrt_get_user_profile_details(int $user_id): array {
|
|
$raw = get_user_meta($user_id, 'aksrt_profile_details', true);
|
|
$raw = is_array($raw) ? $raw : [];
|
|
$privacy = (string) ($raw['privacy'] ?? 'private');
|
|
if (!in_array($privacy, ['private', 'public', 'members'], true)) {
|
|
$privacy = 'private';
|
|
}
|
|
$gender = (string) ($raw['gender'] ?? 'secret');
|
|
if (!in_array($gender, ['secret', 'male', 'female'], true)) {
|
|
$gender = 'secret';
|
|
}
|
|
|
|
return [
|
|
'privacy' => $privacy,
|
|
'gender' => $gender,
|
|
'website' => esc_url_raw((string) ($raw['website'] ?? '')),
|
|
'qq' => sanitize_text_field((string) ($raw['qq'] ?? '')),
|
|
'wechat' => sanitize_text_field((string) ($raw['wechat'] ?? '')),
|
|
'weibo' => esc_url_raw((string) ($raw['weibo'] ?? '')),
|
|
'github' => esc_url_raw((string) ($raw['github'] ?? '')),
|
|
'address' => sanitize_text_field((string) ($raw['address'] ?? '')),
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_get_visible_user_profile_details')) {
|
|
/** @return array{gender:string,website:string,qq:string,wechat:string,weibo:string,github:string,address:string} */
|
|
function aksrt_get_visible_user_profile_details(int $user_id, int $viewer_id = 0): array {
|
|
$details = aksrt_get_user_profile_details($user_id);
|
|
$visible = $viewer_id === $user_id || $details['privacy'] === 'public' || ($details['privacy'] === 'members' && $viewer_id > 0);
|
|
return [
|
|
'gender' => $details['gender'] === 'secret' ? '' : $details['gender'],
|
|
'website' => $visible ? $details['website'] : '',
|
|
'qq' => $visible ? $details['qq'] : '',
|
|
'wechat' => $visible ? $details['wechat'] : '',
|
|
'weibo' => $visible ? $details['weibo'] : '',
|
|
'github' => $visible ? $details['github'] : '',
|
|
'address' => $visible ? $details['address'] : '',
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_save_user_center_profile')) {
|
|
/**
|
|
* Save the user-center profile form for both AJAX and no-JS requests.
|
|
*
|
|
* @param int $user_id User being updated.
|
|
* @param array $input Untrusted request data.
|
|
* @return true|WP_Error
|
|
*/
|
|
function aksrt_save_user_center_profile(int $user_id, array $input) {
|
|
if (!$user_id || $user_id !== get_current_user_id()) {
|
|
return new WP_Error('aksrt_profile_forbidden', __('无权操作', 'aksrt'));
|
|
}
|
|
|
|
$errors = [];
|
|
$update = ['ID' => $user_id];
|
|
|
|
if (isset($input['nickname'])) {
|
|
$name = sanitize_text_field(wp_unslash($input['nickname']));
|
|
if (mb_strlen($name) < 1 || mb_strlen($name) > 50) {
|
|
$errors[] = __('昵称长度需在 1-50 字之间', 'aksrt');
|
|
} else {
|
|
$update['display_name'] = $name;
|
|
}
|
|
}
|
|
|
|
if (isset($input['description'])) {
|
|
$description = sanitize_textarea_field(wp_unslash($input['description']));
|
|
if (mb_strlen($description) > 500) {
|
|
$errors[] = __('个人简介不能超过 500 字', 'aksrt');
|
|
} else {
|
|
$update['description'] = $description;
|
|
}
|
|
}
|
|
|
|
$existing_details = aksrt_get_user_profile_details($user_id);
|
|
$privacy = isset($input['privacy']) ? sanitize_key(wp_unslash($input['privacy'])) : $existing_details['privacy'];
|
|
if (!in_array($privacy, ['private', 'public', 'members'], true)) {
|
|
$errors[] = __('无效的隐私设置。', 'aksrt');
|
|
}
|
|
$gender = isset($input['gender']) ? sanitize_key(wp_unslash($input['gender'])) : $existing_details['gender'];
|
|
if (!in_array($gender, ['secret', 'male', 'female'], true)) {
|
|
$errors[] = __('无效的性别设置。', 'aksrt');
|
|
}
|
|
$details = [
|
|
'privacy' => $privacy,
|
|
'gender' => $gender,
|
|
'website' => isset($input['website']) ? esc_url_raw(wp_unslash($input['website'])) : $existing_details['website'],
|
|
'qq' => isset($input['qq']) ? sanitize_text_field(wp_unslash($input['qq'])) : $existing_details['qq'],
|
|
'wechat' => isset($input['wechat']) ? sanitize_text_field(wp_unslash($input['wechat'])) : $existing_details['wechat'],
|
|
'weibo' => isset($input['weibo']) ? esc_url_raw(wp_unslash($input['weibo'])) : $existing_details['weibo'],
|
|
'github' => isset($input['github']) ? esc_url_raw(wp_unslash($input['github'])) : $existing_details['github'],
|
|
'address' => isset($input['address']) ? sanitize_text_field(wp_unslash($input['address'])) : $existing_details['address'],
|
|
];
|
|
foreach (['website', 'weibo', 'github'] as $field) {
|
|
if (!empty($input[$field]) && $details[$field] === '') {
|
|
$field_label = ['website' => __('个人网站', 'aksrt'), 'weibo' => __('微博', 'aksrt'), 'github' => 'GitHub'][$field];
|
|
$errors[] = sprintf(__('无效的%s链接。', 'aksrt'), $field_label);
|
|
}
|
|
}
|
|
if (mb_strlen($details['qq']) > 50 || mb_strlen($details['wechat']) > 100 || mb_strlen($details['address']) > 200) {
|
|
$errors[] = __('社交资料长度超过限制。', 'aksrt');
|
|
}
|
|
if ($errors) {
|
|
return new WP_Error('aksrt_profile_invalid', implode('<br>', $errors));
|
|
}
|
|
|
|
if (count($update) > 1) {
|
|
$result = wp_update_user($update);
|
|
if (is_wp_error($result)) {
|
|
return $result;
|
|
}
|
|
}
|
|
update_user_meta($user_id, 'aksrt_profile_details', $details);
|
|
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_get_user_center_tab_url')) {
|
|
/**
|
|
* Build a canonical full-page user-center tab URL.
|
|
*/
|
|
function aksrt_get_user_center_tab_url(string $tab): string {
|
|
$tab = sanitize_key($tab);
|
|
return aksrt_get_user_center_url($tab);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_normalize_user_center_panels')) {
|
|
/**
|
|
* Normalize the dashboard tab contract.
|
|
*/
|
|
function aksrt_normalize_user_center_panels(array $tabs): array {
|
|
$normalized = [];
|
|
foreach ($tabs as $key => $tab) {
|
|
$key = sanitize_key((string) $key);
|
|
if (!$key || !is_array($tab)) {
|
|
continue;
|
|
}
|
|
$normalized[$key] = [
|
|
'label' => (string) ($tab['label'] ?? $key),
|
|
'icon' => sanitize_html_class((string) ($tab['icon'] ?? 'circle')),
|
|
'template' => isset($tab['template']) ? (string) $tab['template'] : '',
|
|
'context_callback' => $tab['context_callback'] ?? null,
|
|
];
|
|
}
|
|
return $normalized;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_capture_user_center_view')) {
|
|
/**
|
|
* Render an internal user-center view into an inert HTML payload.
|
|
*/
|
|
function aksrt_capture_user_center_view(string $view, array $context): string {
|
|
// Built-in panels map to renderer files; "profile" content lives in profile-form.php.
|
|
$map = [
|
|
'level' => 'level',
|
|
'profile' => 'form',
|
|
'creator' => 'creator',
|
|
'posts' => 'posts',
|
|
'follow' => 'follow',
|
|
'comments' => 'comments',
|
|
'favorites' => 'favorites',
|
|
'credits' => 'credits',
|
|
'vip' => 'vip',
|
|
'orders' => 'orders',
|
|
'tickets' => 'tickets',
|
|
'auth' => 'auth',
|
|
'revenue' => 'revenue',
|
|
'msg' => 'msg',
|
|
'settings' => 'settings',
|
|
'header' => 'header',
|
|
'sidebar' => 'sidebar',
|
|
];
|
|
$view = sanitize_file_name($view);
|
|
$renderer = $map[$view] ?? $view;
|
|
$path = AKSRT_DIR . '/inc/helpers/user-center-renderers/profile-' . $renderer . '.php';
|
|
if (!is_file($path)) {
|
|
return '';
|
|
}
|
|
|
|
ob_start();
|
|
$args = ['context' => $context];
|
|
require $path;
|
|
return (string) ob_get_clean();
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_capture_user_center_panel')) {
|
|
/**
|
|
* Capture a built-in or registered user-center panel body.
|
|
*/
|
|
function aksrt_capture_user_center_panel(string $tab_key, array $tab, array $context): string {
|
|
$built_in_tabs = ['profile', 'level', 'creator', 'posts', 'follow', 'comments', 'favorites', 'credits', 'vip', 'orders', 'tickets', 'auth', 'revenue', 'msg', 'settings'];
|
|
if (in_array($tab_key, $built_in_tabs, true)) {
|
|
return aksrt_capture_user_center_view($tab_key, $context);
|
|
}
|
|
|
|
$panel_context = $context;
|
|
if (is_callable($tab['context_callback'] ?? null)) {
|
|
$custom_context = call_user_func($tab['context_callback'], $context, $tab_key);
|
|
if (is_array($custom_context)) {
|
|
$panel_context = array_merge($panel_context, $custom_context);
|
|
}
|
|
}
|
|
|
|
$template = ltrim((string) ($tab['template'] ?? ''), '/');
|
|
if ($template === '') {
|
|
return '';
|
|
}
|
|
|
|
$template_path = locate_template([$template . '.php', $template], false, false);
|
|
if (!$template_path) {
|
|
return '';
|
|
}
|
|
|
|
ob_start();
|
|
load_template($template_path, false, ['context' => $panel_context]);
|
|
return (string) ob_get_clean();
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_build_user_center_render_context')) {
|
|
/**
|
|
* Assemble all runtime data before template parts are entered.
|
|
*/
|
|
function aksrt_build_user_center_render_context(array $context): array {
|
|
$active_tab = (string) ($context['active_tab'] ?? 'profile');
|
|
$context['header_html'] = aksrt_capture_user_center_view('header', $context);
|
|
$context['sidebar_html'] = aksrt_capture_user_center_view('sidebar', $context);
|
|
$context['mobile_tabs'] = [];
|
|
foreach ((array) ($context['dashboard_tabs'] ?? []) as $tab_key => $tab) {
|
|
$context['mobile_tabs'][] = [
|
|
'key' => (string) $tab_key,
|
|
'label' => (string) ($tab['label'] ?? $tab_key),
|
|
'url' => aksrt_get_user_center_tab_url((string) $tab_key),
|
|
'is_active' => $active_tab === $tab_key,
|
|
];
|
|
}
|
|
|
|
$context['panels'] = [];
|
|
foreach ((array) ($context['dashboard_tabs'] ?? []) as $tab_key => $tab) {
|
|
$context['panels'][$tab_key] = [
|
|
'key' => (string) $tab_key,
|
|
'url' => aksrt_get_user_center_tab_url((string) $tab_key),
|
|
'is_active' => $active_tab === $tab_key,
|
|
'is_loaded' => $active_tab === $tab_key,
|
|
'html' => $active_tab === $tab_key
|
|
? aksrt_capture_user_center_panel((string) $tab_key, (array) $tab, $context)
|
|
: '',
|
|
];
|
|
}
|
|
|
|
return $context;
|
|
}
|
|
}
|
|
|
|
|
|
if (!function_exists('aksrt_user_center_empty_svgs')) {
|
|
/**
|
|
* Shared empty-state icons for user-center panels.
|
|
*
|
|
* @return array{post:string,comment:string,favorite:string}
|
|
*/
|
|
function aksrt_user_center_empty_svgs(): array {
|
|
$all = aksrt_empty_state_svgs();
|
|
return [
|
|
'post' => $all['post'],
|
|
'comment' => $all['comment'],
|
|
'favorite' => $all['favorite'],
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_user_center_resolve_tabs')) {
|
|
/**
|
|
* Resolve dashboard tabs + active tab for the private user center.
|
|
*
|
|
* @return array{tabs:array,keys:array<int,string>,default:string,active:string,urls:array<string,string>}
|
|
*/
|
|
function aksrt_user_center_resolve_tabs(): array {
|
|
$tabs = class_exists('\AKSRT\User\Center')
|
|
? \AKSRT\User\Center::get_instance()->get_dashboard_tabs()
|
|
: [
|
|
'profile' => ['label' => __('个人信息', 'aksrt'), 'icon' => 'user'],
|
|
'comments' => ['label' => __('我的评论', 'aksrt'), 'icon' => 'comment'],
|
|
'favorites' => ['label' => __('我的收藏', 'aksrt'), 'icon' => 'star'],
|
|
'settings' => ['label' => __('账号设置', 'aksrt'), 'icon' => 'cog'],
|
|
];
|
|
$tabs = aksrt_normalize_user_center_panels($tabs);
|
|
$keys = array_keys($tabs);
|
|
$default = in_array('vip', $keys, true)
|
|
? 'vip'
|
|
: (in_array('profile', $keys, true) ? 'profile' : ($keys[0] ?? 'profile'));
|
|
$active = (string) get_query_var('aksrt_user_center_tab') ?: $default;
|
|
if ($active === 'balance') {
|
|
$active = 'credits';
|
|
}
|
|
if ('signin' === $active || 'assets' === $active) {
|
|
$active = 'credits';
|
|
} elseif ('vip' === $active) {
|
|
// Prefer dedicated vip tab when registered; else credits (VIP shop).
|
|
$active = in_array('vip', $keys, true) ? 'vip' : 'credits';
|
|
}
|
|
if (!in_array($active, $keys, true)) {
|
|
$active = $default;
|
|
}
|
|
$urls = [];
|
|
foreach ($keys as $key) {
|
|
$urls[$key] = aksrt_get_user_center_tab_url($key);
|
|
}
|
|
return [
|
|
'tabs' => $tabs,
|
|
'keys' => $keys,
|
|
'default' => $default,
|
|
'active' => $active,
|
|
'urls' => $urls,
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_user_center_runtime_config')) {
|
|
/**
|
|
* Frontend runtime config injected into the private user center page.
|
|
*/
|
|
function aksrt_user_center_runtime_config(int $user_id, string $default_tab, string $active_tab, array $tab_urls): array {
|
|
return [
|
|
'ajaxUrl' => admin_url('admin-ajax.php'),
|
|
'publicNonce' => wp_create_nonce('aksrt_public_nonce'),
|
|
'settingsNonce' => wp_create_nonce('aksrt_account_settings'),
|
|
'userId' => $user_id,
|
|
'restUrl' => rest_url('aksrt/v1'),
|
|
'restNonce' => wp_create_nonce('wp_rest'),
|
|
'submitNonce' => wp_create_nonce('aksrt_submit'),
|
|
'defaultTab' => $default_tab,
|
|
'activeTab' => $active_tab,
|
|
'tabAliases' => [
|
|
'signin' => 'credits',
|
|
'revenue' => 'revenue',
|
|
'assets' => 'credits',
|
|
// vip → vip when panel exists; SPA may still map missing keys via server resolve.
|
|
'vip' => 'vip',
|
|
],
|
|
'tabUrls' => $tab_urls,
|
|
'i18n' => [
|
|
'contactUrlPlaceholder' => __('链接 URL', 'aksrt'),
|
|
'deleteLabel' => __('删除', 'aksrt'),
|
|
'saving' => __('保存中…', 'aksrt'),
|
|
'saveBtn' => __('保存修改', 'aksrt'),
|
|
'saved' => __('已保存', 'aksrt'),
|
|
'saveFailed' => __('保存失败', 'aksrt'),
|
|
'networkError' => __('网络错误,请重试', 'aksrt'),
|
|
'confirmUnfavorite' => __('确定取消收藏这篇文章?', 'aksrt'),
|
|
'unfavorited' => __('已取消收藏', 'aksrt'),
|
|
'operationFailed' => __('操作失败', 'aksrt'),
|
|
'confirmUnbind' => __('确定解除绑定?', 'aksrt'),
|
|
'unbinding' => __('解除中...', 'aksrt'),
|
|
'unbindSuccess' => __('解除成功', 'aksrt'),
|
|
'unbindFailed' => __('解除失败', 'aksrt'),
|
|
'unbind' => __('解除', 'aksrt'),
|
|
'bindSuccess' => __('绑定成功', 'aksrt'),
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_user_center_avatar_upload_config')) {
|
|
/**
|
|
* Avatar upload config for the private user center.
|
|
*/
|
|
function aksrt_user_center_avatar_upload_config(bool $enabled): array {
|
|
if (!$enabled) {
|
|
return [];
|
|
}
|
|
// 头像上限并入「前端图片上传限制」统一治理(参考主题同源)。
|
|
$max_size = class_exists('\AKSRT\Attachment\UploadLimits') ? \AKSRT\Attachment\UploadLimits::limit_bytes('image') : (int) wp_max_upload_size();
|
|
return [
|
|
'enabled' => true,
|
|
'restUrl' => rest_url('aksrt/v1/user/avatar'),
|
|
'restNonce' => wp_create_nonce('wp_rest'),
|
|
'buttonId' => 'aksrt-upload-avatar-btn',
|
|
'inputId' => 'aksrt-avatar-file-input',
|
|
'imageId' => 'aksrt-user-avatar-image',
|
|
'fieldName' => 'avatar',
|
|
'maxSize' => $max_size,
|
|
'idleText' => __('更换头像', 'aksrt'),
|
|
'loadingText' => __('上传中…', 'aksrt'),
|
|
'tooLargeText' => sprintf(__('图片大小不能超过 %s', 'aksrt'), size_format($max_size)),
|
|
'successText' => __('头像已更新', 'aksrt'),
|
|
'errorText' => __('头像上传失败', 'aksrt'),
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_user_center_cover_upload_config')) {
|
|
/**
|
|
* Cover upload config for the private user-center hero.
|
|
*/
|
|
function aksrt_user_center_cover_upload_config(bool $allow_bg_upload): array {
|
|
if (!$allow_bg_upload) {
|
|
return [];
|
|
}
|
|
// 背景图上限并入「前端图片上传限制」统一治理(参考主题同源)。
|
|
$max_size = class_exists('\AKSRT\Attachment\UploadLimits') ? \AKSRT\Attachment\UploadLimits::limit_bytes('image') : (int) wp_max_upload_size();
|
|
return [
|
|
'enabled' => true,
|
|
'restUrl' => rest_url('aksrt/v1/user/background'),
|
|
'restNonce' => wp_create_nonce('wp_rest'),
|
|
'buttonId' => 'aksrt-upload-bg-btn',
|
|
'inputId' => 'aksrt-bg-file-input',
|
|
'imageId' => 'aksrt-cover-img',
|
|
'fieldName' => 'background',
|
|
'maxSize' => $max_size,
|
|
'fallbackImage' => function_exists('aksrt_get_user_cover_url') ? aksrt_get_user_cover_url(get_current_user_id()) : get_theme_file_uri('assets/img/user_t.jpg'),
|
|
'idleText' => __('修改背景图', 'aksrt'),
|
|
'loadingText' => __('上传中…', 'aksrt'),
|
|
'tooLargeText' => sprintf(__('图片大小不能超过 %s', 'aksrt'), size_format($max_size)),
|
|
'successText' => __('背景图已更新', 'aksrt'),
|
|
'errorText' => __('上传失败', 'aksrt'),
|
|
'networkErrorText' => __('网络错误,请重试', 'aksrt'),
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_get_user_center_render_context')) {
|
|
/**
|
|
* Resolve the current user's complete render context outside template files.
|
|
*/
|
|
function aksrt_get_user_center_render_context(WP_User $current_user): array {
|
|
$user_id = (int) $current_user->ID;
|
|
|
|
$user_center_settings = class_exists('\AKSRT\Settings\Settings')
|
|
? \AKSRT\Settings\Settings::get_user_center_settings()
|
|
: [
|
|
'tabs' => ['profile', 'comments', 'favorites'],
|
|
];
|
|
|
|
$tabs = aksrt_user_center_resolve_tabs();
|
|
$active_tab = $tabs['active'];
|
|
|
|
$dashboard = function_exists('aksrt_get_user_dashboard_view')
|
|
? aksrt_get_user_dashboard_view($user_id, [
|
|
'viewer_id' => $user_id,
|
|
'include_recent_posts' => false,
|
|
'include_governance' => true,
|
|
])
|
|
: [];
|
|
|
|
$post_count = (int) ($dashboard['post_count'] ?? count_user_posts($user_id, 'post', true));
|
|
$comment_count = (int) ($dashboard['comment_count'] ?? get_comments(['user_id' => $user_id, 'count' => true, 'status' => 'approve']));
|
|
$favorite_post_ids = $dashboard['favorite_post_ids'] ?? [];
|
|
$favorite_count = (int) ($dashboard['favorite_count'] ?? count($favorite_post_ids));
|
|
$user_background_url = function_exists('aksrt_get_user_cover_url') ? aksrt_get_user_cover_url($user_id) : '';
|
|
$allow_avatar_upload = function_exists('aksrt_is_avatar_upload_enabled') && aksrt_is_avatar_upload_enabled();
|
|
$allow_bg_upload = function_exists('aksrt_is_user_cover_upload_enabled') && aksrt_is_user_cover_upload_enabled();
|
|
$notification_settings = class_exists('\AKSRT\Settings\Settings')
|
|
? \AKSRT\Settings\Settings::notification_settings()
|
|
: ['enabled' => false, 'icon_show' => []];
|
|
$show_header_notification = !empty($notification_settings['enabled'])
|
|
&& in_array('user_center_header', (array) ($notification_settings['icon_show'] ?? []), true);
|
|
$follower_count = class_exists('\AKSRT\User\Follow')
|
|
? \AKSRT\User\Follow::get_instance()->get_follower_count($user_id)
|
|
: 0;
|
|
$following_count = class_exists('\AKSRT\User\Follow')
|
|
? \AKSRT\User\Follow::get_instance()->get_following_count($user_id)
|
|
: 0;
|
|
$allowed_post_statuses = ['publish', 'draft', 'pending', 'private'];
|
|
$post_status_filter = isset($_GET['post_status']) ? sanitize_key(wp_unslash($_GET['post_status'])) : 'publish';
|
|
if (!in_array($post_status_filter, array_merge($allowed_post_statuses, ['all']), true)) {
|
|
$post_status_filter = 'publish';
|
|
}
|
|
$user_status_counts = [];
|
|
foreach ($allowed_post_statuses as $status) {
|
|
$status_query = new WP_Query([
|
|
'author' => $user_id,
|
|
'post_type' => 'post',
|
|
'post_status' => $status,
|
|
'posts_per_page' => 1,
|
|
'fields' => 'ids',
|
|
'no_found_rows' => false,
|
|
]);
|
|
$user_status_counts[$status] = (int) $status_query->found_posts;
|
|
}
|
|
|
|
$svgs = aksrt_user_center_empty_svgs();
|
|
require_once AKSRT_DIR . '/templates/parts/user-shared-helpers.php';
|
|
|
|
$vip_settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_vip_settings() : [];
|
|
$affiliate_settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_affiliate_settings() : [];
|
|
$show_credit_tabs = (bool) ($dashboard['credits_enabled'] ?? false);
|
|
$currency_name = (string) ($dashboard['currency_name'] ?? __('积分', 'aksrt'));
|
|
$balance_enabled = (bool) ($dashboard['balance_enabled'] ?? false);
|
|
$wallet_balance = (float) ($dashboard['wallet_balance'] ?? 0.0);
|
|
$signin_settings = class_exists('\AKSRT\Settings\Settings')
|
|
? \AKSRT\Settings\Settings::get_signin_reward_settings()
|
|
: ['enabled' => false];
|
|
$signin_enabled = !empty($signin_settings['enabled']) && class_exists('\AKSRT\Credits\Signin');
|
|
$signin_signed_today = $signin_enabled
|
|
? \AKSRT\Credits\Signin::get_instance()->is_signed_today($user_id)
|
|
: false;
|
|
$runtime_config = aksrt_user_center_runtime_config($user_id, $tabs['default'], $active_tab, $tabs['urls']);
|
|
$runtime_config['avatarUpload'] = aksrt_user_center_avatar_upload_config($allow_avatar_upload);
|
|
|
|
|
|
$render_context = [
|
|
'user_center_settings' => $user_center_settings,
|
|
'dashboard_tabs' => $tabs['tabs'],
|
|
'dashboard_tab_keys' => $tabs['keys'],
|
|
'default_dashboard_tab' => $tabs['default'],
|
|
'active_tab' => $active_tab,
|
|
'dashboard' => $dashboard,
|
|
'target_user' => $current_user,
|
|
'user_id' => $user_id,
|
|
'post_count' => $post_count,
|
|
'comment_count' => $comment_count,
|
|
'favorite_post_ids' => $favorite_post_ids,
|
|
'favorite_count' => $favorite_count,
|
|
'follower_count' => $follower_count,
|
|
'following_count' => $following_count,
|
|
'profile_details' => aksrt_get_user_profile_details($user_id),
|
|
'profile_signals' => $dashboard['profile_signals'] ?? [],
|
|
'user_background_url' => $user_background_url,
|
|
'allow_bg_upload' => $allow_bg_upload,
|
|
'show_avatar_edit' => $allow_avatar_upload,
|
|
'notification_unread_count' => function_exists('aksrt_get_user_unread_notification_count') ? aksrt_get_user_unread_notification_count($user_id) : 0,
|
|
'messages_url' => $show_header_notification && function_exists('aksrt_get_messages_page_url') ? aksrt_get_messages_page_url() : '',
|
|
'per_page' => 10,
|
|
'posts_page' => max(1, isset($_GET['posts_page']) ? (int) $_GET['posts_page'] : 1),
|
|
'post_status_filter' => $post_status_filter,
|
|
'user_status_counts' => $user_status_counts,
|
|
'new_post_url' => function_exists('aksrt_get_new_post_url') ? aksrt_get_new_post_url() : '',
|
|
'svg_empty_post' => $svgs['post'],
|
|
'comments_page' => max(1, isset($_GET['comments_page']) ? (int) $_GET['comments_page'] : 1),
|
|
'favorites_page' => max(1, isset($_GET['favorites_page']) ? (int) $_GET['favorites_page'] : 1),
|
|
'svg_empty_comment' => $svgs['comment'],
|
|
'svg_empty_favorite' => $svgs['favorite'],
|
|
'orders_url' => isset($tabs['tabs']['orders']) ? aksrt_get_user_center_tab_url('orders') : '',
|
|
'show_vip' => !empty($vip_settings['enabled']),
|
|
'show_credit_tabs' => $show_credit_tabs,
|
|
'affiliate_enabled' => !empty($affiliate_settings['enabled']),
|
|
'currency_name' => $currency_name,
|
|
'credit_balance' => (float) ($dashboard['credit_balance'] ?? 0.0),
|
|
'credits_enabled' => $show_credit_tabs,
|
|
'signin_enabled' => $signin_enabled,
|
|
'signin_signed_today' => $signin_signed_today,
|
|
'balance_enabled' => $balance_enabled,
|
|
'wallet_balance' => $wallet_balance,
|
|
'vip_settings' => $vip_settings,
|
|
'user_email' => (string) $current_user->user_email,
|
|
'runtime_config' => $runtime_config,
|
|
'cover_upload_config' => aksrt_user_center_cover_upload_config($allow_bg_upload),
|
|
];
|
|
|
|
return aksrt_build_user_center_render_context($render_context);
|
|
}
|
|
}
|