feat(pay): wire VIP-tier pricing into cost, gates, and download box
Resolve user-facing pay amounts via aksrt_get_user_pay_price (cash/points + VIP1/2 tiers), surface pay_modo/pay_limit through download meta and REST policy, and tighten content-visibility / download-box UX for member-only and purchase gates while improving local stream throttle math.
This commit is contained in:
1 parent
1c8e4d3919
commit
abe2f57417
5 files changed
+459
-127
No files matched your search
+160
-22
@@ -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();
|
||||
?>
|
||||
<div class="aksrt-paywall" data-post-id="<?php echo esc_attr((string) $post->ID); ?>" data-pay-type="<?php echo esc_attr($pay_type); ?>">
|
||||
<div class="aksrt-paywall" data-post-id="<?php echo esc_attr((string) $post->ID); ?>" data-pay-type="<?php echo esc_attr($pay_type); ?>" data-pay-modo="<?php echo esc_attr($pay_modo); ?>">
|
||||
<div class="aksrt-paywall__overlay">
|
||||
<div class="aksrt-paywall__blur"></div>
|
||||
<div class="aksrt-paywall__card">
|
||||
@@ -560,10 +692,12 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
<h3 class="aksrt-paywall__title"><?php echo esc_html($type_info['label']); ?></h3>
|
||||
<p class="aksrt-paywall__desc"><?php echo esc_html($type_info['desc']); ?></p>
|
||||
<div class="aksrt-paywall__price">
|
||||
<?php if ($price > 0) : ?>
|
||||
<span class="aksrt-paywall__price-amount"><?php echo esc_html(aksrt_format_price($price) . ' ' . $currency); ?></span>
|
||||
<?php if ($pay_limit > 0) : ?>
|
||||
<span class="aksrt-paywall__price-member"><?php esc_html_e('会员专属', 'aksrt'); ?></span>
|
||||
<?php elseif ($price > 0) : ?>
|
||||
<span class="aksrt-paywall__price-amount"><?php echo esc_html($price_text); ?></span>
|
||||
<?php if ($has_original) : ?>
|
||||
<span class="aksrt-paywall__price-original"><?php echo esc_html(aksrt_format_price($original_price) . ' ' . $currency); ?></span>
|
||||
<span class="aksrt-paywall__price-original"><?php echo esc_html(($pay_modo === 'points' ? aksrt_format_price($original_price) . ' ' . $currency : $cash_symbol . aksrt_format_price($original_price))); ?></span>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<span class="aksrt-paywall__price-free"><?php esc_html_e('免费', 'aksrt'); ?></span>
|
||||
@@ -573,9 +707,13 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
<a href="<?php echo esc_url($login_url); ?>" class="but jb-red padding-lg cashier-link aksrt-paywall__btn">
|
||||
<i class="fa fa-sign-in" aria-hidden="true"></i> <?php esc_html_e('登录后购买', 'aksrt'); ?>
|
||||
</a>
|
||||
<?php elseif ($pay_limit > 0) : ?>
|
||||
<span class="but jb-vip padding-lg aksrt-paywall__btn is-disabled">
|
||||
<i class="fas fa-crown" aria-hidden="true"></i> <?php esc_html_e('开通会员后可查看', 'aksrt'); ?>
|
||||
</span>
|
||||
<?php elseif ($price > 0) : ?>
|
||||
<button type="button" class="but jb-red padding-lg cashier-link aksrt-paywall__btn" data-aksrt-pay-content="<?php echo esc_attr((string) $post->ID); ?>">
|
||||
<i class="fa fa-shopping-cart" aria-hidden="true"></i> <?php printf(esc_html__('立即购买(%s)', 'aksrt'), aksrt_format_price($price) . ' ' . $currency); ?>
|
||||
<button type="button" class="but <?php echo $pay_modo === 'points' ? 'jb-yellow' : 'jb-red'; ?> padding-lg cashier-link aksrt-paywall__btn" data-aksrt-pay-content="<?php echo esc_attr((string) $post->ID); ?>">
|
||||
<i class="fa fa-shopping-cart" aria-hidden="true"></i> <?php printf(esc_html__('立即购买(%s)', 'aksrt'), $price_text); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<p class="aksrt-paywall__hint">
|
||||
|
||||
Reference in new issue
Block a user