344 lines
12 KiB
PHP
344 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* @package AKSRT
|
|
*/
|
|
|
|
namespace AKSRT\User;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
class Center {
|
|
|
|
private static $instance = null;
|
|
|
|
/** @var array 面板注册表 */
|
|
private $panels = [];
|
|
|
|
private function __construct() {}
|
|
|
|
public static function get_instance(): self {
|
|
if (null === self::$instance) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
public function init(): void {
|
|
$this->register_default_panels();
|
|
add_action('rest_api_init', [$this, 'register_rest_routes']);
|
|
}
|
|
|
|
/**
|
|
* Register user-center fragment routes.
|
|
*/
|
|
public function register_rest_routes(): void {
|
|
register_rest_route('aksrt/v1', '/user-center/panel/(?P<tab>[a-z0-9_-]+)', [
|
|
'methods' => \WP_REST_Server::READABLE,
|
|
'callback' => [$this, 'rest_panel'],
|
|
'permission_callback' => static function (): bool {
|
|
return is_user_logged_in();
|
|
},
|
|
'args' => [
|
|
'tab' => [
|
|
'required' => true,
|
|
'sanitize_callback' => 'sanitize_key',
|
|
'validate_callback' => static function ($value): bool {
|
|
return preg_match('/^[a-z0-9_-]+$/', (string) $value) === 1;
|
|
},
|
|
],
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Render a user-center panel or a revenue reward fragment.
|
|
*/
|
|
public function rest_panel(\WP_REST_Request $request) {
|
|
$tab = sanitize_key((string) $request->get_param('tab'));
|
|
$tabs = $this->get_dashboard_tabs();
|
|
if (!isset($tabs[$tab])) {
|
|
return new \WP_Error('aksrt_user_center_panel', __('用户中心面板不存在', 'aksrt'), ['status' => 404]);
|
|
}
|
|
|
|
$user = wp_get_current_user();
|
|
$context = function_exists('aksrt_get_user_center_render_context')
|
|
? aksrt_get_user_center_render_context($user)
|
|
: [];
|
|
if (!is_array($context) || !$context) {
|
|
return new \WP_Error('aksrt_user_center_context', __('用户中心数据加载失败', 'aksrt'), ['status' => 500]);
|
|
}
|
|
|
|
$revenue_request = [];
|
|
if ($tab === 'revenue') {
|
|
$reward_tab = sanitize_key((string) $request->get_param('reward_tab'));
|
|
if (!in_array($reward_tab, ['detail', 'orders', 'users'], true)) {
|
|
$reward_tab = 'detail';
|
|
}
|
|
$revenue_request = [
|
|
'reward_tab' => $reward_tab,
|
|
'commission_page' => max(1, min(100, (int) $request->get_param('commission_page'))),
|
|
'invite_page' => max(1, min(100, (int) $request->get_param('invite_page'))),
|
|
];
|
|
$context['revenue_request'] = $revenue_request;
|
|
}
|
|
|
|
$html = function_exists('aksrt_capture_user_center_panel')
|
|
? aksrt_capture_user_center_panel($tab, $tabs[$tab], $context)
|
|
: '';
|
|
if ($html === '') {
|
|
return new \WP_Error('aksrt_user_center_panel_empty', __('用户中心面板暂不可用', 'aksrt'), ['status' => 500]);
|
|
}
|
|
|
|
return rest_ensure_response([
|
|
'success' => true,
|
|
'data' => [
|
|
'tab' => $tab,
|
|
'html' => $html,
|
|
'reward_tab' => $revenue_request['reward_tab'] ?? '',
|
|
'commission_page' => $revenue_request['commission_page'] ?? 1,
|
|
'invite_page' => $revenue_request['invite_page'] ?? 1,
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 注册默认面板
|
|
*/
|
|
private function register_default_panels(): void {
|
|
$settings = class_exists('\AKSRT\Settings\Settings')
|
|
? \AKSRT\Settings\Settings::get_user_center_settings()
|
|
: [
|
|
'tabs' => ['profile', 'posts', 'comments', 'favorites'],
|
|
'avatar_upload' => true,
|
|
'cover_upload' => true,
|
|
'social_links' => true,
|
|
];
|
|
|
|
$definitions = [
|
|
'profile' => [
|
|
'label' => __('个人信息', 'aksrt'),
|
|
'icon' => 'user',
|
|
'priority' => 10,
|
|
'type' => 'panel',
|
|
],
|
|
'level' => [
|
|
'label' => __('我的等级', 'aksrt'),
|
|
'icon' => 'chart-line',
|
|
'priority' => 15,
|
|
'type' => 'panel',
|
|
],
|
|
'posts' => [
|
|
'label' => __('我的文章', 'aksrt'),
|
|
'icon' => 'file-alt',
|
|
'priority' => 20,
|
|
'type' => 'panel',
|
|
],
|
|
'comments' => [
|
|
'label' => __('我的评论', 'aksrt'),
|
|
'icon' => 'comment',
|
|
'priority' => 30,
|
|
'type' => 'panel',
|
|
],
|
|
'favorites' => [
|
|
'label' => __('我的收藏', 'aksrt'),
|
|
'icon' => 'star',
|
|
'priority' => 40,
|
|
'type' => 'panel',
|
|
],
|
|
'vip' => [
|
|
'label' => __('我的会员', 'aksrt'),
|
|
'icon' => 'crown',
|
|
'priority' => 45,
|
|
'type' => 'panel',
|
|
],
|
|
'orders' => [
|
|
'label' => __('我的订单', 'aksrt'),
|
|
'icon' => 'receipt',
|
|
'priority' => 48,
|
|
'type' => 'panel',
|
|
],
|
|
'credits' => [
|
|
'label' => class_exists('\AKSRT\Settings\Settings')
|
|
? sprintf(__('我的%s', 'aksrt'), \AKSRT\Settings\Settings::get_currency_name())
|
|
: __('我的积分', 'aksrt'),
|
|
'icon' => 'wallet',
|
|
'priority' => 50,
|
|
'type' => 'panel',
|
|
],
|
|
'revenue' => [
|
|
'label' => __('收益中心', 'aksrt'),
|
|
'icon' => 'chart-line',
|
|
'priority' => 55,
|
|
'type' => 'panel',
|
|
],
|
|
'notif' => [
|
|
'label' => __('消息通知', 'aksrt'),
|
|
'icon' => 'bell',
|
|
'priority' => 60,
|
|
'type' => 'link',
|
|
],
|
|
'auth' => [
|
|
'label' => __('官方认证', 'aksrt'),
|
|
'icon' => 'id-badge',
|
|
'priority' => 65,
|
|
'type' => 'panel',
|
|
],
|
|
'settings' => [
|
|
'label' => __('账号设置', 'aksrt'),
|
|
'icon' => 'cog',
|
|
'priority' => 70,
|
|
'type' => 'panel',
|
|
],
|
|
];
|
|
|
|
$this->panels = [];
|
|
$configured = array_values(array_filter(array_map('sanitize_key', (array) ($settings['tabs'] ?? []))));
|
|
if ($configured === []) {
|
|
$configured = ['profile', 'posts', 'comments', 'favorites'];
|
|
}
|
|
|
|
$level_on = class_exists('\AKSRT\User\Level')
|
|
&& !empty(\AKSRT\User\Level::settings()['enabled']);
|
|
$credits_on = class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::credits_enabled();
|
|
$balance_on = class_exists('\AKSRT\Credits\Balance') && \AKSRT\Credits\Balance::enabled();
|
|
$revenue_tab_on = class_exists('\AKSRT\Settings\Settings')
|
|
&& !empty(\AKSRT\Settings\Settings::get_payment_affiliate_settings()['enabled'])
|
|
&& \AKSRT\Settings\Settings::invite_registration_enabled();
|
|
$vip_on = class_exists('\AKSRT\Settings\Settings')
|
|
&& !empty(\AKSRT\Settings\Settings::get_payment_vip_settings()['enabled']);
|
|
|
|
// Follow configured order; always auto-include enabled surfaces.
|
|
$order = $configured;
|
|
|
|
// Growth level is a dedicated user-center surface, separate from spendable points.
|
|
if ($level_on && !in_array('level', $order, true)) {
|
|
$insert_at = array_search('profile', $order, true);
|
|
array_splice($order, $insert_at === false ? 0 : (int) $insert_at + 1, 0, ['level']);
|
|
}
|
|
if (!$level_on) {
|
|
$order = array_values(array_filter($order, static fn(string $key): bool => $key !== 'level'));
|
|
}
|
|
|
|
if ($vip_on && !in_array('vip', $order, true)) {
|
|
$insert_at = count($order);
|
|
foreach (['credits', 'favorites', 'posts'] as $anchor) {
|
|
$idx = array_search($anchor, $order, true);
|
|
if ($idx !== false) {
|
|
$insert_at = (int) $idx + 1;
|
|
break;
|
|
}
|
|
}
|
|
array_splice($order, $insert_at, 0, ['vip']);
|
|
}
|
|
// Orders panel: always available when payment stack exists (UserOrders or Order).
|
|
$orders_on = class_exists('\AKSRT\Payment\UserOrders')
|
|
|| class_exists('\AKSRT\Payment\Order');
|
|
if ($orders_on && !in_array('orders', $order, true)) {
|
|
$insert_at = count($order);
|
|
foreach (['vip', 'credits', 'favorites'] as $anchor) {
|
|
$idx = array_search($anchor, $order, true);
|
|
if ($idx !== false) {
|
|
$insert_at = (int) $idx + ($anchor === 'vip' ? 1 : 0);
|
|
if ($anchor !== 'vip') {
|
|
$insert_at = (int) $idx + 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
array_splice($order, $insert_at, 0, ['orders']);
|
|
}
|
|
if (($credits_on || $balance_on) && !in_array('credits', $order, true)) {
|
|
$order[] = 'credits';
|
|
}
|
|
|
|
if ($revenue_tab_on && !in_array('revenue', $order, true)) {
|
|
$insert_at = count($order);
|
|
foreach (['credits', 'favorites', 'posts'] as $anchor) {
|
|
$idx = array_search($anchor, $order, true);
|
|
if ($idx !== false) {
|
|
$insert_at = (int) $idx + 1;
|
|
break;
|
|
}
|
|
}
|
|
array_splice($order, $insert_at, 0, ['revenue']);
|
|
}
|
|
$auth_on = class_exists('\AKSRT\User\AuthApply')
|
|
&& !empty(\AKSRT\User\AuthApply::settings()['enabled']);
|
|
if ($auth_on && !in_array('auth', $order, true)) {
|
|
$order[] = 'auth';
|
|
}
|
|
if (!in_array('settings', $order, true)) {
|
|
$order[] = 'settings';
|
|
}
|
|
|
|
foreach ($order as $key) {
|
|
if (!isset($definitions[$key])) {
|
|
continue;
|
|
}
|
|
if ($key === 'level' && !$level_on) {
|
|
continue;
|
|
}
|
|
if ($key === 'credits' && !$credits_on && !$balance_on) {
|
|
continue;
|
|
}
|
|
if ($key === 'revenue' && !$revenue_tab_on) {
|
|
continue;
|
|
}
|
|
|
|
if ($key === 'vip' && !$vip_on) {
|
|
continue;
|
|
}
|
|
if ($key === 'orders' && !$orders_on) {
|
|
continue;
|
|
}
|
|
if ($key === 'auth' && !$auth_on) {
|
|
continue;
|
|
}
|
|
$panel = $definitions[$key];
|
|
if ($key === 'credits' && $balance_on) {
|
|
$panel['label'] = __('我的资产', 'aksrt');
|
|
$panel['icon'] = 'wallet';
|
|
}
|
|
$this->panels[$key] = $panel;
|
|
}
|
|
|
|
// Notif is a link entry (messages page), not a dashboard panel body.
|
|
$this->panels['notif'] = $definitions['notif'];
|
|
|
|
// Keep stable order by priority.
|
|
uasort($this->panels, static function (array $a, array $b): int {
|
|
return ((int) ($a['priority'] ?? 100)) <=> ((int) ($b['priority'] ?? 100));
|
|
});
|
|
|
|
/**
|
|
* 允许插件/子主题注册额外面板
|
|
*
|
|
* @param array $panels 面板注册表
|
|
*/
|
|
$this->panels = apply_filters('aksrt_user_center_panels', $this->panels);
|
|
}
|
|
|
|
/**
|
|
* 获取面板注册表
|
|
*/
|
|
public function get_panels(): array {
|
|
return $this->panels;
|
|
}
|
|
|
|
/**
|
|
* 获取可切换的本地面板(不含外链入口)。
|
|
*/
|
|
public function get_dashboard_tabs(): array {
|
|
return array_filter($this->panels, static function (array $panel): bool {
|
|
return ($panel['type'] ?? 'panel') === 'panel';
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 判断当前页面是否为本人中心
|
|
*/
|
|
public static function is_page(): bool {
|
|
return function_exists('aksrt_is_user_center_page') && aksrt_is_user_center_page();
|
|
}
|
|
}
|