fix(pay): render paid reading as fragments

This commit is contained in:
kate522 committed 2026-08-13 18:58:24 +08:00
1 parent 4cc1f2b2ea
commit f040a680d6
9 files changed
+316 -65

No files matched your search

+1 -1
View File
@@ -139,7 +139,7 @@ add_action('enqueue_block_editor_assets', function () {
'aksrt-gutenberg-blocks',
$base_uri . '/assets/js/gutenberg-blocks.js',
// wp-media-utils: MediaUpload for carousel block
['wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor', 'wp-hooks', 'wp-media-utils'],
['wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor', 'wp-hooks', 'wp-media-utils', 'wp-data'],
(string) filemtime($blocks_js),
true
);
+72 -51
View File
@@ -675,6 +675,53 @@ if (!function_exists('aksrt_is_paid_reading')) {
}
}
/**
* Detect the canonical paid-fragment shortcode in a post's raw content.
*
* The editor writes this exact shortcode format, so this is the single
* source of truth for whether a reading price has any protected fragment to
* apply to. It deliberately does not inspect rendered content.
*/
if (!function_exists('aksrt_post_has_payshow_shortcode')) {
function aksrt_post_has_payshow_shortcode($post = null): bool {
$p = get_post($post);
if (!($p instanceof WP_Post)) {
return false;
}
return preg_match(
'/\[hidecontent\b[^\]]*\btype\s*=\s*(?:"payshow"|\'payshow\'|payshow)[^\]]*\]/i',
(string) $p->post_content
) === 1;
}
}
/**
* A paid fragment is active only for an explicitly priced paid-reading post.
*
* A zero-price reading configuration is intentionally public: authors can
* save content before setting a price without accidentally hiding it.
*/
if (!function_exists('aksrt_is_payshow_purchase_enabled')) {
function aksrt_is_payshow_purchase_enabled($post = null): bool {
if (!aksrt_post_has_payshow_shortcode($post)) {
return false;
}
$meta = aksrt_get_pay_meta($post);
if (($meta['pay_type'] ?? AKSRT_PAY_TYPE_NO) !== AKSRT_PAY_TYPE_READING) {
return false;
}
$pay_modo = ($meta['pay_modo'] ?? '0') === 'points' ? 'points' : '0';
$price = $pay_modo === 'points'
? (float) ($meta['points_price'] ?? 0)
: (float) ($meta['price'] ?? 0);
return $price > 0;
}
}
if (!function_exists('aksrt_is_paid_download')) {
function aksrt_is_paid_download($post = null): bool {
return aksrt_get_pay_meta($post)['pay_type'] === AKSRT_PAY_TYPE_DOWNLOAD;
@@ -1093,7 +1140,7 @@ if (!function_exists('aksrt_get_pay_attributes_html')) {
// ============================================================
if (!function_exists('aksrt_get_paywall_html')) {
function aksrt_get_paywall_html(WP_Post $post): string {
function aksrt_get_paywall_html(WP_Post $post, bool $is_fragment = false): string {
$meta = aksrt_get_pay_meta($post);
$pay_type = $meta['pay_type'];
$priced = function_exists('aksrt_get_user_pay_price') ? aksrt_get_user_pay_price($post) : null;
@@ -1117,6 +1164,9 @@ if (!function_exists('aksrt_get_paywall_html')) {
];
$type_info = $type_labels[$pay_type] ?? $type_labels[AKSRT_PAY_TYPE_READING];
if ($is_fragment && $pay_type === AKSRT_PAY_TYPE_READING) {
$type_info['desc'] = __('付费后即可查看此片段内容', 'aksrt');
}
$login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url(get_permalink($post));
$is_logged_in = is_user_logged_in();
$original_price = (float) ($meta['original_price'] ?? 0);
@@ -1129,13 +1179,12 @@ if (!function_exists('aksrt_get_paywall_html')) {
ob_start();
?>
<div class="aksrt-paywall" data-post-id="<?php echo esc_attr((string) $post->ID); ?>" data-pay-type="<?php echo esc_attr($pay_type); ?>" data-pay-modo="<?php echo esc_attr($pay_modo); ?>">
<div class="aksrt-paywall__overlay">
<div class="aksrt-paywall__blur"></div>
<div class="aksrt-paywall__card">
<div class="aksrt-paywall__icon">
<i class="fas <?php echo esc_attr($type_info['icon']); ?>" aria-hidden="true"></i>
</div>
<div class="aksrt-paywall<?php echo $is_fragment ? ' aksrt-paywall--fragment' : ''; ?>" data-post-id="<?php echo esc_attr((string) $post->ID); ?>" data-pay-type="<?php echo esc_attr($pay_type); ?>" data-pay-modo="<?php echo esc_attr($pay_modo); ?>">
<div class="aksrt-paywall__card" role="group" aria-label="<?php esc_attr_e('付费内容购买', 'aksrt'); ?>">
<div class="aksrt-paywall__icon">
<i class="fas <?php echo esc_attr($type_info['icon']); ?>" aria-hidden="true"></i>
</div>
<div class="aksrt-paywall__body">
<h3 class="aksrt-paywall__title"><?php echo esc_html($type_info['label']); ?></h3>
<p class="aksrt-paywall__desc"><?php echo esc_html($type_info['desc']); ?></p>
<div class="aksrt-paywall__price">
@@ -1150,18 +1199,18 @@ if (!function_exists('aksrt_get_paywall_html')) {
<span class="aksrt-paywall__price-free"><?php esc_html_e('免费', 'aksrt'); ?></span>
<?php endif; ?>
</div>
</div>
<div class="aksrt-paywall__actions">
<?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>
<a href="<?php echo esc_url($login_url); ?>" class="aksrt-paywall__login-link"><?php esc_html_e('已有账号?登录后购买', 'aksrt'); ?></a>
<?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>
<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">
@@ -1173,7 +1222,7 @@ if (!function_exists('aksrt_get_paywall_html')) {
</button>
<?php endif; ?>
<p class="aksrt-paywall__hint">
<i class="fas fa-shield-alt"></i> <?php esc_html_e('购买后永久有效,支持重复查看', 'aksrt'); ?>
<i class="fas fa-shield-alt" aria-hidden="true"></i> <?php esc_html_e('购买后永久有效,支持重复查看', 'aksrt'); ?>
</p>
</div>
</div>
@@ -1183,38 +1232,6 @@ if (!function_exists('aksrt_get_paywall_html')) {
}
}
// ============================================================
// 付费墙样式注入
// ============================================================
add_action('wp_head', function (): void {
if (is_admin() || !is_singular()) return;
global $post;
if (!($post instanceof WP_Post)) return;
if (!function_exists('aksrt_can_access_content') || aksrt_can_access_content($post)) return;
?>
<style>
.aksrt-paywall{position:relative;margin:24px 0}
.aksrt-paywall__overlay{position:relative}
.aksrt-paywall__blur{filter:blur(12px);pointer-events:none;user-select:none;max-height:200px;overflow:hidden;opacity:.3}
.aksrt-paywall__card{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:var(--surface-1,#fff);border:1px solid var(--color-line,#e5e7eb);border-radius:var(--radius-lg,14px);padding:40px;text-align:center;box-shadow:0 12px 40px rgba(0,0,0,.12);min-width:320px;max-width:420px}
.aksrt-paywall__icon{font-size:48px;color:var(--color-primary,#f04494);margin-bottom:16px}
.aksrt-paywall__title{font-size:20px;font-weight:700;margin:0 0 8px;color:var(--color-ink,#15171A)}
.aksrt-paywall__desc{font-size:14px;color:var(--color-ink-3,#525866);margin:0 0 20px}
.aksrt-paywall__price{margin-bottom:20px}
.aksrt-paywall__price-amount{font-size:28px;font-weight:700;color:var(--color-error,#EF4444)}
.aksrt-paywall__price-original{font-size:14px;color:var(--color-ink-4,#8A8F98);text-decoration:line-through;margin-left:8px}
.aksrt-paywall__price-free{font-size:20px;font-weight:600;color:var(--color-success,#10B981)}
.aksrt-paywall__btn{display:inline-flex;align-items:center;gap:8px}
.aksrt-paywall__hint{font-size:12px;color:var(--color-ink-4,#8A8F98);margin:16px 0 0}
.aksrt-gallery-locked{filter:blur(8px);pointer-events:none;user-select:none}
.aksrt-paywall-preview{margin:0 0 16px;padding:14px 16px;border-left:3px solid var(--color-primary,#f04494);background:var(--surface-2,#f8fafc);border-radius:0 10px 10px 0;color:var(--color-ink-2,#374151);line-height:1.7}
.aksrt-paywall-preview p:last-child{margin-bottom:0}
.aksrt-paid-gallery__overlay .but,.aksrt-paid-video__placeholder .but{margin-top:10px}
</style>
<?php
});
// ============================================================
// 付费图库轮播(Swiper)
// ============================================================
@@ -1362,13 +1379,17 @@ if (!function_exists('aksrt_paid_content_filter')) {
if (!($post instanceof WP_Post)) {
return $content;
}
$meta = aksrt_get_pay_meta($post);
$pay_type = (string) ($meta['pay_type'] ?? AKSRT_PAY_TYPE_NO);
// Reading is protected only by the payshow shortcode. Never replace
// the entire article body with a post-level purchase wall.
if ($pay_type === AKSRT_PAY_TYPE_READING) {
return $content;
}
if (aksrt_can_access_content($post)) {
return $content;
}
$meta = aksrt_get_pay_meta($post);
$pay_type = (string) ($meta['pay_type'] ?? AKSRT_PAY_TYPE_NO);
if (!in_array($pay_type, [AKSRT_PAY_TYPE_READING, AKSRT_PAY_TYPE_GALLERY, AKSRT_PAY_TYPE_VIDEO], true)) {
if (!in_array($pay_type, [AKSRT_PAY_TYPE_GALLERY, AKSRT_PAY_TYPE_VIDEO], true)) {
return $content;
}
+3 -2
View File
@@ -74,8 +74,9 @@ if (!function_exists('aksrt_single_build_context')) :
$pay_meta = function_exists('aksrt_get_pay_meta') ? aksrt_get_pay_meta($post_id) : ['pay_type' => 'no'];
$pay_type = (string) ($pay_meta['pay_type'] ?? 'no');
$is_paid_post = function_exists('aksrt_is_paid_post') && aksrt_is_paid_post($post_id);
// Pay module: download box OR non-download paid types (reading/gallery/video/vip).
$show_pay_box = $has_download || ($is_paid_post && $pay_type !== 'no' && $pay_type !== 'download');
// Paid-reading purchase is rendered inline by each payshow shortcode.
// Keep the article-level module for download, gallery, video and VIP only.
$show_pay_box = $has_download || ($is_paid_post && !in_array($pay_type, ['no', 'download', 'reading'], true));
$breadcrumbs_html = '';
if (!empty($settings['breadcrumbs']) && function_exists('aksrt_breadcrumbs')) {