feat(pay): VIP package purchase service and user-center open flow

Add AKSRT_Vip_Service (GET/POST /pay/vip), activate aksrt_vip_level/expires on
order paid, package UI in credits panel, and deep-link VIP CTA to credits tab.
This commit is contained in:
kate522 committed 2026-07-14 18:16:15 +08:00
1 parent 8e9e05c859
commit d0b8f7805f
10 files changed
+957 -24

No files matched your search

+3 -1
View File
@@ -958,7 +958,9 @@ if (!function_exists('aksrt_get_paywall_html')) {
$has_original = $original_price > 0 && $original_price > $price;
$pay_limit = (int) ($meta['pay_limit'] ?? 0);
$member_blocked = $pay_limit > 0 && $vip_level < $pay_limit;
$vip_url = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url() : home_url('/');
$vip_url = function_exists('aksrt_get_user_center_tab_url')
? aksrt_get_user_center_tab_url('credits')
: (function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url() : home_url('/'));
ob_start();
?>
+46 -6
View File
@@ -333,18 +333,58 @@ function aksrt_render_vip_badge(int $user_id = 0, string $size = 'sm'): string {
* 获取用户 VIP 等级信息(用于展示)
*
* @param int $user_id
* @return array{is_vip: bool, level: int, badge_text: string, badge_html: string, name: string}
* @return array{is_vip: bool, level: int, badge_text: string, badge_html: string, name: string, expires: int, expires_label: string}
*/
function aksrt_get_vip_info(int $user_id = 0): array {
$level = aksrt_get_user_vip_level($user_id);
$is_vip = $level >= 1;
$badge_text = aksrt_get_vip_badge_text();
$expires = $user_id > 0 ? (int) get_user_meta($user_id, 'aksrt_vip_expires', true) : 0;
$expires_label = __('未开通', 'aksrt');
if ($level > 0) {
if ($expires <= 0) {
$expires_label = __('永久有效', 'aksrt');
} elseif ($expires < time()) {
$expires_label = __('已过期', 'aksrt');
} else {
$expires_label = sprintf(
/* translators: %s: date */
__('到期时间:%s', 'aksrt'),
wp_date('Y-m-d H:i', $expires)
);
}
}
$name = __('普通用户', 'aksrt');
if ($is_vip && class_exists('AKSRT_Settings')) {
$vip = AKSRT_Settings::get_payment_vip_settings();
$name = (string) ($vip['levels'][$level]['name'] ?? ($badge_text . __('会员', 'aksrt')));
} elseif ($is_vip) {
$name = $badge_text . __('会员', 'aksrt');
}
return [
'is_vip' => $is_vip,
'level' => $level,
'badge_text' => $badge_text,
'badge_html' => $is_vip ? aksrt_render_vip_badge($user_id) : '',
'name' => $is_vip ? ($badge_text . '会员') : '普通用户',
'is_vip' => $is_vip,
'level' => $level,
'badge_text' => $badge_text,
'badge_html' => $is_vip ? aksrt_render_vip_badge($user_id) : '',
'name' => $name,
'expires' => $expires,
'expires_label' => $expires_label,
];
}
/**
* VIP 开通页入口(用户中心 credits 面板)。
*/
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');
}
if (function_exists('aksrt_get_user_center_url')) {
return aksrt_get_user_center_url();
}
return home_url('/');
}
}
+114 -13
View File
@@ -1,6 +1,6 @@
<?php
/**
* User center credits: VIP membership card.
* User center credits: VIP membership card + purchase packages.
*
* Expects extracted $context vars.
*
@@ -14,9 +14,46 @@ if (empty($vip_settings['enabled'])) {
return;
}
$user_id = (int) ($user_id ?? get_current_user_id());
$is_vip_user = function_exists('aksrt_is_vip') && aksrt_is_vip($user_id);
$vip_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);
$expires_label = __('未开通', 'aksrt');
if ($vip_level > 0) {
if ($expires <= 0) {
$expires_label = __('永久有效', 'aksrt');
} elseif ($expires < time()) {
$expires_label = __('已过期', 'aksrt');
} else {
$expires_label = sprintf(
/* translators: %s: date */
__('到期时间:%s', 'aksrt'),
wp_date('Y-m-d', $expires)
);
}
}
$level_name = (string) ($vip_settings['name'] ?? __('VIP会员', 'aksrt'));
if ($vip_level >= 1 && !empty($vip_settings['levels'][$vip_level]['name'])) {
$level_name = (string) $vip_settings['levels'][$vip_level]['name'];
}
$packages = [];
if (class_exists('AKSRT_Vip_Service')) {
$catalog = AKSRT_Vip_Service::get_instance()->get_catalog($user_id);
$packages = is_array($catalog['level_packages'] ?? null) ? $catalog['level_packages'] : [];
$methods = is_array($catalog['payment_methods'] ?? null) ? $catalog['payment_methods'] : [];
} else {
$methods = [['id' => 'balance', 'name' => __('站内余额', 'aksrt')]];
}
$cash_symbol = '¥';
if (class_exists('AKSRT_Settings')) {
$paid_display = AKSRT_Settings::get_paid_content_settings();
$cash_symbol = (string) ($paid_display['display']['currency_symbol'] ?? '¥');
}
?>
<div class="uc-vip-card<?php echo $is_vip_user ? ' uc-vip-card--active' : ''; ?>">
<div class="uc-vip-card<?php echo $is_vip_user ? ' uc-vip-card--active' : ''; ?>" data-aksrt-vip-panel>
<div class="uc-vip-card__bg"></div>
<div class="uc-vip-card__content">
<div class="uc-vip-card__header">
@@ -24,27 +61,91 @@ $is_vip_user = function_exists('aksrt_is_vip') && aksrt_is_vip($user_id);
<i class="fas fa-crown" aria-hidden="true"></i>
</div>
<div class="uc-vip-card__info">
<span class="uc-vip-card__label"><?php echo esc_html($vip_settings['name'] ?? __('VIP会员', 'aksrt')); ?></span>
<span class="uc-vip-card__label"><?php echo esc_html($level_name); ?></span>
<?php if ($is_vip_user) : ?>
<span class="uc-vip-card__status uc-vip-card__status--active"><?php esc_html_e('已开通', 'aksrt'); ?></span>
<span class="uc-vip-card__status uc-vip-card__status--active"><?php echo esc_html($expires_label); ?></span>
<?php else : ?>
<span class="uc-vip-card__status"><?php esc_html_e('未开通', 'aksrt'); ?></span>
<?php endif; ?>
</div>
</div>
<?php if ($is_vip_user) : ?>
<div class="uc-vip-card__benefits">
<span class="uc-vip-card__benefit"><i class="fas fa-download" aria-hidden="true"></i> <?php esc_html_e('免费下载', 'aksrt'); ?></span>
<span class="uc-vip-card__benefit"><i class="fas fa-crown" aria-hidden="true"></i> <?php esc_html_e('专属身份', 'aksrt'); ?></span>
<span class="uc-vip-card__benefit"><i class="fas fa-tag" aria-hidden="true"></i> <?php esc_html_e('会员价优惠', 'aksrt'); ?></span>
</div>
<?php else : ?>
<div class="uc-vip-card__benefits">
<span class="uc-vip-card__benefit"><i class="fas fa-download" aria-hidden="true"></i> <?php esc_html_e('解锁免费下载', 'aksrt'); ?></span>
<span class="uc-vip-card__benefit"><i class="fas fa-tag" aria-hidden="true"></i> <?php esc_html_e('享专属折扣', 'aksrt'); ?></span>
</div>
<a href="<?php echo esc_url(aksrt_get_user_center_url('credits')); ?>" class="uc-vip-card__btn">
<?php esc_html_e('立即开通', 'aksrt'); ?>
</a>
<?php if (!empty($vip_settings['desc'])) : ?>
<p class="uc-vip-card__desc"><?php echo esc_html((string) $vip_settings['desc']); ?></p>
<?php endif; ?>
</div>
</div>
<?php if (!empty($packages)) : ?>
<div class="uc-vip-shop" data-aksrt-vip-shop>
<div class="uc-vip-shop__title">
<i class="fas fa-gem" aria-hidden="true"></i>
<span><?php echo $is_vip_user ? esc_html__('续费 / 升级会员', 'aksrt') : esc_html__('开通会员', 'aksrt'); ?></span>
</div>
<?php foreach ($packages as $group) :
$g_level = (int) ($group['level'] ?? 0);
$g_name = (string) ($group['name'] ?? ('VIP' . $g_level));
$items = is_array($group['items'] ?? null) ? $group['items'] : [];
if ($items === []) {
continue;
}
?>
<div class="uc-vip-shop__group" data-vip-level="<?php echo esc_attr((string) $g_level); ?>">
<div class="uc-vip-shop__group-title">
<?php echo esc_html($g_name); ?>
<?php if ($vip_level >= $g_level) : ?>
<span class="uc-vip-shop__badge"><?php esc_html_e('当前档', 'aksrt'); ?></span>
<?php endif; ?>
</div>
<div class="uc-vip-shop__grid">
<?php foreach ($items as $item) :
$pid = (int) ($item['package_id'] ?? 0);
$price_label = (string) ($item['price_label'] ?? ($cash_symbol . ($item['price'] ?? 0)));
$days_label = (string) ($item['days_label'] ?? '');
$title = (string) ($item['title'] ?? '');
?>
<button
type="button"
class="uc-vip-shop__item"
data-aksrt-vip-buy
data-package-id="<?php echo esc_attr((string) $pid); ?>"
data-price-label="<?php echo esc_attr($price_label); ?>"
data-title="<?php echo esc_attr($title); ?>"
>
<span class="uc-vip-shop__item-title"><?php echo esc_html($title); ?></span>
<span class="uc-vip-shop__item-days"><?php echo esc_html($days_label); ?></span>
<span class="uc-vip-shop__item-price"><?php echo esc_html($price_label); ?></span>
<span class="uc-vip-shop__item-cta"><?php esc_html_e('立即开通', 'aksrt'); ?></span>
</button>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
<?php if (count($methods) > 1) : ?>
<div class="uc-vip-shop__methods" data-aksrt-vip-methods>
<span class="uc-vip-shop__methods-label"><?php esc_html_e('支付方式', 'aksrt'); ?></span>
<?php foreach ($methods as $i => $m) :
$mid = (string) ($m['id'] ?? '');
$mname = (string) ($m['name'] ?? $mid);
?>
<label class="uc-vip-shop__method">
<input type="radio" name="aksrt_vip_pay_method" value="<?php echo esc_attr($mid); ?>" <?php checked($i === 0); ?>>
<span><?php echo esc_html($mname); ?></span>
</label>
<?php endforeach; ?>
</div>
<?php elseif (!empty($methods[0]['id'])) : ?>
<input type="hidden" name="aksrt_vip_pay_method" value="<?php echo esc_attr((string) $methods[0]['id']); ?>" data-aksrt-vip-method-fixed>
<?php endif; ?>
<p class="uc-vip-shop__tip" data-aksrt-vip-tip></p>
</div>
<?php elseif (!empty($vip_settings['help_text'])) : ?>
<p class="uc-vip-shop__empty"><?php echo esc_html((string) $vip_settings['help_text']); ?></p>
<?php endif; ?>