feat(pay): guest cash purchase with signed cookie unlock (zibll-style)

Allow pay_no_logged_in cash content orders (user_id=0), set aksrt_pay_* cookies
on paid, accept cookie in access state, and expose guest CTA on paywall/box.
This commit is contained in:
kate522 committed 2026-07-14 12:19:22 +08:00
1 parent 8f15d16d35
commit 8e9e05c859
6 files changed
+301 -35

No files matched your search

+180
View File
@@ -237,6 +237,177 @@ if (!function_exists('aksrt_bump_content_sales_volume')) {
}
}
/**
* Whether guest cash purchase is allowed (Zibll pay_no_logged_in + pay_limit=0).
*/
if (!function_exists('aksrt_allow_guest_content_pay')) {
function aksrt_allow_guest_content_pay($post = null): bool {
$p = get_post($post);
if (!($p instanceof WP_Post)) {
return false;
}
$meta = function_exists('aksrt_get_pay_meta') ? aksrt_get_pay_meta($p) : [];
$pay_limit = (int) ($meta['pay_limit'] ?? 0);
if ($pay_limit > 0) {
return false;
}
$pay_modo = (($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0';
if ($pay_modo === 'points') {
return false; // points require login
}
$order = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_order_settings() : [];
$paid = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_paid_content_settings() : [];
$allow = !empty($order['no_logged_in']) || !empty($paid['no_logged_in']);
/**
* Filter guest content pay allow.
*
* @param bool $allow
* @param WP_Post $p
*/
return (bool) apply_filters('aksrt_allow_guest_content_pay', $allow, $p);
}
}
/**
* Cookie lifetime days for guest paid content (Zibll pay_cookie_day).
*/
if (!function_exists('aksrt_guest_pay_cookie_days')) {
function aksrt_guest_pay_cookie_days(int $post_id = 0): int {
$days = 15;
if (class_exists('AKSRT_Settings')) {
$order = AKSRT_Settings::get_order_settings();
$days = max(1, min(31, (int) ($order['cookie_day'] ?? 15)));
}
/**
* @param int $days
* @param int $post_id
*/
return max(1, (int) apply_filters('aksrt_guest_pay_cookie_days', $days, $post_id));
}
}
/**
* Client IP helper for cookie token binding.
*/
if (!function_exists('aksrt_pay_client_ip')) {
function aksrt_pay_client_ip(): string {
if (function_exists('aksrt_get_client_ip')) {
return (string) aksrt_get_client_ip();
}
return (string) ($_SERVER['REMOTE_ADDR'] ?? '');
}
}
/**
* Build token material for guest order cookie (zibll-style).
*
* @param array<string,mixed> $order
*/
if (!function_exists('aksrt_content_order_cookie_token_key')) {
function aksrt_content_order_cookie_token_key(array $order): string {
$meta = is_array($order['meta_payload'] ?? null) ? $order['meta_payload'] : [];
$ip = (string) ($meta['ip_address'] ?? $order['ip_address'] ?? '');
$id = (string) ($order['id'] ?? $order['order_number'] ?? '');
$post_id = (int) ($order['product_id'] ?? $meta['post_id'] ?? 0);
$num = (string) ($order['order_number'] ?? '');
$amount = function_exists('aksrt_format_price')
? aksrt_format_price((float) ($order['amount'] ?? 0))
: (string) round((float) ($order['amount'] ?? 0), 2);
return $id . '_' . $post_id . '_' . trim($num) . '_' . $amount . '_' . trim($ip);
}
}
/**
* Set guest paid cookies after content order paid (Zibll zibpay_posts_order_created_set_cookie).
*
* @param array<string,mixed> $order
*/
if (!function_exists('aksrt_set_guest_content_pay_cookies')) {
function aksrt_set_guest_content_pay_cookies(array $order): void {
$post_id = (int) ($order['product_id'] ?? 0);
$order_number = (string) ($order['order_number'] ?? '');
if ($post_id <= 0 || $order_number === '') {
return;
}
$days = aksrt_guest_pay_cookie_days($post_id);
$expire = time() + (DAY_IN_SECONDS * $days);
$path = defined('COOKIEPATH') && COOKIEPATH ? COOKIEPATH : '/';
$domain = defined('COOKIE_DOMAIN') ? COOKIE_DOMAIN : '';
$secure = is_ssl();
$httponly = true;
setcookie('aksrt_pay_' . $post_id, $order_number, $expire, $path, $domain, $secure, $httponly);
$_COOKIE['aksrt_pay_' . $post_id] = $order_number;
$token = md5(aksrt_content_order_cookie_token_key($order));
$token_name = 'aksrt_pay_token_' . md5($order_number);
setcookie($token_name, $token, $expire, $path, $domain, $secure, $httponly);
$_COOKIE[$token_name] = $token;
}
}
/**
* Resolve guest paid order from browser cookie for a post.
*
* @return array<string,mixed>|null
*/
if (!function_exists('aksrt_get_guest_content_paid_order')) {
function aksrt_get_guest_content_paid_order(int $post_id): ?array {
if ($post_id <= 0 || empty($_COOKIE['aksrt_pay_' . $post_id])) {
return null;
}
if (!class_exists('AKSRT_Order_Repository')) {
return null;
}
$order_number = sanitize_text_field((string) $_COOKIE['aksrt_pay_' . $post_id]);
if ($order_number === '') {
return null;
}
$order = AKSRT_Order_Repository::get_instance()->get($order_number);
if (!$order) {
return null;
}
if ((string) ($order['product_type'] ?? '') !== AKSRT_Domain_Model::ORDER_PRODUCT_RESOURCE) {
return null;
}
if ((int) ($order['product_id'] ?? 0) !== $post_id) {
return null;
}
$status = (string) ($order['status'] ?? '');
if (!AKSRT_Domain_Model::is_paid_order_status($status)) {
return null;
}
// Cookie day window from paid_at.
$paid_at = (string) ($order['paid_at'] ?? $order['created_at'] ?? '');
if ($paid_at !== '') {
$ts = strtotime($paid_at);
$days = aksrt_guest_pay_cookie_days($post_id);
if ($ts !== false && ($ts + DAY_IN_SECONDS * $days) < time()) {
return null;
}
}
$token_name = 'aksrt_pay_token_' . md5($order_number);
$cookie_token = isset($_COOKIE[$token_name]) ? (string) $_COOKIE[$token_name] : '';
$expect = md5(aksrt_content_order_cookie_token_key($order));
if ($cookie_token === '' || !hash_equals($expect, $cookie_token)) {
return null;
}
return $order;
}
}
/**
* Whether current request has paid access via guest cookie.
*/
if (!function_exists('aksrt_guest_has_paid_access')) {
function aksrt_guest_has_paid_access(int $post_id): bool {
return null !== aksrt_get_guest_content_paid_order($post_id);
}
}
/**
* Resolve the amount a given user should pay for a post (Zibll VIP tier min).
*
@@ -813,9 +984,18 @@ if (!function_exists('aksrt_get_paywall_html')) {
<?php endif; ?>
</div>
<?php if (!$is_logged_in) : ?>
<?php if ($pay_limit <= 0 && $price > 0 && $pay_modo !== 'points' && function_exists('aksrt_allow_guest_content_pay') && aksrt_allow_guest_content_pay($post)) : ?>
<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>
<p class="aksrt-paywall__hint" style="margin-top:10px;">
<a href="<?php echo esc_url($login_url); ?>"><?php esc_html_e('已有账号?登录后购买', 'aksrt'); ?></a>
</p>
<?php else : ?>
<a href="<?php echo esc_url($login_url); ?>" class="but jb-red padding-lg aksrt-paywall__btn">
<i class="fa fa-sign-in" aria-hidden="true"></i> <?php esc_html_e('登录后购买', 'aksrt'); ?>
</a>
<?php endif; ?>
<?php elseif ($member_blocked) : ?>
<a href="<?php echo esc_url($vip_url); ?>" class="but jb-vip padding-lg aksrt-paywall__btn">
<i class="fas fa-crown" aria-hidden="true"></i> <?php esc_html_e('开通会员后可查看', 'aksrt'); ?>