*/ if (!function_exists('aksrt_list_cash_payment_methods')) { function aksrt_list_cash_payment_methods(bool $logged_in = true): array { $ids = $logged_in ? ['balance', 'alipay', 'wechatpay', 'paypal', 'stripe', 'epay_alipay', 'epay_wxpay'] : ['alipay', 'wechatpay', 'paypal', 'stripe', 'epay_alipay', 'epay_wxpay']; if (!class_exists('\AKSRT\Payment\Gateway')) { // No gateway manager → no real methods (avoid dead balance/alipay stubs). return []; } $methods = []; $gw = \AKSRT\Payment\Gateway::get_instance(); foreach ($ids as $id) { $g = $gw->get_gateway($id); if (!$g) { continue; } if (method_exists($g, 'is_configured') && !$g->is_configured()) { continue; } $methods[] = [ 'id' => $id, 'name' => method_exists($g, 'get_name') ? (string) $g->get_name() : $id, ]; } // Do not inject a fake balance/alipay option when nothing is configured — // callers should surface “暂无可用支付方式” instead of a dead method. return $methods; } } // ============================================================ // 元数据读取 // ============================================================ if (!function_exists('aksrt_get_pay_meta')) { function aksrt_get_pay_meta($post = null): array { $p = get_post($post); if (!($p instanceof WP_Post)) return aksrt_default_pay_meta(); $meta = get_post_meta($p->ID, \AKSRT\Core\DomainModel::PAY_META_KEY, true); if (is_array($meta) && isset($meta['pay_type'])) { return wp_parse_args(\AKSRT\Core\DomainModel::sanitize_pay_meta($meta), aksrt_default_pay_meta()); } return aksrt_default_pay_meta(); } } if (!function_exists('aksrt_default_pay_meta')) { function aksrt_default_pay_meta(): array { return \AKSRT\Core\DomainModel::default_pay_meta(); } } if (!function_exists('aksrt_is_downloadable_content')) { function aksrt_is_downloadable_content($post = null): bool { $p = get_post($post); if (!($p instanceof WP_Post)) { return false; } $meta = aksrt_get_pay_meta($p); if (($meta['pay_type'] ?? AKSRT_PAY_TYPE_NO) !== AKSRT_PAY_TYPE_DOWNLOAD) { return false; } return !empty($meta['downloads']) && is_array($meta['downloads']); } } if (!function_exists('aksrt_get_download_box_meta')) { function aksrt_get_download_box_meta($post = null): array { $p = get_post($post); if (!($p instanceof WP_Post)) { return []; } if (function_exists('aksrt_get_resource_meta') && function_exists('aksrt_is_resource_post') && aksrt_is_resource_post($p)) { $meta = aksrt_get_resource_meta($p); $meta['subject_label'] = __('资源', 'aksrt'); return $meta; } $pay_meta = aksrt_get_pay_meta($p); $download_count = (int) get_post_meta($p->ID, \AKSRT\Core\DomainModel::RESOURCE_DOWNLOAD_COUNT_KEY, true); $view_count = (int) get_post_meta($p->ID, \AKSRT\Core\DomainModel::POST_VIEW_COUNT_KEY, true); $virtual_sales = max(0, (int) ($pay_meta['virtual_sales'] ?? 0)); $sales_volume = (int) get_post_meta($p->ID, \AKSRT\Core\DomainModel::RESOURCE_SALES_VOLUME_KEY, true); $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; } $over_price = $pay_meta['download_limit_over_price'] ?? ($pay_modo === 'points' ? 0 : '0.00'); return [ 'version' => (string) ($pay_meta['version'] ?? ''), 'size' => (string) ($pay_meta['size'] ?? ''), 'price' => (string) ($pay_meta['price'] ?? '0.00'), 'points_price' => (int) ($pay_meta['points_price'] ?? 0), 'pay_modo' => $pay_modo, 'pay_limit' => $pay_limit, 'original_price' => (string) ($pay_meta['original_price'] ?? '0.00'), 'vip1_price' => (string) ($pay_meta['vip1_price'] ?? '0.00'), 'vip2_price' => (string) ($pay_meta['vip2_price'] ?? '0.00'), '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'] ?? ''), 'demo_url' => (string) ($pay_meta['demo_url'] ?? ''), '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_volume' => max(0, $sales_volume), // legacy: virtual (pay_cuont) + real sales_volume; fall back to downloads when no sales yet. 'sales_count' => $show_sales ? ($virtual_sales + max(0, $sales_volume, $download_count)) : 0, 'show_sales' => $show_sales, 'download_limit_over_price' => $over_price, 'require_login' => !empty($pay_meta['require_login']), 'require_captcha' => !empty($pay_meta['require_captcha']), 'subject_label' => __('内容', 'aksrt'), ]; } } /** * Latest paid content order for a user/post (resource product_type). * * @return array|null */ if (!function_exists('aksrt_get_user_content_paid_order')) { function aksrt_get_user_content_paid_order(int $post_id, int $user_id = 0): ?array { $uid = $user_id > 0 ? $user_id : get_current_user_id(); if ($uid <= 0 || $post_id <= 0 || !class_exists('\AKSRT\Payment\OrderRepository')) { return null; } $orders = \AKSRT\Payment\OrderRepository::get_instance()->get_user_orders($uid, [ 'product_type' => \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE, 'status' => '', 'limit' => 20, 'offset' => 0, ]); foreach ($orders as $order) { if ((int) ($order['product_id'] ?? 0) !== $post_id) { continue; } $status = (string) ($order['status'] ?? ''); if (\AKSRT\Core\DomainModel::is_paid_order_status($status)) { return $order; } } return null; } } /** * Increment real sales volume for a paid content post (idempotent per order via order meta note flag optional). */ if (!function_exists('aksrt_bump_content_sales_volume')) { function aksrt_bump_content_sales_volume(int $post_id, int $delta = 1): int { if ($post_id <= 0 || $delta === 0) { return 0; } $key = \AKSRT\Core\DomainModel::RESOURCE_SALES_VOLUME_KEY; $cur = (int) get_post_meta($post_id, $key, true); $next = max(0, $cur + $delta); update_post_meta($post_id, $key, $next); return $next; } } /** * Whether guest cash purchase is allowed (legacy pay_no_logged_in + pay_limit=0). */ if (!function_exists('aksrt_allow_guest_content_pay')) { function aksrt_allow_guest_content_pay($post = null): bool { $p = get_post($post); if (!($p instanceof WP_Post)) { return false; } $meta = function_exists('aksrt_get_pay_meta') ? aksrt_get_pay_meta($p) : []; $pay_limit = (int) ($meta['pay_limit'] ?? 0); if ($pay_limit > 0) { return false; } $pay_modo = (($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0'; if ($pay_modo === 'points') { return false; // points require login } $order = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_order_settings() : []; $paid = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_paid_content_settings() : []; $allow = !empty($order['no_logged_in']) || !empty($paid['no_logged_in']); /** * Filter guest content pay allow. * * @param bool $allow * @param WP_Post $p */ return (bool) apply_filters('aksrt_allow_guest_content_pay', $allow, $p); } } /** * Cookie lifetime days for guest paid content (legacy pay_cookie_day). */ if (!function_exists('aksrt_guest_pay_cookie_days')) { function aksrt_guest_pay_cookie_days(int $post_id = 0): int { $days = 15; if (class_exists('\AKSRT\Settings\Settings')) { $order = \AKSRT\Settings\Settings::get_order_settings(); $days = max(1, min(31, (int) ($order['cookie_day'] ?? 15))); } /** * @param int $days * @param int $post_id */ return max(1, (int) apply_filters('aksrt_guest_pay_cookie_days', $days, $post_id)); } } /** * Client IP helper for cookie token binding. */ if (!function_exists('aksrt_pay_client_ip')) { function aksrt_pay_client_ip(): string { if (function_exists('aksrt_get_client_ip')) { return (string) aksrt_get_client_ip(); } return (string) ($_SERVER['REMOTE_ADDR'] ?? ''); } } /** * Build token material for guest order cookie (legacy-style). * * @param array $order */ if (!function_exists('aksrt_content_order_cookie_token_key')) { function aksrt_content_order_cookie_token_key(array $order): string { $meta = is_array($order['meta_payload'] ?? null) ? $order['meta_payload'] : []; $ip = (string) ($meta['ip_address'] ?? $order['ip_address'] ?? ''); $id = (string) ($order['id'] ?? $order['order_number'] ?? ''); $post_id = (int) ($order['product_id'] ?? $meta['post_id'] ?? 0); $num = (string) ($order['order_number'] ?? ''); $amount = function_exists('aksrt_format_price') ? aksrt_format_price((string) ($order['amount'] ?? '0.00')) : (string) ($order['amount'] ?? '0.00'); return $id . '_' . $post_id . '_' . trim($num) . '_' . $amount . '_' . trim($ip); } } /** * Set guest paid cookies after cash order paid (content). * * @param array $order */ if (!function_exists('aksrt_set_guest_pay_cookies')) { function aksrt_set_guest_pay_cookies(array $order): void { $post_id = (int) ($order['product_id'] ?? 0); $order_number = (string) ($order['order_number'] ?? ''); if ($post_id <= 0 || $order_number === '') { return; } $days = aksrt_guest_pay_cookie_days($post_id); $expire = time() + (DAY_IN_SECONDS * $days); $path = defined('COOKIEPATH') && COOKIEPATH ? COOKIEPATH : '/'; $domain = defined('COOKIE_DOMAIN') ? COOKIE_DOMAIN : ''; $secure = is_ssl(); $httponly = true; setcookie('aksrt_pay_' . $post_id, $order_number, $expire, $path, $domain, $secure, $httponly); $_COOKIE['aksrt_pay_' . $post_id] = $order_number; $token = md5(aksrt_content_order_cookie_token_key($order)); $token_name = 'aksrt_pay_token_' . md5($order_number); setcookie($token_name, $token, $expire, $path, $domain, $secure, $httponly); $_COOKIE[$token_name] = $token; } } /** * Set guest paid cookies after content order paid (legacy aksrtpay_posts_order_created_set_cookie). * * @param array $order */ if (!function_exists('aksrt_set_guest_content_pay_cookies')) { function aksrt_set_guest_content_pay_cookies(array $order): void { aksrt_set_guest_pay_cookies($order); } } /** * Resolve guest paid order from browser cookie for a product. * * @return array|null */ if (!function_exists('aksrt_get_guest_paid_order')) { function aksrt_get_guest_paid_order(int $product_id, string $product_type = ''): ?array { if ($product_id <= 0 || empty($_COOKIE['aksrt_pay_' . $product_id])) { return null; } if (!class_exists('\AKSRT\Payment\OrderRepository') || !class_exists('\AKSRT\Core\DomainModel')) { return null; } $order_number = sanitize_text_field((string) $_COOKIE['aksrt_pay_' . $product_id]); if ($order_number === '') { return null; } $order = \AKSRT\Payment\OrderRepository::get_instance()->get($order_number); if (!$order) { return null; } $ptype = sanitize_key((string) ($order['product_type'] ?? '')); $want = sanitize_key($product_type); if ($want !== '' && $ptype !== $want) { return null; } if ((int) ($order['product_id'] ?? 0) !== $product_id) { return null; } // Guest orders only (logged-in users use user_id access). if ((int) ($order['user_id'] ?? -1) !== 0) { return null; } $status = (string) ($order['status'] ?? ''); if (!\AKSRT\Core\DomainModel::is_paid_order_status($status)) { return null; } $paid_at = (string) ($order['paid_at'] ?? $order['created_at'] ?? ''); if ($paid_at !== '') { $ts = strtotime($paid_at); $days = aksrt_guest_pay_cookie_days($product_id); if ($ts !== false && ($ts + DAY_IN_SECONDS * $days) < time()) { return null; } } $token_name = 'aksrt_pay_token_' . md5($order_number); $cookie_token = isset($_COOKIE[$token_name]) ? (string) $_COOKIE[$token_name] : ''; $expect = md5(aksrt_content_order_cookie_token_key($order)); if ($cookie_token === '' || !hash_equals($expect, $cookie_token)) { return null; } return $order; } } /** * Resolve guest paid order from browser cookie for a post (content/resource). * * @return array|null */ if (!function_exists('aksrt_get_guest_content_paid_order')) { function aksrt_get_guest_content_paid_order(int $post_id): ?array { $type = class_exists('\AKSRT\Core\DomainModel') ? \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE : 'resource'; return aksrt_get_guest_paid_order($post_id, $type); } } /** * Whether current request has paid access via guest cookie (content/resource product). */ if (!function_exists('aksrt_guest_has_paid_access')) { function aksrt_guest_has_paid_access(int $post_id): bool { return null !== aksrt_get_guest_content_paid_order($post_id); } } /** * Resolve the amount a given user should pay for a post. * * @param int|WP_Post|null $post * @param int $user_id * @return array{amount:int|string,base:int|string,vip_amount:int|string|null,modo:string,currency:string,is_free:bool,pay_limit:int,vip_level:int,original:int|string,vip1:int|string,vip2:int|string} */ 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\Core\DomainModel::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\Settings') ? \AKSRT\Settings\Settings::get_currency_name() : __('积分', 'aksrt'); $cash_symbol = '¥'; $vip_settings = []; if (class_exists('\AKSRT\Settings\Settings')) { $paid = \AKSRT\Settings\Settings::get_paid_content_settings(); $cash_symbol = (string) ($paid['display']['currency_symbol'] ?? '¥'); $vip_settings = \AKSRT\Settings\Settings::get_payment_vip_settings(); } $vip_levels = is_array($vip_settings['levels'] ?? null) ? $vip_settings['levels'] : []; if ($pay_modo === 'points') { $base_minor = max(0, (int) ($meta['points_price'] ?? 0)); $vip1_minor = max(0, (int) ($meta['vip1_points'] ?? 0)); $vip2_minor = max(0, (int) ($meta['vip2_points'] ?? 0)); $currency_label = $currency; } else { $parse_cash = static function ($value): int { if (!is_string($value)) { return 0; } try { return \AKSRT\Ledger\AssetAmount::balance_minor($value); } catch (\InvalidArgumentException $e) { return 0; } }; $base_minor = $parse_cash($meta['price'] ?? '0'); $vip1_minor = $parse_cash($meta['vip1_price'] ?? '0'); $vip2_minor = $parse_cash($meta['vip2_price'] ?? '0'); $currency_label = $cash_symbol; } $vip_prices = [ 1 => $vip1_minor, 2 => $vip2_minor, ]; $vip_minor = null; for ($level = min(2, $vip_level); $level >= 1; $level--) { if (empty($vip_levels[$level]['enabled'])) { continue; } $level_price = $vip_prices[$level]; if ($level_price < $base_minor) { $vip_minor = $level_price; } break; } $amount_minor = $vip_minor ?? $base_minor; // Role/VIP free-download exemption (global setting). if ($amount_minor > 0 && $uid > 0 && function_exists('aksrt_is_download_credit_exempt_user') && aksrt_is_download_credit_exempt_user($uid)) { $amount_minor = 0; } if ($pay_modo === 'points') { $original = max(0, (int) ($meta['original_price'] ?? 0)); $amount = $amount_minor; $base = $base_minor; $vip1 = $vip1_minor; $vip2 = $vip2_minor; $vip_amount = $vip_minor; } else { $original_minor = $parse_cash($meta['original_price'] ?? '0'); $amount = \AKSRT\Ledger\AssetAmount::decimal_from_minor($amount_minor); $base = \AKSRT\Ledger\AssetAmount::decimal_from_minor($base_minor); $vip1 = \AKSRT\Ledger\AssetAmount::decimal_from_minor($vip1_minor); $vip2 = \AKSRT\Ledger\AssetAmount::decimal_from_minor($vip2_minor); $vip_amount = $vip_minor === null ? null : \AKSRT\Ledger\AssetAmount::decimal_from_minor($vip_minor); $original = \AKSRT\Ledger\AssetAmount::decimal_from_minor($original_minor); } return [ 'amount' => $amount, 'base' => $base, 'vip_amount' => $vip_amount, 'modo' => $pay_modo, 'currency' => $currency_label, 'is_free' => $amount_minor <= 0, 'pay_limit' => $pay_limit, 'vip_level' => $vip_level, 'original' => $original, 'vip1' => $vip1, 'vip2' => $vip2, ]; } } /** * Whether content cashier may accept coupons for this post (legacy coupon_post_s || coupon_s). */ if (!function_exists('aksrt_is_content_coupon_allowed')) { function aksrt_is_content_coupon_allowed($post = null): bool { $meta = function_exists('aksrt_get_pay_meta') ? aksrt_get_pay_meta($post) : []; if (!empty($meta['coupon_s'])) { return true; } if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_content_coupon_settings')) { $cfg = \AKSRT\Settings\Settings::get_content_coupon_settings(); return !empty($cfg['enabled']); } if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_paid_content_settings')) { $paid = \AKSRT\Settings\Settings::get_paid_content_settings(); return !empty($paid['coupon_post_s']); } return false; } } /** * Buyer-facing 推广折扣 amount for a post (0 if no eligible referrer). * Cash only; mirrors aksrtpay_get_post_rebate_discount. */ if (!function_exists('aksrt_get_post_rebate_discount')) { function aksrt_get_post_rebate_discount($post = null, int $user_id = 0): string { $meta = function_exists('aksrt_get_pay_meta') ? aksrt_get_pay_meta($post) : []; $fixed = is_string($meta['pay_rebate_discount'] ?? null) ? (string) $meta['pay_rebate_discount'] : '0.00'; $fixed_minor = aksrt_asset_price_minor($fixed, '0'); if ($fixed_minor <= 0) { return '0.00'; } if (!class_exists('\AKSRT\Settings\Settings') || !method_exists('\AKSRT\Settings\Settings', 'get_payment_affiliate_settings')) { return '0.00'; } $aff = \AKSRT\Settings\Settings::get_payment_affiliate_settings(); if (empty($aff['enabled'])) { return '0.00'; } $uid = $user_id > 0 ? $user_id : (function_exists('get_current_user_id') ? (int) get_current_user_id() : 0); $referrer_id = class_exists('\AKSRT\Payment\ReferralAttribution') ? \AKSRT\Payment\ReferralAttribution::get_instance()->resolve($uid) : 0; if ($referrer_id <= 0) { return '0.00'; } // Need a positive ratio for referrer (VIP tier of referrer preferred). $ratio = (int) \AKSRT\Settings\Settings::affiliate_ratio_for_user($referrer_id); if ($ratio <= 0) { return '0.00'; } return \AKSRT\Ledger\AssetAmount::decimal_from_minor($fixed_minor); } } /** * Whether cash checkout may use points deduction (legacy points_deduction). * * legacy: aksrtpay_is_allow_points_deduction() always returns false ("暂未启用"). * Keep the same contract: schema/UI may exist, runtime is hard-off unless filter overrides. */ if (!function_exists('aksrt_is_allow_points_deduction')) { function aksrt_is_allow_points_deduction(string $context = 'content'): bool { // Mirror legacy hard-off first. $allowed = false; if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_all')) { $all = \AKSRT\Settings\Settings::get_all(); // Even if switch on, default remains false like legacy until product enables it. if (!empty($all['points_deduction_s']) && class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'credits_enabled') && \AKSRT\Settings\Settings::credits_enabled()) { $allowed = false; // still disabled at runtime } } return (bool) apply_filters('aksrt_is_allow_points_deduction', $allowed, $context); } } /** * Content cashier does not accept card_pass payment_method. * Card-pass for balance/VIP/points is user-center redeem (legacy order types 4/8/9), * not content pay types (reading/download/gallery/video). */ if (!function_exists('aksrt_is_content_card_pass_pay_allowed')) { function aksrt_is_content_card_pass_pay_allowed($post = null): bool { return (bool) apply_filters('aksrt_is_content_card_pass_pay_allowed', false, $post); } } // ============================================================ // 状态判断 // ============================================================ if (!function_exists('aksrt_is_paid_post')) { function aksrt_is_paid_post($post = null): bool { return aksrt_get_pay_meta($post)['pay_type'] !== AKSRT_PAY_TYPE_NO; } } if (!function_exists('aksrt_is_paid_reading')) { function aksrt_is_paid_reading($post = null): bool { return aksrt_get_pay_meta($post)['pay_type'] === AKSRT_PAY_TYPE_READING; } } /** * Detect the canonical paid-fragment shortcode in a post's raw content. * * The editor writes this exact shortcode format, so this is the single * source of truth for whether a reading price has any protected fragment to * apply to. It deliberately does not inspect rendered content. */ if (!function_exists('aksrt_post_has_payshow_shortcode')) { function aksrt_post_has_payshow_shortcode($post = null): bool { $p = get_post($post); if (!($p instanceof WP_Post)) { return false; } return preg_match( '/\[hidecontent\b[^\]]*\btype\s*=\s*(?:"payshow"|\'payshow\'|payshow)[^\]]*\]/i', (string) $p->post_content ) === 1; } } /** * A paid fragment is active only for an explicitly priced paid-reading post. * * A zero-price reading configuration is intentionally public: authors can * save content before setting a price without accidentally hiding it. */ if (!function_exists('aksrt_is_payshow_purchase_enabled')) { function aksrt_is_payshow_purchase_enabled($post = null): bool { if (!aksrt_post_has_payshow_shortcode($post)) { return false; } $meta = aksrt_get_pay_meta($post); if (($meta['pay_type'] ?? AKSRT_PAY_TYPE_NO) !== AKSRT_PAY_TYPE_READING) { return false; } $pay_modo = ($meta['pay_modo'] ?? '0') === 'points' ? 'points' : '0'; $price = $pay_modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00'); return aksrt_asset_price_minor($price, $pay_modo) > 0; } } if (!function_exists('aksrt_is_paid_download')) { function aksrt_is_paid_download($post = null): bool { return aksrt_get_pay_meta($post)['pay_type'] === AKSRT_PAY_TYPE_DOWNLOAD; } } if (!function_exists('aksrt_is_paid_gallery')) { function aksrt_is_paid_gallery($post = null): bool { return aksrt_get_pay_meta($post)['pay_type'] === AKSRT_PAY_TYPE_GALLERY; } } if (!function_exists('aksrt_is_paid_video')) { function aksrt_is_paid_video($post = null): bool { return aksrt_get_pay_meta($post)['pay_type'] === AKSRT_PAY_TYPE_VIDEO; } } if (!function_exists('aksrt_is_vip_only')) { function aksrt_is_vip_only($post = null): bool { return aksrt_get_pay_meta($post)['pay_type'] === AKSRT_PAY_TYPE_VIP; } } // ============================================================ // 付费状态检查 // ============================================================ if (!function_exists('aksrt_has_paid_access')) { function aksrt_has_paid_access($post = null, int $user_id = 0): bool { $p = get_post($post); if (!($p instanceof WP_Post)) return true; // 单一真相:付费访问由 \AKSRT\Content\Visibility(基于订单 + VIP)裁决。 if (class_exists('\AKSRT\Content\Visibility')) { $state = \AKSRT\Content\Visibility::get_post_access_state($p, $user_id); return !empty($state['has_paid_access']); } // 兜底:仅在 service 不可用时使用,避免离线环境直接拒绝。 $meta = aksrt_get_pay_meta($p); if ($meta['pay_type'] === AKSRT_PAY_TYPE_NO) return true; $pay_modo = ($meta['pay_modo'] ?? '0') === 'points' ? 'points' : '0'; $price = $pay_modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00'); if (aksrt_asset_price_minor($price, $pay_modo) <= 0 && $meta['pay_type'] !== AKSRT_PAY_TYPE_VIP) return true; $uid = $user_id > 0 ? $user_id : get_current_user_id(); if ($uid > 0 && function_exists('aksrt_is_vip_exempt') && aksrt_is_vip_exempt($uid)) return true; if ($uid > 0 && get_user_meta($uid, '_aksrt_paid_' . $p->ID, true)) return true; return false; } } if (!function_exists('aksrt_can_access_content')) { function aksrt_can_access_content($post = null): bool { $p = get_post($post); if (!($p instanceof WP_Post)) return true; if (class_exists('\AKSRT\Content\Visibility')) { return \AKSRT\Content\Visibility::can_view_paid_content($p); } $pay_type = aksrt_get_pay_meta($p)['pay_type']; if ($pay_type === AKSRT_PAY_TYPE_NO) return true; // 只有 reading/gallery/video 需要隐藏内容 if (!in_array($pay_type, [AKSRT_PAY_TYPE_READING, AKSRT_PAY_TYPE_GALLERY, AKSRT_PAY_TYPE_VIDEO], true)) { return true; } return aksrt_has_paid_access($p); } } if (!function_exists('aksrt_get_download_cost')) { function aksrt_get_download_cost($post = null): int { if (function_exists('aksrt_resource_download_cost')) { return (int) aksrt_resource_download_cost($post); } $meta = aksrt_get_pay_meta($post); if (($meta['pay_modo'] ?? '0') !== 'points') { return 0; } return max(0, (int) ($meta['points_price'] ?? 0)); } } /** * URL of the legacy-style single-post download page (page template + ?post=ID). */ if (!function_exists('aksrt_get_single_download_page_url')) { function aksrt_get_single_download_page_url($post = null): string { $p = get_post($post); if (!($p instanceof WP_Post)) { return ''; } $page_url = ''; if (function_exists('aksrt_find_template_page')) { $page = aksrt_find_template_page('templates/pages/page-download-file.php'); if ($page instanceof WP_Post) { $page_url = get_permalink($page); } } if ($page_url === '') { // Fallback: look for any page using the template via slug convention. $page_url = home_url('/download-file/'); } return add_query_arg('post', (int) $p->ID, $page_url); } } // ============================================================ // 价格显示 // ============================================================ if (!function_exists('aksrt_get_pay_price_label')) { function aksrt_get_pay_price_label($post = null): array { $meta = aksrt_get_pay_meta($post); $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); $vip_level = is_array($priced) ? (int) ($priced['vip_level'] ?? 0) : 0; $currency = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_currency_name() : __('积分', 'aksrt'); $cash_symbol = '¥'; if (class_exists('\AKSRT\Settings\Settings')) { $paid = \AKSRT\Settings\Settings::get_paid_content_settings(); $cash_symbol = (string) ($paid['display']['currency_symbol'] ?? '¥'); } // pay_type VIP-only or pay_limit not met → member-exclusive badge. $member_blocked = ($meta['pay_type'] === AKSRT_PAY_TYPE_VIP) || ($pay_limit > 0 && $vip_level < $pay_limit); if ($member_blocked) { return [ 'text' => __('会员专属', 'aksrt'), 'free' => false, 'amount' => 0, 'base' => is_array($priced) ? ($priced['base'] ?? ($pay_modo === 'points' ? 0 : '0.00')) : ($pay_modo === 'points' ? 0 : '0.00'), 'modo' => $pay_modo, 'pay_limit' => $pay_limit, ]; } $price = is_array($priced) ? ($priced['amount'] ?? ($pay_modo === 'points' ? 0 : '0.00')) : ($pay_modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00')); $base = is_array($priced) ? ($priced['base'] ?? $price) : $price; $price_minor = aksrt_asset_price_minor($price, $pay_modo); if ($price_minor <= 0) { return [ 'text' => __('免费', 'aksrt'), 'free' => true, 'amount' => 0, 'base' => $base, 'modo' => $pay_modo, 'pay_limit' => $pay_limit, ]; } 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' => $pay_limit, ]; } return [ 'text' => $cash_symbol . aksrt_format_price($price), 'free' => false, 'amount' => $price, 'base' => $base, 'modo' => '0', 'pay_limit' => $pay_limit, ]; } } if (!function_exists('aksrt_format_price')) { function aksrt_format_price($price): string { if (is_int($price)) { return (string) max(0, $price); } if (!is_string($price)) { return '0'; } try { $decimal = \AKSRT\Ledger\AssetAmount::balance($price)->decimal(); } catch (\InvalidArgumentException $e) { return '0'; } return str_ends_with($decimal, '.00') ? substr($decimal, 0, -3) : rtrim($decimal, '0'); } } // ============================================================ // 付费类型徽章 // ============================================================ if (!function_exists('aksrt_get_pay_type_badge')) { function aksrt_get_pay_type_badge(string $pay_type): string { $badges = [ AKSRT_PAY_TYPE_READING => ['label' => __('付费阅读', 'aksrt'), 'color' => '#EF4444', 'icon' => 'fa-lock'], AKSRT_PAY_TYPE_DOWNLOAD => ['label' => __('付费下载', 'aksrt'), 'color' => '#F97316', 'icon' => 'fa-download'], AKSRT_PAY_TYPE_GALLERY => ['label' => __('付费图库', 'aksrt'), 'color' => '#10B981', 'icon' => 'fa-image'], AKSRT_PAY_TYPE_VIDEO => ['label' => __('付费视频', 'aksrt'), 'color' => '#8B5CF6', 'icon' => 'fa-play-circle'], AKSRT_PAY_TYPE_VIP => ['label' => __('VIP 专属', 'aksrt'), 'color' => '#3B82F6', 'icon' => 'fa-certificate'], ]; if (!isset($badges[$pay_type])) return ''; $b = $badges[$pay_type]; return sprintf( ' %s', esc_attr($b['color']), esc_attr($b['icon']), esc_html($b['label']) ); } } /** * legacy aksrtpay_get_service() — service bullets under pay/download box. * * @return string HTML list of service items. */ if (!function_exists('aksrt_get_pay_service_html')) { function aksrt_get_pay_service_html(string $class = 'resource-download-box__guarantee'): string { $service = []; if (class_exists('\AKSRT\Settings\Settings')) { $order = \AKSRT\Settings\Settings::get_order_settings(); $service = is_array($order['service'] ?? null) ? $order['service'] : []; } $text = trim((string) ($service['text'] ?? '')); $value = trim((string) ($service['value'] ?? '')); $icon = trim((string) ($service['icon'] ?? 'fa fas fa-check-circle')); if ($icon === '') { $icon = 'fa fas fa-check-circle'; } $lines = []; if ($text !== '') { $lines = preg_split('/\r\n|\r|\n/', $text) ?: []; } if ($value !== '') { $lines[] = $value; } $lines = array_values(array_filter(array_map('trim', $lines))); $html = ''; foreach ($lines as $line) { $html .= ''; $html .= ' '; $html .= esc_html($line); $html .= ''; } return $html; } } /** * Demo link button (legacy aksrtpay_get_demo_link). */ if (!function_exists('aksrt_get_demo_link_html')) { function aksrt_get_demo_link_html($post = null, string $class = 'resource-download-box__btn btn-outline resource-download-box__btn--demo'): string { $p = get_post($post); if (!($p instanceof WP_Post)) { return ''; } $meta = aksrt_get_pay_meta($p); if (($meta['pay_type'] ?? '') !== AKSRT_PAY_TYPE_DOWNLOAD) { return ''; } $url = trim((string) ($meta['demo_url'] ?? '')); if ($url === '') { return ''; } $text = __('查看演示', 'aksrt'); return sprintf( '%s', esc_url($url), esc_attr($class), esc_html($text) ); } } /** * Product attributes row (legacy aksrtpay_get_product_attributes). */ if (!function_exists('aksrt_get_pay_attributes_html')) { function aksrt_get_pay_attributes_html($post = null, string $class = 'resource-download-box__attrs'): string { $p = get_post($post); if (!($p instanceof WP_Post)) { return ''; } $meta = aksrt_get_pay_meta($p); $attrs = is_array($meta['attributes'] ?? null) ? $meta['attributes'] : []; // Built-in version/size/license/compat as attributes when set. $builtin = [ 'version' => __('版本', 'aksrt'), 'size' => __('大小', 'aksrt'), 'license' => __('授权', 'aksrt'), 'compat' => __('兼容', 'aksrt'), ]; $rows = []; foreach ($builtin as $key => $label) { $val = trim((string) ($meta[$key] ?? '')); if ($val !== '') { $rows[] = ['name' => $label, 'value' => $val]; } } foreach ($attrs as $row) { if (!is_array($row)) { continue; } $name = trim((string) ($row['name'] ?? $row['key'] ?? $row['label'] ?? '')); $value = trim((string) ($row['value'] ?? $row['val'] ?? '')); if ($name === '' || $value === '') { continue; } $rows[] = ['name' => $name, 'value' => $value]; } if ($rows === []) { return ''; } $html = '
    '; foreach ($rows as $row) { $html .= '
  • '; $html .= '' . esc_html($row['name']) . ''; $html .= '' . esc_html($row['value']) . ''; $html .= '
  • '; } $html .= '
'; return $html; } } /** * Render the configured icon for a paid-content VIP tier. */ if (!function_exists('aksrt_get_pay_vip_icon_html')) { function aksrt_get_pay_vip_icon_html(array $level_settings, string $class = 'mr3 em14'): string { $icon_url = esc_url((string) ($level_settings['img_icon'] ?? '')); if ($icon_url === '') { return ''; } return ''; } } /** * Render the reference-theme base-price block for a paid article. */ if (!function_exists('aksrt_get_show_pay_price_html')) { function aksrt_get_show_pay_price_html(array $meta, array $priced, string $class = 'c-red'): string { $modo = (($priced['modo'] ?? '0') === 'points') ? 'points' : '0'; $base = $priced['base'] ?? ($modo === 'points' ? 0 : '0.00'); $pay_limit = (int) ($priced['pay_limit'] ?? ($meta['pay_limit'] ?? 0)); $cash_symbol = '¥'; $points_name = __('积分', 'aksrt'); $vip_settings = []; if (class_exists('\AKSRT\Settings\Settings')) { $paid_settings = \AKSRT\Settings\Settings::get_paid_content_settings(); $cash_symbol = (string) ($paid_settings['display']['currency_symbol'] ?? '¥'); $points_name = \AKSRT\Settings\Settings::get_currency_name(); $vip_settings = \AKSRT\Settings\Settings::get_payment_vip_settings(); } $vip_levels = is_array($vip_settings['levels'] ?? null) ? $vip_settings['levels'] : []; if ($pay_limit > 0 && !empty($vip_settings['enabled'])) { $level_settings = is_array($vip_levels[$pay_limit] ?? null) ? $vip_levels[$pay_limit] : []; $level_name = (string) ($level_settings['name'] ?? sprintf(__('VIP%d', 'aksrt'), $pay_limit)); $title = $pay_limit === 2 ? sprintf(__('仅%s可购买', 'aksrt'), $level_name) : sprintf(__('%s及以上会员可购买', 'aksrt'), $level_name); $icon = aksrt_get_pay_vip_icon_html($level_settings); return '
' . $icon . esc_html__('会员专属资源', 'aksrt') . '
'; } if ($modo === 'points') { return '
' . esc_html(aksrt_format_price($base)) . '' . esc_html($points_name) . '
'; } $mark = '' . esc_html($cash_symbol) . ''; $base_minor = aksrt_asset_price_minor($base, '0'); $original = $meta['original_price'] ?? '0.00'; $original_minor = aksrt_asset_price_minor($original, '0'); $original_html = ''; if ($original_minor > $base_minor) { $original_html = '' . $mark . esc_html(aksrt_format_price($original)) . ''; } $promotion_tag = trim((string) ($meta['promotion_tag'] ?? '')); if ($promotion_tag !== '' && $original_minor > 0) { $original_html = '
' . wp_kses_post($promotion_tag) . '
' . $original_html . '
'; } $price = '
' . $mark . esc_html(aksrt_format_price($base)) . '' . $original_html . '
'; return '
' . $price . '
'; } } /** * Render all enabled VIP prices for a paid article. */ if (!function_exists('aksrt_get_posts_vip_price')) { function aksrt_get_posts_vip_price(array $meta): string { if (!class_exists('\AKSRT\Settings\Settings')) { return ''; } $vip_settings = \AKSRT\Settings\Settings::get_payment_vip_settings(); if (empty($vip_settings['enabled'])) { return ''; } $levels = is_array($vip_settings['levels'] ?? null) ? $vip_settings['levels'] : []; $modo = (($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0'; $base = $modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00'); $base_minor = aksrt_asset_price_minor($base, $modo); if ($base_minor <= 0) { return ''; } $mark = $modo === 'points' ? '' : '' . esc_html((string) (\AKSRT\Settings\Settings::get_paid_content_settings()['display']['currency_symbol'] ?? '¥')) . ''; $user_id = get_current_user_id(); $user_vip_level = $user_id > 0 && function_exists('aksrt_get_user_vip_level') ? (int) aksrt_get_user_vip_level($user_id) : 0; $items = []; foreach ([1, 2] as $level) { $level_settings = is_array($levels[$level] ?? null) ? $levels[$level] : []; if (empty($level_settings['enabled'])) { continue; } $key = $modo === 'points' ? 'vip' . $level . '_points' : 'vip' . $level . '_price'; $value = $meta[$key] ?? ($modo === 'points' ? 0 : '0.00'); $vip_minor = aksrt_asset_price_minor($value, $modo); if ($vip_minor >= $base_minor) { continue; } $level_name = (string) ($level_settings['name'] ?? sprintf(__('VIP%d', 'aksrt'), $level)); $price = $vip_minor === 0 ? esc_html__('免费', 'aksrt') : $mark . esc_html(aksrt_format_price($value)); $icon = aksrt_get_pay_vip_icon_html($level_settings); $action_class = $user_id <= 0 ? ' signin-loader' : ($user_vip_level < $level ? ' pay-vip' : ''); $title = sprintf(__('开通%s', 'aksrt'), $level_name); $title_attr = $action_class !== '' ? ' data-toggle="tooltip" title="' . esc_attr($title) . '"' : ''; $items[] = '' . $icon . esc_html($level_name) . '' . $price . ''; } $html = implode('', $items); if (count($items) > 1) { $html = '' . $html . ''; } return $html; } } // ============================================================ // 付费墙 HTML // ============================================================ if (!function_exists('aksrt_get_paywall_html')) { function aksrt_get_paywall_html(WP_Post $post, array $args = []): string { $is_widget = ($args['layout'] ?? 'article') === 'widget'; $theme = sanitize_html_class((string) ($args['theme'] ?? 'jb-red')) ?: 'jb-red'; $meta = aksrt_get_pay_meta($post); $pay_type = (string) ($meta['pay_type'] ?? AKSRT_PAY_TYPE_NO); if ($pay_type === AKSRT_PAY_TYPE_NO) return ''; $priced = aksrt_get_user_pay_price($post); $modo = (string) ($priced['modo'] ?? '0'); $amount = $priced['amount'] ?? 0; $amount_minor = aksrt_asset_price_minor($amount, $modo); $pay_limit = (int) ($priced['pay_limit'] ?? ($meta['pay_limit'] ?? 0)); $vip_level = (int) ($priced['vip_level'] ?? 0); $pay_vip_settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_vip_settings() : []; $member_blocked = $pay_limit > 0 && !empty($pay_vip_settings['enabled']) && $vip_level < $pay_limit; $type_labels = [ AKSRT_PAY_TYPE_READING => __('付费阅读', 'aksrt'), AKSRT_PAY_TYPE_DOWNLOAD => __('付费下载', 'aksrt'), AKSRT_PAY_TYPE_GALLERY => __('付费图库', 'aksrt'), AKSRT_PAY_TYPE_VIDEO => __('付费视频', 'aksrt'), AKSRT_PAY_TYPE_VIP => __('VIP 专属', 'aksrt'), ]; $type_label = $type_labels[$pay_type] ?? __('付费内容', 'aksrt'); $order_types = [ AKSRT_PAY_TYPE_READING => 1, AKSRT_PAY_TYPE_DOWNLOAD => 2, AKSRT_PAY_TYPE_GALLERY => 5, AKSRT_PAY_TYPE_VIDEO => 6, AKSRT_PAY_TYPE_VIP => 4, ]; $order_type = (int) ($order_types[$pay_type] ?? 1); $title = get_the_title($post); $doc = trim((string) ($args['message'] ?? '')); if ($doc === '') { $doc = sprintf(__('此内容为%s,请付费后查看', 'aksrt'), $type_label); } $sales = max(0, (int) ($meta['virtual_sales'] ?? 0)); $sales += max(0, (int) get_post_meta($post->ID, \AKSRT\Core\DomainModel::RESOURCE_SALES_VOLUME_KEY, true)); $tag = $is_widget ? '' . esc_html($type_label) . '' : '
' . esc_html($type_label) . '
'; $block_class = $is_widget ? ' btn-block' : ''; $button = ''; if ($member_blocked) { $level_settings = is_array($pay_vip_settings['levels'][$pay_limit] ?? null) ? $pay_vip_settings['levels'][$pay_limit] : []; $level_name = (string) ($level_settings['name'] ?? sprintf(__('VIP%d', 'aksrt'), $pay_limit)); $vip_action = $vip_level > 0 ? sprintf(__('升级%s', 'aksrt'), $level_name) : __('开通会员', 'aksrt'); $action_class = is_user_logged_in() ? 'pay-vip' : 'signin-loader'; $icon = aksrt_get_pay_vip_icon_html($level_settings); $button = '
' . esc_html(sprintf(__('您暂无购买权限,请先%s', 'aksrt'), $vip_action)) . '
'; $button .= '' . $icon . esc_html($vip_action) . ''; } elseif (!is_user_logged_in()) { if ($amount_minor > 0 && $modo === '0' && aksrt_allow_guest_content_pay($post)) { $button = ''; } else { $button = ''; } } elseif ($amount_minor > 0) { $button = ''; } else { $button = ''; } $price = aksrt_get_show_pay_price_html($meta, $priced); $vip = aksrt_get_posts_vip_price($meta); $attrs = aksrt_get_pay_attributes_html($post, 'pay-attr'); $count = $sales > 0 ? '' . esc_html(sprintf(__('已售 %s', 'aksrt'), $sales)) . '' : ''; $service = aksrt_get_pay_service_html('muted-2-color'); $widget_service = $service !== '' ? '
' . $service . '
' : ''; $article_service = $service !== '' ? '
' . $service . '
' : ''; $demo = aksrt_get_demo_link_html($post, 'but jb-yellow padding-lg'); $demo_row = $demo !== '' ? '
' . $demo . '
' : ''; $discount = $modo === '0' ? aksrt_get_post_rebate_discount($post) : '0.00'; $discount_text = aksrt_asset_price_minor($discount, '0') > 0 ? sprintf(__('推广优惠 %s', 'aksrt'), (string) ($priced['currency'] ?? '¥') . aksrt_format_price($discount)) : ''; $discount_banner = $discount_text !== '' ? '
' . esc_html($discount_text) . '
' : ''; if ($is_widget && aksrt_has_paid_access($post)) { $view_labels = [ AKSRT_PAY_TYPE_DOWNLOAD => '' . esc_html__('获取下载地址', 'aksrt'), AKSRT_PAY_TYPE_GALLERY => '' . esc_html__('查看图片', 'aksrt'), AKSRT_PAY_TYPE_VIDEO => '' . esc_html__('查看视频', 'aksrt'), ]; $view_label = $view_labels[$pay_type] ?? '' . esc_html__('查看内容', 'aksrt'); return ''; } if ($is_widget) { return '
' . $tag . '
' . $price . '
' . $vip . '
' . $discount_banner . '
' . $widget_service . '
' . $button . '
' . $demo_row . $attrs . '
' . $count . '
'; } $thumb = get_the_post_thumbnail($post, 'medium', ['class' => 'fit-cover', 'alt' => '']); if ($thumb === '') { $thumb = '
'; } $graphic_actions = ''; if ($demo !== '' || $discount_text !== '') { $graphic_actions = '
'; $graphic_actions .= $demo !== '' ? '
' . $demo . '
' : ''; $graphic_actions .= $discount_text !== '' ? '' : ''; $graphic_actions .= '
'; } $discount_mobile = $discount_text !== '' ? '
' . esc_html($discount_text) . '
' : ''; if ($pay_type === AKSRT_PAY_TYPE_GALLERY) { $gallery_count = count((array) ($meta['gallery'] ?? [])); $graphic = '
' . $thumb . '
' . esc_html(sprintf(__('共%s张图片', 'aksrt'), $gallery_count)) . '
' . esc_html__('请付费后查看', 'aksrt') . '
' . $graphic_actions . '
'; } elseif ($pay_type === AKSRT_PAY_TYPE_VIDEO) { $graphic = '
' . $thumb . '
' . $graphic_actions . '
'; } else { $graphic = '
' . $thumb . $graphic_actions . '
'; } $demo_mobile = $demo !== '' ? '
' . $demo . '
' : ''; return '
' . $graphic . '
' . esc_html($title) . '
' . wp_kses_post($doc) . '
' . $price . '
' . $discount_mobile . ($vip !== '' ? '
' . $vip . '
' : '') . '
' . $button . '
' . $article_service . $demo_mobile . $attrs . $tag . $count . '
'; } } /** * Resolve the paid order that granted access to a post, when access came from * an actual purchase rather than a free or VIP entitlement. * * @return array|null */ if (!function_exists('aksrt_get_current_content_paid_order')) { function aksrt_get_current_content_paid_order(WP_Post $post): ?array { if (is_user_logged_in()) { return aksrt_get_user_content_paid_order($post->ID); } return aksrt_get_guest_content_paid_order($post->ID); } } /** * Reference-theme download actions used inside the purchased article card. */ if (!function_exists('aksrt_get_paid_download_actions_html')) { function aksrt_get_paid_download_actions_html(array $meta): string { $downloads = is_array($meta['downloads'] ?? null) ? array_values($meta['downloads']) : []; if ($downloads === []) { return '
' . esc_html__('暂无可下载资源', 'aksrt') . '
'; } // 下载总开关关闭 = 直连模式:按钮直接输出原始地址,不走本站中转链接。 $direct_download = class_exists('\AKSRT\Content\Download') && !\AKSRT\Content\Download::get_instance()->is_enabled(); $buttons = ''; foreach ($downloads as $index => $download) { if (!is_array($download)) { continue; } $url = (string) ($download['url'] ?? ''); if ($direct_download && $url === '') { // 直连模式没有可用的原始地址,空源不渲染。 continue; } $label = trim((string) ($download['label'] ?? '')); $service = function_exists('aksrt_detect_cloud_service') ? aksrt_detect_cloud_service($url) : ['key' => 'other', 'name' => __('本地下载', 'aksrt')]; if ($label === '') { $label = (string) ($service['name'] ?? __('本地下载', 'aksrt')); } $type = sanitize_key((string) ($download['type'] ?? 'direct')); $extract_code = trim((string) ($download['extract_code'] ?? '')); $has_extract = $extract_code !== ''; $service_key = sanitize_html_class((string) ($service['key'] ?? 'other')) ?: 'other'; $button_class = trim((string) ($download['class'] ?? '')); $button_class = $button_class !== '' ? $button_class : 'b-theme ' . $service_key; $copy_value = trim((string) ($download['copy_val'] ?? '')); $copy_key = trim((string) ($download['copy_key'] ?? '')); $copy_label = $extract_code !== '' ? $extract_code : ($copy_key !== '' ? $copy_key : __('更多内容', 'aksrt')); $buttons .= '
'; if ($direct_download) { $buttons .= ''; $buttons .= '' . esc_html($label) . ''; } else { $buttons .= ''; } if ($copy_value !== '') { $buttons .= ''; } elseif ($extract_code !== '') { $buttons .= '' . esc_html($extract_code) . ''; } $buttons .= '
'; } return $buttons !== '' ? '
' . $buttons . '
' : '
' . esc_html__('暂无可下载资源', 'aksrt') . '
'; } } /** * Purchased article card matching Zibll's paid-box structure. */ if (!function_exists('aksrt_get_paid_box_html')) { function aksrt_get_paid_box_html(WP_Post $post): string { if (!aksrt_has_paid_access($post)) { return ''; } $meta = aksrt_get_pay_meta($post); $pay_type = (string) ($meta['pay_type'] ?? AKSRT_PAY_TYPE_NO); if ($pay_type === AKSRT_PAY_TYPE_NO) { return ''; } $order_types = [ AKSRT_PAY_TYPE_READING => 1, AKSRT_PAY_TYPE_DOWNLOAD => 2, AKSRT_PAY_TYPE_GALLERY => 5, AKSRT_PAY_TYPE_VIDEO => 6, AKSRT_PAY_TYPE_VIP => 4, ]; $type_labels = [ AKSRT_PAY_TYPE_READING => __('付费阅读', 'aksrt'), AKSRT_PAY_TYPE_DOWNLOAD => __('付费下载', 'aksrt'), AKSRT_PAY_TYPE_GALLERY => __('付费图库', 'aksrt'), AKSRT_PAY_TYPE_VIDEO => __('付费视频', 'aksrt'), AKSRT_PAY_TYPE_VIP => __('VIP 专属', 'aksrt'), ]; $order_type = (int) ($order_types[$pay_type] ?? 1); $type_label = (string) ($type_labels[$pay_type] ?? __('付费内容', 'aksrt')); $title = get_the_title($post); $sales = max(0, (int) ($meta['virtual_sales'] ?? 0)); $sales += max(0, (int) get_post_meta($post->ID, \AKSRT\Core\DomainModel::RESOURCE_SALES_VOLUME_KEY, true)); $count = $sales > 0 ? '' . esc_html(sprintf(__('已售 %s', 'aksrt'), $sales)) . '' : ''; $order = aksrt_get_current_content_paid_order($post); $priced = aksrt_get_user_pay_price($post); $vip_level = max(0, min(2, (int) ($priced['vip_level'] ?? 0))); $header = ''; $paid_box = ''; if (is_array($order)) { $order_number = (string) ($order['order_number'] ?? ''); $paid_at = (string) ($order['paid_at'] ?? $order['created_at'] ?? ''); $order_currency = (string) ($order['currency'] ?? ''); $order_amount = $order['amount'] ?? '0.00'; if ($order_currency === 'points') { $currency_name = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_currency_name() : __('积分', 'aksrt'); $amount_text = aksrt_format_price($order_amount) . ' ' . $currency_name; } else { $cash_symbol = '¥'; if (class_exists('\AKSRT\Settings\Settings')) { $settings = \AKSRT\Settings\Settings::get_paid_content_settings(); $cash_symbol = (string) ($settings['display']['currency_symbol'] ?? '¥'); } $amount_text = $cash_symbol . aksrt_format_price($order_amount); } $paid_info = '
' . esc_html__('订单号', 'aksrt') . '' . esc_html($order_number) . '
'; if ($paid_at !== '') { $paid_info .= '
' . esc_html__('支付时间', 'aksrt') . '' . esc_html($paid_at) . '
'; } $paid_info .= '
' . esc_html__('支付金额', 'aksrt') . '' . esc_html($amount_text) . '
'; $paid_box = '
' . esc_html__('已购买', 'aksrt') . '
'; } elseif ($vip_level > 0 || $pay_type === AKSRT_PAY_TYPE_VIP) { $level = max(1, $vip_level); $price_label = aksrt_get_pay_price_label($post); $price = '
' . esc_html((string) ($price_label['text'] ?? '')) . '
'; $paid_box = '
' . $price . '
' . esc_html(sprintf(__('VIP%d 会员免费', 'aksrt'), $level)) . '
'; } else { $type_label = str_replace(__('付费', 'aksrt'), __('免费', 'aksrt'), $type_label); } if ($pay_type === AKSRT_PAY_TYPE_GALLERY) { $header = aksrt_render_paid_gallery($post); } elseif ($pay_type === AKSRT_PAY_TYPE_VIDEO) { $header = aksrt_render_paid_video($post); } $download_box = ''; $root_data = ''; $captcha = ''; if ($pay_type === AKSRT_PAY_TYPE_DOWNLOAD) { $captcha_active = function_exists('aksrt_is_captcha_enabled_for') && aksrt_is_captcha_enabled_for('download'); $root_data = ' data-aksrt-download-box data-post-id="' . esc_attr((string) $post->ID) . '" data-captcha="' . ($captcha_active ? '1' : '0') . '"'; $download_box = '
' . esc_html__('资源下载', 'aksrt') . '
' . aksrt_get_paid_download_actions_html($meta) . '
'; $demo = aksrt_get_demo_link_html($post, 'but jb-yellow padding-lg'); if ($demo !== '') { $download_box .= '
' . $demo . '
'; } $download_box .= aksrt_get_pay_attributes_html($post, 'pay-attr'); if ($captcha_active && function_exists('aksrt_render_captcha')) { ob_start(); aksrt_render_captcha('download'); $captcha = '
' . (string) ob_get_clean() . '
'; } } $service = aksrt_get_pay_service_html('inline-block ml10'); $service = $service !== '' ? '
' . $service . '
' : ''; $title_style = $count !== '' ? ' style="padding-right:48px"' : ''; $body_class = 'box-body relative' . ($pay_type === AKSRT_PAY_TYPE_VIDEO ? ' dplayer-featured' : ''); return ''; } } // ============================================================ // 付费图库轮播(Swiper) // ============================================================ if (!function_exists('aksrt_render_paid_gallery')) { function aksrt_render_paid_gallery(WP_Post $post): string { $meta = aksrt_get_pay_meta($post); if ($meta['pay_type'] !== AKSRT_PAY_TYPE_GALLERY) return ''; $images = $meta['gallery'] ?? []; if (empty($images)) return ''; if (!aksrt_has_paid_access($post)) return ''; $count = count($images); $backdrop = (string) end($images); ob_start(); ?>
frameborder="0" allowfullscreen>
' . wp_kses_post($preview) . '' : ''; } } // ============================================================ // 付费图库/视频样式 // ============================================================ add_action('wp_head', function (): void { if (is_admin() || !is_singular()) return; global $post; if (!($post instanceof WP_Post)) return; $meta = aksrt_get_pay_meta($post); if (!in_array($meta['pay_type'], [AKSRT_PAY_TYPE_GALLERY, AKSRT_PAY_TYPE_VIDEO], true)) return; ?>