fix(vip): Batch 0 wiring for VIP settings, URLs, and order meta
Wire get_vip_settings alias, tab aliases for vip/assets, expired-level meta, VIP2 order-level fallback, JSON-safe order notes, and header/float pay-vip CTAs.
This commit is contained in:
@@ -161,13 +161,12 @@ if (!function_exists('aksrt_render_header_menu_buttons')) :
|
||||
}
|
||||
}
|
||||
|
||||
// VIP open CTA for guests / non-VIP.
|
||||
$user_id = get_current_user_id();
|
||||
$vip_url = function_exists('aksrt_get_vip_purchase_url') ? aksrt_get_vip_purchase_url() : (function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url('vip') : '#');
|
||||
$show_vip = true;
|
||||
if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_vip_settings')) {
|
||||
$vs = \AKSRT\Settings\Settings::get_vip_settings();
|
||||
$show_vip = !empty($vs['enabled']) || !empty($vs['vip1_enabled']) || !empty($vs['vip2_enabled']);
|
||||
// VIP open CTA for guests / non-VIP (zibll: .pay-vip modal).
|
||||
$user_id = get_current_user_id();
|
||||
$show_vip = false;
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$vs = \AKSRT\Settings\Settings::get_payment_vip_settings();
|
||||
$show_vip = !empty($vs['enabled']);
|
||||
}
|
||||
if ($show_vip) {
|
||||
$is_vip = false;
|
||||
@@ -175,9 +174,9 @@ if (!function_exists('aksrt_render_header_menu_buttons')) :
|
||||
$is_vip = (int) aksrt_get_user_vip_level($user_id) > 0;
|
||||
}
|
||||
if (!$is_vip) {
|
||||
$cls = $user_id ? 'pay-vip' : 'signin-loader';
|
||||
$cls = $user_id > 0 ? 'pay-vip' : 'signin-loader';
|
||||
$html .= '<div class="navbar-form navbar-right navbar-vip hover-show inline-block">';
|
||||
$html .= '<a class="but jb-red radius payvip-icon ml10 ' . esc_attr($cls) . '" href="' . ($user_id ? esc_url($vip_url) : 'javascript:;') . '">';
|
||||
$html .= '<a class="but jb-red radius payvip-icon ml10 ' . esc_attr($cls) . '" href="javascript:;"' . ($user_id > 0 ? ' vip-level="1"' : '') . '>';
|
||||
$html .= '<i class="fa fa-diamond em12 mr3" aria-hidden="true"></i>' . esc_html__('开通会员', 'aksrt');
|
||||
$html .= '</a></div>';
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ if (!function_exists('aksrt_header_user_wallet_mini')) :
|
||||
if (class_exists('\AKSRT\Credits\Balance')) {
|
||||
$wallet = (float) \AKSRT\Credits\Balance::balance($user_id);
|
||||
}
|
||||
$center = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url('assets') : '#';
|
||||
$center = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url('credits') : '#';
|
||||
|
||||
$html = '<a class="aksrt-header-wallet flex ac jsb" href="' . esc_url($center) . '">';
|
||||
$html .= '<span class="aksrt-header-wallet__item"><i class="fas fa-coins" aria-hidden="true"></i> '
|
||||
@@ -116,29 +116,44 @@ endif;
|
||||
|
||||
if (!function_exists('aksrt_header_payvip_bar')) :
|
||||
/**
|
||||
* VIP status / open CTA bar.
|
||||
* VIP status / open CTA bar (zibll zib_get_header_payvip_icon parity).
|
||||
*/
|
||||
function aksrt_header_payvip_bar(int $user_id = 0): string {
|
||||
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
|
||||
if ($user_id <= 0) {
|
||||
return '';
|
||||
}
|
||||
$badge = function_exists('aksrt_render_vip_badge') ? aksrt_render_vip_badge($user_id, 'md') : '';
|
||||
if ($badge !== '') {
|
||||
return '<div class="mt10 em09 aksrt-header-payvip">' . $badge . '</div>';
|
||||
}
|
||||
// Guest-style open VIP for non-members if VIP feature on.
|
||||
$vip_url = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url('vip') : '#';
|
||||
$enabled = true;
|
||||
if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_vip_settings')) {
|
||||
$vs = \AKSRT\Settings\Settings::get_vip_settings();
|
||||
$enabled = !empty($vs['enabled']) || !empty($vs['vip1_enabled']) || !empty($vs['vip2_enabled']);
|
||||
}
|
||||
if (!$enabled) {
|
||||
|
||||
$vip = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_payment_vip_settings()
|
||||
: ['enabled' => false, 'levels' => []];
|
||||
if (empty($vip['enabled'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$level = function_exists('aksrt_get_user_vip_level') ? (int) aksrt_get_user_vip_level($user_id) : 0;
|
||||
if ($level > 0) {
|
||||
$levels = is_array($vip['levels'] ?? null) ? $vip['levels'] : [];
|
||||
$name = (string) ($levels[$level]['name'] ?? ($level === 2 ? __('二级会员', 'aksrt') : __('一级会员', 'aksrt')));
|
||||
$exp_label = '';
|
||||
if (function_exists('aksrt_get_vip_info')) {
|
||||
$info = aksrt_get_vip_info($user_id);
|
||||
$exp_label = (string) ($info['expires_label'] ?? '');
|
||||
}
|
||||
$html = '<div class="mt10 em09 aksrt-header-payvip">';
|
||||
$html .= '<span class="radius4 payvip-icon btn-block text-center vipbg-v2 level-' . (int) $level . '">';
|
||||
$html .= '<i class="fa fa-diamond em12 mr6" aria-hidden="true"></i>';
|
||||
$html .= '<span>' . esc_html($name) . '</span>';
|
||||
if ($exp_label !== '') {
|
||||
$html .= '<span class="ml10 badg jb-yellow vip-expdate-tag"><i class="fa fa-clock-o mr3" aria-hidden="true"></i>'
|
||||
. esc_html($exp_label) . '</span>';
|
||||
}
|
||||
$html .= '</span></div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
return '<div class="mt10 em09 aksrt-header-payvip">'
|
||||
. '<a class="but jb-red radius4 payvip-icon btn-block" href="' . esc_url($vip_url) . '">'
|
||||
. '<a class="pay-vip but radius4 payvip-icon btn-block" href="javascript:;" vip-level="1">'
|
||||
. '<i class="fa fa-diamond mr6" aria-hidden="true"></i>'
|
||||
. esc_html__('开通会员 尊享会员权益', 'aksrt')
|
||||
. '</a></div>';
|
||||
|
||||
@@ -57,10 +57,10 @@ if (!function_exists('aksrt_get_float_pay_vip_html')) :
|
||||
* Floating VIP open button.
|
||||
*/
|
||||
function aksrt_get_float_pay_vip_html(array $item = []): string {
|
||||
$show_vip = true;
|
||||
if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_vip_settings')) {
|
||||
$vs = \AKSRT\Settings\Settings::get_vip_settings();
|
||||
$show_vip = !empty($vs['enabled']) || !empty($vs['vip1_enabled']) || !empty($vs['vip2_enabled']);
|
||||
$show_vip = false;
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$vs = \AKSRT\Settings\Settings::get_payment_vip_settings();
|
||||
$show_vip = !empty($vs['enabled']);
|
||||
}
|
||||
if (!$show_vip) {
|
||||
return '';
|
||||
@@ -74,13 +74,11 @@ if (!function_exists('aksrt_get_float_pay_vip_html')) :
|
||||
if ($level >= 2) {
|
||||
return '';
|
||||
}
|
||||
$vip_url = function_exists('aksrt_get_vip_purchase_url')
|
||||
? aksrt_get_vip_purchase_url()
|
||||
: (function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url('vip') : '#');
|
||||
$title = $level === 1 ? __('升级会员', 'aksrt') : __('开通会员', 'aksrt');
|
||||
$icon = !empty($item['icon']) ? (string) $item['icon'] : 'fa fa-diamond';
|
||||
$cls = $user_id > 0 ? 'float-btn pay-vip' : 'float-btn signin-loader';
|
||||
$href = $user_id > 0 ? $vip_url : 'javascript:;';
|
||||
// Modal path: .pay-vip opens VIP modal (Batch 2+); guests use signin-loader.
|
||||
$href = 'javascript:;';
|
||||
$style = [];
|
||||
if (!empty($item['color'])) {
|
||||
$style[] = '--this-color:' . esc_attr((string) $item['color']);
|
||||
@@ -89,7 +87,8 @@ if (!function_exists('aksrt_get_float_pay_vip_html')) :
|
||||
$style[] = '--this-bg:' . esc_attr((string) $item['bg']);
|
||||
}
|
||||
$style_attr = $style ? ' style="' . implode(';', $style) . '"' : '';
|
||||
return '<a class="' . esc_attr($cls) . '" href="' . esc_url($href) . '" title="' . esc_attr($title) . '"' . $style_attr . '>'
|
||||
$vip_level_attr = $user_id > 0 ? ' vip-level="' . esc_attr((string) max(1, min(2, $level + 1))) . '"' : '';
|
||||
return '<a class="' . esc_attr($cls) . '" href="' . esc_attr($href) . '" title="' . esc_attr($title) . '"' . $style_attr . $vip_level_attr . '>'
|
||||
. '<i class="' . esc_attr($icon) . '" aria-hidden="true"></i>'
|
||||
. '</a>';
|
||||
}
|
||||
@@ -152,28 +151,3 @@ if (!function_exists('aksrt_get_win_runtime_config')) :
|
||||
];
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_print_win_var')) :
|
||||
/**
|
||||
* Echo window._win + alias window.aksrtData bridge.
|
||||
*/
|
||||
function aksrt_print_win_var(): void {
|
||||
static $done = false;
|
||||
if ($done) {
|
||||
return;
|
||||
}
|
||||
$done = true;
|
||||
$cfg = aksrt_get_win_runtime_config();
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<script type="text/javascript">window._win=' . wp_json_encode($cfg, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ';'
|
||||
. 'window.aksrtData=window.aksrtData||{};'
|
||||
. 'window.aksrtData.ajaxUrl=window.aksrtData.ajaxUrl||window._win.ajax_url;'
|
||||
. 'window.aksrtData.siteUrl=window.aksrtData.siteUrl||window._win.www;'
|
||||
. 'window.aksrtData.themeUri=window.aksrtData.themeUri||window._win.uri;'
|
||||
. 'window.aksrtData.restUrl=window.aksrtData.restUrl||window._win.rest_url;'
|
||||
. 'window.aksrtData.restNonce=window.aksrtData.restNonce||window._win.rest_nonce;'
|
||||
. 'window.aksrtData.nonce=window.aksrtData.nonce||window._win.nonce;'
|
||||
. 'window.aksrtData.imgbox=window._win;'
|
||||
. '</script>' . "\n";
|
||||
}
|
||||
endif;
|
||||
|
||||
@@ -296,10 +296,13 @@ if (!function_exists('aksrt_user_center_resolve_tabs')) {
|
||||
$keys = array_keys($tabs);
|
||||
$default = in_array('profile', $keys, true) ? 'profile' : ($keys[0] ?? 'profile');
|
||||
$active = isset($_GET['tab']) ? sanitize_key(wp_unslash($_GET['tab'])) : $default;
|
||||
if ('signin' === $active) {
|
||||
if ('signin' === $active || 'assets' === $active) {
|
||||
$active = 'credits';
|
||||
} elseif ('invite' === $active) {
|
||||
$active = 'settings';
|
||||
} 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;
|
||||
@@ -353,7 +356,13 @@ if (!function_exists('aksrt_user_center_runtime_config')) {
|
||||
'userId' => $user_id,
|
||||
'defaultTab' => $default_tab,
|
||||
'activeTab' => $active_tab,
|
||||
'tabAliases' => ['signin' => 'credits', 'invite' => 'settings'],
|
||||
'tabAliases' => [
|
||||
'signin' => 'credits',
|
||||
'invite' => 'settings',
|
||||
'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'),
|
||||
|
||||
@@ -65,7 +65,8 @@ function aksrt_get_user_vip_level(int $user_id = 0): int {
|
||||
|
||||
if ($meta_level > 0) {
|
||||
if ($expires > 0 && $expires < time()) {
|
||||
// 过期:lazy 清 level,与 capabilities 读 meta 对齐。
|
||||
// 过期:lazy 清 level,记录上次等级(zibll vip_level_expired)。
|
||||
update_user_meta($user_id, 'aksrt_vip_level_expired', min(2, max(1, $meta_level)));
|
||||
update_user_meta($user_id, 'aksrt_vip_level', 0);
|
||||
$candidate = 0;
|
||||
} else {
|
||||
@@ -82,16 +83,36 @@ function aksrt_get_user_vip_level(int $user_id = 0): int {
|
||||
: null;
|
||||
|
||||
if (is_array($valid_order) && !empty($valid_order)) {
|
||||
$order_expires = trim((string) ($valid_order['expires_at'] ?? ''));
|
||||
$order_expired = false;
|
||||
if ($order_expires !== '') {
|
||||
$ts = strtotime($order_expires);
|
||||
if ($ts !== false && $ts < time()) {
|
||||
$order_expired = true;
|
||||
// Order.expires_at is payment checkout deadline, not VIP membership expiry.
|
||||
// Prefer note/meta_payload level + aksrt_vip_expires if present.
|
||||
$meta = [];
|
||||
if (!empty($valid_order['meta_payload']) && is_array($valid_order['meta_payload'])) {
|
||||
$meta = $valid_order['meta_payload'];
|
||||
} elseif (!empty($valid_order['note']) && is_string($valid_order['note'])) {
|
||||
$decoded = json_decode($valid_order['note'], true);
|
||||
if (is_array($decoded)) {
|
||||
$meta = $decoded;
|
||||
}
|
||||
}
|
||||
if (!$order_expired) {
|
||||
// 套餐无 level 列:有效 VIP 订单至少视为 VIP1。
|
||||
|
||||
$order_level = (int) ($meta['level'] ?? 0);
|
||||
if ($order_level <= 0 && !empty($valid_order['product_id']) && class_exists('\AKSRT\Content\VipService')) {
|
||||
// package_id encodes level: decode if possible via service helpers.
|
||||
$pkg_id = (int) $valid_order['product_id'];
|
||||
// Encode scheme: level * 1000 + index (see VipServicePackages).
|
||||
if ($pkg_id >= 1000) {
|
||||
$order_level = (int) floor($pkg_id / 1000);
|
||||
} elseif ($pkg_id > 0) {
|
||||
$order_level = 1;
|
||||
}
|
||||
}
|
||||
$order_level = max(0, min(2, $order_level));
|
||||
|
||||
// Membership still valid if user meta expires is in future or permanent (0 with prior grant).
|
||||
// Without restored meta, treat paid VIP order as at least the ordered level.
|
||||
if ($order_level > 0) {
|
||||
$candidate = $order_level;
|
||||
} else {
|
||||
$candidate = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,17 @@ function aksrt_get_user_center_url(string $tab = ''): string {
|
||||
}
|
||||
|
||||
if ($tab !== '') {
|
||||
$tab = sanitize_key($tab);
|
||||
// Deep-link aliases used by header wallet / VIP CTA.
|
||||
$aliases = [
|
||||
'assets' => 'credits',
|
||||
'vip' => 'vip', // dedicated vip tab when registered; resolver falls back if missing
|
||||
'signin' => 'credits',
|
||||
'invite' => 'settings',
|
||||
];
|
||||
if (isset($aliases[$tab])) {
|
||||
$tab = $aliases[$tab];
|
||||
}
|
||||
$url = add_query_arg('tab', $tab, $url);
|
||||
}
|
||||
return $url;
|
||||
|
||||
@@ -29,6 +29,18 @@ trait OrderRepositoryCore {
|
||||
|
||||
$order_number = $data['order_number'] ?? $this->generate_order_number();
|
||||
|
||||
// Preserve JSON pay meta (VIP/content/coupon). Only strip tags for plain text notes.
|
||||
$note_raw = (string) ($data['note'] ?? '');
|
||||
$note_trim = trim($note_raw);
|
||||
if ($note_trim !== '' && ($note_trim[0] === '{' || $note_trim[0] === '[')) {
|
||||
$decoded = json_decode($note_trim, true);
|
||||
$note = is_array($decoded)
|
||||
? (string) wp_json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
|
||||
: sanitize_textarea_field($note_raw);
|
||||
} else {
|
||||
$note = sanitize_textarea_field($note_raw);
|
||||
}
|
||||
|
||||
$wpdb->insert($this->table(), [
|
||||
'order_number' => $order_number,
|
||||
'user_id' => (int) ($data['user_id'] ?? 0),
|
||||
@@ -42,7 +54,7 @@ trait OrderRepositoryCore {
|
||||
'created_at' => $data['created_at'] ?? current_time('mysql'),
|
||||
'paid_at' => $data['paid_at'] ?? null,
|
||||
'expires_at' => $data['expires_at'] ?? null,
|
||||
'note' => sanitize_textarea_field((string) ($data['note'] ?? '')),
|
||||
'note' => $note,
|
||||
], ['%s', '%d', '%s', '%d', '%f', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s']);
|
||||
|
||||
if ($wpdb->insert_id) {
|
||||
|
||||
@@ -159,6 +159,15 @@ trait CreditsPaymentGroups {
|
||||
return PaymentRuntime::get_payment_vip_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for callers that expect get_vip_settings() (header CTA, float buttons).
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_vip_settings(): array {
|
||||
return self::get_payment_vip_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{enabled:bool,share_ratio:int,settlement_threshold:int,cycle_days:int,note:string}
|
||||
*/
|
||||
|
||||
@@ -192,7 +192,8 @@ class PaymentRuntime {
|
||||
'upgrade' => [
|
||||
'enabled' => !isset($settings['vip_upgrade']) || !empty($settings['vip_upgrade']),
|
||||
'desc' => sanitize_textarea_field((string) ($settings['vip_upgrade_desc'] ?? '')),
|
||||
'product' => sanitize_text_field((string) ($settings['vip_upgrade_product'] ?? '')),
|
||||
// Multi-line upgrade product rules — must not collapse newlines.
|
||||
'product' => sanitize_textarea_field((string) ($settings['vip_upgrade_product'] ?? '')),
|
||||
],
|
||||
'points_exchange' => [
|
||||
'enabled' => !empty($settings['pay_vip_points_exchange_s']),
|
||||
|
||||
Reference in New Issue
Block a user