feat(admin): replicate reference post-page settings page 1:1

- rewrite post_list.page schema (JS+PHP 2.0.0) with the reference field set:
  three cover types with option fieldsets (image 20-200% / slide CFS_Module::slide
  full config with nested dependsOn / video 0-200%), hide-time, p_indent,
  breadcrumbs (home-text as switcher), prevnext, authordesc, maxheight slider,
  yiyan block, copyright, button toptext, front/after content, related posts
- migrate share_s to share page basic group and post_rewards_* to users
  features rewards group (runtime keys unchanged)
- remap get_post_page_settings() to reference keys, normalize slide cover
  option, hardcode non-reference runtime flags (reading progress, favorites,
  author card), drop dual-path legacy aliases
- wire slide option into aksrt_render_slider (effect/direction/spaceBetween/
  speed/interval/loop/autoplay/nav/pagination, scale vs fixed-height modes),
  clamp image scale 20-200 and video scale 0-200 with 16:9 fallback,
  wire p_indent container class + CSS, resync frontend-tags fallback and
  FacadeBulk fallback, remap PostMetaBox cover keys
- add post-page reference contract test; update stale cover-height and
  user-features contract tests

Validation: node --test 464/464 pass, audit-admin-contracts errors=0,
vite build ok, build-public-assets ok, php -l clean.
This commit is contained in:
2026-09-24 16:13:00 +08:00
parent a8060fa71d
commit 66f8bb933d
17 changed files with 797 additions and 267 deletions
+172 -124
View File
@@ -1,144 +1,192 @@
export const pageSchema = {
key: 'post_list.page',
title: '文章页面',
icon: 'fa fas fa-file-alt',
description: '配置单篇文章页面的导航、封面、版权区与互动功能。',
icon: 'fa fas fa-bookmark',
description: '配置文章页面封面、面包屑导航、版权声明、插入内容与相关文章版块。',
defaults: {
post_reading_progress: true,
article_image_cover: true,
article_image_cover_option: { scale: 35 },
article_slide_cover: true,
article_slide_cover_option: {
direction: 'horizontal',
loop: true,
button: false,
pagination: true,
effect: 'slide',
scale_height: true,
scale: 35,
auto_height: false,
max_height: 500,
min_height: 180,
pc_height: 380,
m_height: 180,
spacebetween: 15,
speed: 0,
autoplay: true,
interval: 4,
},
article_video_cover: true,
article_video_cover_option: { scale: 0 },
post_single_hide_time_s: false,
post_p_indent_s: false,
breadcrumbs_single_s: true,
breadcrumbs_home_text: '首页',
breadcrumbs_home_text: true,
post_prevnext_s: true,
post_authordesc_s: true,
post_single_hide_time_s: false,
article_maxheight_kg: false,
article_maxheight: 1000,
yiyan_single_content_header: false,
yiyan_single_content_footer: false,
yiyan_single_box: false,
post_copyright_s: true,
post_copyright: '文章版权归作者所有,未经允许请勿转载。',
post_button_toptext: '喜欢就支持一下吧',
post_front_content: '',
post_after_content: '',
post_related_s: true,
post_related_type: 'img',
related_title: '相关推荐',
post_related_n: 6,
post_related_orderby: 'views',
breadcrumbs_single_text: true,
post_copyright_enabled: true,
post_copyright_text: '',
share_s: true,
post_favorite_enabled: true,
post_front_content: '',
post_after_content: '',
post_yiyan_header: false,
post_yiyan_footer: false,
post_yiyan_box: false,
post_article_image_cover: true,
post_article_image_cover_scale: 35,
post_article_slide_cover: true,
post_article_video_cover: true,
post_article_video_cover_scale: 56,
item_heading_bold: false,
post_button_toptext: '喜欢就支持一下吧',
post_rewards_s: false,
post_rewards_text: '赞赏',
post_author_card_limit: 6,
post_author_card_orderby: 'views',
post_author_card_style: 'card',
article_maxheight_kg: false,
article_maxheight: 1000,
},
groups: [
{
key: 'navigation',
title: '文章导航',
icon: 'fa fas fa-compass',
key: 'post_page',
title: '文章页面',
icon: 'fa fas fa-bookmark',
fields: [
{ key: 'post_reading_progress', label: '阅读进度条', type: 'switch', default: true },
{ key: 'article_image_cover', label: '图片封面', type: 'switch', default: true, description: '允许设置文章页顶部显示封面图' },
{
key: 'article_image_cover_option',
label: ' ',
type: 'fieldset',
default: { scale: 35 },
dependsOn: { key: 'article_image_cover', value: true },
description: '图片封面配置',
fields: [
{ key: 'scale', label: '图片长宽比例', type: 'number', default: 35, min: 20, max: 200, step: 5, unit: '%' },
],
},
{ key: 'article_slide_cover', label: '幻灯片封面', type: 'switch', default: true, description: '允许设置幻灯片为文章封面' },
{
key: 'article_slide_cover_option',
label: ' ',
type: 'fieldset',
default: {
direction: 'horizontal',
loop: true,
button: false,
pagination: true,
effect: 'slide',
scale_height: true,
scale: 35,
auto_height: false,
max_height: 500,
min_height: 180,
pc_height: 380,
m_height: 180,
spacebetween: 15,
speed: 0,
autoplay: true,
interval: 4,
},
dependsOn: { key: 'article_slide_cover', value: true },
fields: [
{ key: 'direction', label: '幻灯片方向', type: 'radio', default: 'horizontal', options: [{ label: '左右切换', value: 'horizontal' }, { label: '上下切换', value: 'vertical' }] },
{ key: 'loop', label: '循环切换', type: 'switch', default: true },
{ key: 'button', label: '显示翻页按钮', type: 'switch', default: false },
{ key: 'pagination', label: '显示指示器', type: 'switch', default: true },
{
key: 'effect',
label: '切换动画',
type: 'select',
default: 'slide',
options: [
{ label: '滑动', value: 'slide' },
{ label: '淡出淡入', value: 'fade' },
{ label: '3D方块', value: 'cube' },
{ label: '3D滑入', value: 'coverflow' },
{ label: '3D翻转', value: 'flip' },
],
},
{ key: 'scale_height', label: '按比例自动高度', type: 'switch', default: true, dependsOn: { key: 'direction', not: 'vertical' } },
{ key: 'scale', label: '长宽比例', type: 'number', default: 35, min: 10, max: 300, step: 5, unit: '%', dependsOn: { all: [{ key: 'direction', not: 'vertical' }, { key: 'scale_height', value: true }] } },
{ key: 'auto_height', label: '自动高度', type: 'switch', default: false, dependsOn: { all: [{ key: 'direction', not: 'vertical' }, { key: 'scale_height', value: false }] } },
{ key: 'max_height', label: '最大高度', type: 'number', default: 500, min: 120, max: 800, step: 20, unit: 'PX', dependsOn: { all: [{ key: 'auto_height', value: true }, { key: 'direction', not: 'vertical' }, { key: 'scale_height', value: false }] } },
{ key: 'min_height', label: '最小高度', type: 'number', default: 180, min: 100, max: 500, step: 20, unit: 'PX', dependsOn: { all: [{ key: 'auto_height', value: true }, { key: 'direction', not: 'vertical' }, { key: 'scale_height', value: false }] } },
{ key: 'pc_height', label: '电脑端高度', type: 'number', default: 380, min: 120, max: 800, step: 20, unit: 'PX' },
{ key: 'm_height', label: '移动端高度', type: 'number', default: 180, min: 100, max: 500, step: 20, unit: 'PX' },
{ key: 'spacebetween', label: '幻灯片间距', type: 'number', default: 15, min: 0, max: 500, step: 5, unit: 'PX' },
{ key: 'speed', label: '切换速度', type: 'number', default: 0, min: 0, max: 3000, step: 100, unit: '毫秒', description: '切换过程的时间(越小越快),设置为0则为自动模式' },
{ key: 'autoplay', label: '自动播放', type: 'switch', default: true },
{ key: 'interval', label: '停顿时间', type: 'number', default: 4, min: 0, max: 20, step: 1, unit: '秒', dependsOn: { key: 'autoplay', value: true }, description: '自动切换的时间间隔(越小越快)' },
],
},
{ key: 'article_video_cover', label: '视频封面', type: 'switch', default: true, description: '允许设置视频为文章封面' },
{
key: 'article_video_cover_option',
label: ' ',
type: 'fieldset',
default: { scale: 0 },
dependsOn: { key: 'article_video_cover', value: true },
description: '视频封面配置 <a href="https://www.zibll.com/1900.html" target="_blank">【查看官方封面配置教程】</a>',
fields: [
{ key: 'scale', label: '固定长宽比例', type: 'number', default: 0, min: 0, max: 200, step: 5, unit: '%', description: '为0则不固定长宽比例' },
],
},
{ key: 'post_single_hide_time_s', label: '隐藏时间', type: 'switch', default: false, description: '隐藏文章的更新及发布时间显示' },
{ key: 'post_p_indent_s', label: '内容段落缩进', type: 'switch', default: false, description: '开启后文章内容每一个段落首行将向右偏移2个文字距离' },
{ key: 'breadcrumbs_single_s', label: '面包屑导航', type: 'switch', default: true },
{ key: 'breadcrumbs_home_text', label: '面包屑首页文字', type: 'input', default: '首页', dependsOn: { key: 'breadcrumbs_single_s', value: true } },
{ key: 'breadcrumbs_single_text', label: '末项显示「正文」', type: 'switch', default: true, dependsOn: { key: 'breadcrumbs_single_s', value: true }, help: '关闭后末项显示文章标题' },
{ key: 'post_prevnext_s', label: '上一篇/下一篇', type: 'switch', default: true },
{ key: 'post_authordesc_s', label: '作者简介', type: 'switch', default: true },
{ key: 'post_author_card_limit', label: '作者卡文章数', type: 'number', default: 6, min: 0, max: 12, dependsOn: { key: 'post_authordesc_s', value: true } },
{ key: 'post_author_card_orderby', label: '作者卡文章排序', type: 'select', default: 'views', options: [
{ label: '浏览量', value: 'views' },
{ label: '发布时间', value: 'date' },
{ label: '更新时间', value: 'modified' },
{ label: '评论数', value: 'comment_count' },
], dependsOn: { key: 'post_authordesc_s', value: true } },
{ key: 'post_author_card_style', label: '作者卡文章样式', type: 'radio', default: 'card', options: [
{ label: '卡片', value: 'card' },
{ label: '列表', value: 'list' },
], dependsOn: { key: 'post_authordesc_s', value: true } },
{ key: 'post_single_hide_time_s', label: '隐藏文章时间', type: 'switch', default: false },
],
},
{
key: 'cover',
title: '封面展示',
icon: 'fa fas fa-image',
fields: [
{ key: 'post_article_image_cover', label: '图片封面', type: 'switch', default: true, help: '文章有特色图时自动展示封面' },
{ key: 'post_article_image_cover_scale', label: '封面高度比例(%)', type: 'number', default: 35, min: 10, max: 100, dependsOn: { key: 'post_article_image_cover', value: true } },
{ key: 'post_article_slide_cover', label: '幻灯片封面', type: 'switch', default: true, help: '文章有图集时以轮播形式展示封面' },
{ key: 'post_article_video_cover', label: '视频封面', type: 'switch', default: true, help: '文章有视频时以视频播放器作为封面' },
{ key: 'post_article_video_cover_scale', label: '视频封面高度比例(%)', type: 'number', default: 56, min: 20, max: 100, dependsOn: { key: 'post_article_video_cover', value: true } },
],
},
{
key: 'related',
title: '相关推荐',
icon: 'fa fas fa-random',
fields: [
{ key: 'post_related_s', label: '显示相关推荐', type: 'switch', default: true },
{ key: 'post_related_type', label: '展示样式', type: 'radio', default: 'img', options: [
{ label: '图文卡片', value: 'img' },
{ label: '列表', value: 'list' },
{ label: '纯文字', value: 'text' },
], dependsOn: { key: 'post_related_s', value: true }, help: '对齐 legacy 相关文章三种样式' },
{ key: 'related_title', label: '推荐标题', type: 'input', default: '相关推荐', dependsOn: { key: 'post_related_s', value: true } },
{ key: 'post_related_n', label: '推荐数量', type: 'number', default: 6, min: 4, max: 12, step: 2, dependsOn: { key: 'post_related_s', value: true } },
{ key: 'post_related_orderby', label: '推荐排序', type: 'select', default: 'views', options: [
{ label: '更新时间', value: 'modified' },
{ label: '发布时间', value: 'date' },
{ label: '浏览量', value: 'views' },
{ label: '点赞量', value: 'like' },
{ label: '评论量', value: 'comment_count' },
{ label: '收藏数量', value: 'favorite' },
{ label: '随机', value: 'rand' },
], dependsOn: { key: 'post_related_s', value: true } },
],
},
{
key: 'interactions',
title: '互动功能',
icon: 'fa fas fa-heart',
fields: [
{ key: 'post_favorite_enabled', label: '收藏', type: 'switch', default: true },
{ key: 'share_s', label: '分享按钮', type: 'switch', default: true },
{ key: 'post_copyright_enabled', label: '版权信息', type: 'switch', default: true },
{ key: 'post_copyright_text', label: '版权默认文案', type: 'textarea', default: '', help: '留空则自动生成"本文由 XX 原创发布"' },
{ key: 'post_button_toptext', label: '按钮上方文案', type: 'input', default: '喜欢就支持一下吧', help: '显示在点赞/打赏/分享按钮上方' },
{ key: 'post_rewards_s', label: '用户打赏', type: 'switch', default: false, help: '开启后,登录用户可使用站内余额赞赏作者,金额直接进入作者余额。' },
{ key: 'post_rewards_text', label: '打赏按钮文案', type: 'input', default: '赞赏', dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'post_rewards_amounts', label: '快捷金额', type: 'input', default: '5,10,20,50,100', help: '使用英文逗号分隔', dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'post_rewards_custom', label: '允许自定义金额', type: 'switch', default: true, dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'post_rewards_min', label: '最低金额', type: 'input', default: '1.00', min: 0.01, max: 1000, step: 0.01, dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'post_rewards_max', label: '最高金额', type: 'input', default: '1000.00', min: 1, max: 100000, step: 0.01, dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'article_maxheight_kg', label: '正文限高', type: 'switch', default: false, help: '开启后长文默认折叠,可展开全文' },
{ key: 'article_maxheight', label: '限高像素', type: 'number', default: 1000, min: 200, max: 5000, dependsOn: { key: 'article_maxheight_kg', value: true } },
],
},
{
key: 'content',
title: '内容插入',
icon: 'fa fas fa-pen-square',
fields: [
{ key: 'post_front_content', label: '文章头部内容', type: 'textarea', default: '', help: '显示在所有文章正文前方(支持 HTML)' },
{ key: 'post_after_content', label: '文章底部内容', type: 'textarea', default: '', help: '显示在所有文章正文后方(支持 HTML)' },
],
},
{
key: 'yiyan',
title: '一言',
icon: 'fa fas fa-quote-left',
fields: [
{ key: 'post_yiyan_header', label: '文章头部一言', type: 'switch', default: false, help: '在文章标题下方显示一言' },
{ key: 'post_yiyan_footer', label: '文章底部一言', type: 'switch', default: false, help: '在文章内容底部显示一言' },
{ key: 'post_yiyan_box', label: '一言盒子', type: 'switch', default: false, help: '在相关文章前显示一言盒子' },
{ key: 'breadcrumbs_home_text', label: '面包屑导航用“首页”替代网站名称', type: 'switch', default: true, dependsOn: { key: 'breadcrumbs_single_s', value: true } },
{ key: 'post_prevnext_s', label: '上一页、下一页版块', type: 'switch', default: true },
{ key: 'post_authordesc_s', label: '作者信息版块', type: 'switch', default: true },
{ key: 'article_maxheight_kg', label: '内容高度限制', type: 'switch', default: false, description: '此处为全局设置,每篇文章可单独设置', help: '全局开关' },
{ key: 'article_maxheight', label: '限制的最大高度', type: 'slider', default: 1000, min: 600, max: 3000, step: 100, unit: 'px', dependsOn: { key: 'article_maxheight_kg', value: true }, description: '开启后如果文章高度超过设定值则会显示展开阅读全文的按钮。每篇文章可单独开启此功能' },
{
key: 'yiyan_intro',
type: 'content',
ui_only: true,
content: '<p style="margin:0;font-size:12px;color:var(--aksrt-color-muted);line-height:1.7;"><b>精彩一言功能:</b>随机显示中英文的文案,在此支持一言内容插入到文章页位置,同时可以使用小工具模块调用。<br/>主题默认调用的文件为:<code>themes/aksrt/yiyan/qv-yiyan.txt</code><br/>您可以将以上文件复制到 <code>wp-content</code> 文件夹,并重命名为 <code>yiyan.txt</code>,再进行修改或添加内容,则今后更新主题就无需二次修改</p>',
},
{ key: 'yiyan_single_content_header', label: '文章内容头部显示一言', type: 'switch', default: false },
{ key: 'yiyan_single_content_footer', label: '文章内容尾部显示一言', type: 'switch', default: false },
{ key: 'yiyan_single_box', label: '文章页面下方独立一言版块', type: 'switch', default: false },
{ key: 'post_copyright_s', label: '版权声明', type: 'switch', default: true },
{ key: 'post_copyright', label: '版权提示内容', type: 'textarea', default: '文章版权归作者所有,未经允许请勿转载。', rows: 2, dependsOn: { key: 'post_copyright_s', value: true }, description: '支持HTML代码,请注意代码规范及标签闭合' },
{ key: 'post_button_toptext', label: '文章页脚文案', type: 'input', default: '喜欢就支持一下吧', description: '文章底部打赏、分享按钮上面的文字' },
{ key: 'post_front_content', label: '在文章内容前-插入内容', type: 'textarea', default: '', rows: 3 },
{ key: 'post_after_content', label: '在文章内容后-插入内容', type: 'textarea', default: '', rows: 3, description: '在每篇文章顶部和尾部插入内容,可以插入广告或者文章说明等内容。支持HTML代码,请注意代码规范及标签闭合' },
{ key: 'post_related_s', label: '相关文章版块', type: 'switch', default: true },
{
key: 'post_related_type',
label: '显示样式',
type: 'image_select',
default: 'img',
dependsOn: { key: 'post_related_s', value: true },
options: [
{ label: '图文卡片', value: 'img', icon: 'fa fas fa-image' },
{ label: '列表', value: 'list', icon: 'fa fas fa-list' },
{ label: '纯文字', value: 'text', icon: 'fa fas fa-align-left' },
],
},
{ key: 'related_title', label: '版块标题', type: 'input', default: '相关推荐', dependsOn: { key: 'post_related_s', value: true } },
{ key: 'post_related_n', label: '显示数量', type: 'number', default: 6, min: 4, max: 12, step: 2, unit: '篇', dependsOn: { key: 'post_related_s', value: true } },
{
key: 'post_related_orderby',
label: '排序方式',
type: 'select',
default: 'views',
dependsOn: { key: 'post_related_s', value: true },
options: [
{ label: '更新时间', value: 'modified' },
{ label: '发布时间', value: 'date' },
{ label: '浏览量', value: 'views' },
{ label: '点赞量', value: 'like' },
{ label: '评论量', value: 'comment_count' },
{ label: '收藏数量', value: 'favorite' },
{ label: '随机', value: 'rand' },
],
},
],
},
],
@@ -4,6 +4,7 @@ export const shareSchema = {
icon: 'fa fas fa-share-alt',
description: '配置微信分享凭据、海报分享和社交分享选项。',
defaults: {
share_s: true,
share_wechat_s: false,
share_wechat_appid: '',
share_wechat_app_secret: '',
@@ -15,6 +16,14 @@ export const shareSchema = {
share_desc: '扫一扫 立即查看',
},
groups: [
{
key: 'basic',
title: '分享按钮',
icon: 'fa fas fa-share-alt',
fields: [
{ key: 'share_s', label: '分享按钮', type: 'switch', default: true, help: '关闭后,在文章页面将不显示分享按钮,论坛及商城不受影响' },
],
},
{
key: 'wechat',
title: '微信分享',
@@ -14,6 +14,12 @@ export const featuresSchema = {
user_cover_upload_s: true,
user_cover_img: `${themeRoot}/assets/img/user_t.jpg`,
user_desc_std: '这家伙很懒,什么都没有写...',
post_rewards_s: true,
post_rewards_text: '赞赏',
post_rewards_amounts: '5,10,20,50,100',
post_rewards_custom: true,
post_rewards_min: '1.00',
post_rewards_max: '1000.00',
},
groups: [
{
@@ -45,5 +51,18 @@ export const featuresSchema = {
{ key: 'user_desc_std', label: '用户默认签名', type: 'input', default: '这家伙很懒,什么都没有写...', help: '用户未设置个人简介时显示的默认文案。' },
],
},
{
key: 'rewards',
title: '打赏',
icon: 'fa fas fa-hand-holding-heart',
fields: [
{ key: 'post_rewards_s', label: '用户打赏功能', type: 'switch', default: true, help: '开启后,登录用户可使用站内余额赞赏作者,金额直接进入作者余额。' },
{ key: 'post_rewards_text', label: '打赏按钮文案', type: 'input', default: '赞赏', dependsOn: { key: 'post_rewards_s', value: true }, help: '自定义打赏按钮文字' },
{ key: 'post_rewards_amounts', label: '快捷金额', type: 'input', default: '5,10,20,50,100', dependsOn: { key: 'post_rewards_s', value: true }, help: '使用英文逗号分隔' },
{ key: 'post_rewards_custom', label: '允许自定义金额', type: 'switch', default: true, dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'post_rewards_min', label: '最低金额', type: 'input', default: '1.00', min: 0.01, max: 1000, step: 0.01, dependsOn: { key: 'post_rewards_s', value: true } },
{ key: 'post_rewards_max', label: '最高金额', type: 'input', default: '1000.00', min: 1, max: 100000, step: 0.01, dependsOn: { key: 'post_rewards_s', value: true } },
],
},
],
}
+5
View File
@@ -476,6 +476,11 @@ article.article.box-body,
margin: 0 0 1.5em;
}
/* 段落首行缩进(参考主题 post_p_indent_s:开启后正文段落首行缩进 2em)。 */
.wp-posts-content.p-indent p {
text-indent: 2em;
}
:is(.entry-content, .wp-posts-content) h2 {
font-size: 20px;
font-weight: 700;
+1 -1
View File
File diff suppressed because one or more lines are too long
@@ -137,6 +137,11 @@ article.article.box-body,
margin: 0 0 1.5em;
}
/* 段落首行缩进(参考主题 post_p_indent_s:开启后正文段落首行缩进 2em)。 */
.wp-posts-content.p-indent p {
text-indent: 2em;
}
:is(.entry-content, .wp-posts-content) h2 {
font-size: 20px;
font-weight: 700;