进行了一些小修复
This commit is contained in:
@@ -1186,6 +1186,10 @@ html.dark .post-drop-meta__item:hover {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.article-header:has(.post-drop-meta.is-open) {
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.post-drop-meta__item {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -50,3 +50,15 @@
|
||||
.pay-box .muted-2-color + .muted-2-color {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.pay-box .pay-vip-level-icon {
|
||||
display: inline-block;
|
||||
width: 1.4em;
|
||||
height: 1.4em;
|
||||
object-fit: contain;
|
||||
vertical-align: -0.28em;
|
||||
}
|
||||
|
||||
.pay-box .pay-vip-exclusive {
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
@@ -446,6 +446,10 @@ html.dark .post-drop-meta__item:hover {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.article-header:has(.post-drop-meta.is-open) {
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.post-drop-meta__item {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
|
||||
+171
-38
@@ -482,10 +482,7 @@ if (!function_exists('aksrt_guest_has_paid_access')) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the amount a given user should pay for a post (legacy VIP tier min).
|
||||
*
|
||||
* VIP tier prices only apply when configured as a positive discount (< base).
|
||||
* Full free for VIP uses vip_free_download / exempt roles (handled separately).
|
||||
* Resolve the amount a given user should pay for a post.
|
||||
*
|
||||
* @param int|WP_Post|null $post
|
||||
* @param int $user_id
|
||||
@@ -511,10 +508,13 @@ if (!function_exists('aksrt_get_user_pay_price')) {
|
||||
|
||||
$currency = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_currency_name() : __('积分', 'aksrt');
|
||||
$cash_symbol = '¥';
|
||||
$vip_settings = [];
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$paid = \AKSRT\Settings\Settings::get_paid_content_settings();
|
||||
$cash_symbol = (string) ($paid['display']['currency_symbol'] ?? '¥');
|
||||
$vip_settings = \AKSRT\Settings\Settings::get_payment_vip_settings();
|
||||
}
|
||||
$vip_levels = is_array($vip_settings['levels'] ?? null) ? $vip_settings['levels'] : [];
|
||||
|
||||
if ($pay_modo === 'points') {
|
||||
$base_minor = max(0, (int) ($meta['points_price'] ?? 0));
|
||||
@@ -538,18 +538,23 @@ if (!function_exists('aksrt_get_user_pay_price')) {
|
||||
$currency_label = $cash_symbol;
|
||||
}
|
||||
|
||||
// Positive VIP tier prices only (0 defaults mean "not configured").
|
||||
$vip_prices = [
|
||||
1 => $vip1_minor,
|
||||
2 => $vip2_minor,
|
||||
];
|
||||
$vip_minor = null;
|
||||
if ($vip_level >= 2 && $vip2_minor > 0) {
|
||||
$vip_minor = $vip2_minor;
|
||||
} elseif ($vip_level >= 1 && $vip1_minor > 0) {
|
||||
$vip_minor = $vip1_minor;
|
||||
for ($level = min(2, $vip_level); $level >= 1; $level--) {
|
||||
if (empty($vip_levels[$level]['enabled'])) {
|
||||
continue;
|
||||
}
|
||||
$level_price = $vip_prices[$level];
|
||||
if ($level_price < $base_minor) {
|
||||
$vip_minor = $level_price;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$amount_minor = $base_minor;
|
||||
if ($vip_minor !== null && ($base_minor <= 0 || $vip_minor < $base_minor)) {
|
||||
$amount_minor = $vip_minor;
|
||||
}
|
||||
$amount_minor = $vip_minor ?? $base_minor;
|
||||
|
||||
// Role/VIP free-download exemption (global setting).
|
||||
if ($amount_minor > 0 && $uid > 0 && function_exists('aksrt_is_download_credit_exempt_user') && aksrt_is_download_credit_exempt_user($uid)) {
|
||||
@@ -1160,6 +1165,142 @@ if (!function_exists('aksrt_get_pay_attributes_html')) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the configured icon for a paid-content VIP tier.
|
||||
*/
|
||||
if (!function_exists('aksrt_get_pay_vip_icon_html')) {
|
||||
function aksrt_get_pay_vip_icon_html(array $level_settings, string $class = 'mr3 em14'): string {
|
||||
$icon_url = esc_url((string) ($level_settings['img_icon'] ?? ''));
|
||||
if ($icon_url === '') {
|
||||
return '<i class="fa fas fa-certificate ' . esc_attr($class) . '" aria-hidden="true"></i>';
|
||||
}
|
||||
|
||||
return '<img class="pay-vip-level-icon ' . esc_attr($class) . '" src="' . $icon_url . '" alt="" decoding="async">';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the reference-theme base-price block for a paid article.
|
||||
*/
|
||||
if (!function_exists('aksrt_get_show_pay_price_html')) {
|
||||
function aksrt_get_show_pay_price_html(array $meta, array $priced, string $class = 'c-red'): string {
|
||||
$modo = (($priced['modo'] ?? '0') === 'points') ? 'points' : '0';
|
||||
$base = $priced['base'] ?? ($modo === 'points' ? 0 : '0.00');
|
||||
$pay_limit = (int) ($priced['pay_limit'] ?? ($meta['pay_limit'] ?? 0));
|
||||
$cash_symbol = '¥';
|
||||
$points_name = __('积分', 'aksrt');
|
||||
$vip_settings = [];
|
||||
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$paid_settings = \AKSRT\Settings\Settings::get_paid_content_settings();
|
||||
$cash_symbol = (string) ($paid_settings['display']['currency_symbol'] ?? '¥');
|
||||
$points_name = \AKSRT\Settings\Settings::get_currency_name();
|
||||
$vip_settings = \AKSRT\Settings\Settings::get_payment_vip_settings();
|
||||
}
|
||||
|
||||
$vip_levels = is_array($vip_settings['levels'] ?? null) ? $vip_settings['levels'] : [];
|
||||
if ($pay_limit > 0 && !empty($vip_settings['enabled'])) {
|
||||
$level_settings = is_array($vip_levels[$pay_limit] ?? null) ? $vip_levels[$pay_limit] : [];
|
||||
$level_name = (string) ($level_settings['name'] ?? sprintf(__('VIP%d', 'aksrt'), $pay_limit));
|
||||
$title = $pay_limit === 2
|
||||
? sprintf(__('仅%s可购买', 'aksrt'), $level_name)
|
||||
: sprintf(__('%s及以上会员可购买', 'aksrt'), $level_name);
|
||||
$icon = aksrt_get_pay_vip_icon_html($level_settings);
|
||||
|
||||
return '<div class="price-box"><div class="' . esc_attr($class) . ' padding-h10"><b data-toggle="tooltip" title="' . esc_attr($title) . '" class="badg radius jb-vip' . esc_attr((string) $pay_limit) . ' pay-vip-exclusive">' . $icon . esc_html__('会员专属资源', 'aksrt') . '</b></div></div>';
|
||||
}
|
||||
|
||||
if ($modo === 'points') {
|
||||
return '<div class="price-box"><div class="c-yellow ' . esc_attr($class) . '"><span class="em12 mr3"><i class="fa fas fa-coins" aria-hidden="true"></i></span><b class="em3x">' . esc_html(aksrt_format_price($base)) . '</b><span class="px12 ml3">' . esc_html($points_name) . '</span></div></div>';
|
||||
}
|
||||
|
||||
$mark = '<span class="pay-mark">' . esc_html($cash_symbol) . '</span>';
|
||||
$base_minor = aksrt_asset_price_minor($base, '0');
|
||||
$original = $meta['original_price'] ?? '0.00';
|
||||
$original_minor = aksrt_asset_price_minor($original, '0');
|
||||
$original_html = '';
|
||||
if ($original_minor > $base_minor) {
|
||||
$original_html = '<span class="original-price" title="' . esc_attr(sprintf(__('原价 %s', 'aksrt'), aksrt_format_price($original))) . '">' . $mark . esc_html(aksrt_format_price($original)) . '</span>';
|
||||
}
|
||||
|
||||
$promotion_tag = trim((string) ($meta['promotion_tag'] ?? ''));
|
||||
if ($promotion_tag !== '' && $original_minor > 0) {
|
||||
$original_html = '<div class="inline-block ml10 text-left"><badge>' . wp_kses_post($promotion_tag) . '</badge><br>' . $original_html . '</div>';
|
||||
}
|
||||
|
||||
$price = '<div class="' . esc_attr($class) . '"><b class="em3x">' . $mark . esc_html(aksrt_format_price($base)) . '</b>' . $original_html . '</div>';
|
||||
|
||||
return '<div class="price-box">' . $price . '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render all enabled VIP prices for a paid article.
|
||||
*/
|
||||
if (!function_exists('aksrt_get_posts_vip_price')) {
|
||||
function aksrt_get_posts_vip_price(array $meta): string {
|
||||
if (!class_exists('\AKSRT\Settings\Settings')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$vip_settings = \AKSRT\Settings\Settings::get_payment_vip_settings();
|
||||
if (empty($vip_settings['enabled'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$levels = is_array($vip_settings['levels'] ?? null) ? $vip_settings['levels'] : [];
|
||||
$modo = (($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0';
|
||||
$base = $modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00');
|
||||
$base_minor = aksrt_asset_price_minor($base, $modo);
|
||||
if ($base_minor <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$mark = $modo === 'points'
|
||||
? '<span class="px12"><i class="fa fas fa-coins" aria-hidden="true"></i></span>'
|
||||
: '<span class="px12">' . esc_html((string) (\AKSRT\Settings\Settings::get_paid_content_settings()['display']['currency_symbol'] ?? '¥')) . '</span>';
|
||||
$user_id = get_current_user_id();
|
||||
$user_vip_level = $user_id > 0 && function_exists('aksrt_get_user_vip_level')
|
||||
? (int) aksrt_get_user_vip_level($user_id)
|
||||
: 0;
|
||||
$items = [];
|
||||
|
||||
foreach ([1, 2] as $level) {
|
||||
$level_settings = is_array($levels[$level] ?? null) ? $levels[$level] : [];
|
||||
if (empty($level_settings['enabled'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$key = $modo === 'points' ? 'vip' . $level . '_points' : 'vip' . $level . '_price';
|
||||
$value = $meta[$key] ?? ($modo === 'points' ? 0 : '0.00');
|
||||
$vip_minor = aksrt_asset_price_minor($value, $modo);
|
||||
if ($vip_minor >= $base_minor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$level_name = (string) ($level_settings['name'] ?? sprintf(__('VIP%d', 'aksrt'), $level));
|
||||
$price = $vip_minor === 0
|
||||
? esc_html__('免费', 'aksrt')
|
||||
: $mark . esc_html(aksrt_format_price($value));
|
||||
$icon = aksrt_get_pay_vip_icon_html($level_settings);
|
||||
$action_class = $user_id <= 0 ? ' signin-loader' : ($user_vip_level < $level ? ' pay-vip' : '');
|
||||
$title = sprintf(__('开通%s', 'aksrt'), $level_name);
|
||||
$title_attr = $action_class !== ''
|
||||
? ' data-toggle="tooltip" title="' . esc_attr($title) . '"'
|
||||
: '';
|
||||
|
||||
$items[] = '<span class="but vip-price' . $action_class . '" vip-level="' . esc_attr((string) $level) . '" data-vip-level="' . esc_attr((string) $level) . '"' . $title_attr . '>' . $icon . esc_html($level_name) . '<span class="em12 ml3 vip-price-text">' . $price . '</span></span>';
|
||||
}
|
||||
|
||||
$html = implode('', $items);
|
||||
if (count($items) > 1) {
|
||||
$html = '<span class="vip-price-buts but-average inline">' . $html . '</span>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 付费墙 HTML
|
||||
// ============================================================
|
||||
@@ -1176,11 +1317,10 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
$modo = (string) ($priced['modo'] ?? '0');
|
||||
$amount = $priced['amount'] ?? 0;
|
||||
$amount_minor = aksrt_asset_price_minor($amount, $modo);
|
||||
$price_label = aksrt_get_pay_price_label($post);
|
||||
$price_text = (string) ($price_label['text'] ?? __('免费', 'aksrt'));
|
||||
$pay_limit = (int) ($priced['pay_limit'] ?? ($meta['pay_limit'] ?? 0));
|
||||
$vip_level = (int) ($priced['vip_level'] ?? 0);
|
||||
$member_blocked = $pay_limit > 0 && $vip_level < $pay_limit;
|
||||
$pay_vip_settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_vip_settings() : [];
|
||||
$member_blocked = $pay_limit > 0 && !empty($pay_vip_settings['enabled']) && $vip_level < $pay_limit;
|
||||
$type_labels = [
|
||||
AKSRT_PAY_TYPE_READING => __('付费阅读', 'aksrt'),
|
||||
AKSRT_PAY_TYPE_DOWNLOAD => __('付费下载', 'aksrt'),
|
||||
@@ -1209,36 +1349,29 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
: '<div class="pay-tag abs-center">' . esc_html($type_label) . '</div>';
|
||||
$block_class = $is_widget ? ' btn-block' : '';
|
||||
$button = '';
|
||||
if (!is_user_logged_in()) {
|
||||
if ($pay_limit <= 0 && $amount_minor > 0 && $modo === '0' && aksrt_allow_guest_content_pay($post)) {
|
||||
if ($member_blocked) {
|
||||
$level_settings = is_array($pay_vip_settings['levels'][$pay_limit] ?? null) ? $pay_vip_settings['levels'][$pay_limit] : [];
|
||||
$level_name = (string) ($level_settings['name'] ?? sprintf(__('VIP%d', 'aksrt'), $pay_limit));
|
||||
$vip_action = $vip_level > 0
|
||||
? sprintf(__('升级%s', 'aksrt'), $level_name)
|
||||
: __('开通会员', 'aksrt');
|
||||
$action_class = is_user_logged_in() ? 'pay-vip' : 'signin-loader';
|
||||
$icon = aksrt_get_pay_vip_icon_html($level_settings);
|
||||
$button = '<div class="badg c-yellow em09 mb6"><i class="fa fa-fw fa-info-circle mr6" aria-hidden="true"></i>' . esc_html(sprintf(__('您暂无购买权限,请先%s', 'aksrt'), $vip_action)) . '</div>';
|
||||
$button .= '<a href="javascript:;" vip-level="' . esc_attr((string) $pay_limit) . '" data-vip-level="' . esc_attr((string) $pay_limit) . '" class="but btn-block jb-vip' . esc_attr((string) $pay_limit) . ' ' . esc_attr($action_class) . ' padding-lg">' . $icon . esc_html($vip_action) . '</a>';
|
||||
} elseif (!is_user_logged_in()) {
|
||||
if ($amount_minor > 0 && $modo === '0' && aksrt_allow_guest_content_pay($post)) {
|
||||
$button = '<button type="button" class="but jb-red padding-lg cashier-link' . $block_class . '" data-aksrt-pay-content="' . esc_attr((string) $post->ID) . '"><i class="fa fa-shopping-cart" aria-hidden="true"></i> ' . esc_html__('立即购买', 'aksrt') . '</button>';
|
||||
} else {
|
||||
$button = '<a href="' . esc_url(wp_login_url(get_permalink($post))) . '" class="but jb-blue padding-lg' . $block_class . '"><i class="fa fa-sign-in" aria-hidden="true"></i> ' . esc_html__('登录购买', 'aksrt') . '</a>';
|
||||
$button = '<a href="javascript:;" class="but jb-blue signin-loader padding-lg' . $block_class . '"><i class="fa fa-sign-in mr10" aria-hidden="true"></i>' . esc_html__('登录购买', 'aksrt') . '</a>';
|
||||
}
|
||||
} elseif ($member_blocked) {
|
||||
$vip_url = aksrt_get_user_center_tab_url('vip');
|
||||
$button = '<a href="' . esc_url($vip_url) . '" class="but jb-vip' . max(1, min(2, $pay_limit)) . ' padding-lg' . $block_class . '"><i class="fa fa-certificate" aria-hidden="true"></i> ' . esc_html__('开通会员后可查看', 'aksrt') . '</a>';
|
||||
} elseif ($amount_minor > 0) {
|
||||
$button = '<button type="button" class="but ' . ($modo === 'points' ? 'jb-yellow' : 'jb-red') . ' padding-lg cashier-link' . $block_class . '" data-aksrt-pay-content="' . esc_attr((string) $post->ID) . '"><i class="fa fa-shopping-cart" aria-hidden="true"></i> ' . esc_html__('立即购买', 'aksrt') . '</button>';
|
||||
} else {
|
||||
$button = '<button type="button" class="but jb-blue padding-lg cashier-link' . $block_class . '" data-aksrt-pay-content="' . esc_attr((string) $post->ID) . '"><i class="fa fa-eye" aria-hidden="true"></i> ' . esc_html__('查看内容', 'aksrt') . '</button>';
|
||||
}
|
||||
$price_color = ($price_label['free'] ?? false) ? 'c-green' : ($modo === 'points' ? 'c-yellow' : 'c-red');
|
||||
$price = '<div class="price-box"><div class="' . esc_attr($price_color) . '"><b class="em3x">' . esc_html($price_text) . '</b></div></div>';
|
||||
$vip_items = [];
|
||||
$base_minor = aksrt_asset_price_minor($priced['base'] ?? $amount, $modo);
|
||||
foreach ([1, 2] as $level) {
|
||||
$key = $modo === 'points' ? 'vip' . $level . '_points' : 'vip' . $level . '_price';
|
||||
$value = $meta[$key] ?? 0;
|
||||
$vip_minor = aksrt_asset_price_minor($value, $modo);
|
||||
if ($vip_minor > 0 && ($base_minor <= 0 || $vip_minor < $base_minor)) {
|
||||
$vip_items[] = '<span class="but vip-price"><span class="vip-price-text">' . esc_html(sprintf(__('VIP%d', 'aksrt'), $level)) . '</span><span class="em12 ml3">' . esc_html(aksrt_format_price($value)) . '</span></span>';
|
||||
}
|
||||
}
|
||||
$vip = implode('', $vip_items);
|
||||
if (count($vip_items) > 1) {
|
||||
$vip = '<span class="vip-price-buts but-average inline">' . $vip . '</span>';
|
||||
}
|
||||
$price = aksrt_get_show_pay_price_html($meta, $priced);
|
||||
$vip = aksrt_get_posts_vip_price($meta);
|
||||
$attrs = aksrt_get_pay_attributes_html($post, 'pay-attr');
|
||||
$count = $sales > 0 ? '<badge class="img-badge hot jb-blue px12">' . esc_html(sprintf(__('已售 %s', 'aksrt'), $sales)) . '</badge>' : '';
|
||||
$service = aksrt_get_pay_service_html('muted-2-color');
|
||||
|
||||
@@ -22,6 +22,20 @@ test('paid article and sidebar widget use the Zibll purchase-card DOM', () => {
|
||||
assert.match(pay, /pay-tag abs-center/);
|
||||
assert.match(pay, /price-box/);
|
||||
assert.match(pay, /vip-price-buts but-average inline/);
|
||||
assert.match(pay, /function aksrt_get_show_pay_price_html/);
|
||||
assert.match(pay, /function aksrt_get_posts_vip_price/);
|
||||
assert.match(pay, /get_payment_vip_settings/);
|
||||
assert.match(pay, /\['img_icon'\]/);
|
||||
assert.match(pay, /signin-loader/);
|
||||
assert.match(pay, /pay-vip/);
|
||||
assert.match(pay, /vip-level/);
|
||||
assert.match(pay, /免费/);
|
||||
assert.match(pay, /original-price/);
|
||||
assert.match(pay, /promotion_tag/);
|
||||
assert.doesNotMatch(pay, /\$vip_minor > 0/);
|
||||
assert.doesNotMatch(pay, /\$vip_items/);
|
||||
assert.doesNotMatch(pay, /wp_login_url\(get_permalink\(\$post\)\)/);
|
||||
assert.doesNotMatch(pay, /aksrt_get_user_center_tab_url\('vip'\)/);
|
||||
assert.match(pay, /cashier-link/);
|
||||
assert.match(pay, /function aksrt_get_paid_box_html/);
|
||||
assert.match(pay, /pay-box zib-widget paid-box order-type-/);
|
||||
@@ -51,6 +65,8 @@ test('the purchase card owns one direct stylesheet and no retired paywall path',
|
||||
assert.match(assets, /assets\/css\/frontend\/pay-box\.css|\'pay-box\'/);
|
||||
assert.match(shortcodes, /return aksrt_get_paywall_html\(\$post, \['message' => \$message\]\);/);
|
||||
assert.match(css, /\.zib-widget\.pay-box/);
|
||||
assert.match(css, /\.pay-box \.pay-vip-level-icon/);
|
||||
assert.match(css, /\.pay-box \.pay-vip-exclusive/);
|
||||
assert.doesNotMatch(css, /@media/);
|
||||
assert.match(publicCss, /\.pay-box\.pay-widget \.vip-price/);
|
||||
assert.match(publicCss, /\.pay-flexbox\s*\{\s*flex-wrap:\s*wrap;/);
|
||||
|
||||
@@ -521,6 +521,7 @@ test('single post more menu has one accessible runtime and an in-flow author anc
|
||||
assert.doesNotMatch(singleRender, /cover-meta|str_replace\('single-metabox'/);
|
||||
assert.match(styles, /\.single-meta-row > \.single-metabox\s*\{[^}]*position:\s*relative;[^}]*transform:\s*none;/s);
|
||||
assert.match(styles, /\.post-drop-meta__menu\s*\{[^}]*position:\s*absolute;[^}]*right:\s*0;/s);
|
||||
assert.match(styles, /\.article-header:has\(\.post-drop-meta\.is-open\)\s*\{[^}]*z-index:\s*30;/s);
|
||||
});
|
||||
|
||||
test('single post has no word-count or estimated-reading-time chain', () => {
|
||||
|
||||
Reference in New Issue
Block a user