diff --git a/inc/classes/class-aksrt-content-visibility.php b/inc/classes/class-aksrt-content-visibility.php index 35993bf1..1257580d 100644 --- a/inc/classes/class-aksrt-content-visibility.php +++ b/inc/classes/class-aksrt-content-visibility.php @@ -38,7 +38,17 @@ class AKSRT_Content_Visibility { ? aksrt_get_pay_meta($resource_post) : AKSRT_Domain_Model::default_pay_meta(); $pay_type = AKSRT_Domain_Model::normalize_pay_type((string) ($pay_meta['pay_type'] ?? AKSRT_Domain_Model::PAY_TYPE_NO)); - $price = (float) ($pay_meta['price'] ?? 0); + $priced = function_exists('aksrt_get_user_pay_price') + ? aksrt_get_user_pay_price($resource_post, $uid) + : null; + $pay_modo = is_array($priced) + ? ((($priced['modo'] ?? '0') === 'points') ? 'points' : '0') + : ((($pay_meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0'); + $price = is_array($priced) + ? (float) ($priced['amount'] ?? 0) + : (($pay_modo === 'points') + ? (float) ($pay_meta['points_price'] ?? 0) + : (float) ($pay_meta['price'] ?? 0)); $paid_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_paid_content_settings() : [ @@ -50,6 +60,7 @@ class AKSRT_Content_Visibility { $state = [ 'post_id' => $resource_post instanceof WP_Post ? (int) $resource_post->ID : 0, 'pay_type' => $pay_type, + 'pay_modo' => $pay_modo, 'price' => $price, 'need_login' => false, 'need_purchase' => false, @@ -59,6 +70,8 @@ class AKSRT_Content_Visibility { 'can_view' => true, 'can_download' => true, 'download_cost' => 0, + 'pay_limit' => 0, + 'user_vip_level' => 0, ]; if (!($resource_post instanceof WP_Post)) { @@ -68,20 +81,16 @@ class AKSRT_Content_Visibility { } if ($pay_type === AKSRT_Domain_Model::PAY_TYPE_NO) { + $state['has_paid_access'] = true; return $state; } $has_free_access = $price <= 0 && $pay_type !== AKSRT_Domain_Model::PAY_TYPE_VIP; - // Prefer points_price when pay_modo=points. - if (is_array($pay_meta) && (($pay_meta['pay_modo'] ?? '0') === 'points')) { - $price = (float) ($pay_meta['points_price'] ?? $price); - $state['price'] = $price; - $has_free_access = $price <= 0 && $pay_type !== AKSRT_Domain_Model::PAY_TYPE_VIP; - } $pay_limit = (int) ($pay_meta['pay_limit'] ?? 0); if (!in_array($pay_limit, [0, 1, 2], true)) { $pay_limit = 0; } + $state['pay_limit'] = $pay_limit; $has_paid_order = false; if ($uid > 0 && class_exists('AKSRT_Order')) { @@ -93,47 +102,60 @@ class AKSRT_Content_Visibility { } $has_vip_access = false; - $user_vip_level = 0; + $user_vip_level = is_array($priced) ? (int) ($priced['vip_level'] ?? 0) : 0; if ($uid > 0) { - if (function_exists('aksrt_get_user_vip_level')) { + if ($user_vip_level <= 0 && function_exists('aksrt_get_user_vip_level')) { $user_vip_level = aksrt_get_user_vip_level($uid); } if (function_exists('aksrt_is_vip_exempt') && aksrt_is_vip_exempt($uid)) { $has_vip_access = true; $user_vip_level = max($user_vip_level, 2); - } elseif (function_exists('aksrt_is_vip') && ($pay_type === AKSRT_Domain_Model::PAY_TYPE_VIP || $pay_limit > 0)) { + } elseif ($pay_type === AKSRT_Domain_Model::PAY_TYPE_VIP || $pay_limit > 0) { $has_vip_access = $user_vip_level >= max(1, $pay_limit); } elseif ($user_vip_level > 0) { + // VIP tier pricing may zero cost; still track membership. $has_vip_access = $pay_limit <= 0 || $user_vip_level >= $pay_limit; } } + $state['user_vip_level'] = $user_vip_level; // Member-only purchase restriction (Zibll pay_limit). if ($pay_limit > 0 && $pay_type !== AKSRT_Domain_Model::PAY_TYPE_NO) { $state['need_vip'] = true; - $state['pay_limit'] = $pay_limit; - $allowed_member = $has_vip_access && $user_vip_level >= $pay_limit; + $allowed_member = $uid > 0 && $user_vip_level >= $pay_limit; if ($pay_type === AKSRT_Domain_Model::PAY_TYPE_DOWNLOAD) { $download_cost = function_exists('aksrt_resource_download_cost') ? (int) aksrt_resource_download_cost($resource_post) : (int) ceil($price); + // If member is free via VIP price, cost is 0. + if ($allowed_member && $price <= 0) { + $download_cost = 0; + } $state['download_cost'] = max(0, $download_cost); $state['need_login'] = $uid <= 0; $state['need_purchase'] = $allowed_member && $state['download_cost'] > 0 && !$has_paid_order; - $state['has_paid_access'] = $allowed_member && ($has_paid_order || $state['download_cost'] <= 0 || $has_vip_access); + $state['has_paid_access'] = $allowed_member && ($has_paid_order || $state['download_cost'] <= 0); $state['can_view'] = true; - $state['can_download'] = $allowed_member && ($uid > 0) && ($has_paid_order || $state['download_cost'] <= 0 || $has_vip_access); + $state['can_download'] = $allowed_member && ($uid > 0) && ($has_paid_order || $state['download_cost'] <= 0); if (!$allowed_member) { $state['can_download'] = false; $state['has_paid_access'] = false; + $state['need_purchase'] = false; } return $state; } - $state['has_paid_access'] = $allowed_member || $has_paid_order; + $state['has_paid_access'] = ($allowed_member && $price <= 0) || $has_paid_order || ($allowed_member && $has_vip_access && $pay_type === AKSRT_Domain_Model::PAY_TYPE_VIP); + // For reading/gallery/video with pay_limit: members still need to purchase unless free. + if ($allowed_member) { + $state['has_paid_access'] = $has_paid_order || $price <= 0; + $state['need_purchase'] = !$state['has_paid_access']; + } else { + $state['has_paid_access'] = false; + $state['need_purchase'] = false; + } $state['can_view'] = $state['has_paid_access']; $state['can_download'] = false; - $state['need_purchase'] = !$state['has_paid_access']; return $state; } @@ -149,10 +171,23 @@ class AKSRT_Content_Visibility { || !empty($pay_meta['require_login']) || ($free_logged_show && $state['download_cost'] <= 0); $state['require_captcha'] = !empty($paid_settings['download_captcha']) || !empty($pay_meta['require_captcha']); - $state['need_purchase'] = !$has_vip_access && $state['download_cost'] > 0; - $state['has_paid_access'] = $has_vip_access || $has_paid_order || !$state['need_purchase']; + // Cash mode with cost handled by orders: need purchase when no order and base price > 0. + $needs_pay = $state['download_cost'] > 0 || ($pay_modo === '0' && $price > 0 && !$has_paid_order && empty($paid_settings['download_credit'])); + if ($pay_modo === '0' && $price > 0 && empty($paid_settings['download_credit'])) { + $state['need_purchase'] = !$has_paid_order && !($has_vip_access && $price <= 0); + $state['has_paid_access'] = $has_paid_order || $price <= 0; + // Download still gated by login/credit path for token; cash unlock is order-based. + $state['can_view'] = true; + $state['can_download'] = ($has_paid_order || $price <= 0) && (!$state['need_login'] || $uid > 0); + return $state; + } + + $state['need_purchase'] = !$has_paid_order && $state['download_cost'] > 0 && !$has_free_access; + // VIP with free tier amount already reflected in download_cost. + $state['has_paid_access'] = $has_paid_order || $state['download_cost'] <= 0 || $has_free_access; $state['can_view'] = true; - $state['can_download'] = !$state['need_login'] || $uid > 0; + $state['can_download'] = (!$state['need_login'] || $uid > 0) && ($has_paid_order || $state['download_cost'] <= 0 || true); + // can_download true only means "may request token"; rest_request still deducts credits. return $state; } @@ -167,8 +202,13 @@ class AKSRT_Content_Visibility { } $state['need_login'] = !empty($pay_meta['require_login']); - $state['need_purchase'] = !$has_free_access; - $state['has_paid_access'] = $has_free_access || $has_paid_order || $has_vip_access; + $state['need_purchase'] = !$has_free_access && !$has_paid_order; + $state['has_paid_access'] = $has_free_access || $has_paid_order; + // VIP free tier for reading etc. via amount. + if (!$state['has_paid_access'] && $price <= 0 && $pay_type !== AKSRT_Domain_Model::PAY_TYPE_VIP) { + $state['has_paid_access'] = true; + $state['need_purchase'] = false; + } $state['can_view'] = $state['has_paid_access'] && (!$state['need_login'] || $uid > 0); $state['can_download'] = false; @@ -217,6 +257,26 @@ class AKSRT_Content_Visibility { ]); } + // Member-only (pay_limit). + if (!empty($state['need_vip']) && empty($state['has_paid_access']) && empty($state['can_download'])) { + $need_level = (int) ($state['pay_limit'] ?? 1); + return new WP_Error('aksrt_need_vip', sprintf( + /* translators: %d: required VIP level */ + __('该资源仅限 VIP%s 及以上会员购买/下载。', 'aksrt'), + max(1, $need_level) + ), [ + 'status' => 403, + 'pay_limit' => $need_level, + ]); + } + + // Cash purchase required (order path). + if (!empty($state['need_purchase']) && empty($state['has_paid_access']) && $cost <= 0 && (($state['pay_modo'] ?? '0') === '0')) { + return new WP_Error('aksrt_need_purchase', __('请先购买后再下载。', 'aksrt'), [ + 'status' => 402, + ]); + } + // Zibll daily free-download quota. if ($cost <= 0 && function_exists('aksrt_check_free_download_quota')) { $quota = aksrt_check_free_download_quota($uid, $cost); @@ -225,7 +285,12 @@ class AKSRT_Content_Visibility { } } - if (!empty($paid_settings['download_credit']) && $cost > 0) { + $pay_modo = (string) ($state['pay_modo'] ?? '0'); + $need_credit_check = $cost > 0 && ( + $pay_modo === 'points' + || !empty($paid_settings['download_credit']) + ); + if ($need_credit_check) { $balance = class_exists('AKSRT_Credits') ? AKSRT_Credits::balance($uid) : 0; if ($balance < $cost) { return new WP_Error('aksrt_credits_insufficient', __('积分不足,无法下载。', 'aksrt'), [ diff --git a/inc/classes/class-aksrt-download.php b/inc/classes/class-aksrt-download.php index c00c3188..498b6393 100644 --- a/inc/classes/class-aksrt-download.php +++ b/inc/classes/class-aksrt-download.php @@ -114,6 +114,11 @@ class AKSRT_Download { $paid_settings = AKSRT_Settings::get_paid_content_settings(); $cost = aksrt_resource_download_cost($post); $uid = get_current_user_id(); + $priced = function_exists('aksrt_get_user_pay_price') ? aksrt_get_user_pay_price($post, $uid) : null; + $pay_modo = is_array($priced) + ? ((($priced['modo'] ?? '0') === 'points') ? 'points' : '0') + : ((($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0'); + $display_price = is_array($priced) ? (float) ($priced['amount'] ?? 0) : (float) ($meta['price'] ?? 0); $need_captcha = !empty($paid_settings['download_captcha']) || !empty($meta['require_captcha']); if ($need_captcha && function_exists('aksrt_is_captcha_enabled_for') && !aksrt_is_captcha_enabled_for('download')) { @@ -122,7 +127,10 @@ class AKSRT_Download { return new WP_REST_Response([ 'post_id' => $post_id, - 'price' => (float) $meta['price'], + 'price' => $display_price, + 'base_price' => is_array($priced) ? (float) ($priced['base'] ?? $display_price) : (float) ($meta['price'] ?? 0), + 'pay_modo' => $pay_modo, + 'pay_limit' => (int) ($meta['pay_limit'] ?? 0), 'cost' => $cost, 'require_login' => !empty($paid_settings['download_login']) || !empty($meta['require_login']) || (!empty($paid_settings['free_logged_show']) && $cost <= 0), 'require_captcha' => $need_captcha, @@ -139,7 +147,7 @@ class AKSRT_Download { 'type' => $row['type'] ?? 'direct', 'has_extract' => $extract_code !== '', ]; - }, $meta['downloads'], array_keys($meta['downloads'])), + }, $meta['downloads'] ?? [], array_keys($meta['downloads'] ?? [])), ], 200); } @@ -354,14 +362,25 @@ class AKSRT_Download { header('Content-Length: ' . (string) $size); $chunk = 1024 * 64; // 64KB + $sleep_us = 0; if ($speed_kb > 0) { - $chunk = max(1024, min($chunk, $speed_kb * 1024)); + // Emit ~speed_kb KB per second using fixed 64KB chunks when possible. + $bytes_per_sec = max(1024, $speed_kb * 1024); + $chunk = min(1024 * 64, $bytes_per_sec); + $chunk = max(1024, $chunk); + // Sleep so chunk_bytes / second ≈ bytes_per_sec. + $sleep_us = (int) max(0, (int) round(($chunk / $bytes_per_sec) * 1000000) - 1000); } $fh = fopen($path, 'rb'); if (!$fh) { $this->fail_410(); } + // Disable output compression for accurate Content-Length / throttle. + if (function_exists('apache_setenv')) { + @apache_setenv('no-gzip', '1'); + } + @ini_set('zlib.output_compression', 'Off'); while (!feof($fh)) { $buf = fread($fh, $chunk); if ($buf === false) { @@ -371,9 +390,8 @@ class AKSRT_Download { if (function_exists('flush')) { flush(); } - if ($speed_kb > 0) { - // Approximate throttle: sleep 1s per speed_kb window when chunk ~= speed_kb KB. - usleep(200000); // 0.2s per chunk for smoother throttle + if ($sleep_us > 0) { + usleep($sleep_us); } } fclose($fh); diff --git a/inc/helpers/aksrt-pay.php b/inc/helpers/aksrt-pay.php index ff7a8e9a..632448a4 100644 --- a/inc/helpers/aksrt-pay.php +++ b/inc/helpers/aksrt-pay.php @@ -149,14 +149,26 @@ if (!function_exists('aksrt_get_download_box_meta')) { $pay_meta = aksrt_get_pay_meta($p); $download_count = (int) get_post_meta($p->ID, AKSRT_Domain_Model::RESOURCE_DOWNLOAD_COUNT_KEY, true); $view_count = (int) get_post_meta($p->ID, AKSRT_Domain_Model::POST_VIEW_COUNT_KEY, true); + $virtual_sales = max(0, (int) ($pay_meta['virtual_sales'] ?? 0)); + $show_sales = !isset($pay_meta['show_sales']) || !empty($pay_meta['show_sales']); + $pay_modo = (($pay_meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0'; + $pay_limit = (int) ($pay_meta['pay_limit'] ?? 0); + if (!in_array($pay_limit, [0, 1, 2], true)) { + $pay_limit = 0; + } return [ 'version' => (string) ($pay_meta['version'] ?? ''), 'size' => (string) ($pay_meta['size'] ?? ''), 'price' => (float) ($pay_meta['price'] ?? 0), + 'points_price' => (int) ($pay_meta['points_price'] ?? 0), + 'pay_modo' => $pay_modo, + 'pay_limit' => $pay_limit, 'original_price' => (float) ($pay_meta['original_price'] ?? 0), 'vip1_price' => (float) ($pay_meta['vip1_price'] ?? 0), 'vip2_price' => (float) ($pay_meta['vip2_price'] ?? 0), + 'vip1_points' => (int) ($pay_meta['vip1_points'] ?? 0), + 'vip2_points' => (int) ($pay_meta['vip2_points'] ?? 0), 'pay_type' => (string) ($pay_meta['pay_type'] ?? AKSRT_PAY_TYPE_NO), 'license' => (string) ($pay_meta['license'] ?? ''), 'compat' => (string) ($pay_meta['compat'] ?? ''), @@ -164,6 +176,9 @@ if (!function_exists('aksrt_get_download_box_meta')) { 'downloads' => array_values(is_array($pay_meta['downloads'] ?? null) ? $pay_meta['downloads'] : []), 'download_count' => max(0, $download_count), 'view_count' => max(0, $view_count), + 'virtual_sales' => $virtual_sales, + 'sales_count' => $show_sales ? ($virtual_sales + max(0, $download_count)) : 0, + 'show_sales' => $show_sales, 'require_login' => !empty($pay_meta['require_login']), 'require_captcha' => !empty($pay_meta['require_captcha']), 'subject_label' => __('内容', 'aksrt'), @@ -171,6 +186,89 @@ if (!function_exists('aksrt_get_download_box_meta')) { } } +/** + * Resolve the amount a given user should pay for a post (Zibll VIP tier min). + * + * VIP tier prices only apply when configured as a positive discount (< base). + * Full free for VIP uses vip_free_download / exempt roles (handled separately). + * + * @param int|WP_Post|null $post + * @param int $user_id + * @return array{amount:float,base:float,vip_amount:float,modo:string,currency:string,is_free:bool,pay_limit:int,vip_level:int,original:float,vip1:float,vip2:float} + */ +if (!function_exists('aksrt_get_user_pay_price')) { + function aksrt_get_user_pay_price($post = null, int $user_id = 0): array { + $meta = function_exists('aksrt_get_pay_meta') ? aksrt_get_pay_meta($post) : AKSRT_Domain_Model::default_pay_meta(); + $pay_modo = (($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0'; + $pay_limit = (int) ($meta['pay_limit'] ?? 0); + if (!in_array($pay_limit, [0, 1, 2], true)) { + $pay_limit = 0; + } + + $uid = $user_id > 0 ? $user_id : (function_exists('get_current_user_id') ? (int) get_current_user_id() : 0); + $vip_level = 0; + if ($uid > 0 && function_exists('aksrt_get_user_vip_level')) { + $vip_level = (int) aksrt_get_user_vip_level($uid); + } + if ($uid > 0 && function_exists('aksrt_is_vip_exempt') && aksrt_is_vip_exempt($uid)) { + $vip_level = max($vip_level, 2); + } + + $currency = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_currency_name() : __('积分', 'aksrt'); + $cash_symbol = '¥'; + if (class_exists('AKSRT_Settings')) { + $paid = AKSRT_Settings::get_paid_content_settings(); + $cash_symbol = (string) ($paid['display']['currency_symbol'] ?? '¥'); + } + + if ($pay_modo === 'points') { + $base = (float) ($meta['points_price'] ?? 0); + $vip1 = (float) ($meta['vip1_points'] ?? 0); + $vip2 = (float) ($meta['vip2_points'] ?? 0); + $currency_label = $currency; + } else { + $base = (float) ($meta['price'] ?? 0); + $vip1 = (float) ($meta['vip1_price'] ?? 0); + $vip2 = (float) ($meta['vip2_price'] ?? 0); + $currency_label = $cash_symbol; + } + + // Positive VIP tier prices only (0 defaults mean "not configured"). + $vip_amount = -1.0; + if ($vip_level >= 2 && $vip2 > 0) { + $vip_amount = $vip2; + } elseif ($vip_level >= 1 && $vip1 > 0) { + $vip_amount = $vip1; + } + + $amount = $base; + if ($vip_amount >= 0 && ($base <= 0 || $vip_amount < $base)) { + $amount = $vip_amount; + } + + // Role/VIP free-download exemption (global setting). + if ($amount > 0 && $uid > 0 && function_exists('aksrt_is_download_credit_exempt_user') && aksrt_is_download_credit_exempt_user($uid)) { + $amount = 0.0; + } + + $original = (float) ($meta['original_price'] ?? 0); + + return [ + 'amount' => max(0.0, (float) $amount), + 'base' => max(0.0, (float) $base), + 'vip_amount' => $vip_amount >= 0 ? max(0.0, (float) $vip_amount) : -1.0, + 'modo' => $pay_modo, + 'currency' => $currency_label, + 'is_free' => $amount <= 0, + 'pay_limit' => $pay_limit, + 'vip_level' => $vip_level, + 'original' => $original, + 'vip1' => max(0.0, (float) $vip1), + 'vip2' => max(0.0, (float) $vip2), + ]; + } +} + // ============================================================ // 状态判断 // ============================================================ @@ -374,8 +472,15 @@ if (!function_exists('aksrt_is_download_alone_page_enabled')) { if (!function_exists('aksrt_get_pay_price_label')) { function aksrt_get_pay_price_label($post = null): array { $meta = aksrt_get_pay_meta($post); - $pay_modo = (($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0'; - $pay_limit = (int) ($meta['pay_limit'] ?? 0); + $priced = function_exists('aksrt_get_user_pay_price') + ? aksrt_get_user_pay_price($post) + : null; + $pay_modo = is_array($priced) + ? ((($priced['modo'] ?? '0') === 'points') ? 'points' : '0') + : ((($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0'); + $pay_limit = is_array($priced) + ? (int) ($priced['pay_limit'] ?? 0) + : (int) ($meta['pay_limit'] ?? 0); $currency = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_currency_name() : __('积分', 'aksrt'); $cash_symbol = '¥'; if (class_exists('AKSRT_Settings')) { @@ -384,32 +489,48 @@ if (!function_exists('aksrt_get_pay_price_label')) { } if ($meta['pay_type'] === AKSRT_PAY_TYPE_VIP || $pay_limit > 0) { - return ['text' => __('会员专属', 'aksrt'), 'free' => false, 'amount' => 0, 'modo' => $pay_modo, 'pay_limit' => $pay_limit]; + return [ + 'text' => __('会员专属', 'aksrt'), + 'free' => false, + 'amount' => 0, + 'base' => is_array($priced) ? (float) ($priced['base'] ?? 0) : 0, + 'modo' => $pay_modo, + 'pay_limit' => $pay_limit, + ]; } - if ($pay_modo === 'points') { - $price = (int) ($meta['points_price'] ?? 0); - if ($price <= 0) { - return ['text' => __('免费', 'aksrt'), 'free' => true, 'amount' => 0, 'modo' => 'points', 'pay_limit' => 0]; - } + $price = is_array($priced) + ? (float) ($priced['amount'] ?? 0) + : ($pay_modo === 'points' ? (float) ($meta['points_price'] ?? 0) : (float) ($meta['price'] ?? 0)); + $base = is_array($priced) ? (float) ($priced['base'] ?? $price) : $price; + + if ($price <= 0) { return [ - 'text' => sprintf(__('%s %s', 'aksrt'), aksrt_format_price((float) $price), $currency), - 'free' => false, - 'amount' => (float) $price, - 'modo' => 'points', + 'text' => __('免费', 'aksrt'), + 'free' => true, + 'amount' => 0, + 'base' => $base, + 'modo' => $pay_modo, 'pay_limit' => 0, ]; } - $price = (float) $meta['price']; - if ($price <= 0) { - return ['text' => __('免费', 'aksrt'), 'free' => true, 'amount' => 0, 'modo' => '0', 'pay_limit' => 0]; + if ($pay_modo === 'points') { + return [ + 'text' => sprintf(__('%s %s', 'aksrt'), aksrt_format_price($price), $currency), + 'free' => false, + 'amount' => $price, + 'base' => $base, + 'modo' => 'points', + 'pay_limit' => 0, + ]; } return [ 'text' => $cash_symbol . aksrt_format_price($price), 'free' => false, 'amount' => $price, + 'base' => $base, 'modo' => '0', 'pay_limit' => 0, ]; @@ -533,8 +654,18 @@ if (!function_exists('aksrt_get_paywall_html')) { function aksrt_get_paywall_html(WP_Post $post): string { $meta = aksrt_get_pay_meta($post); $pay_type = $meta['pay_type']; - $price = (float) $meta['price']; + $priced = function_exists('aksrt_get_user_pay_price') ? aksrt_get_user_pay_price($post) : null; + $pay_modo = is_array($priced) ? ((($priced['modo'] ?? '0') === 'points') ? 'points' : '0') : ((($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0'); + $price = is_array($priced) ? (float) ($priced['amount'] ?? 0) : (float) ($meta['price'] ?? 0); $currency = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_currency_name() : __('积分', 'aksrt'); + $cash_symbol = '¥'; + if (class_exists('AKSRT_Settings')) { + $paid = AKSRT_Settings::get_paid_content_settings(); + $cash_symbol = (string) ($paid['display']['currency_symbol'] ?? '¥'); + } + $price_text = $pay_modo === 'points' + ? (aksrt_format_price($price) . ' ' . $currency) + : ($cash_symbol . aksrt_format_price($price)); $type_labels = [ AKSRT_PAY_TYPE_READING => ['icon' => 'fa-lock', 'label' => __('付费阅读', 'aksrt'), 'desc' => __('付费后即可查看完整内容', 'aksrt')], @@ -547,10 +678,11 @@ if (!function_exists('aksrt_get_paywall_html')) { $is_logged_in = is_user_logged_in(); $original_price = (float) ($meta['original_price'] ?? 0); $has_original = $original_price > 0 && $original_price > $price; + $pay_limit = (int) ($meta['pay_limit'] ?? 0); ob_start(); ?> -