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
@@ -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'), [
|
||||
|
||||
Reference in new issue
Block a user