导入 AKSRT 主题开发源码

This commit is contained in:
Claude Code committed 2026-07-03 22:50:34 +08:00
1 parent 9681dd3d48
commit 1268a55dd0
595 files changed
+127705

No files matched your search

@@ -0,0 +1,282 @@
<?php
/**
* AKSRT Content Visibility
*
* Central access policy for shortcode-gated content and paid-content runtime.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_Content_Visibility {
private static $instance = null;
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function init(): void {
// 短代码注册统一在 AKSRT_Shortcodes(registry);本类只提供渲染实现。
add_action('wp_ajax_aksrt_check_visibility', [$this, 'ajax_check_visibility']);
add_action('wp_ajax_nopriv_aksrt_check_visibility', [$this, 'ajax_check_visibility']);
}
/**
* @param int|WP_Post|null $post
* @return array<string, mixed>
*/
public static function get_post_access_state($post = null, int $user_id = 0): array {
$resource_post = get_post($post);
$uid = $user_id > 0 ? $user_id : get_current_user_id();
$pay_meta = function_exists('aksrt_get_pay_meta')
? 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);
$paid_settings = class_exists('AKSRT_Settings')
? AKSRT_Settings::get_paid_content_settings()
: [
'download_login' => true,
'download_credit' => true,
'download_captcha' => false,
];
$state = [
'post_id' => $resource_post instanceof WP_Post ? (int) $resource_post->ID : 0,
'pay_type' => $pay_type,
'price' => $price,
'need_login' => false,
'need_purchase' => false,
'need_vip' => false,
'require_captcha' => false,
'has_paid_access' => false,
'can_view' => true,
'can_download' => true,
'download_cost' => 0,
];
if (!($resource_post instanceof WP_Post)) {
$state['can_view'] = false;
$state['can_download'] = false;
return $state;
}
if ($pay_type === AKSRT_Domain_Model::PAY_TYPE_NO) {
return $state;
}
$has_free_access = $price <= 0 && $pay_type !== AKSRT_Domain_Model::PAY_TYPE_VIP;
$has_paid_order = false;
if ($uid > 0 && class_exists('AKSRT_Order')) {
$has_paid_order = AKSRT_Order::get_instance()->has_paid_access(
$uid,
AKSRT_Domain_Model::ORDER_PRODUCT_RESOURCE,
(int) $resource_post->ID
);
}
$has_vip_access = false;
if ($uid > 0) {
if (function_exists('aksrt_is_vip_exempt') && aksrt_is_vip_exempt($uid)) {
$has_vip_access = true;
} elseif (function_exists('aksrt_is_vip') && $pay_type === AKSRT_Domain_Model::PAY_TYPE_VIP) {
$has_vip_access = aksrt_is_vip($uid);
}
}
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);
$state['download_cost'] = max(0, $download_cost);
$state['need_login'] = !empty($paid_settings['download_login']) || !empty($pay_meta['require_login']);
$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'];
$state['can_view'] = true;
$state['can_download'] = !$state['need_login'] || $uid > 0;
return $state;
}
if ($pay_type === AKSRT_Domain_Model::PAY_TYPE_VIP) {
$state['need_vip'] = true;
$state['has_paid_access'] = $has_vip_access;
$state['can_view'] = $has_vip_access;
$state['can_download'] = false;
return $state;
}
$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['can_view'] = $state['has_paid_access'] && (!$state['need_login'] || $uid > 0);
$state['can_download'] = false;
return $state;
}
public static function can_view_paid_content($post = null, int $user_id = 0): bool {
$state = self::get_post_access_state($post, $user_id);
return !empty($state['can_view']);
}
/**
* @param int|WP_Post|null $post
* @return true|WP_Error
*/
public static function can_download_resource($post = null, int $user_id = 0) {
$resource_post = get_post($post);
if (!($resource_post instanceof WP_Post) || !function_exists('aksrt_is_resource_post') || !aksrt_is_resource_post($resource_post)) {
return new WP_Error('aksrt_not_resource', __('该内容不是可下载资源。', 'aksrt'));
}
$state = self::get_post_access_state($resource_post, $user_id);
$uid = $user_id > 0 ? $user_id : get_current_user_id();
if (($state['pay_type'] ?? '') !== AKSRT_Domain_Model::PAY_TYPE_DOWNLOAD) {
return new WP_Error('aksrt_not_downloadable', __('该内容不是可下载资源。', 'aksrt'));
}
if (!empty($state['need_login']) && $uid <= 0) {
return new WP_Error('aksrt_need_login', __('请先登录后再下载。', 'aksrt'), [
'status' => 401,
'login_url' => wp_login_url(get_permalink($resource_post)),
]);
}
$cost = (int) ($state['download_cost'] ?? 0);
$paid_settings = class_exists('AKSRT_Settings')
? AKSRT_Settings::get_paid_content_settings()
: ['download_credit' => true];
if (!empty($paid_settings['download_credit']) && $cost > 0) {
$balance = class_exists('AKSRT_Credits') ? AKSRT_Credits::balance($uid) : 0;
if ($balance < $cost) {
return new WP_Error('aksrt_credits_insufficient', __('积分不足,无法下载。', 'aksrt'), [
'status' => 402,
'balance' => $balance,
'cost' => $cost,
]);
}
}
return true;
}
public function render_hide_shortcode(array $atts, string $content = ''): string {
$atts = shortcode_atts([
'mode' => 'comment',
'message' => '',
'pid' => get_the_ID(),
], $atts, 'aksrt_hide');
$mode = sanitize_key((string) $atts['mode']);
$pid = (int) $atts['pid'];
$message = (string) $atts['message'];
if ($pid <= 0) {
return '';
}
if ($this->is_unlocked($mode, $pid)) {
return '<div class="aksrt-hidden-content aksrt-hidden-content--unlocked">' . do_shortcode($content) . '</div>';
}
if ($message === '') {
switch ($mode) {
case 'comment':
$message = __('评论后查看隐藏内容', 'aksrt');
break;
case 'login':
$message = __('登录后查看隐藏内容', 'aksrt');
break;
case 'password':
$message = __('输入密码后查看隐藏内容', 'aksrt');
break;
default:
$message = __('此内容已隐藏', 'aksrt');
}
}
$wrapper_class = 'aksrt-hidden-content aksrt-hidden-content--locked aksrt-hidden-content--' . esc_attr($mode);
$html = '<div class="' . $wrapper_class . '" data-aksrt-visibility-mode="' . esc_attr($mode) . '" data-aksrt-visibility-pid="' . esc_attr((string) $pid) . '">';
$html .= '<div class="aksrt-hidden-content__message">';
$html .= '<i class="fas fa-lock" aria-hidden="true"></i> ';
$html .= '<span>' . esc_html($message) . '</span>';
$html .= '</div>';
if ($mode === 'password') {
$html .= '<div class="aksrt-hidden-content__form">';
$html .= '<input type="password" class="aksrt-hidden-content__password-input" placeholder="' . esc_attr__('请输入密码', 'aksrt') . '">';
$html .= '<button type="button" class="aksrt-hidden-content__submit-btn btn-primary btn-sm">' . esc_html__('验证', 'aksrt') . '</button>';
$html .= '</div>';
}
$html .= '</div>';
return $html;
}
private function is_unlocked(string $mode, int $pid): bool {
switch ($mode) {
case 'comment':
if (!is_user_logged_in()) {
return false;
}
return get_comments([
'post_id' => $pid,
'user_id' => get_current_user_id(),
'count' => true,
'status' => 'approve',
]) > 0;
case 'login':
return is_user_logged_in();
case 'password':
return !empty($_COOKIE['aksrt_hide_pwd_' . $pid]);
default:
return false;
}
}
public function ajax_check_visibility(): void {
check_ajax_referer('aksrt_visibility', '_nonce');
$mode = sanitize_key((string) ($_POST['mode'] ?? ''));
$pid = (int) ($_POST['pid'] ?? 0);
if ($pid <= 0 || !in_array($mode, ['comment', 'login', 'password'], true)) {
wp_send_json_error(['message' => __('参数无效', 'aksrt')]);
}
if ($mode === 'password') {
$password = sanitize_text_field((string) ($_POST['password'] ?? ''));
$post_password = get_post_password($pid);
if ($post_password === '' || $password !== $post_password) {
wp_send_json_error(['message' => __('密码错误', 'aksrt')]);
}
setcookie('aksrt_hide_pwd_' . $pid, '1', time() + HOUR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true);
wp_send_json_success(['message' => __('验证成功', 'aksrt')]);
}
if ($this->is_unlocked($mode, $pid)) {
wp_send_json_success(['message' => __('已解锁', 'aksrt')]);
}
wp_send_json_error(['message' => __('未满足条件', 'aksrt')]);
}
}