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\Settings')) { return 0; } $vip_settings = \AKSRT\Settings\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\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\Payment\Order')) { $order_mgr = \AKSRT\Payment\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 { return aksrt_get_user_vip_level($user_id) >= 1; } /** * 检查用户是否为 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; } /** * 获取 VIP 徽标文本 * * @return string */ function aksrt_get_vip_badge_text(): string { if (!class_exists('\AKSRT\Settings\Settings')) { return 'VIP'; } $vip_settings = \AKSRT\Settings\Settings::get_payment_vip_settings(); return sanitize_text_field($vip_settings['badge_text'] ?? 'VIP'); } /** * Daily free-download limit for a user (0 = unlimited). * Aligns with zibll pay_download_limit / pay_download_limit_vip_{n}. */ if (!function_exists('aksrt_get_user_free_download_limit')) { function aksrt_get_user_free_download_limit(int $user_id = 0): int { if ($user_id <= 0) { $user_id = get_current_user_id(); } if ($user_id <= 0 || !class_exists('\AKSRT\Settings\Settings')) { return 0; } $vip = \AKSRT\Settings\Settings::get_payment_vip_settings(); $level = function_exists('aksrt_get_user_vip_level') ? aksrt_get_user_vip_level($user_id) : 0; $levels = is_array($vip['levels'] ?? null) ? $vip['levels'] : []; $benefit = is_array($vip['benefit'] ?? null) ? $vip['benefit'] : []; if ($level >= 1 && !empty($levels[$level]['enabled'])) { return max(0, (int) ($levels[$level]['download_limit'] ?? 0)); } return max(0, (int) ($benefit['download_limit'] ?? 0)); } } /** * Download speed cap in KB/s for a user (0 = unlimited). */ if (!function_exists('aksrt_get_user_download_speed')) { function aksrt_get_user_download_speed(int $user_id = 0): int { if ($user_id <= 0) { $user_id = get_current_user_id(); } if ($user_id <= 0 || !class_exists('\AKSRT\Settings\Settings')) { return 0; } $vip = \AKSRT\Settings\Settings::get_payment_vip_settings(); $level = function_exists('aksrt_get_user_vip_level') ? aksrt_get_user_vip_level($user_id) : 0; $levels = is_array($vip['levels'] ?? null) ? $vip['levels'] : []; $benefit = is_array($vip['benefit'] ?? null) ? $vip['benefit'] : []; if ($level >= 1 && !empty($levels[$level]['enabled'])) { return max(0, (int) ($levels[$level]['download_speed'] ?? 0)); } return max(0, (int) ($benefit['download_speed'] ?? 0)); } } /** * Count free downloads used today for a user (zibll pay_down_number). */ if (!function_exists('aksrt_get_user_free_downloaded_number')) { function aksrt_get_user_free_downloaded_number(int $user_id = 0): int { if ($user_id <= 0) { $user_id = get_current_user_id(); } if ($user_id <= 0) { return 0; } $day = current_time('Y-m-d'); $mate = get_user_meta($user_id, 'aksrt_pay_down_number', true); if (!is_array($mate) || empty($mate[$day]) || !is_array($mate[$day])) { return 0; } return count($mate[$day]); } } /** * Record a free download for daily quota (zibll pay_down_number). */ if (!function_exists('aksrt_record_user_free_download')) { function aksrt_record_user_free_download(int $user_id, int $post_id): void { if ($user_id <= 0 || $post_id <= 0) { return; } $day = current_time('Y-m-d'); $mate = get_user_meta($user_id, 'aksrt_pay_down_number', true); if (!is_array($mate)) { $mate = []; } // Drop old days to keep meta small. foreach (array_keys($mate) as $k) { if ($k !== $day) { unset($mate[$k]); } } if (!isset($mate[$day]) || !is_array($mate[$day])) { $mate[$day] = []; } $mate[$day][(string) $post_id] = 1; update_user_meta($user_id, 'aksrt_pay_down_number', $mate); } } /** * Whether a free download is allowed under daily quota. * Paid downloads (cost > 0) always pass. * * @return true|WP_Error */ if (!function_exists('aksrt_check_free_download_quota')) { function aksrt_check_free_download_quota(int $user_id, int $cost = 0) { if ($cost > 0) { return true; } if ($user_id <= 0) { return true; // login gate handled elsewhere } $limit = aksrt_get_user_free_download_limit($user_id); if ($limit <= 0) { return true; // unlimited } $used = aksrt_get_user_free_downloaded_number($user_id); if ($used >= $limit) { $data = [ 'status' => 429, 'limit' => $limit, 'used' => $used, ]; // Optional overbuy price for free-quota exhausted (Zibll download_limit_over_price). // Callers may pass post context via filter. $over = apply_filters('aksrt_download_limit_over_price', 0.0, $user_id); if ($over > 0) { $data['download_limit_over_price'] = $over; $data['allow_limit_over'] = true; } return new WP_Error( 'aksrt_download_limit', __('您今日下载免费资源个数已超限,请明日再下载。', 'aksrt'), $data ); } return true; } } /** * Remaining free downloads today (null = unlimited). */ if (!function_exists('aksrt_get_free_download_surplus')) { function aksrt_get_free_download_surplus(int $user_id = 0): ?int { if ($user_id <= 0) { $user_id = get_current_user_id(); } $limit = aksrt_get_user_free_download_limit($user_id); if ($limit <= 0) { return null; } $used = aksrt_get_user_free_downloaded_number($user_id); return max(0, $limit - $used); } } /** * 渲染 VIP 徽标 HTML * * @param int $user_id * @param string $size sm | md | lg * @return string */ function aksrt_render_vip_badge(int $user_id = 0, string $size = 'sm'): string { if (!aksrt_is_vip($user_id)) { return ''; } $badge_text = aksrt_get_vip_badge_text(); $size_class = 'aksrt-vip-badge--' . $size; return ' ' . esc_html($badge_text) . ''; } /** * 获取用户 VIP 等级信息(用于展示) * * @param int $user_id * @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\Settings')) { $vip = \AKSRT\Settings\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' => $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('/'); } }