侧栏「文章分类」挂件是 WP 自带的、没被主题接管也未美化 → 主题自建一个好看的分类挂件 #24

Closed
opened 2026-10-27 02:56:34 +00:00 by laoyang · 6 comments
Owner

来源

用户 2026-10-27 提出:

可以了。下一个需求,现在侧边栏的文章分类那个小挂件,是咱们主题的吗?有点丑,如果是,就美化一下,如果不是,咱们就重做一个好看一点的。

一、先回答「是不是咱们主题的」——实测结论:不是

三条独立证据一致:

  1. 主题自带的挂件类只有 6 个(grep -n "^class widget_" inc/theme-widgets.php):

    430:class widget_search extends WP_Widget
    484:class widget_ad extends WP_Widget
    598:class widget_about extends WP_Widget
    872:class widget_tags extends WP_Widget
    950:class widget_posts extends WP_Widget
    1095:class widget_recent_comments extends WP_Widget
    

    没有分类挂件。

  2. 全仓库零命中(grep -rn "WP_Widget_Categories\|widget_categories\|categories" --include=*.php .):空。主题从未碰过分类挂件,既没美化也没复用。

  3. 主题注销的默认挂件列表里有 8 个,WP_Widget_Categories 不在其中(inc/theme-widgets.php:22-31):

    WP_Widget_Pages / WP_Widget_Meta / WP_Widget_Recent_Posts / WP_Widget_Recent_Comments
    WP_Widget_RSS / WP_Widget_Search / WP_Widget_Tag_Cloud / WP_Nav_Menu_Widget
    

    ⇒ 侧栏那个分类挂件是 WordPress 核心自带的 WP_Widget_Categories,主题既没接管、也没美化,原样输出核心的裸 <ul><li> 列表。

结论:不是主题的。 按用户要求走「重做一个好看一点的」。

二、需求:主题自建分类挂件,替换默认分类挂件的观感

2.1 做法(沿用 3.2.52「最近评论」的成功成例)

  • 新建 widget_categories 类(主题自有 id_base,不复用 categories),
    在 widgets_init() 里 unregister_widget('WP_Widget_Categories') 注销核心那个,
    再 register_widget() 上自己的。
  • id_base 与核心的 categories 必须不同(计划用 yang_categories),
    否则会接管用户已有实例、把存量配置搞成孤儿。
  • CSS 内联进主题 assets/css/kratos.css,不新增额外文件、不额外发 HTTP 请求。
  • 视觉与现有挂件统一:外层用主题的 w-xxx class 体系、标题走 .title、
    字号/间距/圆点/悬停与 .w-comments(3.2.52)、.w-tags(3.2.49)同源。

2.2 具体要做的几件事(验收点)

  1. 层级可读:支持显示「父分类 / 子分类」的缩进层级,且缩进不靠固定 padding 堆叠
    (深层级不溢出挂件宽度)。
  2. 文章数:可开关显示每类文章数,数字用 number_format_i18n 之外的轻量处理
    (注意坑:编号/计数类数字不过 number_format_i18n,否则千分位分隔符会混进去)。
  3. 无文章的分类:可开关「隐藏空分类」,空分类默认不显示。
  4. 排序:按名称 / 按文章数,两种都要能选。
  5. 样式:与侧栏其余挂件同一套字号与间距;链接悬停有明确反馈;
    长分类名不撑破挂件(overflow-wrap)。
  6. 无障碍/语义:ul/li 结构保留、当前分类页高亮(current-cat)。
  7. 后台表单:标题、显示层级、显示文章数、隐藏空分类、排序方式,每项都能存住。
    —— 🔴 空串/0 是合法业务值,判空一律用 trim() 不用 empty()(!empty('0') 是 false)。

2.3 兼容与红线

  • 线上已有 WP_Widget_Categories 的实例配置(widget_categories option)不迁移、不删除,
    注销后旧实例自然不显示;用户重新拖一个新挂件即可。
  • 发布只走 /theme-update/ 主题更新通道,绝不覆盖服务器上的 wp-content/themes/kratos_yang/。
  • 版本号 3.2.53 → 3.2.54。

三、验收标准

  • 侧栏分类挂件视觉与其余主题挂件统一,不再是核心裸列表。
  • 后台表单 5 个选项改完保存,刷新后全部保持。
  • 父/子分类层级、文章数、空分类隐藏、排序四种行为各自可验证。
  • 老代码(3.2.53)跑同一套判据应红,新代码全绿(反证见发布脚本)。
  • 打包后 update.json 更新到 3.2.54,服务器主题目录版本号仍为 3.2.53(未被覆盖)。

为什么单独建单

侧栏分类挂件是 WP 核心自带、主题未接管也未美化,属新增自建挂件,与 #20(既有挂件一致性)/#22(最近评论)可独立验收

## 来源 用户 2026-10-27 提出: > 可以了。下一个需求,现在侧边栏的文章分类那个小挂件,是咱们主题的吗?有点丑,如果是,就美化一下,如果不是,咱们就重做一个好看一点的。 ## 一、先回答「是不是咱们主题的」——实测结论:**不是** 三条独立证据一致: 1. **主题自带的挂件类只有 6 个**(`grep -n "^class widget_" inc/theme-widgets.php`): ``` 430:class widget_search extends WP_Widget 484:class widget_ad extends WP_Widget 598:class widget_about extends WP_Widget 872:class widget_tags extends WP_Widget 950:class widget_posts extends WP_Widget 1095:class widget_recent_comments extends WP_Widget ``` 没有分类挂件。 2. **全仓库零命中**(`grep -rn "WP_Widget_Categories\|widget_categories\|categories" --include=*.php .`):空。主题从未碰过分类挂件,既没美化也没复用。 3. **主题注销的默认挂件列表里有 8 个,`WP_Widget_Categories` 不在其中**(`inc/theme-widgets.php:22-31`): ``` WP_Widget_Pages / WP_Widget_Meta / WP_Widget_Recent_Posts / WP_Widget_Recent_Comments WP_Widget_RSS / WP_Widget_Search / WP_Widget_Tag_Cloud / WP_Nav_Menu_Widget ``` ⇒ 侧栏那个分类挂件是 **WordPress 核心自带的 `WP_Widget_Categories`**,主题既没接管、也没美化,原样输出核心的裸 `<ul><li>` 列表。 **结论:不是主题的。** 按用户要求走「重做一个好看一点的」。 ## 二、需求:主题自建分类挂件,替换默认分类挂件的观感 ### 2.1 做法(沿用 3.2.52「最近评论」的成功成例) - 新建 `widget_categories` 类(主题自有 id_base,**不复用 `categories`**), 在 `widgets_init()` 里 `unregister_widget('WP_Widget_Categories')` 注销核心那个, 再 `register_widget()` 上自己的。 - `id_base` 与核心的 `categories` **必须不同**(计划用 `yang_categories`), 否则会接管用户已有实例、把存量配置搞成孤儿。 - CSS 内联进主题 `assets/css/kratos.css`,不新增额外文件、不额外发 HTTP 请求。 - 视觉与现有挂件统一:外层用主题的 `w-xxx` class 体系、标题走 `.title`、 字号/间距/圆点/悬停与 `.w-comments`(3.2.52)、`.w-tags`(3.2.49)同源。 ### 2.2 具体要做的几件事(验收点) 1. **层级可读**:支持显示「父分类 / 子分类」的缩进层级,且缩进不靠固定 padding 堆叠 (深层级不溢出挂件宽度)。 2. **文章数**:可开关显示每类文章数,数字用 `number_format_i18n` 之外的轻量处理 (**注意坑:编号/计数类数字不过 `number_format_i18n`,否则千分位分隔符会混进去**)。 3. **无文章的分类**:可开关「隐藏空分类」,空分类默认不显示。 4. **排序**:按名称 / 按文章数,两种都要能选。 5. **样式**:与侧栏其余挂件同一套字号与间距;链接悬停有明确反馈; 长分类名不撑破挂件(`overflow-wrap`)。 6. **无障碍/语义**:`ul/li` 结构保留、当前分类页高亮(`current-cat`)。 7. **后台表单**:标题、显示层级、显示文章数、隐藏空分类、排序方式,**每项都能存住**。 —— 🔴 **空串/0 是合法业务值**,判空一律用 `trim()` 不用 `empty()`(`!empty('0')` 是 false)。 ### 2.3 兼容与红线 - 线上已有 `WP_Widget_Categories` 的实例配置(`widget_categories` option)**不迁移、不删除**, 注销后旧实例自然不显示;用户重新拖一个新挂件即可。 - 发布只走 `/theme-update/` 主题更新通道,**绝不覆盖服务器上的 `wp-content/themes/kratos_yang/`**。 - 版本号 3.2.53 → **3.2.54**。 ## 三、验收标准 - 侧栏分类挂件视觉与其余主题挂件统一,不再是核心裸列表。 - 后台表单 5 个选项改完保存,刷新后全部保持。 - 父/子分类层级、文章数、空分类隐藏、排序四种行为各自可验证。 - 老代码(3.2.53)跑同一套判据应**红**,新代码全绿(反证见发布脚本)。 - 打包后 `update.json` 更新到 3.2.54,服务器主题目录版本号**仍为 3.2.53**(未被覆盖)。 --- ### 为什么单独建单 侧栏分类挂件是 WP 核心自带、主题未接管也未美化,属新增自建挂件,与 #20(既有挂件一致性)/#22(最近评论)可独立验收
Author
Owner

实现完成 + 一处与建单方案不同的决定(2026-10-27)

一、先说要紧的:id_base 与建单时写的方案不一样

建单正文 2.1 写的是「新建 widget_categories 类(主题自有 id_base,不复用 categories),计划用 yang_categories」。

实际做成了相反的方向:沿用 categories 直接顶替核心挂件。 原因如下,请确认。

建单时那条判断的依据是「换了 id_base 会接管用户已有实例、把存量配置搞成孤儿」。查了线上实际情况后发现恰好相反:

  • 线上侧栏确实有一个核心分类挂件实例 categories-3,配置是
    array('title' => '文章分类', 'count' => 1, 'hierarchical' => 1, 'dropdown' => 1);
  • 如果换新 id_base(yang_categories),option 名就变成 widget_yang_categories,
    旧实例的配置留在 widget_categories 里没人读;
  • 结果是:旧挂件凭空消失,用户要手动删掉残留、再拖一个新的、重新填标题。

沿用 categories 则完全相反:

  • option 名不变,_register_widgets() 按 id_base 读 widget_categories,存量实例继续被认领;
  • 那个 categories-3 就地变成新样式,位置不变、标题「文章分类」原样沿用;
  • 用户升级后什么都不用做。

⇒ 所以建单时那句「必须不同」的前提("接管会把已有配置搞成孤儿")实测不成立,结论要反过来。

这里也有个真实代价:update() 必须容忍核心那套老字段(dropdown / hierarchical)。
处理方式是:不读它们、不显式删它们 —— 只在用户重新保存表单时才让它们自然消失。
widget() 完全不读 = 无害。

二、为什么「丑」的直接原因不是"没写样式"

这是本单最重要的一个发现,比"重做一个挂件"本身更值:

那个实例的 dropdown = 1,核心走的是 wp_dropdown_categories(),输出的是一个 <select>。

而主题 CSS 里早就有一整套 .widget_categories ul li 规则(kratos.css 2293 行起)——
它只匹配 ul li,下拉框里根本没有 ul。

线上实际渲染: <select name="cat" ...><option>...</option></select>
主题规则匹配: .k-main .sidebar .widget_categories ul li  → 命中 0 个元素

⇒ 写了但一条都没生效。 不是"样式没写",是样式和渲染形态对不上。
这解释了为什么它跟侧栏其它挂件完全不搭 —— 从来没被美化过。

所以这次除了做新挂件,也把那一整套失效规则(.widget_categories ul li 及其
@media 里的宽度规则)删掉了。留着只会误导下一个维护的人。

三、「父级常显 + 子级可折叠」的两个实现决定

用 <details>/<summary>,不写一行 JS。 理由:

  • 不依赖 jQuery / Bootstrap 版本,也不跟主题其它脚本抢事件;
  • 键盘 Tab + 回车天然可用,读屏软件正确朗读展开状态;
  • 关掉 JS 仍能展开 —— 分类导航是基础功能,不该依赖脚本。

父级链接放在 <summary> 里不会误触折叠,这是 HTML 规范给的:
<summary> 的"激活即折叠"只在该点击目标是 non-interactive 时才触发,<a> 属于
interactive content ⇒ 点名字是纯导航,点箭头/数字/空白才折叠。两个动作各归各的。

⚠️ 这条有个隐含前提,已在代码注释里写死:若哪天有人把 <a> 换成 <span onclick>,这条就失效了。

四、pad_counts —— 这条如果不做,用户会以为文章丢了

核心 wp_list_categories() 是在 show_count && hierarchical 时隐式打开 pad_counts
(category-template.php:392)。实测本站:

生活记录  原始 count = 188
生活记录  带 pad_counts = 220   (188 + 博士6 + 美国22 + 游泳4)

线上那个下拉框显示的也是 220。若这里取原始 count,同一个分类会在升级前后
显示成 220 → 188,用户会以为丢了 32 篇文章。⇒ 显式 'pad_counts' => true。

五、orderby=count 不能交给 SQL —— 实测踩过

orderby=count 在 WP_Term_Query::parse_orderby() 里被翻成 ORDER BY tt.count
(class-wp-term-query.php:926-927),排的是数据库里的原始 count。
而 pad_counts 是查询之后由 PHP 补的。两者不一致的实测后果:

生活记录 220 ← 排第 1(原始 188)
评论杂谈 168
信息技术 233 ← 排第 3(原始 233,实际最大)

界面上看就是"数字大的排在小的后面"。⇒ 改成本地取回后按补过的 count 在 PHP 里排,
并且显式做 tie-break(count 相同时按名称 strnatcasecmp),否则相等项顺序随请求变化。

六、分类名里的 HTML 实体:一次自我纠正

线上有一个分类名库里存的就是 Ubuntu&amp;Debian(id=122),不是 Ubuntu&Debian。
我一开始认定必须 html_entity_decode() 一层,理由是"下拉框会显示成 Ubuntu&amp;Debian"。

实测证明这个判断是错的:

raw         = [Ubuntu&amp;Debian]
decode      = [Ubuntu&Debian]
esc(raw)    = [Ubuntu&amp;Debian]
esc(decode) = [Ubuntu&amp;Debian]      ← 两者完全相同

关键点:esc_html() 对 & 的输出恒为 &amp;。所以库里存 & 还是存 &amp;,
经 esc_html() 后字节完全一致,浏览器里都是 Ubuntu&Debian,本来就是正常的。

⇒ 不 decode,直接用 esc_html()。少一层处理 = 少一处出错的地方;
而且 decode 有真实风险:若将来分类名里有人写了字面量 &lt;script&gt;,decode 会让它变成真标签。

七、三个样式缺陷(都是「代码看着对、量出来才发现」)

样式写完不算,我把新 CSS 套到线上真实页面上量了实际坐标,抓出三处:

# 现象(实测数字) 根因
1 相邻行间隙 gaps=[6,6,6,6,6,6,6],8 行累积 42px 主题全局 ul > li { margin-bottom:6px; padding-left:2px; list-style:circle; line-height:22px }(kratos.css:74)未被重置
2 带箭头行名字右边距比别的行多 2px(pl:2px 未被覆盖,display:list-item 没变 flex) 同上,我只给 :not(.has-children) 写了 flex,带子级的 <li> 完全没被覆盖
3 父级数字右边界 [220.5, 220.5, 227.6, 227.6, 220.5],差 7.1px 有子级行的 <li> 里只有 <details> 一个 flex 子项,space-between 推不动;<details> 默认按内容收缩

第 3 条尤其值得记:<summary> 自己写 width 是没用的 —— 父级 <details>
收缩了,子级撑满的只是那个收缩后的宽度。修法是给 <details> 加
flex: 1 1 auto; min-width: 0(min-width:0 不能省,长分类名才能换行不撑破)。

八、验证结果

端到端(真实 WP 加载待测主题副本):通过 77 / 失败 0

覆盖:接管是否真生效(callback / 工厂注销 / 注册表名字)· 渲染结构 · pad_counts
三个数字(188→220、233、子级 6)· 转义四种情况 · 后台表单 7 个字段 · update()
存取 12 项(含"标题就叫 0")· 开关生效 7 项 · 边界与安全 5 项 · 代码质量 15 项

反证 12 组(_rev_cats.sh):全部命中预期判据,无一组空跑

CSS 视觉反向验证 3 组(_rev_cats_css.js):把三处样式缺陷逐个注回去,
全部被量出来(gaps=[6] / rightsUniq=[220.5,227.6] / 颜色变红)

视觉几何 18 项全绿:行距均匀 · 胶囊同高同圆角同底色 · 父级数字同一列 ·
左右留白对称 · 无箭头行贴最左 · 有箭头行缩进正好等于箭头占位 · 与相邻挂件 23px ·
悬停变主题蓝(等过渡结束后采样)+ 胶囊联动 · 箭头是 CSS 三角形且可见

用 3.2.53 老代码跑同一套判据:11 通过 / 57 失败

九、过程中修掉的 5 条假判据(都在我自己的测试脚本里)

这一步比测试本身更值。用老代码跑时发现它居然"通过 16 条",逐条查全是假绿:

假判据 为什么恒真 修法
已删除 @media 里的分类宽度规则 正则 /@media[^{]*\{[^}]*widget_categories/ 的 [^}]* 遇到块内第一个 } 就截断 ⇒ 永远匹配不到 按花括号配对把 @media 块完整切出来再查
文章数没走 number_format_i18n 老代码没这个类,$cls_src='' ⇒ !preg_match(...,'') 恒真 加「类体定位到」存在性前置
类内没把 empty() 用在开关字段上 同上 同上
.w-cats 没绑 .k-main .sidebar 祖先 $cm[0] 是空数组 ⇒ count($bad_anc)===0 恒真 要求「找到 >=1 条 .w-cats 规则」且无前缀
挂件没有内联 <script> 同上 加存在性前置

修完后老代码从「16 通过 / 50 失败」变成「11 通过 / 57 失败」,@media 那条
还直接把老代码里 2354 行的 .widget_categories ul li { width:110px } 整块打了出来。

根因是同一个:否定式断言作用在空靶上。→ 与 pitfalls #424 同一族。

十、发布

  • 包 kratos_yang-3.2.54.zip:4783259 字节 / 237 成员 / 0 个 1980 时间戳
  • readme 45 个版本标题(44 + 1)
  • update.json → 3.2.54
  • 服务器主题目录仍 3.2.53,未被覆盖(红线)
  • commit 1b3a9e7(下一轮补)

待用户确认

后台 → 外观 → 小工具 → 文章分类,及前台侧栏:

  1. 原来的下拉框应变成分类树,位置不变、标题仍是「文章分类」
  2. 有子级的父级前面有小三角,点三角能展开;点名字是跳转、不展开
  3. 父级数字与升级前一致(生活记录应是 220,不是 188)
  4. 六个选项改完保存,刷新后都还在
## 实现完成 + 一处与建单方案不同的决定(2026-10-27) ### 一、先说要紧的:`id_base` 与建单时写的方案不一样 建单正文 2.1 写的是「新建 `widget_categories` 类(主题自有 id_base,**不复用 `categories`**),计划用 `yang_categories`」。 **实际做成了相反的方向:沿用 `categories` 直接顶替核心挂件。** 原因如下,请确认。 建单时那条判断的依据是「换了 id_base 会接管用户已有实例、把存量配置搞成孤儿」。查了线上实际情况后发现**恰好相反**: - 线上侧栏确实有一个核心分类挂件实例 `categories-3`,配置是 `array('title' => '文章分类', 'count' => 1, 'hierarchical' => 1, 'dropdown' => 1)`; - 如果换新 id_base(`yang_categories`),option 名就变成 `widget_yang_categories`, 旧实例的配置留在 `widget_categories` 里**没人读**; - 结果是:**旧挂件凭空消失,用户要手动删掉残留、再拖一个新的、重新填标题。** 沿用 `categories` 则完全相反: - option 名不变,`_register_widgets()` 按 id_base 读 `widget_categories`,存量实例继续被认领; - 那个 `categories-3` **就地变成新样式**,位置不变、标题「文章分类」原样沿用; - 用户升级后**什么都不用做**。 ⇒ 所以建单时那句「必须不同」的前提("接管会把已有配置搞成孤儿")实测不成立,结论要反过来。 **这里也有个真实代价**:`update()` 必须容忍核心那套老字段(`dropdown` / `hierarchical`)。 处理方式是:不读它们、不显式删它们 —— 只在用户重新保存表单时才让它们自然消失。 `widget()` 完全不读 = 无害。 ### 二、为什么「丑」的直接原因不是"没写样式" 这是本单最重要的一个发现,比"重做一个挂件"本身更值: 那个实例的 `dropdown = 1`,核心走的是 `wp_dropdown_categories()`,**输出的是一个 `<select>`**。 而主题 CSS 里早就有一整套 `.widget_categories ul li` 规则(kratos.css 2293 行起)—— 它只匹配 `ul li`,**下拉框里根本没有 `ul`**。 ``` 线上实际渲染: <select name="cat" ...><option>...</option></select> 主题规则匹配: .k-main .sidebar .widget_categories ul li → 命中 0 个元素 ``` ⇒ **写了但一条都没生效。** 不是"样式没写",是**样式和渲染形态对不上**。 这解释了为什么它跟侧栏其它挂件完全不搭 —— 从来没被美化过。 所以这次除了做新挂件,也把那一整套失效规则(`.widget_categories ul li` 及其 `@media` 里的宽度规则)**删掉**了。留着只会误导下一个维护的人。 ### 三、「父级常显 + 子级可折叠」的两个实现决定 **用 `<details>/<summary>`,不写一行 JS。** 理由: - 不依赖 jQuery / Bootstrap 版本,也不跟主题其它脚本抢事件; - 键盘 Tab + 回车天然可用,读屏软件正确朗读展开状态; - 关掉 JS 仍能展开 —— 分类导航是基础功能,不该依赖脚本。 **父级链接放在 `<summary>` 里不会误触折叠**,这是 HTML 规范给的: `<summary>` 的"激活即折叠"只在该点击目标是 non-interactive 时才触发,`<a>` 属于 interactive content ⇒ **点名字是纯导航**,点箭头/数字/空白才折叠。两个动作各归各的。 ⚠️ 这条有个隐含前提,已在代码注释里写死:**若哪天有人把 `<a>` 换成 `<span onclick>`,这条就失效了。** ### 四、`pad_counts` —— 这条如果不做,用户会以为文章丢了 核心 `wp_list_categories()` 是在 `show_count && hierarchical` 时**隐式**打开 `pad_counts` (`category-template.php:392`)。实测本站: ``` 生活记录 原始 count = 188 生活记录 带 pad_counts = 220 (188 + 博士6 + 美国22 + 游泳4) ``` 线上那个下拉框显示的也是 **220**。若这里取原始 count,同一个分类会在升级前后 显示成 220 → 188,用户会以为丢了 32 篇文章。⇒ 显式 `'pad_counts' => true`。 ### 五、`orderby=count` 不能交给 SQL —— 实测踩过 `orderby=count` 在 `WP_Term_Query::parse_orderby()` 里被翻成 `ORDER BY tt.count` (`class-wp-term-query.php:926-927`),排的是数据库里的**原始** count。 而 `pad_counts` 是查询**之后**由 PHP 补的。两者不一致的实测后果: ``` 生活记录 220 ← 排第 1(原始 188) 评论杂谈 168 信息技术 233 ← 排第 3(原始 233,实际最大) ``` 界面上看就是"数字大的排在小的后面"。⇒ 改成本地取回后按**补过的 count** 在 PHP 里排, 并且显式做 tie-break(count 相同时按名称 `strnatcasecmp`),否则相等项顺序随请求变化。 ### 六、分类名里的 HTML 实体:一次自我纠正 线上有一个分类名库里存的就是 `Ubuntu&amp;Debian`(id=122),不是 `Ubuntu&Debian`。 我一开始认定必须 `html_entity_decode()` 一层,理由是"下拉框会显示成 `Ubuntu&amp;Debian`"。 **实测证明这个判断是错的**: ``` raw = [Ubuntu&amp;Debian] decode = [Ubuntu&Debian] esc(raw) = [Ubuntu&amp;Debian] esc(decode) = [Ubuntu&amp;Debian] ← 两者完全相同 ``` 关键点:`esc_html()` 对 `&` 的输出**恒为** `&amp;`。所以库里存 `&` 还是存 `&amp;`, 经 `esc_html()` 后**字节完全一致**,浏览器里都是 `Ubuntu&Debian`,本来就是正常的。 ⇒ **不 decode**,直接用 `esc_html()`。少一层处理 = 少一处出错的地方; 而且 decode 有真实风险:若将来分类名里有人写了字面量 `&lt;script&gt;`,decode 会让它变成真标签。 ### 七、三个样式缺陷(都是「代码看着对、量出来才发现」) 样式写完不算,我把新 CSS 套到**线上真实页面**上量了实际坐标,抓出三处: | # | 现象(实测数字) | 根因 | |---|---|---| | 1 | 相邻行间隙 `gaps=[6,6,6,6,6,6,6]`,8 行累积 42px | 主题全局 `ul > li { margin-bottom:6px; padding-left:2px; list-style:circle; line-height:22px }`(kratos.css:74)未被重置 | | 2 | 带箭头行名字右边距比别的行多 2px(`pl:2px` 未被覆盖,`display:list-item` 没变 flex) | 同上,我只给 `:not(.has-children)` 写了 flex,带子级的 `<li>` 完全没被覆盖 | | 3 | 父级数字右边界 `[220.5, 220.5, 227.6, 227.6, 220.5]`,差 **7.1px** | 有子级行的 `<li>` 里只有 `<details>` **一个** flex 子项,`space-between` 推不动;`<details>` 默认按内容收缩 | 第 3 条尤其值得记:`<summary>` 自己写 `width` 是没用的 —— 父级 `<details>` 收缩了,子级撑满的只是那个收缩后的宽度。修法是给 `<details>` 加 `flex: 1 1 auto; min-width: 0`(`min-width:0` 不能省,长分类名才能换行不撑破)。 ### 八、验证结果 **端到端(真实 WP 加载待测主题副本)**:通过 **77 / 失败 0** 覆盖:接管是否真生效(callback / 工厂注销 / 注册表名字)· 渲染结构 · `pad_counts` 三个数字(188→220、233、子级 6)· 转义四种情况 · 后台表单 7 个字段 · `update()` 存取 12 项(含"标题就叫 0")· 开关生效 7 项 · 边界与安全 5 项 · 代码质量 15 项 **反证 12 组(`_rev_cats.sh`)**:全部命中预期判据,无一组空跑 **CSS 视觉反向验证 3 组(`_rev_cats_css.js`)**:把三处样式缺陷逐个注回去, 全部被量出来(`gaps=[6]` / `rightsUniq=[220.5,227.6]` / 颜色变红) **视觉几何 18 项全绿**:行距均匀 · 胶囊同高同圆角同底色 · 父级数字同一列 · 左右留白对称 · 无箭头行贴最左 · 有箭头行缩进正好等于箭头占位 · 与相邻挂件 23px · 悬停变主题蓝(等过渡结束后采样)+ 胶囊联动 · 箭头是 CSS 三角形且可见 **用 3.2.53 老代码跑同一套判据:11 通过 / 57 失败** ### 九、过程中修掉的 5 条**假判据**(都在我自己的测试脚本里) 这一步比测试本身更值。用老代码跑时发现它居然"通过 16 条",逐条查全是假绿: | 假判据 | 为什么恒真 | 修法 | |---|---|---| | `已删除 @media 里的分类宽度规则` | 正则 `/@media[^{]*\{[^}]*widget_categories/` 的 `[^}]*` 遇到块内第一个 `}` 就截断 ⇒ **永远匹配不到** | 按花括号配对把 `@media` 块完整切出来再查 | | `文章数没走 number_format_i18n` | 老代码没这个类,`$cls_src=''` ⇒ `!preg_match(...,'')` 恒真 | 加「类体定位到」存在性前置 | | `类内没把 empty() 用在开关字段上` | 同上 | 同上 | | `.w-cats 没绑 .k-main .sidebar 祖先` | `$cm[0]` 是空数组 ⇒ `count($bad_anc)===0` 恒真 | 要求「找到 >=1 条 .w-cats 规则」**且**无前缀 | | `挂件没有内联 <script>` | 同上 | 加存在性前置 | 修完后老代码从「16 通过 / 50 失败」变成「**11 通过 / 57 失败**」,`@media` 那条 还直接把老代码里 2354 行的 `.widget_categories ul li { width:110px }` 整块打了出来。 **根因是同一个**:否定式断言作用在空靶上。→ 与 pitfalls #424 同一族。 ### 十、发布 - 包 `kratos_yang-3.2.54.zip`:**4783259 字节 / 237 成员 / 0 个 1980 时间戳** - readme **45 个版本标题**(44 + 1) - `update.json` → 3.2.54 - **服务器主题目录仍 3.2.53,未被覆盖**(红线) - commit `1b3a9e7`(下一轮补) ## 待用户确认 后台 → 外观 → 小工具 → 文章分类,及前台侧栏: 1. 原来的下拉框应变成**分类树**,位置不变、标题仍是「文章分类」 2. 有子级的父级前面有小三角,点三角能展开;**点名字是跳转、不展开** 3. 父级数字与升级前一致(生活记录应是 **220**,不是 188) 4. 六个选项改完保存,刷新后都还在
Author
Owner

补充:已在 4c1d67b 提交并推送(75848f2..4c1d67b)。

补充:已在 `4c1d67b` 提交并推送(`75848f2..4c1d67b`)。
Author
Owner

样式方向改判:常显折叠树 → 点击展开的下拉面板(2026-10-27 用户反馈)

3.2.54 交付的形态是「父级常显 + 子级可折叠」,8 个父级铺开在侧栏里。用户反馈:

不是这样的样式,还是那种下拉式的,就是说,不点击的话,就一行,这样占用的空间小,
点击后把所有的一级分类拉出来,就类似于之前的那样,但是要把样式做好看点。

一、理解到的两条硬要求

  1. 收起时只占一行 —— 侧栏空间是第一约束。之前 8 行铺开占了约 300px,这不符合要求。
  2. 点击后弹出列表,只列一级分类 —— 与升级前的 <select> 行为对齐(用户说的"类似于之前的那样")。
    差别只在"好看":原生下拉框是浏览器绘制的系统控件,改不了样式;自己做才能统一到侧栏视觉。

二、做法

用 <details> + position:absolute 浮层做真下拉:

  • 收起:一行(当前分类名 / 默认「选择分类」+ 箭头)
  • 展开:浮层面板浮在标题下方,不推开下面的挂件(用 absolute,不占文档流)
  • 只列一级分类;子分类仍可通过 children 开关打开(缩进显示),默认关
  • 点击外部 / 按 Esc 关闭 —— 这一条 <details> 原生没有,补一段极短 JS 做渐进增强
    (无 JS 时仍能展开、仍能跳转,只是点外部不自动收回)

三、这条改动不改变需求性质

仍是「主题自建一个好看的分类挂件」,只是呈现形态按用户明确要求调整。验收点从
「父级常显 + 折叠」改为「收起一行 + 点击弹出 + 只列一级」。

版本 3.2.54 → 3.2.55(3.2.54 已落 update.json,同号重发会让 WP 的版本比较失效、
用户点不到升级)。

## 样式方向改判:常显折叠树 → 点击展开的下拉面板(2026-10-27 用户反馈) 3.2.54 交付的形态是「父级常显 + 子级可折叠」,8 个父级铺开在侧栏里。用户反馈: > 不是这样的样式,还是那种下拉式的,就是说,不点击的话,就一行,这样占用的空间小, > 点击后把所有的一级分类拉出来,就类似于之前的那样,但是要把样式做好看点。 ### 一、理解到的两条硬要求 1. **收起时只占一行** —— 侧栏空间是第一约束。之前 8 行铺开占了约 300px,这不符合要求。 2. **点击后弹出列表,只列一级分类** —— 与升级前的 `<select>` 行为对齐(用户说的"类似于之前的那样")。 差别只在"好看":原生下拉框是浏览器绘制的系统控件,改不了样式;自己做才能统一到侧栏视觉。 ### 二、做法 用 `<details>` + `position:absolute` 浮层做**真下拉**: - 收起:一行(当前分类名 / 默认「选择分类」+ 箭头) - 展开:浮层面板浮在标题下方,**不推开下面的挂件**(用 absolute,不占文档流) - 只列一级分类;子分类仍可通过 `children` 开关打开(缩进显示),默认关 - 点击外部 / 按 Esc 关闭 —— 这一条 `<details>` 原生没有,补一段极短 JS 做渐进增强 (无 JS 时仍能展开、仍能跳转,只是点外部不自动收回) ### 三、这条改动不改变需求性质 仍是「主题自建一个好看的分类挂件」,只是呈现形态按用户明确要求调整。验收点从 「父级常显 + 折叠」改为「收起一行 + 点击弹出 + 只列一级」。 版本 3.2.54 → **3.2.55**(3.2.54 已落 update.json,同号重发会让 WP 的版本比较失效、 用户点不到升级)。
Author
Owner

已按新要求重做,版本 3.2.55 已发到更新通道

你上次说「不是这样的样式,还是那种下拉式的,不点击的话就一行,点击后把所有的一级分类拉出来,就类似于之前的那样,但是要把样式做好看点」。3.2.54 那版(父级常显 + 子级折叠树)已经整个推翻重做,不是微调。

一、现在的形态

  • 收起时:整个挂件只有一行(实测 40.5px 高),左边「选择分类」,右边一个小箭头;
  • 在分类页上看的时候,左边不写「选择分类」,而是显示当前所在分类名;
  • 点这一行:向下弹出 8 个一级分类,每行左边名字、右边圆角数字;
  • 面板是浮层,盖在下面的内容上,不把后面的挂件推走(这是量过的:「下一个挂件」的文档坐标在一像素没变);
  • 点别处、按 Esc、或再点一下:收起;
  • 面板最高 320px(手机上是 60vh),分类多时面板内部滚动,不拉长页面。

二、「默认只列一级分类」是怎么做到的(用户零操作)

查了线上那个挂件实例的配置,是 {title:'文章分类', count:1, hierarchical:1, dropdown:1} —— 里面根本没有 children 这个键。所以代码里 pick() 的兜底值就是线上实际生效的值。把这个兜底从 true 改成 false,就等于直接改了线上行为:

  • 不需要你进后台勾一次;
  • 不需要动数据库;
  • 后台那个开关仍在(外观 → 小工具 → 文章分类 →「展开时同时列出子分类」),默认不勾。勾上之后,有子级的父级下面会缩进列出子级,字号小一档。

三、验收点变了(这是判据必须跟着需求改的地方)

上一轮的验收点是「父级常显 + 子级可折叠」,这一版的验收点完全不同:

项3.2.54(作废)3.2.55(本版)
收起时占高约 300px(8 个父级铺开)≤130px(只有一行)
展开方式每个父级各自一个 details整块一个 details,面板浮出
展开是否推挤下方不适用(本来就占位)不许推挤,下方挂件坐标不变
默认列几级全部父级 + 可折叠子级只有 8 个一级分类
details 数量9 个1 个

所以三套测试全部重写了,没有一条是照抄上一轮的。

四、量出来并修掉的一个真缺陷

子级数字比父级多缩进 12px,父子排不成一列。原因是子级 <ul> 嵌在已经 padding: 0 12px 的父级 <li> 里,而我又给子级 <li> 写了一遍右内边距 ⇒ 叠加成 24px。数字是要竖着比大小的,错开一列就没法比。改成 0 后父子同列。

这个缺陷光看代码看不出来 —— 是拿真实浏览器量两个数字的 getBoundingClientRect().right 才发现的。

五、验证结果

  • 端到端(跑在线上真实 WordPress 里):96 项全通过;
  • 内容判据反证 12 组(R1~R12):不注销核心类 / id_base 换名 / 去掉 pad_counts / 漏注册 / details 换 div / children 默认改回 true / 脚本接管开合 / 去掉 margin 重置 / 面板改 static / 去掉收起隐藏 / 子级 padding 叠加 / 压缩版退化 —— 12 组全部真红,无一组空跑;
  • 端到端判据反证 3 组(E1~E3):在真实 WP 里改坏再跑,失败数 2/3/1,全部真红;
  • 视觉几何(真实浏览器 50 项):全通过;
  • 上一版(3.2.53)老代码跑同一套端到端判据:88 项失败 —— 确认判据不是「怎么写都通过」。

六、反证过程中抓出的三个「判据自己有问题」

这一轮特别值得记的是:反证不是为了证明产品对,是为了证明判据有牙齿。它当场抓出三处判据本身有毛病:

  1. C7 恒红:两条正则漏了收尾的 # 定界符,preg_match 直接返回 false 并抛 warning。它恒红的样子很像「真抓到问题」,比恒绿更难发现 —— 是靠「R11 注入后失败数不增加(1→1)」才暴露:没有牙齿的判据对注入没反应。
  2. 类名判据是子串匹配:strpos($html, 'yang-cats-panel') 在类名改成 yang-cats-panel-x 后照样命中。改成精确类名匹配后,E3 才报红。
  3. 端到端反证副本放错层级:引导脚本有硬检查要求副本必须直接位于 themes/ 下,我放进了子目录 ⇒ exit 2 ⇒ 三个反证全部"跑崩",输出「没测到汇总行」。这如果只看「失败数 0」就会误判成「判据没牙齿」。

七、发布与红线

  • 只写了 theme-update/:zip + readme + update.json → 3.2.55;
  • HTTP 独立复核:zip/readme 均 200,下载回来的 md5 与本地一致,包内版本号 3.2.55;
  • 线上主题目录仍是 3.2.54(红线,脚本最后一条判据专门守这个);
  • 为什么必须换号:3.2.54 已经落过 update.json,同号重发会让 WP 的 version_compare 判「没有新版本」,用户永远升不上去。

提交:f5fd363。

工单先不关 —— 请你在后台点升级到 3.2.55,确认侧栏那个「文章分类」变成一行横条、点一下才弹出 8 个一级分类、下方挂件不被推走,确认没问题我再关闭。

<h2>已按新要求重做,版本 3.2.55 已发到更新通道</h2> <p>你上次说「不是这样的样式,还是那种下拉式的,不点击的话就一行,点击后把所有的一级分类拉出来,就类似于之前的那样,但是要把样式做好看点」。<b>3.2.54 那版(父级常显 + 子级折叠树)已经整个推翻重做</b>,不是微调。</p> <h3>一、现在的形态</h3> <ul> <li>收起时:<b>整个挂件只有一行</b>(实测 40.5px 高),左边「选择分类」,右边一个小箭头;</li> <li>在分类页上看的时候,左边不写「选择分类」,而是<b>显示当前所在分类名</b>;</li> <li>点这一行:向下弹出 8 个一级分类,每行左边名字、右边圆角数字;</li> <li>面板是<b>浮层</b>,盖在下面的内容上,<b>不把后面的挂件推走</b>(这是量过的:「下一个挂件」的文档坐标在一像素没变);</li> <li>点别处、按 Esc、或再点一下:收起;</li> <li>面板最高 320px(手机上是 60vh),分类多时面板内部滚动,不拉长页面。</li> </ul> <h3>二、「默认只列一级分类」是怎么做到的(用户零操作)</h3> <p>查了线上那个挂件实例的配置,是 <code>{title:'文章分类', count:1, hierarchical:1, dropdown:1}</code> —— <b>里面根本没有 <code>children</code> 这个键</b>。所以代码里 <code>pick()</code> 的兜底值就是线上实际生效的值。把这个兜底从 <code>true</code> 改成 <code>false</code>,就等于直接改了线上行为:</p> <ul> <li><b>不需要你进后台勾一次</b>;</li> <li><b>不需要动数据库</b>;</li> <li>后台那个开关仍在(外观 → 小工具 → 文章分类 →「展开时同时列出子分类」),默认不勾。勾上之后,有子级的父级下面会缩进列出子级,字号小一档。</li> </ul> <h3>三、验收点变了(这是判据必须跟着需求改的地方)</h3> <p>上一轮的验收点是「父级常显 + 子级可折叠」,这一版的验收点完全不同:</p> <table> <tr><th>项</th><th>3.2.54(作废)</th><th>3.2.55(本版)</th></tr> <tr><td>收起时占高</td><td>约 300px(8 个父级铺开)</td><td><b>≤130px(只有一行)</b></td></tr> <tr><td>展开方式</td><td>每个父级各自一个 details</td><td><b>整块一个 details,面板浮出</b></td></tr> <tr><td>展开是否推挤下方</td><td>不适用(本来就占位)</td><td><b>不许推挤,下方挂件坐标不变</b></td></tr> <tr><td>默认列几级</td><td>全部父级 + 可折叠子级</td><td><b>只有 8 个一级分类</b></td></tr> <tr><td>details 数量</td><td>9 个</td><td><b>1 个</b></td></tr> </table> <p>所以三套测试<b>全部重写了</b>,没有一条是照抄上一轮的。</p> <h3>四、量出来并修掉的一个真缺陷</h3> <p><b>子级数字比父级多缩进 12px,父子排不成一列。</b>原因是子级 <code>&lt;ul&gt;</code> 嵌在已经 <code>padding: 0 12px</code> 的父级 <code>&lt;li&gt;</code> 里,而我又给子级 <code>&lt;li&gt;</code> 写了一遍右内边距 ⇒ 叠加成 24px。<b>数字是要竖着比大小的,错开一列就没法比。</b>改成 0 后父子同列。</p> <p>这个缺陷光看代码看不出来 —— 是拿真实浏览器量两个数字的 <code>getBoundingClientRect().right</code> 才发现的。</p> <h3>五、验证结果</h3> <ul> <li><b>端到端</b>(跑在线上真实 WordPress 里):<b>96 项全通过</b>;</li> <li><b>内容判据反证 12 组</b>(R1~R12):不注销核心类 / id_base 换名 / 去掉 pad_counts / 漏注册 / details 换 div / children 默认改回 true / 脚本接管开合 / 去掉 margin 重置 / 面板改 static / 去掉收起隐藏 / 子级 padding 叠加 / 压缩版退化 —— <b>12 组全部真红</b>,无一组空跑;</li> <li><b>端到端判据反证 3 组</b>(E1~E3):在真实 WP 里改坏再跑,失败数 2/3/1,<b>全部真红</b>;</li> <li><b>视觉几何</b>(真实浏览器 50 项):全通过;</li> <li><b>上一版(3.2.53)老代码跑同一套端到端判据:88 项失败</b> —— 确认判据不是「怎么写都通过」。</li> </ul> <h3>六、反证过程中抓出的三个「判据自己有问题」</h3> <p>这一轮特别值得记的是:<b>反证不是为了证明产品对,是为了证明判据有牙齿</b>。它当场抓出三处判据本身有毛病:</p> <ol> <li><b>C7 恒红</b>:两条正则漏了收尾的 <code>#</code> 定界符,<code>preg_match</code> 直接返回 false 并抛 warning。它恒红的样子很像「真抓到问题」,比恒绿更难发现 —— 是靠「R11 注入后失败数不增加(1→1)」才暴露:<b>没有牙齿的判据对注入没反应</b>。</li> <li><b>类名判据是子串匹配</b>:<code>strpos($html, 'yang-cats-panel')</code> 在类名改成 <code>yang-cats-panel-x</code> 后照样命中。改成精确类名匹配后,E3 才报红。</li> <li><b>端到端反证副本放错层级</b>:引导脚本有硬检查要求副本必须直接位于 <code>themes/</code> 下,我放进了子目录 ⇒ exit 2 ⇒ 三个反证全部"跑崩",输出「没测到汇总行」。这如果只看「失败数 0」就会误判成「判据没牙齿」。</li> </ol> <h3>七、发布与红线</h3> <ul> <li>只写了 <code>theme-update/</code>:zip + readme + update.json → <b>3.2.55</b>;</li> <li>HTTP 独立复核:zip/readme 均 200,下载回来的 md5 与本地一致,包内版本号 3.2.55;</li> <li><b>线上主题目录仍是 3.2.54</b>(红线,脚本最后一条判据专门守这个);</li> <li>为什么必须换号:3.2.54 已经落过 update.json,同号重发会让 WP 的 <code>version_compare</code> 判「没有新版本」,用户永远升不上去。</li> </ul> <p>提交:<code>f5fd363</code>。</p> <p><b>工单先不关 —— 请你在后台点升级到 3.2.55,确认侧栏那个「文章分类」变成一行横条、点一下才弹出 8 个一级分类、下方挂件不被推走,确认没问题我再关闭。</b></p>
Author
Owner

3.2.56 已发布:面板列出全部层级 + 缩进

按你的追加要求「把多级目录也放进去,现在只显示第一级,把其他的也放进去,注意缩进」改完了,已通过 theme-update/ 通道发布。

先说实测数据(不是猜的)

跑了脚本导出线上分类表,确认是 29 个分类 = 8 个一级 + 21 个二级,没有第三层。所以这次要做的就是把那 21 个二级显示出来。

但代码做成了任意深度递归,不是"两层":本站现在虽然只有两层,可只按两层写死的话,将来你加第三级,那一层会凭空消失 —— 页面不报错、只是少几个分类,这种缺陷最难发现。

面板现在长什么样

点开触发条后,29 项一次列全:

  • 一级 8 个,15px、深色;
  • 二级 21 个缩进 12px,14px、颜色浅一档;
  • 二级再往下(将来)继续缩进,第 4 层起每层只加 6px,免得深层把 250px 面板吃光、中文挤成两三个字一行。

缩进是怎么做的(为什么数字还能对齐)

你之前强调过「数字要竖着比大小,错开一列就没法比」。这次特意保住了这一点:

  • 二级列表嵌在一级那一行里面,天然从一级的缩进位置开始;
  • 每往下一层只加左边距,右边距一律不加;
  • 右侧那 12px 只由最外层统一给一次。

结果:不管多少层,右边数字都落在同一竖线上。几何实测全距 ≤ 2px。

过程中修掉的一个真实缺陷

第一版同时给"子级列表"和"子级行"都加了 12px 左缩进 ⇒ 每层实际缩进 24px,第 3 层名字只剩 148px,"第 4 层起收敛"也一起失效了。

这是几何判据量出来的(不是看代码看出来的):stepPx=[24,24,18]。改成"缩进只由一处给"之后是 [12,12,6],符合设计。

后台那个勾选框

「外观 → 小工具 → 文章分类」里现在叫「列出子分类(含更多层级)」,默认勾着。

  • 勾着(默认):列全部层级;
  • 取消:只留一级 —— 分类特别多、嫌面板长要滚很久时用。

升级后不用做任何操作:你线上那个挂件实例的配置里本来没存这个字段,走的是代码兜底值,所以升级后自动就是"列全部层级"。

验证

项目 结果
端到端(真实 WordPress) 120 通过 / 0 失败
旧代码跑同一套判据 100 / 17 失败(差的正是新需求点)
反证(改坏产品,失败数必须增) 20 组全部命中
视觉几何(线上真实页面量坐标) 56 通过 / 0 失败
打包内容自检 26 项全过
发布判据 79 条全过

发布状态

  • update.json → 3.2.56,md5 0aa90b30e76d754de41febcb9271ddef
  • 服务器主题目录仍是 3.2.55(红线守住,没有覆盖),等你在后台点升级
  • commit b7dcdc1

工单状态

先不关。 按流程等你在后台升级、实际看一眼多级缩进的效果,确认没问题后我再关单。如果哪一层缩进量或层级观感还要调,直接在这里说。

## 3.2.56 已发布:面板列出全部层级 + 缩进 按你的追加要求「把多级目录也放进去,现在只显示第一级,把其他的也放进去,注意缩进」改完了,已通过 `theme-update/` 通道发布。 ### 先说实测数据(不是猜的) 跑了脚本导出线上分类表,确认是 **29 个分类 = 8 个一级 + 21 个二级,没有第三层**。所以这次要做的就是把那 21 个二级显示出来。 但代码做成了**任意深度递归**,不是"两层":本站现在虽然只有两层,可只按两层写死的话,将来你加第三级,那一层会**凭空消失** —— 页面不报错、只是少几个分类,这种缺陷最难发现。 ### 面板现在长什么样 点开触发条后,29 项一次列全: - 一级 8 个,15px、深色; - 二级 21 个缩进 12px,14px、颜色浅一档; - 二级再往下(将来)继续缩进,**第 4 层起每层只加 6px**,免得深层把 250px 面板吃光、中文挤成两三个字一行。 ### 缩进是怎么做的(为什么数字还能对齐) 你之前强调过「数字要竖着比大小,错开一列就没法比」。这次特意保住了这一点: - 二级列表**嵌在一级那一行里面**,天然从一级的缩进位置开始; - 每往下一层只加左边距,**右边距一律不加**; - 右侧那 12px 只由最外层统一给一次。 结果:**不管多少层,右边数字都落在同一竖线上**。几何实测全距 ≤ 2px。 ### 过程中修掉的一个真实缺陷 第一版同时给"子级列表"和"子级行"都加了 12px 左缩进 ⇒ 每层实际缩进 **24px**,第 3 层名字只剩 148px,"第 4 层起收敛"也一起失效了。 这是**几何判据量出来的**(不是看代码看出来的):`stepPx=[24,24,18]`。改成"缩进只由一处给"之后是 `[12,12,6]`,符合设计。 ### 后台那个勾选框 「外观 → 小工具 → 文章分类」里现在叫「**列出子分类(含更多层级)**」,默认**勾着**。 - 勾着(默认):列全部层级; - 取消:只留一级 —— 分类特别多、嫌面板长要滚很久时用。 **升级后不用做任何操作**:你线上那个挂件实例的配置里本来没存这个字段,走的是代码兜底值,所以升级后自动就是"列全部层级"。 ### 验证 | 项目 | 结果 | |---|---| | 端到端(真实 WordPress) | **120 通过 / 0 失败** | | 旧代码跑同一套判据 | 100 / **17 失败**(差的正是新需求点) | | 反证(改坏产品,失败数必须增) | **20 组全部命中** | | 视觉几何(线上真实页面量坐标) | **56 通过 / 0 失败** | | 打包内容自检 | 26 项全过 | | 发布判据 | 79 条全过 | ### 发布状态 - `update.json` → **3.2.56**,md5 `0aa90b30e76d754de41febcb9271ddef` - 服务器主题目录**仍是 3.2.55**(红线守住,没有覆盖),等你在后台点升级 - commit `b7dcdc1` ### 工单状态 **先不关。** 按流程等你在后台升级、实际看一眼多级缩进的效果,确认没问题后我再关单。如果哪一层缩进量或层级观感还要调,直接在这里说。
Author
Owner

需求完成,用户已确认(2026-10-27)

本工单从「美化分类挂件」出发,经历 3 次形态调整,最终形态已上线并由用户确认。

三次形态演进

版本 形态 用户反馈
3.2.54 父级常显 + 子级折叠树(<details>) 否掉:「还是那种下拉式的,不点击的话就一行」
3.2.55 点开才展开的下拉面板,只列 8 个一级分类 「还需要修改,把多级目录也放进去」
3.2.56 点开列出全部层级(29 项)+ 逐层缩进 确认通过

3.2.56 最终交付内容

PHP(inc/theme-widgets.php)

  • get_tree() 改任意深度递归(不再写死两层),带 $seen 已访问集合 + $max_depth=10 双保险。
    parent 成环时只跳过、不抛异常 —— 侧栏挂件白屏会把整站带下去。
  • 排序 $sort_level 递归到所有层(原来只排前两层)。
  • 新增 find_name():触发条文案与面板渲染共用同一套遍历,避免两处各自硬编码层数。
  • 新增 render_level():面板单次递归调用;关掉 children 时把 children 清空交给同一函数,
    不另写第二份循环(两份循环必然漂移)。
  • 下层 <ul> 放在本层 <li> 内部(HTML 里 <ul> 的直接子元素只能是 <li>)。
  • children 兜底值 false → true,两处同步(widget() 与 form())。

CSS(assets/css/kratos.css)

.yang-cats-item     { display:flex; flex-wrap:wrap; }          /* 允许换行 */
.yang-cats-children { flex: 0 0 100%; padding: 0; }            /* 独占整行 + 左缩进归零 */
.yang-cats-children > .yang-cats-item { padding: 0 0 0 12px; }/* 缩进只由这里给 */
.w-cats .yang-cats-list > .yang-cats-item { padding: 0 12px; } /* 右侧 12px 只给一次 */

第 4 层起收敛到 6px。--cat-d 只做深度标记 + 收敛选择器 + 测试读取,不参与算缩进。

验证结果

项 结果
端到端 _cats_test.php(真实 WordPress,120 项) 120 通过 / 0 失败
旧代码跑同一套 100 / 17 失败(全部落在新需求点)
内容反证 _rev_cats.sh 20 组全部命中(R1~R19 + R13b)
视觉几何 _cats_geom.js(线上真实页面,56 项) 56 通过 / 0 失败
打包自检 _mkzip356.py 26 项全过
发布 _publish356.sh 79 条判据全过
线上包复核 md5 0aa90b30e76d754de41febcb9271ddef 与 update.json 一致,237 成员 / 0 个 1980 时间戳

发布

  • update.json → 3.2.56,commit b7dcdc1(带 #24),只写 theme-update/
  • 红线守住:服务器 wp-content/themes/kratos_yang/ 未被覆盖(仍为 3.2.55),用户从后台正常升级

本轮沉淀的坑(详见 pitfalls.md)

#438 两处默认值只改一处 / #439 嵌套 ul 放 li 外面 / #440 flex-wrap + flex:0 0 100% 是唯一解法 /
#441 缩进写两处翻倍成 24px(结构判据隐形,只有几何能量出来)/ #442 红线判据把上一版版本号当违规

其中 #441 最值钱:第一版缩进写在 ul 和 li 两处,叠加成 24px/层,而结构判据全绿,
只有量真实坐标才发现。此后「结构」与「几何」被拆成两类独立判据。

## 需求完成,用户已确认(2026-10-27) 本工单从「美化分类挂件」出发,经历 **3 次形态调整**,最终形态已上线并由用户确认。 ### 三次形态演进 | 版本 | 形态 | 用户反馈 | |---|---|---| | 3.2.54 | 父级常显 + 子级折叠树(`<details>`) | 否掉:「还是那种下拉式的,不点击的话就一行」 | | 3.2.55 | 点开才展开的下拉面板,只列 8 个一级分类 | 「还需要修改,把多级目录也放进去」 | | **3.2.56** | **点开列出全部层级(29 项)+ 逐层缩进** | **确认通过** | ### 3.2.56 最终交付内容 **PHP(`inc/theme-widgets.php`)** - `get_tree()` 改**任意深度递归**(不再写死两层),带 `$seen` 已访问集合 + `$max_depth=10` 双保险。 parent 成环时**只跳过、不抛异常** —— 侧栏挂件白屏会把整站带下去。 - 排序 `$sort_level` 递归到所有层(原来只排前两层)。 - 新增 `find_name()`:触发条文案与面板渲染共用同一套遍历,避免两处各自硬编码层数。 - 新增 `render_level()`:面板单次递归调用;关掉 children 时把 children 清空交给同一函数, **不另写第二份循环**(两份循环必然漂移)。 - 下层 `<ul>` 放在本层 `<li>` **内部**(HTML 里 `<ul>` 的直接子元素只能是 `<li>`)。 - `children` 兜底值 `false → true`,**两处同步**(`widget()` 与 `form()`)。 **CSS(`assets/css/kratos.css`)** ```css .yang-cats-item { display:flex; flex-wrap:wrap; } /* 允许换行 */ .yang-cats-children { flex: 0 0 100%; padding: 0; } /* 独占整行 + 左缩进归零 */ .yang-cats-children > .yang-cats-item { padding: 0 0 0 12px; }/* 缩进只由这里给 */ .w-cats .yang-cats-list > .yang-cats-item { padding: 0 12px; } /* 右侧 12px 只给一次 */ ``` 第 4 层起收敛到 6px。`--cat-d` 只做深度标记 + 收敛选择器 + 测试读取,**不参与算缩进**。 ### 验证结果 | 项 | 结果 | |---|---| | 端到端 `_cats_test.php`(真实 WordPress,120 项) | **120 通过 / 0 失败** | | 旧代码跑同一套 | 100 / **17 失败**(全部落在新需求点) | | 内容反证 `_rev_cats.sh` | **20 组全部命中**(R1~R19 + R13b) | | 视觉几何 `_cats_geom.js`(线上真实页面,56 项) | **56 通过 / 0 失败** | | 打包自检 `_mkzip356.py` | 26 项全过 | | 发布 `_publish356.sh` | **79 条判据全过** | | 线上包复核 md5 | `0aa90b30e76d754de41febcb9271ddef` 与 update.json 一致,237 成员 / 0 个 1980 时间戳 | ### 发布 - `update.json` → **3.2.56**,commit `b7dcdc1`(带 #24),只写 `theme-update/` - **红线守住**:服务器 `wp-content/themes/kratos_yang/` 未被覆盖(仍为 3.2.55),用户从后台正常升级 ### 本轮沉淀的坑(详见 pitfalls.md) #438 两处默认值只改一处 / #439 嵌套 ul 放 li 外面 / #440 `flex-wrap` + `flex:0 0 100%` 是唯一解法 / #441 缩进写两处翻倍成 24px(结构判据隐形,只有几何能量出来)/ #442 红线判据把上一版版本号当违规 其中 **#441 最值钱**:第一版缩进写在 ul 和 li 两处,叠加成 24px/层,而结构判据全绿, 只有量真实坐标才发现。此后「结构」与「几何」被拆成两类独立判据。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: laoyang/wordpress-kratos-yang#24