From 8f8cffd69e0c69a31295f420f1d09363e9daff49 Mon Sep 17 00:00:00 2001 From: laoyang Date: Mon, 26 Oct 2026 11:00:47 +0800 Subject: [PATCH] =?UTF-8?q?3.2.43:=20=E4=BF=AE=E4=BB=A3=E7=A0=81=E5=9D=97?= =?UTF-8?q?=E9=87=8D=E5=BD=B1=E4=B8=8E=E8=AF=AD=E8=A8=80=E8=AF=86=E5=88=AB?= =?UTF-8?q?=EF=BC=8C=E5=90=AB=204=20=E4=B8=AA=E9=9D=99=E9=BB=98=20bug=20(#?= =?UTF-8?q?12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 排查结论:不是插件冲突,对手是主题自己的 kratos.css。 现象一「重影/阴影」的真实成因是 CSS 优先级 + 行高错位: kratos.css 的 .content code(0,4,1) / .content pre code(0,4,2) 抢走了 border-radius:4px、color:#333、font-size:13px。字号被顶到 13px 后 行高算成 21.06px,而行号槽是 12.5px/20.25px,每行错开 0.81px, 30 行累计 24px —— 视觉上就是「两层东西叠在一起」。 现象二「多一个 copy 按钮」未能复现:2 个页面实测每张卡恰好 1 个 .cb-copy;Prism.plugins 只有 autoloader,copy-to-clipboard 未注册; Enlighter 插件目录不存在。已请用户指认页面。 修复: - highlight.css 的选择器提到与原主题同级 (0,4,2),靠出现更晚取胜, 不用 !important。 - 顺带修掉 4 个静默 bug(都不报错、页面看着正常): 1. header.php 从未调 body_class(),裸 ⇒ 所有挂 body_class 过滤器的类全部静默失效,包括行号开关 opt-ln(选项已开却不显示)。 2. 79 个代码块的语言写在
 或 data-enlighter-language 上,
     只读  class 必然读不到 ⇒ 标签显示「—」。
  3. 白名单 4 项指向未打包语言(powershell/dos/dockerfile/nginx)。
     hljs 遇到不认识的语言不抛错,只 warn 一句就退回不高亮 ⇒
     整块白板。站内这 4 种用量均为 0,属潜伏 bug。
  4. hljs 把 plaintext 块改写成 language-undefined;highlightAuto
     对纯文本返回字符串 'undefined',if (r.language) 会误当真值。

顺带收敛:yang_hl_languages() 原本手写第二份清单,与 yang_hl_norm_lang()
里的表互相漂移,改为从 yang_hl_known_map() 单一来源派生。

验证:
- 单测 44 + 24 断言全通过
- 反向验证 10 组注入全部变红(含专门注入「恢复手写清单」验证新判据)
- 全站 284 块直连数据库校验:568 通过 / 0 失败,
  语言覆盖率 71.8% → 98.6%,残留与污染全 0
- 剩余 4 块显示「—」是正确降级(jsp×2、latex×2 未打包进 hljs)
- 夹具对照:新版 0 失败 vs 全旧版 10 失败
---
 assets/css/highlight.css |  30 +++++
 assets/js/highlight.js   |  68 ++++++++++-
 header.php               |  10 +-
 inc/theme-highlight.php  | 246 +++++++++++++++++++++++++++++++--------
 style.css                |   2 +-
 5 files changed, 304 insertions(+), 52 deletions(-)

diff --git a/assets/css/highlight.css b/assets/css/highlight.css
index 1310adc..65fd709 100644
--- a/assets/css/highlight.css
+++ b/assets/css/highlight.css
@@ -152,15 +152,45 @@
 
 .cb .cb-body > pre { flex: 1 1 auto; min-width: 0; }
 
+/* 🔴 卡片里的 code 必须彻底摆脱原主题 `.content code` 的影响。
+ *
+ * 原主题 kratos.css 有两条规则(实测优先级):
+ *   `.k-main .details .article .content code`      → (0,4,1)
+ *        margin:0 3px; padding:2px 4px; border-radius:4px;
+ *        background-color:#eff0f1; color:#333; font-size:13px
+ *   `.k-main .details .article .content pre code`  → (0,4,2)
+ *        margin:0; padding:0; background-color:transparent
+ *
+ * 后者只救了 margin/padding/background。**border-radius、color、font-size
+ * 全都漏了**,于是:
+ *   · border-radius:4px  → 代码区里嵌一块 4px 圆角,和卡片 8px 圆角打架,
+ *                          视觉上就是用户说的「有阴影/重影」
+ *   · font-size:13px     → 代码字号被顶大,行高跟着从 20.25px 变 21.06px,
+ *                          而行号槽用的是 12.5px/20.25px ⇒ 每行错开 0.81px,
+ *                          30 行累计错 24px,行号与代码彻底对不上
+ *   · color:#333         → 把 hljs 主题给 
 的基色(.hljs{color:#000})
+ *                          覆盖成固定的深灰。深色配色下就是深灰压深底,看不清
+ *
+ * 修法:选择器强度提到与 `.content pre code` 同级的 (0,4,2) ——
+ *   靠**出现更晚**取胜,不靠 !important(!important 会让用户/插件再也没法覆盖)。
+ *   显式写 border-radius:0 而不是依赖"没声明就继承",因为 border-radius
+ *   不继承、初始值是 0,但原主题那条规则会直接命中 code。 */
+.k-main .details .article .content .cb pre code,
+.comment-body .cb pre code,
 .cb pre code {
 	display: block;
 	margin: 0;
 	padding: 0;
+	border: 0;
+	border-radius: 0;
 	background: transparent;
 	font-size: inherit;
 	line-height: inherit;
 	color: inherit;
 	font-family: inherit;
+	/* 原主题给了 word-break:inherit,pre 上是 normal,这里跟住 */
+	word-break: inherit;
+	overflow-wrap: inherit;
 }
 
 /* 深色配色必须让卡片自带深色底与深色顶条。
diff --git a/assets/js/highlight.js b/assets/js/highlight.js
index 82d65a3..54d5218 100644
--- a/assets/js/highlight.js
+++ b/assets/js/highlight.js
@@ -34,6 +34,60 @@
 		if (typeof hljs.highlightAll === 'function') {
 			hljs.highlightAll();
 		}
+		fixPlaintextClass();
+		return true;
+	}
+
+	/* ── 修掉 hljs 留下的 language-undefined ──────────────────
+	 * 🔴 实测(真实浏览器):hljs 11.12.0 的 highlightElement() 处理
+	 *    `` 之后,会把 class 改写成
+	 *    **`hljs language-undefined`**。
+	 *
+	 *    原因是 plaintext 的定义只有 {name, aliases, disableAutodetect,
+	 *    rawDefinition},**没有 `language` 字段**,而 highlightElement
+	 *    内部用 `result.language` 拼了 className —— 于是拼出字面量 "undefined"。
+	 *
+	 *    后果不是报错(页面一切正常、颜色也对,因为 plaintext 本来就不上色),
+	 *    但 class 被污染成 `language-undefined`:
+	 *      · 任何人按 `[class*="language-"]` 统计语言都会多数出一个"undefined"
+	 *      · 自动化判据会被它误导(本项目的探针就吃到这个假数据)
+	 *    所以这里显式改回 language-plaintext。
+	 *
+	 *    判据必须直接查 class 字面量,不能只看"有没有颜色"——
+	 *    plaintext 本来就没颜色,看颜色永远看不出这个问题。 */
+	function fixPlaintextClass () {
+		var codes = document.querySelectorAll('code.language-undefined');
+		for (var i = 0; i < codes.length; i++) {
+			var cb = codes[i].closest ? codes[i].closest('.cb') : null;
+			// 只修我们自己卡片里、且 data-lang 确实是 plaintext 的
+			if (!cb) { continue; }
+			if (cb.getAttribute('data-lang') !== 'plaintext') { continue; }
+			codes[i].className = 'hljs language-plaintext';
+		}
+	}
+
+	/* 判断 highlightAuto 的返回是不是"真的识别出来了"
+	 *
+	 * 🔴 绝不能用 `if (r && r.language)`:
+	 *    实测 hljs 11.12.0 对纯文本/中文内容的 highlightAuto 返回
+	 *    `{language: 'undefined', relevance: 0}` —— 注意是**字符串**
+	 *    'undefined',不是 undefined 值。用真值判断会把它当成功,
+	 *    于是 class 写成 `language-undefined`、标签写成 labelOf('undefined')
+	 *    再被 toUpperCase() 变成「UNDEFINED」,直接显示在页面上。
+	 *
+	 *    另有一个真实的正确性隐患:英文短句会被猜成 sql(relevance 只有 1)。
+	 *    relevance 太低说明"没有可信匹配",这种也应该当作没认出来。 */
+	function autoOk (r) {
+		if (!r || !r.value) { return false; }
+		var lang = r.language;
+		if (!lang || lang === 'undefined' || lang === 'null') { return false; }
+		if (typeof lang !== 'string') { return false; }
+		// relevance 为 0 = 完全没有命中任何语法特征
+		if (!r.relevance || r.relevance <= 0) { return false; }
+		// 语言必须在 hljs 里真的注册过,否则写进 class 就是白板
+		if (typeof hljs.getLanguage === 'function' && !hljs.getLanguage(lang)) {
+			return false;
+		}
 		return true;
 	}
 
@@ -69,7 +123,7 @@
 
 				if (on) {
 					var r = hljs.highlightAuto(src);
-					if (r && r.language) {
+					if (autoOk(r)) {
 						code.innerHTML = r.value;
 						code.className = 'hljs language-' + r.language;
 						if (tag) {
@@ -111,9 +165,19 @@
 					}
 			})(boxes[i]);
 		}
+		// runAuto 里也会重写 code.className,所以这里必须再修一次。
+		// (只放在 paint() 里不够:runAuto 是 DOMContentLoaded 之后又跑一遍的,
+		//   会把 paint() 刚修好的 class 覆盖掉。)
+		fixPlaintextClass();
 	}
 
-	/* 语言名 → 显示名 */
+	/* 语言名 → 显示名
+	 *
+	 * 🔴 表里只能放**确实打包进 highlight.min.js 的语言**。
+	 *    放进来但没打包 → hljs 认不出 → 代码块静默白板(只 console.warn,
+	 *    不抛错)。所以 dos / dockerfile / nginx / powershell 已从映射链路
+	 *    与语言白名单里移除,这里保留文案只是为了 highlightAuto 万一返回
+	 *    它们时标签不是全大写,不影响上色。 */
 	function labelOf (lang) {
 		var M = {
 			bash: 'Bash', c: 'C', cpp: 'C++', csharp: 'C#', css: 'CSS',
diff --git a/header.php b/header.php
index 7e783cf..63b5c9d 100644
--- a/header.php
+++ b/header.php
@@ -25,12 +25,20 @@
     
 
 
-
+
 )。
  * 主题之前没有调用它,导致所有挂在这个钩子上的东西(插件、主题自己的提示条)静默失效。
  * 补上是必须的:不调用它不会报错,只会"什么都没发生",极难发现。
+ *
+ * 🔴 body_class() 曾经犯过一模一样的错:这里原来就是裸的 ``,
+ *    根本没有调用 body_class()。后果不是报错,而是**所有**挂在
+ *    `body_class` 过滤器上的类都不输出 —— 包括代码高亮的行号开关
+ *    (.opt-ln)和评论头像的开关。表现是"后台勾了行号,前台一行都没有",
+ *    而 CSS、JS、选项值全是对的,只有  是空 class。
+ *    实测:修前 body.className === '',修后才有 opt-ln 等类。
+ *    判据不能只看"页面有没有报错",必须直接读 body 的 className。
  */
 wp_body_open();
 ?>
diff --git a/inc/theme-highlight.php b/inc/theme-highlight.php
index 3cb8527..b194740 100644
--- a/inc/theme-highlight.php
+++ b/inc/theme-highlight.php
@@ -90,11 +90,6 @@ function yang_hl_lang_map()
         'shell'      => 'bash',
         'console'    => 'bash',
         'terminal'   => 'bash',
-        'ps'         => 'powershell',
-        'ps1'        => 'powershell',
-        'bat'        => 'dos',
-        'batch'      => 'dos',
-        'cmd'        => 'dos',
         'c++'        => 'cpp',
         'cs'         => 'csharp',
         'c#'         => 'csharp',
@@ -102,12 +97,22 @@ function yang_hl_lang_map()
         'rs'         => 'rust',
         'rb'         => 'ruby',
         'kt'         => 'kotlin',
-        'objectivec' => 'objectivec',
         'objc'       => 'objectivec',
-        'dockerfile' => 'dockerfile',
-        'docker'     => 'dockerfile',
-        'nginx'      => 'nginx',
         'sql'        => 'sql',
+
+        /* 🔴 下面这几组**故意不映射**,因为目标语言没有打包进
+         *    assets/hljs/highlight.min.js:
+         *      powershell / dos / dockerfile / nginx —— 实测 listLanguages()
+         *      的 36 项里一个都没有。
+         *
+         *    之前它们被映射过去,结果 hljs 找不到语言后**静默退回不高亮**
+         *    (只在控制台 warn 一句,不抛错),代码块变成纯白板 ——
+         *    页面不报错、脚本无异常、CSS 全对,几乎不可能被发现。
+         *
+         *    站内当前这几种写法使用次数都是 0,所以一直没暴露。
+         *    真要支持它们,正确做法是往 highlight.min.js 里补打包对应语言,
+         *    而不是在这里"映射成名字"。现在不映射 = 退回自动识别
+         *    (标签打虚线,明确标示"这是猜的"),比"假装标了、实际没色"诚实。 */
     );
 }
 
@@ -139,19 +144,8 @@ function yang_hl_norm_lang($raw)
         return $map[$raw];
     }
 
-    // hljs 官方的语言名直接用
-    static $known = null;
-    if ($known === null) {
-        // 与 assets/js/hljs/highlight.min.js 打包的语言一致(36 种)
-        $known = array_flip(array(
-            'bash', 'c', 'cpp', 'csharp', 'css', 'diff', 'go', 'graphql',
-            'ini', 'java', 'javascript', 'json', 'kotlin', 'less', 'lua',
-            'makefile', 'markdown', 'objectivec', 'perl', 'php',
-            'plaintext', 'powershell', 'python', 'r', 'ruby', 'rust',
-            'scss', 'shell', 'sql', 'swift', 'typescript', 'xml', 'yaml',
-            'dos', 'dockerfile', 'nginx',
-        ));
-    }
+    // hljs 官方的语言名直接用(表的正文与理由见 yang_hl_known_map())
+    $known = yang_hl_known_map();
     return isset($known[$raw]) ? $raw : '';
 }
 
@@ -210,18 +204,67 @@ function yang_hl_label($lang)
 /**
  * 允许高亮的语言白名单(与打包进 hljs 的一致)
  *
+ * 🔴 这里**不能再手写一份清单**。
+ *
+ *    3.2.43 之前这个函数手写了 36 项,与 yang_hl_norm_lang() 里那张
+ *    `$known` 表是**两份互相独立的真相**:`$known` 已经按实测校正过
+ *    (剔掉没打包的 powershell/dos/dockerfile/nginx,补上 php-template/
+ *     python-repl/vbnet/wasm),而这里还留着旧内容。
+ *
+ *    两份清单不一致的后果是静默的:hljs 遇到不认识的语言不抛错,
+ *    只 console.warn 一句就退回不高亮 —— 代码块整块变白板。
+ *
+ *    改为从 `$known` 单一来源派生,以后只维护一张表。
+ *
  * @return array
  */
 function yang_hl_languages()
 {
-    return array_keys(array_flip(array(
-        'bash', 'c', 'cpp', 'csharp', 'css', 'diff', 'go', 'graphql',
-        'ini', 'java', 'javascript', 'json', 'kotlin', 'less', 'lua',
-        'makefile', 'markdown', 'objectivec', 'perl', 'php',
-        'plaintext', 'powershell', 'python', 'r', 'ruby', 'rust',
-        'scss', 'sql', 'swift', 'typescript', 'xml', 'yaml',
-        'dos', 'dockerfile', 'nginx',
-    )));
+    return array_keys(yang_hl_known_map());
+}
+
+/**
+ * `$known` 白名单的表本体(唯一真相源)
+ *
+ * 🔴 这张表必须与 assets/hljs/highlight.min.js **实际打包**的语言逐字一致。
+ *
+ *    之前它写着 36 项,但其中 powershell / dos / dockerfile / nginx
+ *    **根本没有打包**(实测 hljs.listLanguages() 36 项里没有这四个),
+ *    同时漏掉了实际打包进来的 php-template / python-repl / vbnet / wasm。
+ *
+ *    后果是静默的:hljs 遇到不认识的语言**不抛错**,只 console.warn 一句
+ *    "Could not find the language 'xxx'" 然后退回不高亮 ——
+ *    代码块整块变成白板,没有红色报错、没有脚本异常、页面一切正常。
+ *    站内当前这 4 种语言的使用次数都是 0,所以尚未触发;
+ *    但只要以后写一篇 PowerShell 文章,就会出现"代码块没有颜色"
+ *    且完全查不出原因的情况。
+ *
+ *    现按实测结果校正(下面 36 项 = node 里 hljs.listLanguages() 的原始输出):
+ *      bash c cpp csharp css diff go graphql ini java javascript json
+ *      kotlin less lua makefile markdown objectivec perl php php-template
+ *      plaintext python python-repl r ruby rust scss shell sql swift
+ *      typescript vbnet wasm xml yaml
+ *
+ *    ⚠️ 未打包的语言(powershell/dos/dockerfile/nginx/latex/jsp 等)
+ *       一律不放进这张表 —— 放进来才会造成白板。它们会返回空串,
+ *       由前端 highlightAuto 兜底(标签打虚线,明确表示"这是猜的")。
+ *
+ * @return array 语言名 => 下标
+ */
+function yang_hl_known_map()
+{
+    static $known = null;
+    if ($known === null) {
+        $known = array_flip(array(
+            'bash', 'c', 'cpp', 'csharp', 'css', 'diff', 'go', 'graphql',
+            'ini', 'java', 'javascript', 'json', 'kotlin', 'less', 'lua',
+            'makefile', 'markdown', 'objectivec', 'perl', 'php',
+            'php-template', 'plaintext', 'python', 'python-repl', 'r',
+            'ruby', 'rust', 'scss', 'shell', 'sql', 'swift', 'typescript',
+            'vbnet', 'wasm', 'xml', 'yaml',
+        ));
+    }
+    return $known;
 }
 
 /**
@@ -260,14 +303,112 @@ function yang_hl_pick_lang_from_class($class)
     }
     return '';
 }
+
+/**
+ * 从 `
` 自身的属性里取语言
+ *
+ * 🔴 为什么必须单独做这一件事:站内 284 个代码块,语言标记的载体有四种,
+ *    之前的 `yang_hl_pick_lang_from_class()` **只认第一种**:
+ *
+ *      ① `
`            204 个  ← 认到了
+ *      ② `
`                             22 个  ← 漏
+ *      ③ `
`          57 个  ← 漏
+ *      ④ 真无标记                                       1 个
+ *
+ *    ②③ 合计 79 个(占 27.8%,涉及 26 篇文章)判不出语言 ⇒ 标签显示「—」,
+ *    而实际语言一直明明白白写在属性里。这不是"覆盖不到",是**读错了载体**。
+ *
+ * ⚠️ 上一轮我把这 79 个记成「裸 pre,无 code 子元素」,只统计了 ``
+ *    子元素、没查 `
` 自己的属性,所以得出"需要自动识别"的错误结论。
+ *    教训:判据要把所有可能的承载位置都列出来,不能只认一种形态。
+ *
+ * Enlighter 的取值语义(官方文档):
+ *    generic / raw → 不高亮,等价于纯文本(28 + 8 = 36 个块)
+ *    其余值就是语言名(bash 17、latex 2、json 1、php 1)
+ *    所以 generic/raw 映射到 plaintext 是**语义正确**,不是猜。
+ *
+ * @param string $attrs `
` 里的属性原文(不含 
)
+ * @return string        规范化后的语言名;取不到返回空串
+ */
+function yang_hl_pick_lang_from_attrs($attrs)
+{
+    $attrs = (string) $attrs;
+    if (trim($attrs) === '') {
+        return '';
+    }
+
+    // ② Enlighter 数据属性
+    if (preg_match('/data-enlighter-language\s*=\s*["\']([^"\']*)["\']/i', $attrs, $m)) {
+        $raw = strtolower(trim($m[1]));
+        // Enlighter 这两个值表示"不要高亮"
+        if ($raw === 'generic' || $raw === 'raw') {
+            return 'plaintext';
+        }
+        $lang = yang_hl_norm_lang($raw);
+        if ($lang !== '') {
+            return $lang;
+        }
+    }
+
+    // ② lang 属性
+    if (preg_match('/(?:^|\s)lang\s*=\s*["\']([^"\']*)["\']/i', $attrs, $m)) {
+        $lang = yang_hl_norm_lang($m[1]);
+        if ($lang !== '') {
+            return $lang;
+        }
+    }
+    /* 🔴 容错:属性值的闭合引号缺失。
+     *
+     *    站内实测存在这种脏数据(十几年前手工编辑留下的):
+     *        
」范围内 ——
+     *    这样不会把 `lang="a" class="b"` 里的后半段吞进来。
+     *
+     *    ⚠️ 绝不能改成 `lang\s*=\s*(\S+)` 这种"取到空白为止"的写法:
+     *       它会把行内 style 之类的内容也当语言名,属于用更宽的错盖住窄的错。 */
+    if (preg_match('/(?:^|\s)lang\s*=\s*["\']([^\s"\'>]+)/i', $attrs, $m)) {
+        $lang = yang_hl_norm_lang($m[1]);
+        if ($lang !== '') {
+            return $lang;
+        }
+    }
+
+    // ③ class(可能是 language-x,也可能是 EnlighterJSRAW / editor-md-pre 这种纯样式类)
+    if (preg_match('/\bclass\s*=\s*["\']([^"\']*)["\']/i', $attrs, $m)) {
+        $cls = preg_replace('/\b(editor-md-pre|EnlighterJSRAW)\b/i', '', $m[1]);
+        $lang = yang_hl_pick_lang_from_class($cls);
+        if ($lang !== '') {
+            return $lang;
+        }
+        // 退一步:整串当语言名试(`
`)
+        $probe = trim(preg_replace('/\s+/', '', $cls));
+        if ($probe !== '') {
+            $lang = yang_hl_norm_lang($probe);
+            if ($lang !== '') {
+                return $lang;
+            }
+        }
+    }
+
+    return '';
+}
 /**
  * 把一个 
 片段规范化成"代码块卡片"的结构
  *
- * 输入可能是四种形态中的任意一种(站内都实测存在):
- *   A. 
…
← 标准,204 个 - * B.
…
← 类在 pre 上 - * C.
…
← 无标记,需自动识别 - * D.
…
← 裸 pre,80 个,必须处理 + * 输入可能是四种形态中的任意一种(站内都实测存在,数字是 284 个块的真实分布): + * A.
…
204 个 + * B.
…
22 个 + * C.
…
57 个 + * D.
…
1 个 + * + * 🔴 B/C 的语言都在 **pre 自己的属性**上,不在 code 子元素的 class 上。 + * 早先只读 code 的 class,导致这 79 个块(27.8%,26 篇文章)的语言标签 + * 全部退化成「—」,同时被前端 highlightAuto 乱猜(准确率实测仅 22%)。 * * 输出统一是: *
@@ -291,9 +432,10 @@ function yang_hl_pick_lang_from_class($class) * * @param array $m preg_match_all 的匹配组 * @param string $inner_pre pre 内部原文(已含未处理的 HTML) + * @param string $attr_pre pre 自身的属性原文(含 lang= / class= / data-*) * @return string */ -function yang_hl_render_block($inner_pre, $attr_class = '') +function yang_hl_render_block($inner_pre, $attr_pre = '') { $code = $inner_pre; $lang = ''; @@ -306,10 +448,22 @@ function yang_hl_render_block($inner_pre, $attr_class = '') || preg_match("/class\s*=\s*'([^']*)'/i", $attrs, $cm)) { $lang = yang_hl_pick_lang_from_class($cm[1]); } + /* code 上也可能挂 lang= 属性。 + * + * 🔴 锚定必须是 `(?:^|\s)lang`,**不能**写 `\blang`。 + * `-` 是非单词字符,`\b` 在 `data-lang=` 的 `l` 前面同样成立 + * ⇒ 会把 data-lang 的值当语言名读走。 + * 这是同一类错误在本文件的**第二处**:上面 + * yang_hl_pick_lang_from_attrs() 里已经修过一次,这里漏改。 + * 教训:修正则时要 grep 同款写法,不能只改报错的那一处。 */ + if ($lang === '' + && preg_match('/(?:^|\s)lang\s*=\s*["\']([^"\']*)["\']/i', $attrs, $lm)) { + $lang = yang_hl_norm_lang($lm[1]); + } } - // pre 自己的 class 也可能是语言来源(形态 B) - if ($lang === '' && $attr_class !== '') { - $lang = yang_hl_pick_lang_from_class($attr_class); + // pre 自己的属性也是语言来源(形态 B/C —— 站内共 79 个块靠这里) + if ($lang === '' && $attr_pre !== '') { + $lang = yang_hl_pick_lang_from_attrs($attr_pre); } // 代码内容保持原样:它已经是 HTML 转义过的(< &), @@ -394,15 +548,11 @@ function yang_hl_filter_content($content) $out = preg_replace_callback( '#]*)>(.*?)
#is', function ($m) { + // 🔴 必须把**完整属性串**传下去,不能只传 class。 + // 站内 79 个块的语言写在 lang= / data-enlighter-language= 上, + // 只传 class 会把这 79 个块的语言全部丢掉(实测:标签退化成「—」)。 $attrs = isset($m[1]) ? $m[1] : ''; - $cls = ''; - if (preg_match('/class\s*=\s*"([^"]*)"/i', $attrs, $cm) - || preg_match("/class\s*=\s*'([^']*)'/i", $attrs, $cm)) { - $cls = $cm[1]; - } - // wp-editormd 会产出 class="editor-md-pre",那是纯样式类,不是语言 - $cls = preg_replace('/\beditor-md-pre\b/i', '', $cls); - return yang_hl_render_block($m[2], $cls); + return yang_hl_render_block($m[2], $attrs); }, $content ); @@ -535,7 +685,7 @@ function yang_hl_enqueue() * (本项目历史上被 OPcache/缓存这类"文件名对、内容旧"坑过多次)。 * 读主题头用 wp_get_theme()->get('Version'),WordPress 自带缓存,无额外开销。 */ $theme = wp_get_theme(); - $ver = $theme && $theme->get('Version') ? $theme->get('Version') : '3.2.42'; + $ver = $theme && $theme->get('Version') ? $theme->get('Version') : '3.2.43'; $uri = get_template_directory_uri(); $key = yang_hl_theme_key(); diff --git a/style.css b/style.css index 42d331f..29a793c 100644 --- a/style.css +++ b/style.css @@ -1,7 +1,7 @@ /* Theme Name: Kratos_Yang Text Domain: kratos_Yang -Version: 3.2.42 +Version: 3.2.43 Requires PHP: 7.0 Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。 Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好