为 Typecho 打造的增强版 Markdown 解析器
目录
EnhancedMarkdown:为 Typecho 打造的增强版 Markdown 解析器
用一篇文章,解锁 Typecho 博客的 Markdown 全部潜力。
这篇文章本身就是用 EnhancedMarkdown 的全部语法写成的——你看到的每一种排版效果,都是插件的实时渲染。
为什么需要这个插件?
Typecho 默认使用 HyperDown 作为 Markdown 解析器,在日常写作中够用,但当你需要更丰富的排版能力时,它的局限性就显现出来了:
-
不支持脚注、定义列表、缩写词等 Markdown Extra 语法→ 现在支持了 -
GFM 表格对齐等能力缺失→ 完整 GFM 支持 -
正则后处理导致占位符冲突和渲染异常→ 彻底消除
ℹ️ 核心思路
EnhancedMarkdown 的解决思路很直接——完全替换默认解析器,而非在其基础上打补丁。基于 Parsedown + ParsedownExtra 引擎,从根本上解决问题,同时大幅扩展语法能力。
插件概览
| 项目 | 说明 |
|---|---|
| 当前版本 | v3.8.1 |
| 解析引擎 | Parsedown + ParsedownExtra |
| 工作方式 | 完全替换系统默认 Markdown 解析器 |
| 最低要求 | Typecho(支持命名空间插件机制的版本) |
| 许可证 | BSD License |
演进历程
插件的开发经历了几次关键迭代,每一次都在解决真实的使用问题:
v2.0 — 起步阶段(基于 HyperDown 扩展)
最初的实现方式是在 HyperDown 解析结果上做正则后处理——用 str_replace 替换占位符来扩展语法。这种方式简单直接,但随着扩展语法增多,占位符冲突导致的显示故障越来越频繁。
v3.0 — 重大重构(切换 Parsedown 引擎)
这是最关键的一次变更。将整个解析引擎从 HyperDown 切换为 Parsedown + ParsedownExtra,扩展方式也从正则后处理改为 Parsedown 原生的 InlineTypes / BlockTypes 注册机制:
- 彻底消除占位符冲突:不再有字符串替换带来的副作用
- 原生语法扩展:通过注册自定义解析器实现新语法,与标准语法和平共处
- 获得 Markdown Extra 支持:脚注、定义列表、缩写词开箱即用
💡 技术细节
Parsedown 使用 BlockTypes 和 InlineTypes 数组注册自定义解析器。例如,:::type 容器语法通过将 Container 注册到 : 字符触发;^text^ 上标通过将 Superscript 注册到 ^ 字符触发。
优先级很关键:同一个字符可以注册多个处理器,Parsedown 按数组顺序依次尝试。: 字符上同时注册了 Table、DefinitionList 和 Container。v3.4.2 使用 array_unshift 将 Container 提升为最高优先级,避免 DefinitionList 在容器前紧挨段落时错误拦截 :::type 行。
v3.2 — 细节完善
修正了代码语言标识的兼容性问题——将 language-php 风格的 class 名转换为 Typecho 约定的 lang-php 前缀,确保 Prism.js、Highlight.js 等语法高亮插件正常工作。
v3.3 — 公式与图表
新增两大重量级功能:
- 数学公式(KaTeX 渲染):支持
\(...\)行内公式和$\(...\)$块级公式 - Mermaid 图表:支持流程图、时序图、甘特图等,用
```mermaid代码块书写
v3.4 — 性能优化 + 修复
⚠️ 性能优化要点
引入按需加载机制——KaTeX(约 1.5MB)和 Mermaid(约 3.2MB)仅在实际包含公式/图表的页面才加载。纯文字文章页面零额外资源开销。同时修复了公式定界符缺失和 Mermaid 数组路径错误两个 Bug。
v3.4.2 — 容器语法关键修复
修复了两个影响 :::type 容器语法的 Bug:
- Bug #1:容器内容为空 —
blockContainer()初始化时设置了空text属性,Parsedown 渲染时isset(\(Element['text'])` 优先于 `rawHtml`,导致容器内容永远不显示。修复:`unset(\)Block['element']['text']) - Bug #2:容器被定义列表拦截 — ParsedownExtra 的 DefinitionList 注册在
:字符上,当:::info前紧挨段落时会错误拦截。修复:使用array_unshift将 Container 注册为:字符的最高优先级处理器
v3.5.0 — 解析增强
本次更新带来了 3 项解析增强:
- HTML 块内 Markdown 解析:新增
blockMarkupComplete()方法,对白名单标签(<center>、<details>、<div>等)自动解析内部 Markdown。使用白名单机制确保<script>/<style>/<pre>等标签不受影响 - 代码块标题支持:新增
blockFencedCode()方法提取title="..."参数,支持```javascript title="示例"语法显示代码块标题栏 - 容器方括号语法:扩展
blockContainer()正则,支持:::note[自定义标题]Docusaurus Admonition 风格语法,向后兼容:::note 标题空格语法
v3.5.1 — 纯 HTML 内容误编码修正
v3.5.0 的 blockMarkupComplete() 引入了一个回归问题:当 <div> 等白名单标签内部为纯 HTML(不含 Markdown 语法)时,text() 的递归解析会将 HTML 标签转义为实体编码并错误包裹在 <pre><code> 中。
🚫 回归问题示例
<div style="color:#fff">标题</div><audio>...</audio> 会被错误渲染为:
<pre><code><div style="color:#fff">标题</div>...</code></pre>
修复方案:新增 containsMarkdownSyntax() 启发式检测方法——使用 strip_tags() 去除 HTML 标签后,通过正则检测纯文本中是否包含 Markdown 语法标记(**、`、[、$ 等)。纯 HTML 内容跳过 text() 调用,直接保留原始输出。
v3.5.2 — 主题兼容性修复
本次更新聚焦于与主题的兼容性,修复了两个问题:
- 标题 ID 改用 Slug 格式:旧版使用
toc-0、toc-1等数字 ID,依赖解析顺序且不可预测,主题 JS 无法构建有效锚点链接。v3.5.2 新增generateSlug()方法,将标题文本转为可读的 slug 格式 ID(如hello-world、为什么需要这个插件),重复标题自动追加-2、-3后缀。同时新增配置项,可选择 Slug 格式或保留旧版数字格式 - 脚注样式补全:ParsedownExtra 生成
.footnotes、.footnote-ref、.footnote-backref等元素但无样式,脚注内容显示混乱。新增完整的脚注 CSS:分割线、字号缩小、有序列表间距、上标定位、回链样式,确保在任何主题下都有良好的视觉呈现
v3.5.3 — PHP 8.2+ 兼容性修复
修复了一个属性大小写错误导致的 PHP 8.2+ 兼容性问题:
- BreaksEnabled 大小写不一致:Parser 构造函数中使用
\(this->BreaksEnabled = true`(大写 B),而父类 Parsedown 声明的属性为 `\)breaksEnabled(小写 b)。PHP 属性名大小写敏感,导致在 PHP 8.2+ 上触发Deprecated: Creation of dynamic property弃用警告,且 GFM 自动换行功能实际未生效(赋值到了错误的动态属性) - 修复方式:改用 Parsedown 提供的公共 setter 方法
$this->setBreaksEnabled(true),所有 PHP 版本均兼容
⚠️ PHP 8.2+ 注意
如果你的服务器运行 PHP 8.2 或更高版本,旧版插件会在每次解析时产生弃用警告。v3.5.3 彻底解决了此问题。同时,GFM 换行功能(文本中的单个换行符渲染为 <br>)现在能正确生效。
v3.6.0 — 代码语法高亮(Prism.js)
新增内置代码语法高亮功能,基于 Prism.js 前端渲染引擎:
- Prism.js 集成:自动为
```language围栏代码块添加语法着色,下载版已包含 200+ 编程语言支持 - 按需加载:沿用 KaTeX/Mermaid 的按需加载模式——仅当代码块存在时才加载 Prism.js CSS/JS 资源,无代码块的页面零开销
- 配置开关:插件设置新增「代码语法高亮(Prism.js)」选项,默认启用
v3.7.0 — 代码块暗色主题重构
对代码块的视觉呈现进行了全面重构,从浅色主题切换为暗色主题,并统一了所有代码块的 HTML 结构:
- 暗色主题:代码块背景从
#f6f8fa浅灰切换为#1e1e1e深色,文字颜色为#d4d4d4,顶栏为#2d2d2d,整体视觉更专业 - 统一包裹结构:所有非 Mermaid 代码块(无论有无标题)统一包裹为
<div class="code-block-wrapper">容器,内含顶栏(code-top-bar)和代码区(actual-code-content) - 复制按钮:顶栏右侧新增「语言名 | 复制」按钮,点击复制代码内容到剪贴板,显示"已复制"反馈 2 秒后恢复
- Prism.js 适配:
prism.css全面适配暗色主题——移除pre的 border/box-shadow/margin(由 wrapper 控制),背景设为 transparent,隐藏 Prism.js Toolbar 插件
⚠️ 结构变更说明
v3.7.0 之前的版本中,有标题的代码块和无标题的代码块使用不同的 HTML 结构。v3.7.0 统一为单一结构,简化了 CSS 维护和功能扩展。行号插件(line-numbers 类)也适配了新的 actual-code-content 选择器。
v3.8.0 — CDN 资源来源选择
增强了 KaTeX 和 Mermaid 的资源加载灵活性,支持在本地文件和 CDN 之间自由切换:
- 资源来源选择:插件设置新增「KaTeX 资源来源」和「Mermaid 资源来源」配置项,可选「插件本地文件」或「CDN 网址」
- CDN 基础路径:选择 CDN 模式后,可自定义 CDN 目录路径(如
https://cdn.jsdelivr.net/npm/[email protected]/dist/),插件自动拼接具体文件名 - 安全回退:CDN 基础路径为空时自动回退到本地文件,避免生成无效 URL
- 新增
getResourceUrl()方法:统一处理本地/CDN 路径逻辑,减少代码重复
💡 CDN 默认地址
插件预设了 jsDelivr CDN 的默认地址:
- KaTeX:
https://cdn.jsdelivr.net/npm/[email protected]/dist/ - Mermaid:
https://cdn.jsdelivr.net/npm/[email protected]/dist/
使用 CDN 模式可减轻服务器带宽压力,但需要外部网络请求。默认使用本地文件,升级后行为不变。
v3.8.1 — Prism .token.tag 主题样式污染修复
修复了博客主题的 .tag CSS 类污染 Prism.js 代码高亮的问题:
- 问题:博客主题为标签云定义了
.tag类样式(padding/background-color/border-radius),Prism.js 在 PHP/markup 类语言中为 HTML 标签 token 生成<span class="token tag">,CSS 选择器.tag命中了 token 元素,导致代码块内出现白色背景块 - 修复:在
prism.css中新增.token.tag覆盖规则,使用!important重置布局属性(background/border/padding/margin/box-shadow/border-radius/display/font-size/line-height),保留 Prism 主题定义的 token 颜色
功能全览
标准 Markdown 增强
完整的 GFM(GitHub Flavored Markdown)支持:
删除线
这段文字已经被删除了,但你仍然可以看到它。
GFM 表格
支持左对齐、居中、右对齐:
| 左对齐 | 居中对齐 | 右对齐 |
|---|---|---|
| 内容 A | 内容 B | 100 |
| 内容 C | 内容 D | 200 |
任务列表
- 安装 Typecho
- 启用 EnhancedMarkdown 插件
- 写一篇使用增强语法的文章
- 分享给朋友
Markdown Extra 语法
这些是标准 Markdown 不支持、但对技术写作非常有用的语法。
脚注1
这是一段包含脚注引用的文字2,脚注会自动显示在文章末尾,点击可以跳转。
定义列表
- Typecho
- 一个轻量级的博客引擎,以简洁高效著称
- Markdown
- 一种轻量级标记语言,让你用纯文本格式编写文档
- EnhancedMarkdown
- Typecho 的增强版 Markdown 解析器插件
缩写词
在技术文章中,HTML、CSS 和 API 这些缩写词很常见。鼠标悬停即可看到完整含义。
自定义扩展语法
以下是插件独创的语法扩展,标准 Markdown 不支持。
TOC 自动目录
你已经在文章开头看到了——本篇文章顶部的目录就是用 [toc] 标记自动生成的。它会自动扫描所有标题,生成带锚点链接的嵌套目录树。
容器/提示块
用 :::type 语法创建彩色提示框。下面展示所有 8 种类型:
💡 小技巧
这是一个提示信息(tip),适合用来分享技巧和最佳实践。
ℹ️ 信息
这是一个信息说明块(info),适合用来补充背景知识。
⚠️ 注意
这是一个警告信息(warning),适合用来提醒读者注意潜在问题。
🚫 危险
这是一个危险警示(danger),适合用来标记可能导致数据丢失等严重后果的操作。
📝 备注
这是一个备注块(note),适合用来记录补充说明。
✅ 成功
这是一个成功状态块(success),适合用来确认操作已正确完成。
📋 详细信息
这是一个详细信息块(details),适合用来收纳较长的补充内容,保持文章主体简洁。
💬 引用
这是一个引用块(quote),适合用来展示名人名言或重要观点。
📝 🆕 方括号语法
v3.5.0 新增支持 Docusaurus Admonition 风格的方括号语法::::note[自定义标题]。方括号内的标题优先于空格标题,向后完全兼容。你现在看到的这个提示框就是用方括号语法创建的!
上标 / 下标 / 高亮
物理学中最著名的方程:E = mc2,其中 c 代表光速。
水的化学式是 H2O,硫酸是 H2SO4。
在学习过程中,标记重点内容 是提高效率的好方法。
等等,你注意到了吗?上面这行文字中,2 被渲染成了上标,2 被渲染成了下标,标记重点内容 被高亮显示了。
图片尺寸
 → 宽 300px,高 200px
 → 宽 300px,高度自适应
 → 高度 200px,宽度自适应数学公式(KaTeX)
支持 LaTeX 语法,使用 KaTeX 前端渲染,速度远优于 MathJax。
行内公式
质能方程 \(E = mc^2\) 是物理学最著名的公式之一。勾股定理 \(a^2 + b^2 = c^2\) 是几何学的基础。欧拉公式 \(e^{i\pi} + 1 = 0\) 被誉为数学中最美的等式。
块级公式
💡 转义支持
如果你只是想写一个美元符号,比如 \$100,使用反斜杠转义即可,不会被识别为公式定界符。
Mermaid 图表
用文本描述图表,前端自动渲染。文章中的图表不再是截图,而是可维护的文本代码。
流程图
时序图
甘特图
性能优化
插件在设计上追求零代价——不用的时候不产生任何开销。
按需加载机制
不是简单地判断"功能是否开启",而是扫描页面实际内容:
- 解析 Markdown 时检测输出 HTML 中是否包含
.math-block/.math-inline/.mermaid元素 - 设置静态标志
\(hasMath` / `\)hasMermaid - CSS 注入(
<head>)和 JS 注入(</body>前)根据标志决定是否加载
✅ 性能对比
| 页面类型 | 优化前 | 优化后 |
|---|---|---|
| 纯文字文章 | ~4.5MB | 0KB |
| 含公式文章 | ~4.5MB | ~300KB |
| 含图表文章 | ~4.5MB | ~3.2MB |
字体精简
KaTeX 字体文件从 TTF + WOFF + WOFF2 三种格式精简为仅 WOFF2:
TTF 格式(~600KB)→ 已移除WOFF 格式(~500KB)→ 已移除- WOFF2 格式(300KB) → 唯一保留
浏览器会优先加载 WOFF2 格式,自动跳过不存在的格式引用,无需修改 CSS。
技术实现(开发者视角)
📝 面向开发者
以下内容面向有 Typecho 插件开发经验的读者。如果你只是想使用插件,可以跳过这部分。
Hook 注册
插件通过 4 个 Hook 点接入 Typecho:
// ① 替换文章 Markdown 解析器
\Typecho\Plugin::factory('Widget\Base\Contents')->markdown = [__CLASS__, 'parse'];
// ② 替换评论 Markdown 解析器
\Typecho\Plugin::factory('Widget\Base\Comments')->markdown = [__CLASS__, 'parse'];
// ③ 注入 CSS 到 <head>
\Typecho\Plugin::factory('Widget\Archive')->header = [__CLASS__, 'injectStyles'];
// ④ 注入 JS 到 </body> 前
\Typecho\Plugin::factory('Widget\Archive')->footer = [__CLASS__, 'injectScripts'];自定义语法扩展
基于 Parsedown 的扩展机制,注册自定义的行内元素和块级元素:
// 注册容器块语法(:::type 触发)
$this->BlockTypes[':'][] = 'Container';
// 注册上标语法(^ 触发)
$this->InlineTypes['^'] = ['Superscript'];
// 注册高亮语法(= 触发)
$this->InlineTypes['='] = ['Highlight'];
// 扩展扫描字符列表(Parsedown 只扫描此列表中的字符)
$this->inlineMarkerList .= '^=';数学公式保护机制
数学公式中的 _、*、\ 等字符会被 Parsedown 误解析。解决方案是预处理-后处理两阶段:
- 预处理:在 Parsedown 解析前,用
\x00占位符替换公式内容 - Parsedown 解析:占位符不包含特殊字符,不会被误解析
- 后处理:将占位符替换为带有 KaTeX 定界符的 HTML 标签
// 块级公式占位符 → HTML(使用 \[...\] 定界符)
\(replacement = '<div class="math-block">\[' . \)escapedFormula . '\]</div>';
// 行内公式占位符 → HTML(使用 \(...\) 定界符)
\(replacement = '<span class="math-inline">\(' . \)escapedFormula . '\)</span>';容器嵌套的脚注保护
🚫 技术陷阱
容器内容通过 $this->text() 递归解析,但 Parsedown 的 text() 方法内部会执行 DefinitionData = array(),这会清空容器外已收集的脚注定义!必须使用保存/恢复机制来防止数据丢失。
// ① 保存当前定义数据(脚注、引用、缩写)
\(savedDefinitionData = \)this->DefinitionData;
// ② 递归解析容器内容(会触发 DefinitionData 重置)
\(contentHtml = \)this->text($Block['content']);
// ③ 合并子解析产生的定义回主数据
\(this->DefinitionData = \)savedDefinitionData;安装与配置
安装步骤
- 步骤一:将
EnhancedMarkdown文件夹上传至usr/plugins/目录 - 步骤二:登录 Typecho 后台 → 插件管理 → 启用 EnhancedMarkdown
- 步骤三:在插件设置中按需开关各项功能
配置项一览
所有 15 项配置均可独立设置,语法功能默认全部启用:
| # | 功能 | 语法示例 | 默认 |
|---|---|---|---|
| 1 | TOC 目录 | [toc] |
启用 |
| 2 | 任务列表 | - [x] / - [ ] |
启用 |
| 3 | 上标 | ^text^ |
启用 |
| 4 | 下标 | ~text~ |
启用 |
| 5 | 高亮标记 | ==text== |
启用 |
| 6 | 容器/提示块 | :::type ... ::: |
启用 |
| 7 | 图片尺寸 |  |
启用 |
| 8 | 数学公式 | \(...\) / $\(...\)$ |
启用 |
| 9 | Mermaid 图表 | ```mermaid |
启用 |
| 10 | 代码语法高亮 | ```language |
启用 |
| 11 | 标题锚点 ID 格式 | Slug 格式 / 数字格式 | Slug 格式 |
| 12 | KaTeX 资源来源 | 本地 / CDN | 本地 |
| 13 | KaTeX CDN 路径 | 自定义目录 URL | jsDelivr |
| 14 | Mermaid 资源来源 | 本地 / CDN | 本地 |
| 15 | Mermaid CDN 路径 | 自定义目录 URL | jsDelivr |
文件结构
EnhancedMarkdown/
├── Plugin.php # 插件主入口(Hook 注册、配置面板、CSS/JS 注入)
├── Parser.php # 增强解析器(基于 Parsedown 扩展)
├── Parsedown.php # Parsedown 核心引擎
├── ParsedownExtra.php # Parsedown Extra 扩展
├── katex/ # KaTeX 数学公式渲染库
│ ├── katex.min.js
│ ├── katex.min.css
│ ├── auto-render.min.js
│ └── fonts/ # WOFF2 字体(仅 300KB)
├── mermaid.min.js # Mermaid 图表渲染库
├── prism/ # Prism.js 代码语法高亮库
│ ├── prism.js # 核心 + 全部语言支持
│ └── prism.css # 主题样式
└── README.md总结
💬 一句话总结
EnhancedMarkdown 的设计目标很明确:让 Typecho 的 Markdown 写作体验不输于任何现代写作平台。
通过完全替换解析引擎而非打补丁的方式,从根本上保证了语法的正确性和扩展的可靠性。回到这篇文章本身——你所看到的目录、提示框、高亮、上下标、数学公式、流程图、甘特图、脚注、任务列表、定义列表……全部来自插件的实际渲染。
如果你在 Typecho 博客中需要用到这些丰富排版能力,不妨试试这个插件。
EnhancedMarkdown-v3.5.3.zip(暂时保留)
EnhancedMarkdown-v3.8.1.zip
在php 8.4下报错Deprecated: Creation of dynamic property TypechoPlugin\EnhancedMarkdown\Parser::$BreaksEnabled is deprecated in Parser.php on line 133
这个错误是因为在 PHP 8.2+ 版本中,动态创建属性已被弃用。$BreaksEnabled 是 Parsedown 父类的一个属性,但在构造函数中直接赋值时被当作了动态属性。
v3.5.3 — PHP 8.2+ 兼容性修复解决,感谢您的回馈