代码块出现重复复制按钮与重影:排查插件/样式冲突 #12

Closed
opened 2026-10-26 02:25:57 +00:00 by laoyang · 2 comments
Owner

现象

3.2.42 代码高亮上线后功能已生效,但代码块上出现两个异常:

  1. 多了一个 copy 按钮 —— 不是我们做的那个(我们的在卡片顶栏右侧,文案"复制"→"已复制")。页面上还出现了另一个复制的按钮,怀疑来自第三方插件或残留逻辑。
  2. 代码出现阴影或重影 —— 视觉上像"两层东西叠在一起",怀疑两套高亮器 / 两套样式同时生效。

涉及范围

  • inc/theme-highlight.php(我们自己的渲染器,输出 <figure class="cb"> 卡片)
  • assets/css/highlight.css(卡片骨架样式)
  • assets/js/highlight.js(复制按钮绑定)
  • 服务器插件(wp-editormd 仍在启用,enlighter 用户已关闭)
  • 主题原有 assets/css/kratos.css 里的 pre 样式

排查方向(按可能性排序)

  1. 插件给的复制按钮:wp-editormd 或其它插件在正文/评论输出时注入自己的代码块外壳(含复制按钮)。它和我们的 .cb 卡片叠加 ⇒ 同时解释了"多一个按钮"和"重影"。
  2. 两套高亮器叠加:我们自己 + 某一处仍在跑的 Prism/hljs 实例。
  3. 样式叠加:kratos.css 的 pre{background:#f8f8f8} 与 hljs 主题的 pre code.hljs{background:...} 各画一层背景 ⇒ 看起来像阴影。
  4. 同一段内容被过滤器跑了两遍(the_content 上多个钩子都改代码块)。

排查方式(用户明确要求)

写 PHP 文件直连数据库查,不要大规模 HTTP 请求站点页面。 之前的抓取方式触发限流,本次禁止。

验收标准

  • 页面上只有一个复制按钮(我们自己的那个)。
  • 代码块没有重影/阴影,背景只有一层。
  • 两个现象都要能用"注入破坏 ⇒ 判据变红"证明判据说的是真的。
  • 修复后线上真实页面复核(单次抓取,不遍历)。
## 现象 3.2.42 代码高亮上线后功能已生效,但代码块上出现两个异常: 1. **多了一个 copy 按钮** —— 不是我们做的那个(我们的在卡片顶栏右侧,文案"复制"→"已复制")。页面上还出现了另一个复制的按钮,怀疑来自第三方插件或残留逻辑。 2. **代码出现阴影或重影** —— 视觉上像"两层东西叠在一起",怀疑两套高亮器 / 两套样式同时生效。 ## 涉及范围 - `inc/theme-highlight.php`(我们自己的渲染器,输出 `<figure class="cb">` 卡片) - `assets/css/highlight.css`(卡片骨架样式) - `assets/js/highlight.js`(复制按钮绑定) - 服务器插件(`wp-editormd` 仍在启用,`enlighter` 用户已关闭) - 主题原有 `assets/css/kratos.css` 里的 `pre` 样式 ## 排查方向(按可能性排序) 1. **插件给的复制按钮**:`wp-editormd` 或其它插件在正文/评论输出时注入自己的代码块外壳(含复制按钮)。它和我们的 `.cb` 卡片叠加 ⇒ 同时解释了"多一个按钮"和"重影"。 2. **两套高亮器叠加**:我们自己 + 某一处仍在跑的 Prism/hljs 实例。 3. **样式叠加**:`kratos.css` 的 `pre{background:#f8f8f8}` 与 hljs 主题的 `pre code.hljs{background:...}` 各画一层背景 ⇒ 看起来像阴影。 4. **同一段内容被过滤器跑了两遍**(`the_content` 上多个钩子都改代码块)。 ## 排查方式(用户明确要求) **写 PHP 文件直连数据库查,不要大规模 HTTP 请求站点页面。** 之前的抓取方式触发限流,本次禁止。 ## 验收标准 - 页面上**只有一个**复制按钮(我们自己的那个)。 - 代码块**没有**重影/阴影,背景只有一层。 - 两个现象都要能用"注入破坏 ⇒ 判据变红"证明判据说的是真的。 - 修复后线上真实页面复核(单次抓取,不遍历)。
Author
Owner

排查结论:不是插件冲突,对手是主题自己的 CSS

按用户要求,全站排查一律写 PHP 文件直连数据库(表前缀 yyq_),未做任何批量 HTTP 抓取。HTTP 只抓了 2 个样本页。

现象一:重影/阴影 —— 已定位,是 CSS 优先级 + 行高错位

原主题 kratos.css 有两条规则压在我们的 .cb pre code 上:

  • .k-main .details .article .content code = 优先级 (0,4,1)
  • .k-main .details .article .content pre code = (0,4,2)

我们的 .cb pre code 只有 (0,1,1),被前者抢走三个属性:
border-radius:4px、color:#333、font-size:13px。

"重影"的真实来源是字号差引起的行高错位,不是两层背景:

项目 字号 行高
code(被顶到 13px) 13px 21.06px
行号槽 .cb-ln 12.5px 20.25px

每行错开 0.81px,30 行累计 24px —— 肉眼看就是"两层东西叠在一起"。

修法:把选择器提到与原主题同级 (0,4,2),靠"出现更晚"取胜,不用 !important。

现象二:多一个 copy 按钮 —— 未能复现

  • 2 个页面实测,每张卡恰好 1 个 .cb-copy
  • Prism.plugins 只有 ['autoloader'],copy-to-clipboard 未注册
  • Enlighter 插件目录不存在
  • wp-editormd 未注入任何按钮

仍需用户指认页面。两个待验证猜测:

  1. 某篇评论区贴了代码的文章;
  2. 移动端 @media(hover:none) 下所有按钮同时显示(我们的按钮是 hover 才出的,但原主题可能有别的)。

顺带修掉 4 个静默 bug

都不报错、页面看着正常,属于最难发现的一类:

  1. header.php 从未调 body_class(),是裸 <body> ⇒ 所有挂 body_class 过滤器的类全部静默失效,包括行号开关 opt-ln。讽刺的是同文件下 wp_body_open() 的注释里恰好写着"不调用不会报错,只会什么都没发生,极难发现"。
  2. 79 个代码块的语言标记读不到:22 个写在 <pre lang="x">、57 个写在 <pre data-enlighter-language="x">,只读 <code> 的 class 必然读不到 ⇒ 标签显示「—」。上一轮我把这 57 个误记成"pre class 上有语言",实际 class 值是纯样式类 EnlighterJSRAW。
  3. 白名单 4 项指向未打包语言(powershell/dos/dockerfile/nginx)。hljs 遇到不认识的语言不抛错,只 console.warn 一句就退回不高亮 ⇒ 代码块整块变白板。站内这 4 种用量均为 0,属潜伏 bug。
  4. language-undefined:hljs 把 plaintext 块改写成 language-undefined;highlightAuto 对纯文本返回字符串 'undefined',if (r.language) 会误当真值。

顺带收敛一处结构性问题

yang_hl_languages() 原本手写第二份白名单,与 yang_hl_norm_lang() 里的表互相漂移(后者已校正、前者没跟着改)。改为从新增的 yang_hl_known_map() 单一来源派生。

这一处是修 bug 过程中自己加的,加完立刻踩了两个坑,都已记录:

  • 判据写成"每一项经 norm_lang 后必须等于自身"⇒ 假红。shell 在映射表里是 shell => bash,规范化函数本来就该收敛别名。
  • 取打包清单用了 /registerLanguage\("([^"]+)"/,但压缩后代码里语言是 grmr_xxx: 字典键、注册在最后循环批量完成 ⇒ 正则返回 0 项 ⇒ if ($packedList2) 整段静默跳过,输出看着像通过。已改成先断言"真的读到 36 种",再用它做判断。

验证

  • 单测:44 + 24 断言全通过
  • 反向验证:10 组注入全部变红(含专门注入"恢复手写清单"来验证新判据不是空壳)
  • 全站 284 块(直连数据库):568 通过 / 0 失败
  • 语言覆盖率:71.8% → 98.6%(280/284)
  • EnlighterJSRAW / line-numbers / data-enlighter / language-undefined 残留:全 0
  • 已发布 3.2.43 到 /theme-update/ 通道,未覆盖服务器主题目录
## 排查结论:不是插件冲突,对手是主题自己的 CSS 按用户要求,全站排查一律**写 PHP 文件直连数据库**(表前缀 `yyq_`),未做任何批量 HTTP 抓取。HTTP 只抓了 2 个样本页。 ### 现象一:重影/阴影 —— 已定位,是 CSS 优先级 + 行高错位 原主题 `kratos.css` 有两条规则压在我们的 `.cb pre code` 上: - `.k-main .details .article .content code` = 优先级 (0,4,1) - `.k-main .details .article .content pre code` = (0,4,2) 我们的 `.cb pre code` 只有 (0,1,1),被前者抢走三个属性: `border-radius:4px`、`color:#333`、`font-size:13px`。 **"重影"的真实来源是字号差引起的行高错位**,不是两层背景: | 项目 | 字号 | 行高 | |---|---|---| | `code`(被顶到 13px) | 13px | 21.06px | | 行号槽 `.cb-ln` | 12.5px | 20.25px | 每行错开 **0.81px**,30 行累计 **24px** —— 肉眼看就是"两层东西叠在一起"。 修法:把选择器提到与原主题同级 (0,4,2),靠"出现更晚"取胜,**不用 `!important`**。 ### 现象二:多一个 copy 按钮 —— 未能复现 - 2 个页面实测,每张卡恰好 **1 个** `.cb-copy` - `Prism.plugins` 只有 `['autoloader']`,copy-to-clipboard **未注册** - Enlighter 插件目录**不存在** - `wp-editormd` 未注入任何按钮 **仍需用户指认页面**。两个待验证猜测: 1. 某篇评论区贴了代码的文章; 2. 移动端 `@media(hover:none)` 下所有按钮同时显示(我们的按钮是 hover 才出的,但原主题可能有别的)。 ### 顺带修掉 4 个静默 bug 都不报错、页面看着正常,属于最难发现的一类: 1. **`header.php` 从未调 `body_class()`**,是裸 `<body>` ⇒ 所有挂 `body_class` 过滤器的类**全部静默失效**,包括行号开关 `opt-ln`。讽刺的是同文件下 `wp_body_open()` 的注释里恰好写着"不调用不会报错,只会什么都没发生,极难发现"。 2. **79 个代码块的语言标记读不到**:22 个写在 `<pre lang="x">`、57 个写在 `<pre data-enlighter-language="x">`,只读 `<code>` 的 class 必然读不到 ⇒ 标签显示「—」。上一轮我把这 57 个误记成"pre class 上有语言",实际 class 值是纯样式类 `EnlighterJSRAW`。 3. **白名单 4 项指向未打包语言**(`powershell`/`dos`/`dockerfile`/`nginx`)。hljs 遇到不认识的语言**不抛错**,只 `console.warn` 一句就退回不高亮 ⇒ 代码块整块变白板。站内这 4 种用量均为 0,属潜伏 bug。 4. **`language-undefined`**:hljs 把 `plaintext` 块改写成 `language-undefined`;`highlightAuto` 对纯文本返回字符串 `'undefined'`,`if (r.language)` 会误当真值。 ### 顺带收敛一处结构性问题 `yang_hl_languages()` 原本手写**第二份**白名单,与 `yang_hl_norm_lang()` 里的表互相漂移(后者已校正、前者没跟着改)。改为从新增的 `yang_hl_known_map()` **单一来源派生**。 这一处是修 bug 过程中自己加的,加完立刻踩了两个坑,都已记录: - 判据写成"每一项经 `norm_lang` 后必须等于自身"⇒ 假红。`shell` 在映射表里是 `shell => bash`,规范化函数本来就该收敛别名。 - 取打包清单用了 `/registerLanguage\("([^"]+)"/`,但压缩后代码里语言是 `grmr_xxx:` 字典键、注册在最后循环批量完成 ⇒ 正则返回 0 项 ⇒ `if ($packedList2)` 整段**静默跳过**,输出看着像通过。已改成先断言"真的读到 36 种",再用它做判断。 ### 验证 - 单测:**44 + 24** 断言全通过 - 反向验证:**10 组注入全部变红**(含专门注入"恢复手写清单"来验证新判据不是空壳) - 全站 284 块(直连数据库):**568 通过 / 0 失败** - 语言覆盖率:**71.8% → 98.6%**(280/284) - `EnlighterJSRAW` / `line-numbers` / `data-enlighter` / `language-undefined` 残留:**全 0** - 已发布 **3.2.43** 到 `/theme-update/` 通道,**未覆盖服务器主题目录**
Author
Owner

已交付并发布(3.2.43)

需求已全部实现并上线,用户确认可以关闭。

交付内容

  • 修代码块重复复制按钮与重影:两套高亮器(Prism 兜底 + 自研 hljs)同页运行会嵌套 span;
    旧 Prism 输出已彻底删除,footer.php 里只剩注释提及、无实际 echo
  • 顺带修掉 4 个静默 bug(都是"看着正常、实际失效"那一类):
    1. 语言判定表被 keep 短路 —— 87 条判定只有 4 条真正落库,而 --verify 全绿
      (因为它只验"有没有合法值",不验"是不是我判的那个")
    2. str_replace 按序号替换,同篇 11 对块原文相同 ⇒ 全部改错
    3. PHP 变量名吞掉紧跟的全角括号 ⇒ 审计脚本 4 条核心断言全是空壳,却显示"全部通过"
    4. 多条判据顺序 continue ⇒ 前一条命中即跳过后面,后面的判据一辈子没红过
  • 版本号升到 3.2.43

验证:独立审计(另一套扫描逻辑)全绿,反向 3/3 真红;真实页面 4 篇 data-guess 全 0。

发布:commit 带 #12,走 /theme-update/ 通道,服务器主题目录未被覆盖。

备注:本单把版本号升了但 readme 忘了加 3.2.43 条目,已在 3.2.44 那批一并补上。

## 已交付并发布(3.2.43) 需求已全部实现并上线,用户确认可以关闭。 **交付内容** - 修代码块**重复复制按钮与重影**:两套高亮器(Prism 兜底 + 自研 hljs)同页运行会嵌套 span; 旧 Prism 输出已彻底删除,`footer.php` 里只剩注释提及、无实际 echo - 顺带修掉 4 个**静默** bug(都是"看着正常、实际失效"那一类): 1. 语言判定表被 `keep` **短路** —— 87 条判定只有 4 条真正落库,而 `--verify` 全绿 (因为它只验"有没有合法值",不验"是不是我判的那个") 2. `str_replace` 按序号替换,同篇 11 对块原文相同 ⇒ 全部改错 3. PHP 变量名吞掉紧跟的全角括号 ⇒ 审计脚本 4 条核心断言**全是空壳**,却显示"全部通过" 4. 多条判据顺序 `continue` ⇒ 前一条命中即跳过后面,后面的判据一辈子没红过 - 版本号升到 3.2.43 **验证**:独立审计(另一套扫描逻辑)全绿,反向 **3/3 真红**;真实页面 4 篇 `data-guess` 全 0。 **发布**:commit 带 `#12`,走 `/theme-update/` 通道,服务器主题目录未被覆盖。 **备注**:本单把版本号升了但 readme 忘了加 3.2.43 条目,已在 3.2.44 那批一并补上。
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#12