3.2.30: 文章目录进后台(新增「自动目录」标签页)—— 位置/插入点/默认展开可配,手写 [TOC] 永远优先

后台「主题设置」新增第 5 个标签页「自动目录」,7 个选项:
  目录位置   正文中间 / 页面左侧(浮动)/ 页面右侧(浮动)
  添加方式   手动(只认 [TOC])/ 自动
  自动插入位置  文章开头 / 第一个 H1、H2 之前 / 文章结尾
  默认状态   默认显示 / 默认隐藏
  另外:目录标题、收录层级(H1~H4)、是否显示序号

设计要点:
- 插入方式拆成 toc_mode(manual/auto) x toc_anchor(start/first/end) 两个正交
  字段,不合成一个四值下拉:侧栏模式下插入位置毫无意义,合并会产生歧义。
- 手写 [TOC] 绝对优先:yang_toc_plan() 里 $has_marker 最先返回,inline_at
  ='marker' 且 rail=false —— 否则同一篇会出现两份目录,老文章升级后突然多
  出一个目录。这条是刻意守住的。
- 纯函数 + 薄壳分层:normalize_settings / plan / inject / build_list 全部不查库,
  单进程可喂几十种组合;settings() 只负责读库 + 调纯函数 + static 缓存。
- <details open> 是唯一可靠的「默认收起」手段:展开态不接受 CSS 覆盖,只能
  由 open 属性决定,所以隐藏时必须不输出该属性。
- 侧栏收起态必须 translateX(±100%) 完全移出视口:只做 opacity 会让透明面板
  留在原位吃掉正文点击(探针 elementFromPoint 才抓得到)。
- yang_toc_rail_ready() 开关:侧栏在 wp_footer 输出,那时正文可能没走
  the_content(缓存插件/OEmbed),标题没 id ⇒ 侧栏链接全跳不动却看起来正常。
  宁可不出侧栏。
- 后台联动隐藏「插入位置」不用 jQuery show()/hide():会把 .section 的行内
  display 写成 block,悄悄回退 3.2.28 的 display:flow-root BFC 修复。改用
  class + display:none!important。

验证(全部在本轮重跑):
  _test_toc.php       53/0   旧 TOC 行为回归
  _toc330_logic.php   88/0   逻辑判据
  _toc330_falsify     13/13  注入全变红且红对地方
  _geo330_rail.js     73/0   侧栏真实几何(左/右 x 展开/收起 x 宽窄屏)
  _geo330_falsify     8/8
  _guard330.php       46/0   后台控件与运行时默认值双向一致
  _guard330_falsify   8/8
  _admin330_tab_check 36/0   新标签页几何 + 联动 + 载入态
  _admin330_falsify   8/8
  _admin328_check     13/0   3.2.28 布局回归

发布:只发 zip + readme + update.json 到 theme-update/,不动服务器主题目录,
用户在 WP 后台自行升级(沿用 3.2.24 起的策略)。
This commit is contained in:
2026-10-25 12:18:52 +08:00
parent 677de0f24e
commit 6f51d50a58
7 changed files with 1060 additions and 91 deletions
+102 -6
View File
@@ -381,7 +381,103 @@ function kratos_options()
);
/* ══════════════════════════════════════════════════════════
* 五、站长信息 —— 文章页页脚那张名片
* 五、自动目录 —— 把长文切成能跳的章节
*
* 与「文章配置」分开成独立标签页,是刻意的:目录的选项有六项,
* 塞进文章配置里会把「页面布局 / 打赏」这些一眼要看到的东西挤下去。
*
* ⚠️ 这里的 std 必须与 inc/theme-toc.php 的 yang_toc_defaults() 一致。
* 前者只服务「后台预填」和「恢复默认」,运行时一律走
* kratos_option($id, 默认值) —— 两处不一致会出现
* 「页面照 A 渲染、后台框里显示 B」的错位,而且极难发现。
* ══════════════════════════════════════════════════════════ */
$options[] = array(
'name' => __('自动目录', 'kratos'),
'type' => 'heading',
);
$options[] = array(
'name' => __('目录位置', 'kratos'),
'desc' => __('<b>正文中间</b>:目录是正文的一部分,按下面的「自动插入位置」插进去。<br><b>页面左侧 / 右侧</b>:目录变成贴在页面边缘的浮动面板,点边上的小标签滑出,正文里不放任何东西(「自动插入位置」对它无效)。窄屏(手机)上也是从边缘滑出的抽屉,不会挤占正文。', 'kratos'),
'id' => 'toc_place',
'std' => 'center',
'type' => 'select',
'options' => array(
'center' => __('正文中间', 'kratos'),
'left' => __('页面左侧(浮动)', 'kratos'),
'right' => __('页面右侧(浮动)', 'kratos'),
),
);
$options[] = array(
'name' => __('添加方式', 'kratos'),
'desc' => __('<b>手动</b>:不自动加,只有正文里手写了 <b>[TOC]</b> 的地方才显示(老文章的行为,升级后不会突然多出目录)。<br><b>自动</b>:由主题自己加,不用改任何文章。', 'kratos'),
'id' => 'toc_mode',
'std' => 'manual',
'type' => 'select',
'options' => array(
'manual' => __('手动(只在写 [TOC] 的地方显示)', 'kratos'),
'auto' => __('自动添加', 'kratos'),
),
);
$options[] = array(
'name' => __('自动插入位置', 'kratos'),
'desc' => __('只在「添加方式 = 自动」且「目录位置 = 正文中间」时起作用。<br><b>第一个标题之前</b>取正文里最先出现的 h1 或 h2 —— 文章大标题在正文之外,不会被算进去;一个 h1/h2 都没有时退回插在文章开头。', 'kratos'),
'id' => 'toc_anchor',
'std' => 'first',
'type' => 'select',
'options' => array(
'start' => __('文章开头', 'kratos'),
'first' => __('第一个标题之前(H1 / H2)', 'kratos'),
'end' => __('文章结尾', 'kratos'),
),
);
$options[] = array(
'name' => __('默认状态', 'kratos'),
'desc' => __('<b>默认显示</b>:进来就能看到全部条目。<b>默认隐藏</b>:先只露出标题栏(或侧边的标签),读者自己点开。<b>较长或标题很多的文章建议默认隐藏</b>,否则目录会占掉一屏。<br>注:这里只管「默认长什么样」,读者点开后仍然可以正常使用;正文里手写的 <b>[TOC]</b> 也可以用 <b>open="0"</b> 单独指定。', 'kratos'),
'id' => 'toc_default',
'std' => 'show',
'type' => 'select',
'options' => array(
'show' => __('默认显示', 'kratos'),
'hide' => __('默认隐藏', 'kratos'),
),
);
$options[] = array(
'name' => __('目录标题', 'kratos'),
'desc' => __('显示在目录顶部的那行字。留空则用「目录」。', 'kratos'),
'id' => 'toc_title',
'std' => __('目录', 'kratos'),
'type' => 'text',
);
$options[] = array(
'name' => __('收录标题级别', 'kratos'),
'desc' => __('勾选要进目录的标题级别。<b>正文里的 h1 是作者自己写的章节标题</b>(文章大标题在正文之外,不会被收进来),所以要用 h1 分章的文章也建议勾上 h1。<br>h4 以下通常是细节,勾上会让目录变得很长。', 'kratos'),
'id' => 'toc_levels',
'std' => array('1' => 1, '2' => 1, '3' => 1, '4' => 0),
'type' => 'multicheck',
'options' => array(
'1' => array('name' => 'H1', 'note' => __('一级标题', 'kratos')),
'2' => array('name' => 'H2', 'note' => __('二级标题', 'kratos')),
'3' => array('name' => 'H3', 'note' => __('三级标题', 'kratos')),
'4' => array('name' => 'H4', 'note' => __('四级标题', 'kratos')),
),
);
$options[] = array(
'name' => __('显示序号', 'kratos'),
'desc' => __('在条目前面加 1 / 1.1 / 1.1.1 这样的序号。', 'kratos'),
'id' => 'toc_numbering',
'std' => '0',
'type' => 'checkbox',
);
/* ══════════════════════════════════════════════════════════
* 六、站长信息 —— 文章页页脚那张名片
* ══════════════════════════════════════════════════════════ */
$options[] = array(
'name' => __('站长信息', 'kratos'),
@@ -411,7 +507,7 @@ function kratos_options()
);
/* ══════════════════════════════════════════════════════════
* 六、页脚配置 —— 页面最底下那几行
* 七、页脚配置 —— 页面最底下那几行
* ══════════════════════════════════════════════════════════ */
$options[] = array(
'name' => __('页脚配置', 'kratos'),
@@ -465,7 +561,7 @@ function kratos_options()
);
/* ══════════════════════════════════════════════════════════
* 七、哀悼模式 —— 整站级功能,与首页无关
* 八、哀悼模式 —— 整站级功能,与首页无关
*
* 这一组原来错放在「首页配置」下面。它影响的是整站配色
* (首页、文章页、说明页都变黑白),放首页下面会让人以为
@@ -560,7 +656,7 @@ function kratos_options()
);
/* ══════════════════════════════════════════════════════════
* 八、收录与统计 —— 给搜索引擎看的
* 九、收录与统计 —— 给搜索引擎看的
* ══════════════════════════════════════════════════════════ */
$options[] = array(
'name' => __('收录与统计', 'kratos'),
@@ -618,7 +714,7 @@ function kratos_options()
);
/* ══════════════════════════════════════════════════════════
* 九、邮件通知 —— SMTP 与评论提醒
* 十、邮件通知 —— SMTP 与评论提醒
* ══════════════════════════════════════════════════════════ */
$options[] = array(
'name' => __('邮件通知', 'kratos'),
@@ -716,7 +812,7 @@ function kratos_options()
);
/* ══════════════════════════════════════════════════════════
* 十、自定义代码 —— 兜底用,放最后
* 十一、自定义代码 —— 兜底用,放最后
*
* 3.2.29 起这两项默认都为空:站点自己的通用样式
* (段落缩进、h2 蓝条、列表缩进)已并入 assets/css/site.css,