From 619d2bc17027db6e17024a1c469b50e97f20f002 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 11 Jul 2026 22:08:50 +0800 Subject: [PATCH] feat(frontend): single pay-box positions + Zibll cover episodes/slides Wire pay_box_position to box_top/top/bottom/box_bottom, render download or paywall modules at those slots, and resolve featured_slide/attachment IDs plus video episode chrome for single covers. --- .../src/schema/sections/payment/order.js | 2 +- .../admin/src/schema/sections/payment/paid.js | 2 +- assets/css/frontend/single-post/cover.css | 20 ++ .../class-aksrt-admin-schema-payment.php | 12 +- .../class-aksrt-settings-payment-runtime.php | 5 +- inc/helpers/aksrt-frontend-tags.php | 45 +++- inc/helpers/aksrt-single.php | 210 +++++++++++++----- 7 files changed, 221 insertions(+), 75 deletions(-) diff --git a/assets/admin/src/schema/sections/payment/order.js b/assets/admin/src/schema/sections/payment/order.js index 3991f482..c6217a54 100644 --- a/assets/admin/src/schema/sections/payment/order.js +++ b/assets/admin/src/schema/sections/payment/order.js @@ -57,7 +57,7 @@ export const orderSchema = { icon: 'fas fa-eye', fields: [ { key: 'pay_mark', label: '付费标记', type: 'input', default: '付费' }, - { key: 'pay_box_position', label: '付费框位置', type: 'radio', default: 'top', options: [{ label: '内容顶部(正文前)', value: 'top' }, { label: '内容底部(正文后)', value: 'bottom' }] }, + { key: 'pay_box_position', label: '付费框位置', type: 'radio', default: 'top', options: [{ label: '文章框顶部(封面后)', value: 'box_top' }, { label: '正文顶部', value: 'top' }, { label: '正文底部', value: 'bottom' }, { label: '文章框底部(相关前)', value: 'box_bottom' }] }, { key: 'pay_free_logged_show', label: '登录用户显示免费', type: 'switch', default: false }, { key: 'payment_show_ip', label: '显示用户IP', type: 'switch', default: false }, { key: 'payment_show_device', label: '显示设备信息', type: 'switch', default: false }, diff --git a/assets/admin/src/schema/sections/payment/paid.js b/assets/admin/src/schema/sections/payment/paid.js index 75978605..dddb4c88 100644 --- a/assets/admin/src/schema/sections/payment/paid.js +++ b/assets/admin/src/schema/sections/payment/paid.js @@ -51,7 +51,7 @@ export const paidSchema = { { key: 'payment_currency_symbol', label: '货币符号', type: 'input', default: '¥', help: '商品价格前缀,如 ¥、$、¥' }, { key: 'pay_show_user', label: '显示购买用户', type: 'switch', default: true }, { key: 'pay_show_paycount', label: '显示购买次数', type: 'switch', default: true }, - { key: 'pay_box_position', label: '付费框位置', type: 'radio', default: 'top', options: [{ label: '内容顶部(正文前)', value: 'top' }, { label: '内容底部(正文后)', value: 'bottom' }] }, + { key: 'pay_box_position', label: '付费框位置', type: 'radio', default: 'top', options: [{ label: '文章框顶部(封面后)', value: 'box_top' }, { label: '正文顶部', value: 'top' }, { label: '正文底部', value: 'bottom' }, { label: '文章框底部(相关前)', value: 'box_bottom' }] }, ], }, { diff --git a/assets/css/frontend/single-post/cover.css b/assets/css/frontend/single-post/cover.css index 2e9e6183..022527c5 100644 --- a/assets/css/frontend/single-post/cover.css +++ b/assets/css/frontend/single-post/cover.css @@ -193,3 +193,23 @@ color: var(--color-ink); } + + +/* ===== Video footer (Zibll single-video-footer) ===== */ +.single-head-cover .single-video-footer { padding: 12px 4px 4px; } +.single-head-cover .single-video-footer .article-title { + font-size: clamp(1.1rem, 2.4vw, 1.45rem); font-weight: 700; margin: 8px 0 0; line-height: 1.35; +} +.single-head-cover .featured-video-episode { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; } +.single-head-cover .featured-video-episode .switch-video { + display: inline-flex; align-items: center; max-width: 100%; padding: 6px 10px; border-radius: 8px; + background: var(--surface-2, rgba(0,0,0,.04)); color: var(--color-ink); font-size: 13px; +} +.single-head-cover .featured-video-episode .switch-video.active { + background: var(--color-primary-soft, rgba(240, 68, 148, 0.12)); color: var(--color-primary); +} +.single-head-cover .cover-meta.single-metabox { + display: flex; flex-wrap: wrap; gap: 8px 12px; font-size: 12px; color: var(--color-ink-4); +} +.aksrt-single-pay-box { margin: 16px 0 20px; } +.aksrt-single-pay-box .pay-box, .aksrt-single-pay-box .aksrt-paywall { margin: 0; } diff --git a/inc/classes/admin/schema/class-aksrt-admin-schema-payment.php b/inc/classes/admin/schema/class-aksrt-admin-schema-payment.php index 9433af92..d2c102c0 100644 --- a/inc/classes/admin/schema/class-aksrt-admin-schema-payment.php +++ b/inc/classes/admin/schema/class-aksrt-admin-schema-payment.php @@ -35,8 +35,10 @@ class AKSRT_Admin_Schema_Payment { ['key' => 'pay_show_user', 'label' => '显示购买用户', 'type' => 'switch', 'default' => true], ['key' => 'pay_show_paycount', 'label' => '显示购买次数', 'type' => 'switch', 'default' => true], ['key' => 'pay_box_position', 'label' => '付费框位置', 'type' => 'radio', 'default' => 'top', 'options' => [ - ['label' => '内容顶部(正文前)', 'value' => 'top'], - ['label' => '内容底部(正文后)', 'value' => 'bottom'], + ['label' => '文章框顶部', 'value' => 'box_top'], + ['label' => '正文顶部', 'value' => 'top'], + ['label' => '正文底部', 'value' => 'bottom'], + ['label' => '文章框底部', 'value' => 'box_bottom'], ]], ]], ['key' => 'download', 'title' => '下载能力', 'fields' => [ @@ -282,8 +284,10 @@ class AKSRT_Admin_Schema_Payment { ['key' => 'display', 'title' => '展示设置', 'fields' => [ ['key' => 'pay_mark', 'label' => '付费标记', 'type' => 'input', 'default' => '付费'], ['key' => 'pay_box_position', 'label' => '付费框位置', 'type' => 'radio', 'default' => 'top', 'options' => [ - ['label' => '内容顶部(正文前)', 'value' => 'top'], - ['label' => '内容底部(正文后)', 'value' => 'bottom'], + ['label' => '文章框顶部', 'value' => 'box_top'], + ['label' => '正文顶部', 'value' => 'top'], + ['label' => '正文底部', 'value' => 'bottom'], + ['label' => '文章框底部', 'value' => 'box_bottom'], ]], ['key' => 'pay_free_logged_show', 'label' => '登录用户显示免费', 'type' => 'switch', 'default' => false], ['key' => 'payment_show_ip', 'label' => '显示用户IP', 'type' => 'switch', 'default' => false], diff --git a/inc/classes/settings/class-aksrt-settings-payment-runtime.php b/inc/classes/settings/class-aksrt-settings-payment-runtime.php index be69c048..bd805076 100644 --- a/inc/classes/settings/class-aksrt-settings-payment-runtime.php +++ b/inc/classes/settings/class-aksrt-settings-payment-runtime.php @@ -37,7 +37,8 @@ class AKSRT_Settings_Payment_Runtime { $manual_note = trim((string) ($settings['payment_manual_delivery_note'] ?? '')); $box_position = sanitize_key((string) ($settings['pay_box_position'] ?? 'top')); - if (!in_array($box_position, ['top', 'bottom'], true)) { + // Zibll: box_top | top | bottom | box_bottom + if (!in_array($box_position, ['box_top', 'top', 'bottom', 'box_bottom'], true)) { $box_position = 'top'; } @@ -312,7 +313,7 @@ class AKSRT_Settings_Payment_Runtime { $max_minutes = max(5, min(1440, (int) ($s['payment_order_max_minutes'] ?? 30))); $box_position = sanitize_key((string) ($s['pay_box_position'] ?? 'top')); - if (!in_array($box_position, ['top', 'bottom'], true)) { + if (!in_array($box_position, ['box_top', 'top', 'bottom', 'box_bottom'], true)) { $box_position = 'top'; } diff --git a/inc/helpers/aksrt-frontend-tags.php b/inc/helpers/aksrt-frontend-tags.php index ff131488..8e3f03eb 100644 --- a/inc/helpers/aksrt-frontend-tags.php +++ b/inc/helpers/aksrt-frontend-tags.php @@ -254,19 +254,49 @@ if (!function_exists('aksrt_resolve_single_post_display_settings')) : $video_url = (string) ($meta['featured_video'] ?? ''); } - // 2. Slide cover — check for gallery/cover_images. + // 2. Slide cover — featured_slide URLs and/or cover_images (attachment IDs). $slide_images = []; - if ($slide_cover_on && !empty($meta['cover_images'])) { - $slide_images = array_filter(array_map('trim', explode(',', (string) $meta['cover_images']))); + if ($slide_cover_on) { + $raw_slides = []; + if (!empty($meta['featured_slide'])) { + $raw_slides = array_merge($raw_slides, preg_split('/[,\s]+/', (string) $meta['featured_slide']) ?: []); + } + if (!empty($meta['cover_images'])) { + $raw_slides = array_merge($raw_slides, preg_split('/[,\s]+/', (string) $meta['cover_images']) ?: []); + } + foreach ($raw_slides as $token) { + $token = trim((string) $token); + if ($token === '') { + continue; + } + if (ctype_digit($token)) { + $src = wp_get_attachment_image_url((int) $token, 'full'); + if (is_string($src) && $src !== '') { + $slide_images[] = $src; + } + continue; + } + if (filter_var($token, FILTER_VALIDATE_URL)) { + $slide_images[] = esc_url_raw($token); + } + } + $slide_images = array_values(array_unique(array_filter($slide_images))); } // 3. Image cover — existing logic. if ($video_url !== '') { $cover_type = 'video'; $cover_url = $video_url; - } elseif (!empty($slide_images) && count($slide_images) > 1) { - $cover_type = 'slide'; - $cover_url = $slide_images[0]; + } elseif (!empty($slide_images) && count($slide_images) >= 1) { + // One explicit slide image still becomes image cover; 2+ become slide. + if (count($slide_images) > 1) { + $cover_type = 'slide'; + $cover_url = $slide_images[0]; + } else { + $cover_type = 'image'; + $cover_url = $slide_images[0]; + $slide_images = []; + } } elseif ($image_cover_on) { if ($cover_mode === 'auto') { $cover_url = function_exists('aksrt_get_first_content_image_url') @@ -287,6 +317,9 @@ if (!function_exists('aksrt_resolve_single_post_display_settings')) : $settings['cover_type'] = $cover_type; $settings['show_cover'] = $cover_type !== 'none'; $settings['slide_images'] = $slide_images ?? []; + $settings['featured_video'] = (string) ($meta['featured_video'] ?? ''); + $settings['episode_count'] = max(0, (int) ($meta['featured_video_episode'] ?? 0)); + $settings['video_poster'] = (string) ($meta['cover_image'] ?? ''); $meta_copyright = trim((string) ($meta['copyright_text'] ?? '')); if ($meta_copyright !== '') { $settings['copyright_text'] = $meta_copyright; diff --git a/inc/helpers/aksrt-single.php b/inc/helpers/aksrt-single.php index 2bb05e26..bdb61379 100644 --- a/inc/helpers/aksrt-single.php +++ b/inc/helpers/aksrt-single.php @@ -74,19 +74,20 @@ if (!function_exists('aksrt_single_build_context')) : $paid_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_paid_content_settings() : []; $paid_display = is_array($paid_settings['display'] ?? null) ? $paid_settings['display'] : []; - $paid_box_position = (string) ($paid_display['box_position'] ?? 'top'); - if ($paid_box_position === 'box_top') { - $paid_box_position = 'top'; - } elseif ($paid_box_position === 'box_bottom') { - $paid_box_position = 'bottom'; - } - if (!in_array($paid_box_position, ['top', 'bottom'], true)) { + $paid_box_position = sanitize_key((string) ($paid_display['box_position'] ?? 'top')); + // Zibll positions: box_top | top | bottom | box_bottom (do not collapse). + if (!in_array($paid_box_position, ['box_top', 'top', 'bottom', 'box_bottom'], true)) { $paid_box_position = 'top'; } $show_cover = !empty($settings['show_cover']) && (string) ($settings['cover_url'] ?? '') !== ''; $show_toc = !empty($settings['toc_enabled']); $has_download = function_exists('aksrt_is_downloadable_content') && aksrt_is_downloadable_content($post_id); + $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'); $breadcrumbs_html = ''; if (!empty($settings['breadcrumbs']) && function_exists('aksrt_breadcrumbs')) { @@ -124,7 +125,8 @@ if (!function_exists('aksrt_single_build_context')) : 'img_scale' => (int) ($settings['article_image_cover_scale'] ?? 35), 'video_scale' => (int) ($settings['article_video_cover_scale'] ?? 56), 'slide_images' => array_values(array_filter((array) ($settings['slide_images'] ?? []))), - 'episode_count' => max(0, (int) get_post_meta($post_id, '_aksrt_featured_video_episode', true)), + 'episode_count' => max(0, (int) ($settings['episode_count'] ?? 0)), + 'video_poster' => (string) ($settings['video_poster'] ?? ''), 'meta_items' => $meta_items, 'views' => $views, 'comment_count' => $comment_count, @@ -137,10 +139,13 @@ if (!function_exists('aksrt_single_build_context')) : 'after_content' => (string) ($settings['after_content'] ?? ''), 'content_maxheight' => !empty($settings['maxheight_enabled']) ? max(0, (int) ($settings['maxheight'] ?? 0)) : 0, 'has_download' => $has_download, + 'show_pay_box' => $show_pay_box, + 'pay_type' => $pay_type, + 'is_paid_post' => $is_paid_post, 'paid_box_position' => $paid_box_position, 'breadcrumbs_html' => $breadcrumbs_html, 'status_badge' => $status_badge, - 'show_aside' => $aside_widgets || $show_toc || $has_download, + 'show_aside' => $aside_widgets || $show_toc || $has_download || $show_pay_box, 'toc_title' => __('文章目录', 'aksrt'), ]; } @@ -177,7 +182,7 @@ endif; if (!function_exists('aksrt_single_render_cover')) : /** - * Cover / slide / video header. + * Cover / slide / video header (Zibll single-head-cover). * * @param array $ctx Single context. */ @@ -190,29 +195,44 @@ if (!function_exists('aksrt_single_render_cover')) : $badge = (string) $ctx['status_badge']; $crumbs = (string) $ctx['breadcrumbs_html']; $meta_items = is_array($ctx['meta_items'] ?? null) ? $ctx['meta_items'] : []; - $img_scale = (int) $ctx['img_scale']; - $video_scale = (int) $ctx['video_scale']; + $img_scale = max(10, min(100, (int) $ctx['img_scale'])); + $video_scale = max(20, min(100, (int) $ctx['video_scale'])); $episode = (int) $ctx['episode_count']; $slides = is_array($ctx['slide_images'] ?? null) ? $ctx['slide_images'] : []; + $poster = (string) ($ctx['video_poster'] ?? ''); + $title = get_the_title(); if ($type === 'video') : ?> -
- -
-
- -
- -

- -
- - - +
+
+ +
+
+
@@ -222,27 +242,29 @@ if (!function_exists('aksrt_single_render_cover')) : if ($type === 'slide' && !empty($slides)) : ?> -
-
- $slide_url) : ?> -
- <?php echo esc_attr(get_the_title()); ?> -
- -
-
-
- -
- -

- +
+
+
+ $slide_url) : ?> +
+ <?php echo esc_attr($title); ?> +
+ +
+
+
+ +
+ +

+ +
-