feat(admin,forum): download logs, hidecontent, VIP tiers, users commerce

Add aksrt_download_logs workbench, zibll hidecontent alias + topic
partial-hide path, VIP1/VIP2 price matrix for topics, and users list
commerce snapshot column with deep links.
This commit is contained in:
kate522 committed 2026-07-15 11:13:48 +08:00
1 parent cf6ad0e972
commit 8d31e65ccd
14 files changed
+611 -32

No files matched your search

@@ -68,11 +68,18 @@ trait AKSRT_Forum_Topic_Service_Part_3 {
$pay_hide_part = (int) get_post_meta($topic_id, '_aksrt_pay_hide_part', true) === 1;
$content = (string) $post->post_content;
if (!$can_view) {
// Prevent content leak via payload/API when template forgets can_view check.
// Partial-hide flag only applies after unlock; denied users get empty body.
$content = '';
if (in_array($visibility, [AKSRT_Forum::VISIBILITY_CREDITS, AKSRT_Forum::VISIBILITY_PAY, AKSRT_Forum::VISIBILITY_LOGIN, AKSRT_Forum::VISIBILITY_COMMENT, AKSRT_Forum::VISIBILITY_ROLE, AKSRT_Forum::VISIBILITY_MODERATOR], true)) {
$excerpt = '';
// Partial hide: keep body for shortcode processing; strip locked blocks at render.
// Full hide (default): blank content to avoid API/template leaks.
if ($pay_hide_part && in_array($visibility, [AKSRT_Forum::VISIBILITY_CREDITS, AKSRT_Forum::VISIBILITY_PAY], true)) {
// leave content; payshow/hidecontent shortcodes gate paid parts
$excerpt = wp_trim_words(wp_strip_all_tags(
preg_replace('/\[(payshow|hidecontent)[^\]]*\].*?\[\/\1\]/is', '', $content) ?? $content
), 40);
} else {
$content = '';
if (in_array($visibility, [AKSRT_Forum::VISIBILITY_CREDITS, AKSRT_Forum::VISIBILITY_PAY, AKSRT_Forum::VISIBILITY_LOGIN, AKSRT_Forum::VISIBILITY_COMMENT, AKSRT_Forum::VISIBILITY_ROLE, AKSRT_Forum::VISIBILITY_MODERATOR], true)) {
$excerpt = '';
}
}
}
@@ -334,6 +341,34 @@ trait AKSRT_Forum_Topic_Service_Part_3 {
}
$cost = max(0, (int) get_post_meta($topic_id, '_aksrt_credits_cost', true));
if ($cost <= 0) {
$cost = max(0, (int) get_post_meta($topic_id, '_aksrt_pay_credits', true));
}
// VIP tier discount for credits.
$vip_level = 0;
if (function_exists('aksrt_get_user_vip_level')) {
$vip_level = (int) aksrt_get_user_vip_level($user_id);
} elseif (function_exists('aksrt_is_vip2') && aksrt_is_vip2($user_id)) {
$vip_level = 2;
} elseif (function_exists('aksrt_is_vip') && aksrt_is_vip($user_id)) {
$vip_level = 1;
}
if ($vip_level >= 2) {
$v2 = get_post_meta($topic_id, '_aksrt_credits_vip2', true);
if ($v2 !== '' && $v2 !== null && $v2 !== false) {
$cost = max(0, (int) $v2);
}
} elseif ($vip_level >= 1) {
$v1 = get_post_meta($topic_id, '_aksrt_credits_vip1', true);
if ($v1 !== '' && $v1 !== null && $v1 !== false) {
$cost = max(0, (int) $v1);
}
}
if ($cost <= 0 && $vip_level > 0) {
// VIP free credits unlock.
$this->mark_topic_unlocked($user_id, $topic_id);
return $this->forum->success(__('VIP 免费解锁成功', 'aksrt'), ['free' => true]);
}
if ($cost <= 0) {
return $this->forum->error(__('积分价格未设置', 'aksrt'));
}
@@ -491,31 +526,69 @@ trait AKSRT_Forum_Topic_Service_Part_3 {
/**
* Resolve cash price for a pay-visibility topic.
*
* @return array{amount:float,is_vip_price:bool,is_free:bool,label:string,base:float,vip_set:bool}
* VIP resolution: VIP2 price → VIP1/legacy VIP price → base.
*
* @return array{amount:float,is_vip_price:bool,is_free:bool,label:string,base:float,vip_set:bool,vip_level:int}
*/
public function resolve_topic_pay_price(int $topic_id, int $user_id = 0): array {
$base_raw = get_post_meta($topic_id, '_aksrt_pay_price', true);
$base = is_numeric($base_raw) ? (float) $base_raw : 0.0;
$vip_raw = get_post_meta($topic_id, '_aksrt_pay_vip_price', true);
$vip_set = ($vip_raw !== '' && $vip_raw !== null && $vip_raw !== false);
$vip_price = $vip_set && is_numeric($vip_raw) ? (float) $vip_raw : 0.0;
$is_vip = $user_id > 0 && function_exists('aksrt_is_vip') && aksrt_is_vip($user_id);
if (!$is_vip && $user_id > 0 && function_exists('aksrt_is_vip_exempt') && aksrt_is_vip_exempt($user_id)) {
$is_vip = true;
$vip_level = 0;
if ($user_id > 0) {
if (function_exists('aksrt_get_user_vip_level')) {
$vip_level = (int) aksrt_get_user_vip_level($user_id);
} elseif (function_exists('aksrt_is_vip2') && aksrt_is_vip2($user_id)) {
$vip_level = 2;
} elseif (function_exists('aksrt_is_vip') && aksrt_is_vip($user_id)) {
$vip_level = 1;
}
if ($vip_level <= 0 && function_exists('aksrt_is_vip_exempt') && aksrt_is_vip_exempt($user_id)) {
$vip_level = 1;
}
}
if ($is_vip && $vip_set) {
$pick = static function ($raw) {
if ($raw === '' || $raw === null || $raw === false) {
return null;
}
return is_numeric($raw) ? (float) $raw : null;
};
$vip2 = $pick(get_post_meta($topic_id, '_aksrt_pay_vip2_price', true));
$vip1 = $pick(get_post_meta($topic_id, '_aksrt_pay_vip1_price', true));
if ($vip1 === null) {
// Legacy single VIP key.
$vip1 = $pick(get_post_meta($topic_id, '_aksrt_pay_vip_price', true));
}
$amount = $base;
$is_vip_price = false;
$vip_set = ($vip1 !== null || $vip2 !== null);
if ($vip_level >= 2 && $vip2 !== null) {
$amount = max(0.0, $vip2);
$is_vip_price = true;
} elseif ($vip_level >= 1 && $vip1 !== null) {
$amount = max(0.0, $vip1);
$is_vip_price = true;
} elseif ($vip_level >= 2 && $vip1 !== null) {
// VIP2 user falls back to VIP1 price when VIP2 unset.
$amount = max(0.0, $vip1);
$is_vip_price = true;
}
if ($is_vip_price) {
return [
'amount' => max(0.0, $vip_price),
'amount' => $amount,
'is_vip_price' => true,
'is_free' => $vip_price <= 0,
'label' => $vip_price <= 0
'is_free' => $amount <= 0,
'label' => $amount <= 0
? __('VIP 免费', 'aksrt')
: sprintf(__('VIP ¥%s', 'aksrt'), number_format($vip_price, 2, '.', '')),
: sprintf(__('VIP ¥%s', 'aksrt'), number_format($amount, 2, '.', '')),
'base' => $base,
'vip_set' => true,
'vip_level' => $vip_level,
];
}
@@ -528,6 +601,7 @@ trait AKSRT_Forum_Topic_Service_Part_3 {
: __('价格未设置', 'aksrt'),
'base' => $base,
'vip_set' => $vip_set,
'vip_level' => $vip_level,
];
}