自动目录两份默认状态分别设置,老配置平滑迁移 #27
正文那份与浮层那份的「默认状态」拆成两项,各管各的: - theme-toc.php:toc_default 拆成 inline_default / float_default; normalize 加四分支迁移段(新键合法→用它;新键非法→回落该键默认; 新键缺失 + 老键存在→用老键;都不存在→各键默认); 读库键列表继续读老键 'default',不读就拿不到迁移值,老站点会被静默重置; 正文的 open 与浮层的 is_open 各读自己的键,互不引用。 - theme-options.php:两个独立下拉分别落在「正文里的目录」「浮动目录」 分组末尾;共用分组里那句「对两份同时生效」已过时,改写。 - 新增 yang_toc_admin_legacy_values() 挂 option_kratos(仅 is_admin): 后台读配置时把老键的值内存投影到缺失的新键上。不投影的话, 老站点会出现「页面按 hide 渲染、后台下拉框却显示 show」的错位。 只在读取时投影,库不动,降级回旧版仍有退路。 - style.css 版本号 3.2.59(本版未改前台 CSS,kratos.min.css 与 JS 均未动)。 验证:桩判据 61/0,反证 16 组 36/0,真实 WP 判据 30/0, 回归 _toc330_logic 101/0、_test_toc 53/0,打包自检 42/0。
This commit is contained in:
+147
-5
@@ -115,7 +115,25 @@ function yang_toc_defaults()
|
||||
'float_side' => 'left', // left | right(贴页面哪一边)
|
||||
'mode' => 'manual', // manual | auto
|
||||
'anchor' => 'first', // start | first | end(只对 inline 有效)
|
||||
'default' => 'show', // show | hide
|
||||
|
||||
/* ── 默认开合:两份**各自独立**(3.2.59 起)───────────────
|
||||
*
|
||||
* 原来只有一个 'default',正文那份和浮层那份共用同一个值,
|
||||
* 改一个另一个必然跟着变。用户要的是「浮层默认隐藏、正文默认显示」
|
||||
* 这种组合,一个值表达不了。
|
||||
*
|
||||
* ⚠️ 'default' 不再出现在返回数组里,但它**仍然是被接受的输入键**
|
||||
* (见 yang_toc_normalize_settings() 里的迁移段)。老配置、
|
||||
* 老版本的子主题调用传进来都还能生效。
|
||||
*
|
||||
* 为什么不在返回值里保留 'default' 当"两者的投影":
|
||||
* 那会变成一个可能跟两个新键不一致的影子值,
|
||||
* 将来谁读到它就成了一个说不清来源的 bug。宁可让老键
|
||||
* 在输出里彻底消失 —— 输入兼容、输出单一事实。
|
||||
*/
|
||||
'inline_default' => 'show', // show | hide(正文那份)
|
||||
'float_default' => 'show', // show | hide(浮层那份)
|
||||
|
||||
'title' => __('目录', 'kratos'),
|
||||
'levels' => array('1' => 1, '2' => 1, '3' => 1, '4' => 0),
|
||||
'numbering' => 0,
|
||||
@@ -219,7 +237,46 @@ function yang_toc_normalize_settings($raw)
|
||||
$s['float_side'] = $pick('float_side', array('left', 'right'));
|
||||
$s['mode'] = $pick('mode', array('manual', 'auto'));
|
||||
$s['anchor'] = $pick('anchor', array('start', 'first', 'end'));
|
||||
$s['default'] = $pick('default', array('show', 'hide'));
|
||||
|
||||
/* ── 默认开合:两份各自独立 + 老配置迁移 ───────────────────────
|
||||
*
|
||||
* 3.2.59 把原来的单个 'default' 拆成 inline_default / float_default。
|
||||
* 这里要同时满足四件事,少一件就会有人升级后设置被偷偷改掉:
|
||||
*
|
||||
* ① 新键存在且合法 → 用它
|
||||
* ② 新键存在但值非法 → 回落该键的默认(不用老键顶,老键更可能是脏的)
|
||||
* ③ 新键**不存在**、老键存在 → 老键的值(这就是迁移:老站点只存了
|
||||
* toc_default,升级后两份都该保持原样)
|
||||
* ④ 新旧都不存在 → 各键默认
|
||||
*
|
||||
* 🔴 为什么不能简单写成 $pick('inline_default', ...):
|
||||
* $pick 的语义是「键不存在 ⇒ 取 $d[$key]」,也就是 ④。
|
||||
* 那样一来 ③ 就落进 ④,老站点设了「默认隐藏」的,升级后
|
||||
* 两份**全部变回 show**,而界面上还看不出任何异常 ——
|
||||
* 这正是「静默重置用户配置」,比崩掉更难发现。
|
||||
*
|
||||
* 为什么顺序是「先看新键,再退回老键」而不是反过来:
|
||||
* 用户一旦在 3.2.59 之后动过新下拉框,库里就有新键了,
|
||||
* 此时老键成了历史残留 —— 必须让新键完全压过它,否则
|
||||
* 用户「改成默认显示」保存后会发现没生效(老键还在那儿赢)。
|
||||
*/
|
||||
$legacy = null;
|
||||
if (array_key_exists('default', $raw) && in_array($raw['default'], array('show', 'hide'), true)) {
|
||||
$legacy = $raw['default'];
|
||||
}
|
||||
|
||||
$new_pair = array('inline_default', 'float_default');
|
||||
$s['inline_default'] = $d['inline_default'];
|
||||
$s['float_default'] = $d['float_default'];
|
||||
foreach ($new_pair as $k) {
|
||||
if (array_key_exists($k, $raw)) {
|
||||
$s[$k] = in_array($raw[$k], array('show', 'hide'), true)
|
||||
? $raw[$k]
|
||||
: $d[$k];
|
||||
} elseif ($legacy !== null) {
|
||||
$s[$k] = $legacy; // ③ 迁移:只存过老键的站点
|
||||
}
|
||||
}
|
||||
|
||||
$title = array_key_exists('title', $raw) ? $raw['title'] : $d['title'];
|
||||
$title = is_string($title) ? trim(wp_strip_all_tags($title)) : '';
|
||||
@@ -249,7 +306,13 @@ function yang_toc_settings()
|
||||
|
||||
$raw = array();
|
||||
foreach (array('inline', 'inline_align', 'float', 'float_side',
|
||||
'mode', 'anchor', 'default', 'title', 'levels', 'numbering') as $k) {
|
||||
'mode', 'anchor', 'title', 'levels', 'numbering',
|
||||
'inline_default', 'float_default',
|
||||
/* 'default' 是 3.2.58 及更早版本的旧键,**必须继续读**:
|
||||
不读就不知道老配置里存了什么,迁移段拿不到值,
|
||||
老站点升级后默认开合会被重置成 show。
|
||||
读进来之后由 normalize 的迁移段消化掉,不会出现在输出里。 */
|
||||
'default') as $k) {
|
||||
$raw[$k] = kratos_option('toc_' . $k, null);
|
||||
}
|
||||
// 库里没有的键用 null 占位,normalize 时按「未配置」回落默认值
|
||||
@@ -263,6 +326,80 @@ function yang_toc_settings()
|
||||
return $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台表单读设置时,把老键 toc_default 的值"投影"到两个新键上
|
||||
*
|
||||
* ── 为什么需要这一层(3.2.59,工单 #27,实测出来的问题)───────────
|
||||
*
|
||||
* 迁移在 yang_toc_normalize_settings() 里已经做对了:老站点只存
|
||||
* toc_default=hide 时,页面**实际**渲染成 hide。
|
||||
*
|
||||
* 但后台表单不是走 normalize 的 —— 框架(class-options-interface.php:87-96)
|
||||
* 的规则是:
|
||||
* $val = $value['std']; // 先取 std
|
||||
* if (isset($settings[$id])) { $val = $settings[$id]; } // 库里有就覆盖
|
||||
* 老站点库里**没有** toc_inline_default 这个键 ⇒ `$val` 停在 std=show。
|
||||
*
|
||||
* 结果就是(真机上实测到的):
|
||||
* 页面实际渲染:hide
|
||||
* 后台下拉框: show ← 错位
|
||||
*
|
||||
* 用户看到下拉框写着「默认显示」,会以为自己的设置丢了;而且他若不
|
||||
* 主动去改,就永远不会触发保存,这个错位会一直存在。
|
||||
* 更糟的是"看起来是 show、实际是 hide",两边单独看都正常。
|
||||
*
|
||||
* ── 怎么做:内存里投影,不写库 ─────────────────────────────────
|
||||
* 用 `option_kratos` filter(WP 核心在 get_option 之后触发,**只影响读取**),
|
||||
* 把老键的值补进缺的两个新键。库不动 —— 这样:
|
||||
* · 用户没保存:每次读都投影一次,显示始终和页面一致
|
||||
* · 用户保存了:框架写库时带上新键,之后投影自动失效(他动过了)
|
||||
* · 想回滚到旧版:库里从未被加过新键,旧版读 toc_default 一切照旧
|
||||
*
|
||||
* 🔴 为什么不用 `pre_option_kratos`:那个 filter 在 get_option **之前**,
|
||||
* 拿到的是 null,得自己去查库,等于绕开缓存重查一次。
|
||||
* `option_kratos` 拿到的已经是解析好的数组,改完直接返回即可。
|
||||
*
|
||||
* 🔴 为什么不放在 normalize 里做:normalize 是纯函数,它的职责是
|
||||
* 「输入 → 可渲染的设置」。让它去改后台表单看到的东西,是把
|
||||
* 「渲染语义」和「配置界面语义」混在一起。这里用一层 filter 分开,
|
||||
* 哪一层出问题都能单独定位。
|
||||
*
|
||||
* @param mixed $value get_option('kratos') 的返回值
|
||||
* @return mixed
|
||||
*/
|
||||
function yang_toc_admin_legacy_values($value)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/* 老键必须存在且合法,否则没有可投影的值 */
|
||||
if (!array_key_exists('toc_default', $value)) {
|
||||
return $value;
|
||||
}
|
||||
$legacy = $value['toc_default'];
|
||||
if (!in_array($legacy, array('show', 'hide'), true)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/* 只补**缺失**的键。已经有的不动 —— 用户动过新下拉框之后,
|
||||
新键才是真相,老键是历史残留。 */
|
||||
foreach (array('toc_inline_default', 'toc_float_default') as $k) {
|
||||
if (!array_key_exists($k, $value)) {
|
||||
$value[$k] = $legacy;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/* 只在后台挂。前台也挂上的话,会让 kratos_option() 读到的值多出两个
|
||||
本来不存在的键 —— 虽然无害(normalize 有白名单),但那是没有理由的
|
||||
行为改变,且会让前台与"库里真实内容"不再一致。 */
|
||||
if (is_admin()) {
|
||||
add_filter('option_kratos', 'yang_toc_admin_legacy_values');
|
||||
}
|
||||
|
||||
/**
|
||||
* 把设置翻译成渲染参数(与短代码属性同名同格式)
|
||||
*
|
||||
@@ -293,7 +430,9 @@ function yang_toc_atts_from_settings($s = null)
|
||||
'levels' => implode(',', $levels),
|
||||
'numbering' => !empty($s['numbering']) ? '1' : '0',
|
||||
'toggle' => '1',
|
||||
'open' => $s['default'] === 'show' ? '1' : '0',
|
||||
/* 正文那份默认开合。只影响正文内嵌的 <details open>;
|
||||
浮层走 yang_toc_rail_html() 自己的 float_default,两条路互不引用。 */
|
||||
'open' => $s['inline_default'] === 'show' ? '1' : '0',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -979,7 +1118,10 @@ function yang_toc_rail_html($items, $plan)
|
||||
}
|
||||
|
||||
$side = ($plan['side'] === 'right') ? 'right' : 'left';
|
||||
$open = ($s['default'] === 'show');
|
||||
/* 浮层那份默认开合,**独立于**正文那份(3.2.59 起)。
|
||||
展开态写在 class 上(is-open),所以没有 JS 也能看到默认状态;
|
||||
JS 只负责之后的切换 —— 这个特性由 3.2.30 定下,拆分后必须保留。 */
|
||||
$open = ($s['float_default'] === 'show');
|
||||
$title = $s['title'];
|
||||
|
||||
$cls = 'yang-toc-rail yang-toc-rail-' . $side . ($open ? ' is-open' : '');
|
||||
|
||||
Reference in New Issue
Block a user