diff --git a/inc/classes/shop/shop-traits/trait-aksrt-shop-part-3.php b/inc/classes/shop/shop-traits/trait-aksrt-shop-part-3.php index 68ee9fe6..eacee5d6 100644 --- a/inc/classes/shop/shop-traits/trait-aksrt-shop-part-3.php +++ b/inc/classes/shop/shop-traits/trait-aksrt-shop-part-3.php @@ -334,6 +334,11 @@ trait AKSRT_Shop_Part_3 { $current = (int) get_user_meta($user_id, 'aksrt_vip_expires', true); $base = max($current, time()); update_user_meta($user_id, 'aksrt_vip_expires', $base + ((int) $gift_value * DAY_IN_SECONDS)); + // 赠送 VIP 天数时确保至少 VIP1;不降级已有 VIP2。 + $level = (int) get_user_meta($user_id, 'aksrt_vip_level', true); + if ($level < 1) { + update_user_meta($user_id, 'aksrt_vip_level', 1); + } } } } diff --git a/inc/helpers/aksrt-vip.php b/inc/helpers/aksrt-vip.php index 9fd828c5..bfad8164 100644 --- a/inc/helpers/aksrt-vip.php +++ b/inc/helpers/aksrt-vip.php @@ -1,6 +1,6 @@ 0 视为永久) + * 4. 有效 VIP 订单兜底 → 1(套餐无 level 列,订单无法区分 VIP2) + * 5. 按 pay_user_vip_1/2 开关钳制 + * + * @param int $user_id 用户 ID,0 时取当前用户。 + * @return int 0|1|2 + */ +function aksrt_get_user_vip_level(int $user_id = 0): int { + if ($user_id <= 0) { + $user_id = get_current_user_id(); + } + if ($user_id <= 0) { + return 0; + } + + if (!class_exists('AKSRT_Settings')) { + return 0; + } + + $vip_settings = AKSRT_Settings::get_payment_vip_settings(); + if (empty($vip_settings['enabled'])) { + return 0; + } + + $levels = is_array($vip_settings['levels'] ?? null) ? $vip_settings['levels'] : []; + $vip1_enabled = !empty($levels[1]['enabled']); + $vip2_enabled = !empty($levels[2]['enabled']); + + // 1. 角色豁免:特权角色取当前启用最高档。 + $paid_settings = AKSRT_Settings::get_paid_content_settings(); + $exempt_roles = $paid_settings['vip_exempt_roles'] ?? []; + if (!empty($exempt_roles)) { + $user = get_userdata($user_id); + if ($user && !empty(array_intersect((array) $user->roles, $exempt_roles))) { + if ($vip2_enabled) { + return 2; + } + if ($vip1_enabled) { + return 1; + } + return 0; + } + } + + $candidate = 0; + + // 2. meta 主路径。 + $meta_level = (int) get_user_meta($user_id, 'aksrt_vip_level', true); + $expires = (int) get_user_meta($user_id, 'aksrt_vip_expires', true); + + if ($meta_level > 0) { + if ($expires > 0 && $expires < time()) { + // 过期:lazy 清 level,与 capabilities 读 meta 对齐。 + update_user_meta($user_id, 'aksrt_vip_level', 0); + $candidate = 0; + } else { + // expires === 0 视为永久;expires >= now 视为有效。 + $candidate = min(2, max(0, $meta_level)); + } + } + + // 3. 订单兜底(meta 无有效等级时)。 + if ($candidate <= 0 && class_exists('AKSRT_Order')) { + $order_mgr = AKSRT_Order::get_instance(); + $valid_order = method_exists($order_mgr, 'get_valid_vip_order') + ? $order_mgr->get_valid_vip_order($user_id) + : 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; + } + } + if (!$order_expired) { + // 套餐无 level 列:有效 VIP 订单至少视为 VIP1。 + $candidate = 1; + } + } + } + + // 4. 按档位开关钳制。 + if ($candidate >= 2) { + if ($vip2_enabled) { + return 2; + } + if ($vip1_enabled) { + return 1; + } + return 0; + } + + if ($candidate === 1) { + return $vip1_enabled ? 1 : 0; + } + + return 0; +} + +/** + * 检查用户是否为 VIP(level >= 1)。 * * @param int $user_id * @return bool */ function aksrt_is_vip(int $user_id = 0): bool { - if ($user_id <= 0) $user_id = get_current_user_id(); - if ($user_id <= 0) return false; + return aksrt_get_user_vip_level($user_id) >= 1; +} - if (!class_exists('AKSRT_Settings')) return false; - - $vip_settings = AKSRT_Settings::get_payment_vip_settings(); - if (empty($vip_settings['enabled'])) return false; - - // 1. 角色豁免:VIP exempt_roles 中的角色直接视为 VIP - $paid_settings = AKSRT_Settings::get_paid_content_settings(); - $exempt_roles = $paid_settings['vip_exempt_roles'] ?? []; - if (!empty($exempt_roles)) { - $user = get_userdata($user_id); - if ($user && !empty(array_intersect($user->roles, $exempt_roles))) { - return true; - } - } - - // 2. 订单判定:检查是否有有效的 VIP 订单 - if (class_exists('AKSRT_Order')) { - $order_mgr = AKSRT_Order::get_instance(); - $valid_order = method_exists($order_mgr, 'get_valid_vip_order') - ? $order_mgr->get_valid_vip_order($user_id) - : null; - if ($valid_order) { - return true; - } - } - - return false; +/** + * 检查用户是否为 VIP2(level >= 2)。 + * + * @param int $user_id + * @return bool + */ +function aksrt_is_vip2(int $user_id = 0): bool { + return aksrt_get_user_vip_level($user_id) >= 2; } /** @@ -57,7 +141,9 @@ function aksrt_is_vip(int $user_id = 0): bool { * @return string */ function aksrt_get_vip_badge_text(): string { - if (!class_exists('AKSRT_Settings')) return 'VIP'; + if (!class_exists('AKSRT_Settings')) { + return 'VIP'; + } $vip_settings = AKSRT_Settings::get_payment_vip_settings(); return sanitize_text_field($vip_settings['badge_text'] ?? 'VIP'); @@ -71,7 +157,9 @@ function aksrt_get_vip_badge_text(): string { * @return string */ function aksrt_render_vip_badge(int $user_id = 0, string $size = 'sm'): string { - if (!aksrt_is_vip($user_id)) return ''; + if (!aksrt_is_vip($user_id)) { + return ''; + } $badge_text = aksrt_get_vip_badge_text(); $size_class = 'aksrt-vip-badge--' . $size; @@ -83,14 +171,16 @@ function aksrt_render_vip_badge(int $user_id = 0, string $size = 'sm'): string { * 获取用户 VIP 等级信息(用于展示) * * @param int $user_id - * @return array{is_vip: bool, badge_text: string, badge_html: string, name: string} + * @return array{is_vip: bool, level: int, badge_text: string, badge_html: string, name: string} */ function aksrt_get_vip_info(int $user_id = 0): array { - $is_vip = aksrt_is_vip($user_id); + $level = aksrt_get_user_vip_level($user_id); + $is_vip = $level >= 1; $badge_text = aksrt_get_vip_badge_text(); 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 . '会员') : '普通用户',