最近发现 steinslab.io 上的一篇文章(archives/3477)中 LaTeX 数学公式无法渲染,显示为原始文本。花了点时间从源码读到线上抓包,定位到问题并整理出正确的使用方式,记录如下。
问题
线上 https://steinslab.io/archives/3477 页面中 LaTeX 数学公式无法渲染,显示为原始文本。
环境概况
- WordPress + Kratos 4.2.3 主题
- WP Githuber MD 1.16.3:Markdown 编辑器 + 内置 KaTeX 0.12.0
- 独立 KaTeX 插件 2.2.5(已于排查期间卸载):加载 KaTeX 0.16.22
- WP Super Cache、Redis Cache:缓存层
排查过程
1. 阅读 githuber-md 源码,梳理 KaTeX 渲染链路
保存链路(Markdown.php:808-872):
编辑器中 Markdown 内容
↓ wp_insert_post_data
原始 Markdown → post_content_filtered
transform() 将 Markdown 转为 HTML → post_content
├── single_line_code_preserve(): 反引号内容 → <code>...</code>
├── ParsedownExtra::text(): Markdown → HTML
├── do_restore(): 还原被 hash 暂存的 <code> 内容
└── katex_inline_markup(): <code>$$...$$</code> → <code class="katex-inline">
detect_code_languages(): 扫描 language-katex / katex-inline,写入 post meta
└── _is_githuber_katex = true / false
显示链路(KaTeX.php:53-57):
前端请求文章
↓
is_module_should_be_loaded('_is_githuber_katex')
├── true → wp_enqueue_script('katex') → 加载 katex.min.js + katex.min.css
│ → wp_print_footer_scripts → 输出渲染脚本,查找 .language-katex / .katex-inline
└── false → 什么都不加载
关键代码位置:
src/Modules/KaTeX.php:167-189—katex_inline_markup正则(只匹配<code>$$...$$</code>)src/Modules/ModuleAbstract.php:81-95—is_module_should_be_loaded(检查 post meta)src/Controllers/Markdown.php:426-542—detect_code_languages(扫描 HTML class 写 meta)src/Controllers/Markdown.php:808-877—wp_insert_post_data(保存时转换入口)
2. 线上页面抓取分析
总共抓取了 4 次页面,每次对应不同状态:
| 阶段 | 文章语法 | 独立插件 | 页面状态 |
|---|---|---|---|
| 初始 | `$...$`(单美元) | 启用 | <code>$...$</code>,无渲染 |
| 改双美元 | `$$...$$` | 启用 | <code>$$...$$</code>,独立插件接管 CSS/JS,githuber-md 脚本消失 |
| 去反引号 | $$...$$(裸写) | 启用 | 纯文本 $$...$$,独立插件 PHP 端未处理 |
| 关独立插件 | $$...$$(裸写) | 禁用 | 纯文本 $$...$$,githuber-md JS/CSS 未加载 |
3. 正则验证
用 Python 复现 katex_inline_markup 的正则,确认能正确匹配 <code>$$ i $$</code>:
Regex: <code>\$\$((?:[^$]+|(?<=(?<!\\)\\)\$)+)(?<!\\)\$\$<\/code>
Input: <code>$$ i $$</code>
Result: MATCH — captured group: " i "
正则本身没有问题。
4. 最终定位
两条故障链路同时存在:
链路 A(独立插件启用时):
- githuber-md 的
katex.min.js和独立插件的katex.min.js同时注册,句柄冲突 - 独立插件的
render.js只查找.katex-eq元素,不兼容 githuber-md 的.katex-inline/.language-katex - 独立插件的 PHP 端内容过滤也未生效(无
.katex-eq输出)
链路 B(独立插件禁用后):
- 文章语法从
`$$...$$`改成裸$$...$$,githuber-md 不再识别 _is_githuber_katexmeta 为 false →katex.min.js不加载- 即使 footer 渲染脚本输出了,页面也没有可渲染的元素
根本原因:githuber-md 的 Markdown→HTML 转换只在保存时执行。之前的多次语法修改因独立插件干扰或不兼容的语法格式,均未触发正确的转换 + meta 写入。
正确的使用方式
行内公式
位置 `$$ i $$` 只能聚合来自位置 `$$ \leq i $$` 的 token
即 反引号包裹 + 双美元符号。
块级公式
```katex
\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^T}{\sqrt{d_k}}\right) V
```
为什么必须是双 $$
githuber-md 的 katex_inline_markup 正则只匹配 $$...$$,不匹配 $...$。这是上游设计决定。
为什么必须用反引号
反引号告诉 Markdown 解析器这是 inline code,githuber-md 将其包裹为 <code>...</code>,katex_inline_markup 再基于 <code> 标签进行替换。裸写 $$...$$ 不会被处理。
为什么必须保存
githuber-md 的转换在 wp_insert_post_data 钩子(保存时)执行,不是 the_content(显示时)。每次修改公式后必须保存文章才能生效。
建议
-
保持单一 KaTeX 方案。只用 githuber-md 内置 KaTeX,不安装其他 KaTeX/MathJax 插件,避免冲突。
-
统一公式语法。所有文章统一使用
`$$...$$`(行内)和```katex(块级)。 -
若需升级 KaTeX 版本。githuber-md 内置的是 KaTeX 0.12.0(2020年),可将其
assets/vendor/katex/下的katex.min.js和katex.min.css替换为新版本文件。 -
若需支持单
$语法。可修改src/Modules/KaTeX.php:169的katex_inline_markup正则,增加对$...$的匹配。 -
排查其他文章的公式。其他使用公式的历史文章可能存在同样的渲染问题,可按本文正确语法重新保存修复。