feat(vip): Batch 3 dedicated user-center VIP tab
Register 我的会员 panel, zibll-style status/equity cards, sidebar deep-link, and slim credits-tab entry so VIP is no longer nested only under assets.
This commit is contained in:
@@ -1075,3 +1075,13 @@ body.uc-modal-open {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #22c55e, #16a34a);
|
||||
}
|
||||
|
||||
/* VIP tab */
|
||||
.uc-vip-tab .user-content-myvip{position:relative;padding:16px;margin-bottom:16px}
|
||||
.uc-vip-level-cards{display:flex;flex-wrap:wrap;gap:12px}
|
||||
.uc-vip-level-card{position:relative;flex:1 1 240px;padding:18px 14px;overflow:hidden}
|
||||
.uc-vip-level-card .v-equity{text-align:left;margin:10px 0 14px;padding-left:1.1em;font-size:13px;line-height:1.55}
|
||||
.uc-vip-level-card .pay-vip{display:inline-block;margin-top:4px}
|
||||
.uc-vip-assets-entry{gap:12px}
|
||||
.jb-vip1{background:linear-gradient(90deg,#f6c453,#f39c12);color:#3b2a00;border:0}
|
||||
.jb-vip2{background:linear-gradient(90deg,#8e44ad,#3f51b5);color:#fff;border:0}
|
||||
|
||||
@@ -169,6 +169,7 @@ if (!function_exists('aksrt_capture_user_center_view')) {
|
||||
'comments' => 'comments',
|
||||
'favorites' => 'favorites',
|
||||
'credits' => 'credits',
|
||||
'vip' => 'vip',
|
||||
'settings' => 'settings',
|
||||
'header' => 'header',
|
||||
'sidebar' => 'sidebar',
|
||||
@@ -193,7 +194,7 @@ 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', 'posts', 'comments', 'favorites', 'credits', 'settings'];
|
||||
$built_in_tabs = ['profile', 'posts', 'comments', 'favorites', 'credits', 'vip', 'settings'];
|
||||
if (in_array($tab_key, $built_in_tabs, true)) {
|
||||
return aksrt_capture_user_center_view($tab_key, $context);
|
||||
}
|
||||
|
||||
@@ -407,10 +407,10 @@ function aksrt_get_vip_info(int $user_id = 0): array {
|
||||
if (!function_exists('aksrt_get_vip_purchase_url')) {
|
||||
function aksrt_get_vip_purchase_url(): string {
|
||||
if (function_exists('aksrt_get_user_center_tab_url')) {
|
||||
return aksrt_get_user_center_tab_url('credits');
|
||||
return aksrt_get_user_center_tab_url('vip');
|
||||
}
|
||||
if (function_exists('aksrt_get_user_center_url')) {
|
||||
return aksrt_get_user_center_url();
|
||||
return aksrt_get_user_center_url('vip');
|
||||
}
|
||||
return home_url('/');
|
||||
}
|
||||
|
||||
@@ -39,7 +39,15 @@ if ($show_wallet || $show_credits) :
|
||||
endif;
|
||||
|
||||
if (!empty($show_vip)) {
|
||||
require $dir . '/credits-vip.php';
|
||||
// Slim entry to dedicated VIP tab (full shop lives under tab=vip).
|
||||
$vip_url = function_exists('aksrt_get_user_center_tab_url')
|
||||
? aksrt_get_user_center_tab_url('vip')
|
||||
: '#';
|
||||
echo '<div class="zib-widget flex ac jsb padding-15 mb15 uc-vip-assets-entry">';
|
||||
echo '<div class="flex ac gap10"><i class="fas fa-crown c-yellow"></i><div><div class="font-bold">' . esc_html__('我的会员', 'aksrt') . '</div>';
|
||||
echo '<div class="muted-2-color em09">' . esc_html__('查看权益、续费与升级', 'aksrt') . '</div></div></div>';
|
||||
echo '<a class="but jb-yellow radius" href="' . esc_url($vip_url) . '">' . esc_html__('进入会员中心', 'aksrt') . '</a>';
|
||||
echo '</div>';
|
||||
}
|
||||
if ($show_credits) {
|
||||
require $dir . '/credits-signin.php';
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* User center VIP panel entry (maps tab=vip).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
|
||||
require __DIR__ . '/vip-tab.php';
|
||||
@@ -59,7 +59,7 @@ if (empty($orders_url) && empty($show_vip) && empty($show_credit_tabs) && empty(
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($show_vip)) : ?>
|
||||
<a class="uc-sidebar__btn<?php echo (!empty($active_tab) && $active_tab === 'credits') ? ' is-active' : ''; ?>" href="<?php echo esc_url(aksrt_get_user_center_tab_url('credits')); ?>" data-tab="credits">
|
||||
<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>
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/**
|
||||
* User center VIP tab (zibll 我的会员 1:1 structure).
|
||||
*
|
||||
* Expects extracted $context vars via profile-vip.php / capture path.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$vip_settings = is_array($vip_settings ?? null) ? $vip_settings : [];
|
||||
if (empty($vip_settings['enabled']) && class_exists('\AKSRT\Settings\Settings')) {
|
||||
$vip_settings = \AKSRT\Settings\Settings::get_payment_vip_settings();
|
||||
}
|
||||
if (empty($vip_settings['enabled'])) {
|
||||
echo '<div class="zib-widget padding-20 muted-2-color">' . esc_html__('会员功能未启用。', 'aksrt') . '</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
$user_id = (int) ($user_id ?? get_current_user_id());
|
||||
$level = function_exists('aksrt_get_user_vip_level') ? aksrt_get_user_vip_level($user_id) : 0;
|
||||
$expires = (int) get_user_meta($user_id, 'aksrt_vip_expires', true);
|
||||
$expired_level = (int) get_user_meta($user_id, 'aksrt_vip_level_expired', true);
|
||||
$levels = is_array($vip_settings['levels'] ?? null) ? $vip_settings['levels'] : [];
|
||||
$desc_top = (string) ($vip_settings['desc'] ?? '');
|
||||
|
||||
$user = get_userdata($user_id);
|
||||
$display = $user ? $user->display_name : '';
|
||||
$avatar = get_avatar($user_id, 56);
|
||||
|
||||
// Status header box.
|
||||
$status_html = '';
|
||||
$btn_type = 'pay';
|
||||
if ($level > 0) {
|
||||
$lv_name = (string) ($levels[$level]['name'] ?? ('VIP' . $level));
|
||||
$lv_desc = (string) ($levels[$level]['desc'] ?? '');
|
||||
if ($expires <= 0) {
|
||||
$badge = '<span class="badg c-green p2-10 em09"><i class="fa fa-clock-o mr3" aria-hidden="true"></i>' . esc_html__('永久会员', 'aksrt') . '</span>';
|
||||
if ($level < 2) {
|
||||
$btn_type = 'upgrade';
|
||||
}
|
||||
} else {
|
||||
$badge = '<span class="badg c-yellow p2-10 em09"><i class="fa fa-clock-o mr3" aria-hidden="true"></i>'
|
||||
. esc_html(sprintf(__('到期时间:%s', 'aksrt'), wp_date('Y年m月d日', $expires))) . '</span>';
|
||||
$btn_type = 'renew_' . $level;
|
||||
}
|
||||
$status_html = '<div class="flex xx gap6">'
|
||||
. '<div class="em16 mr10 flex ac"><i class="fas fa-crown mr6"></i><div class="font-bold ml6">' . esc_html($lv_name) . '</div></div>'
|
||||
. $badge
|
||||
. ($lv_desc !== '' ? '<div class="muted-color em09">' . esc_html($lv_desc) . '</div>' : '')
|
||||
. '</div>';
|
||||
} elseif ($expired_level > 0) {
|
||||
$exp_label = $expires > 0
|
||||
? sprintf(__('过期时间:%s', 'aksrt'), wp_date('Y年m月d日', $expires))
|
||||
: __('已过期', 'aksrt');
|
||||
$status_html = '<div class="flex xx gap6">'
|
||||
. '<div class="font-bold c-red">' . esc_html__('会员已过期', 'aksrt') . '</div>'
|
||||
. '<div class="badg c-red em09"><i class="fa fa-clock-o mr3" aria-hidden="true"></i>' . esc_html($exp_label) . '</div>'
|
||||
. ($desc_top !== '' ? '<div class="muted-color em09">' . esc_html($desc_top) . '</div>' : '')
|
||||
. '</div>';
|
||||
$btn_type = 'pay';
|
||||
} else {
|
||||
$status_html = '<div class="flex xx gap6">'
|
||||
. '<div class="font-bold">' . esc_html__('开通会员', 'aksrt') . '</div>'
|
||||
. ($desc_top !== '' ? '<div class="muted-color em09">' . esc_html($desc_top) . '</div>' : '<div class="muted-color em09">' . esc_html__('开通会员,尊享专属特权', 'aksrt') . '</div>')
|
||||
. '</div>';
|
||||
$btn_type = 'pay';
|
||||
}
|
||||
|
||||
// Level cards.
|
||||
$cards = '';
|
||||
foreach ([1, 2] as $lv) {
|
||||
if (empty($levels[$lv]['enabled'])) {
|
||||
continue;
|
||||
}
|
||||
$lv_name = (string) ($levels[$lv]['name'] ?? ('VIP' . $lv));
|
||||
$lv_desc = (string) ($levels[$lv]['desc'] ?? '');
|
||||
$equity = (string) ($levels[$lv]['equity'] ?? '');
|
||||
$cta = sprintf(__('开通%s', 'aksrt'), $lv_name);
|
||||
$vip_attr = $lv;
|
||||
if (str_starts_with($btn_type, 'renew_')) {
|
||||
$renew_lv = (int) substr($btn_type, 6);
|
||||
if ($lv === $renew_lv) {
|
||||
$cta = sprintf(__('续费%s', 'aksrt'), $lv_name);
|
||||
} elseif ($lv > $renew_lv) {
|
||||
$cta = sprintf(__('升级%s', 'aksrt'), $lv_name);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} elseif ($btn_type === 'upgrade') {
|
||||
if ($lv <= $level) {
|
||||
continue;
|
||||
}
|
||||
$cta = sprintf(__('升级%s', 'aksrt'), $lv_name);
|
||||
$vip_attr = 2;
|
||||
} elseif ($level > 0 && $lv < $level) {
|
||||
continue;
|
||||
} elseif ($level > 0 && $lv === $level) {
|
||||
$cta = sprintf(__('续费%s', 'aksrt'), $lv_name);
|
||||
}
|
||||
|
||||
$cards .= '<div class="zib-widget text-center pay-vip-info flex1 level-' . $lv . ' uc-vip-level-card">';
|
||||
$cards .= '<div class="abs-center vip-baicon"><i class="fa fa-diamond" aria-hidden="true"></i></div>';
|
||||
$cards .= '<div class="relative">';
|
||||
$cards .= '<div class="v-iconbox mb10 flex jc gap10"><div class="v-icon flex jc"><i class="fas fa-crown"></i></div>';
|
||||
$cards .= '<div class="v-info text-left"><div class="v-name font-bold">' . esc_html($lv_name) . '</div>';
|
||||
if ($lv_desc !== '') {
|
||||
$cards .= '<div class="v-desc em09 muted-2-color">' . esc_html($lv_desc) . '</div>';
|
||||
}
|
||||
$cards .= '</div></div>';
|
||||
if ($equity !== '') {
|
||||
$cards .= '<ul class="v-equity text-left">' . $equity . '</ul>';
|
||||
}
|
||||
$cards .= '<a class="padding-lg but jb-vip' . $lv . ' radius pay-vip" href="javascript:;" vip-level="' . (int) $vip_attr . '">'
|
||||
. esc_html($cta) . '<span class="ml10"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i></span></a>';
|
||||
$cards .= '</div></div>';
|
||||
}
|
||||
|
||||
// Points exchange (non-VIP only) — slim link; full shop stays optional under credits.
|
||||
$points_html = '';
|
||||
if ($level <= 0 && !empty($vip_settings['points_exchange']['enabled'])) {
|
||||
$points_html = '<div class="c-yellow zib-widget flex ac jsb uc-vip-points-link mt10">'
|
||||
. '<div class="flex1 em12"><i class="fas fa-coins mr6"></i>' . esc_html__('积分兑换会员', 'aksrt') . '</div>'
|
||||
. '<a class="badg radius c-yellow pay-vip" href="javascript:;" vip-level="1">' . esc_html__('立即兑换', 'aksrt')
|
||||
. '<i class="fa fa-chevron-circle-right ml6" aria-hidden="true"></i></a></div>';
|
||||
}
|
||||
?>
|
||||
<div class="uc-vip-tab" data-aksrt-vip-tab>
|
||||
<div class="zib-widget flex ac gap20 user-content-myvip overflow-hidden mb15">
|
||||
<div class="vip-img abs-right opacity3"><i class="fas fa-crown em3x" aria-hidden="true"></i></div>
|
||||
<div class="flex ac gap12 flex1">
|
||||
<div class="avatar-img"><?php echo $avatar; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
|
||||
<div class="flex1">
|
||||
<div class="font-bold mb3"><?php echo esc_html($display); ?></div>
|
||||
<?php echo $status_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap20 gap10-sm uc-vip-level-cards">
|
||||
<?php echo $cards; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
|
||||
<?php echo $points_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
|
||||
<?php if (!empty($vip_settings['more'])) : ?>
|
||||
<div class="muted-2-color em09 muted-box padding-10 mini-radius mt15">
|
||||
<?php echo $vip_settings['more']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -73,6 +73,12 @@ class Center {
|
||||
'priority' => 50,
|
||||
'type' => 'panel',
|
||||
],
|
||||
'vip' => [
|
||||
'label' => __('我的会员', 'aksrt'),
|
||||
'icon' => 'crown',
|
||||
'priority' => 45,
|
||||
'type' => 'panel',
|
||||
],
|
||||
'notif' => [
|
||||
'label' => __('消息通知', 'aksrt'),
|
||||
'icon' => 'bell',
|
||||
@@ -119,12 +125,26 @@ class Center {
|
||||
$this->panels['credits'] = $panel;
|
||||
}
|
||||
|
||||
// Dedicated VIP tab when membership is enabled.
|
||||
$vip_on = class_exists('\AKSRT\Settings\Settings')
|
||||
&& !empty(\AKSRT\Settings\Settings::get_payment_vip_settings()['enabled']);
|
||||
if ($vip_on && !isset($this->panels['vip'])) {
|
||||
$this->panels['vip'] = $definitions['vip'];
|
||||
} elseif (!$vip_on && isset($this->panels['vip'])) {
|
||||
unset($this->panels['vip']);
|
||||
}
|
||||
|
||||
if (!isset($this->panels['settings'])) {
|
||||
$this->panels['settings'] = $definitions['settings'];
|
||||
}
|
||||
|
||||
$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));
|
||||
});
|
||||
|
||||
/**
|
||||
* 允许插件/子主题注册额外面板
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user