feat(vip): implement layered membership expiry flow

This commit is contained in:
kate522 committed 2026-08-11 16:58:01 +08:00
1 parent ddc762bfbd
commit 80283df6b2
8 files changed
+251 -47

No files matched your search

+65 -33
View File
@@ -13,7 +13,7 @@ defined('ABSPATH') || exit;
* Explicit membership meta is authoritative, including an explicit level 0.
* Order fallback is only for users without a canonical membership level.
*
* @return array{level:int,expires:int,state:string,expired_level:int,source:string,has_explicit_state:bool,is_permanent:bool}
* @return array{level:int,expires:int,state:string,expired_level:int,source:string,has_explicit_state:bool,is_permanent:bool,current_level:int,current_expires:int,current_state:string,fallback_level:int,fallback_expires:int,fallback_state:string,has_fallback:bool,is_layered_upgrade:bool}
*/
function aksrt_get_user_vip_state(int $user_id = 0): array {
$empty = [
@@ -24,6 +24,14 @@ function aksrt_get_user_vip_state(int $user_id = 0): array {
'source' => 'none',
'has_explicit_state' => false,
'is_permanent' => false,
'current_level' => 0,
'current_expires' => 0,
'current_state' => 'unopened',
'fallback_level' => 0,
'fallback_expires' => 0,
'fallback_state' => 'none',
'has_fallback' => false,
'is_layered_upgrade' => false,
];
if ($user_id <= 0) {
$user_id = get_current_user_id();
@@ -44,58 +52,79 @@ function aksrt_get_user_vip_state(int $user_id = 0): array {
$expired_level = min(2, max(0, (int) get_user_meta($user_id, 'aksrt_vip_level_expired', true)));
if ($has_explicit) {
if ($level > 0 && $expires > 0 && $expires < time()) {
$base_level = min(2, max(0, (int) get_user_meta($user_id, 'aksrt_vip_base_level', true)));
$base_expires = max(0, (int) get_user_meta($user_id, 'aksrt_vip_base_expires', true));
if ($base_level > 0 && ($base_expires === 0 || $base_expires >= time())) {
update_user_meta($user_id, 'aksrt_vip_level', $base_level);
update_user_meta($user_id, 'aksrt_vip_expires', $base_expires);
delete_user_meta($user_id, 'aksrt_vip_base_level');
delete_user_meta($user_id, 'aksrt_vip_base_expires');
$level = $base_level;
$expires = $base_expires;
$expired_level = 0;
if ($level > 0 && $expires > 0 && $expires <= time()) {
if (class_exists('\\AKSRT\\Content\\VipMembershipExpiry')) {
\AKSRT\Content\VipMembershipExpiry::process_user($user_id, 'resolver');
$level = min(2, max(0, (int) get_user_meta($user_id, 'aksrt_vip_level', true)));
$expires = max(0, (int) get_user_meta($user_id, 'aksrt_vip_expires', true));
} else {
$expired_level = max($expired_level, $level);
update_user_meta($user_id, 'aksrt_vip_level_expired', $expired_level);
update_user_meta($user_id, 'aksrt_vip_level', 0);
$level = 0;
$expires = 0;
$base_level = min(2, max(0, (int) get_user_meta($user_id, 'aksrt_vip_base_level', true)));
$base_expires = max(0, (int) get_user_meta($user_id, 'aksrt_vip_base_expires', true));
if ($base_level > 0 && ($base_expires === 0 || $base_expires > time())) {
update_user_meta($user_id, 'aksrt_vip_level', $base_level);
update_user_meta($user_id, 'aksrt_vip_expires', $base_expires);
delete_user_meta($user_id, 'aksrt_vip_base_level');
delete_user_meta($user_id, 'aksrt_vip_base_expires');
$level = $base_level;
$expires = $base_expires;
$expired_level = 0;
} else {
$expired_level = max($expired_level, $level);
update_user_meta($user_id, 'aksrt_vip_level_expired', $expired_level);
update_user_meta($user_id, 'aksrt_vip_level', 0);
update_user_meta($user_id, 'aksrt_vip_expires', 0);
delete_user_meta($user_id, 'aksrt_vip_base_level');
delete_user_meta($user_id, 'aksrt_vip_base_expires');
$level = 0;
$expires = 0;
}
}
}
$fallback_level = min(2, max(0, (int) get_user_meta($user_id, 'aksrt_vip_base_level', true)));
$fallback_expires = max(0, (int) get_user_meta($user_id, 'aksrt_vip_base_expires', true));
if ($level > 0) {
$level = $level >= 2 && $vip2_enabled ? 2 : ($vip1_enabled ? 1 : 0);
$current_state = $expires > 0 ? 'active' : 'permanent';
$fallback_state = $fallback_level > 0 ? ($fallback_expires > 0 ? 'active' : 'permanent') : 'none';
return [
'level' => $level,
'expires' => $expires,
'state' => $expires > 0 ? 'active' : 'permanent',
'state' => $current_state,
'expired_level' => 0,
'source' => 'meta',
'has_explicit_state' => true,
'is_permanent' => $expires <= 0,
'current_level' => $level,
'current_expires' => $expires,
'current_state' => $current_state,
'fallback_level' => $fallback_level,
'fallback_expires' => $fallback_expires,
'fallback_state' => $fallback_state,
'has_fallback' => $fallback_level > 0,
'is_layered_upgrade' => $fallback_level > 0 && $fallback_level < $level,
];
}
return [
'level' => 0,
'expires' => 0,
return array_merge($empty, [
'state' => $expired_level > 0 ? 'expired' : 'unopened',
'expired_level' => $expired_level,
'source' => 'meta',
'has_explicit_state' => true,
'is_permanent' => false,
];
'current_state' => $expired_level > 0 ? 'expired' : 'unopened',
]);
}
$paid = \AKSRT\Settings\Settings::get_paid_content_settings();
$user = get_userdata($user_id);
if ($user && array_intersect((array) $user->roles, (array) ($paid['vip_exempt_roles'] ?? []))) {
$level = $vip2_enabled ? 2 : ($vip1_enabled ? 1 : 0);
return [
'level' => $level, 'expires' => 0,
return array_merge($empty, [
'level' => $level,
'state' => $level > 0 ? 'permanent' : 'unopened',
'expired_level' => 0, 'source' => 'exempt',
'has_explicit_state' => false, 'is_permanent' => $level > 0,
];
'source' => 'exempt',
'is_permanent' => $level > 0,
'current_level' => $level,
'current_state' => $level > 0 ? 'permanent' : 'unopened',
]);
}
if (class_exists('\AKSRT\Payment\Order')) {
@@ -115,12 +144,15 @@ function aksrt_get_user_vip_state(int $user_id = 0): array {
$level = min(2, max(1, $level));
$level = $level >= 2 && $vip2_enabled ? 2 : ($vip1_enabled ? 1 : 0);
$order_expires = max(0, (int) ($order_meta['expires'] ?? $order_meta['vip_expires'] ?? 0));
return [
'level' => $level, 'expires' => $order_expires,
return array_merge($empty, [
'level' => $level,
'expires' => $order_expires,
'state' => $level > 0 ? 'active' : 'unopened',
'expired_level' => 0, 'source' => 'order',
'has_explicit_state' => false, 'is_permanent' => false,
];
'source' => 'order',
'current_level' => $level,
'current_expires' => $order_expires,
'current_state' => $level > 0 ? 'active' : 'unopened',
]);
}
}
return $empty;