前段时间,我一直在处理 WordPress 站点中的历史文章,包括中文摘要回填、旧代码格式迁移、SyntaxHighlighter 短代码处理,以及对应英文文章的覆盖翻译。
此前相关处理过程可以参考:
这项工作持续了相当长一段时间。历史文章中同时存在 Gutenberg、Classic Editor、Code Block Pro、SyntaxHighlighter、<pre>、<code> 等不同格式,还有不少 mixed 内容,因此很难通过一次简单的批量替换全部解决。
到现在,这一轮历史文章迁移终于正式收尾。
而且在准备发布本文之前,我也已经正式停用了 SyntaxHighlighter Evolved。
暂时只是停用,还没有立即删除插件文件。接下来准备等待大约 5 天,让此前生成的旧页面缓存自然过期,再彻底删除插件。
一、67 个固定批次、1281 篇历史文章全部处理完成
最终的 history migration 状态为:
- 固定批次:67
- 固定文章:1281
remaining=0integrity=ok- 最新未完成批次:无
- 所有批次均已完成
执行证据中保留了:
completed=1279failed=2pending=0translation_started=0
这里的 2 条 failed 属于历史执行证据,并不代表当前还有两篇文章没有处理。
最终流程状态已经全部收敛,remaining=0,而且当前不存在未完成批次。

完成历史文章迁移以后,我开始考虑另外一个已经拖了很久的问题:
SyntaxHighlighter Evolved 是否终于可以退出这个 WordPress 站点了?
二、为什么不能直接删除 SyntaxHighlighter
之前的大量历史文章已经完成代码格式迁移,但我仍然担心正文中残留 [text]、[php]、[json]、[js],以及其他 SyntaxHighlighter shortcode。
如果某篇文章原本就是依靠下面这样的短代码生成代码高亮:
[bash]
真正的代码或终端输出
[/bash]那么直接删除插件以后,这些短代码就可能重新作为普通文字出现在页面中,原来的代码块也会失去正常展示效果。
因此,在真正让 SyntaxHighlighter 退出之前,我决定在历史迁移全部完成之后,再做一次独立的:
SyntaxHighlighter retirement audit
也就是 SyntaxHighlighter 退役前审计。
这一次不再自动修改文章,只负责把所有值得人工检查的中文文章找出来。
三、不能只搜索 [text]、[php]、[json] 和 [js]
最开始我想到的,只是重新搜索几个以前比较常见的短代码。
但真正检查生产环境中 SyntaxHighlighter Evolved 3.7.2 的运行时注册情况以后,发现远比这复杂。
除了三个通用 shortcode:
sourcecodesourcecode
不同 brush 还注册了大量语言别名,例如:
bashshellphpgogolangjsjavascriptsqltextplainpythonjavahtmlxmlyaml
等等。
最终确认生产运行时实际需要考虑 65 个 shortcode。
这也意味着,如果只是手工搜索几个我印象中的字符串,很容易漏掉一些真正仍然依赖插件的历史文章。
因此这次没有简单使用几个固定关键字进行 grep,而是单独增加了一套 retirement audit scanner,根据生产插件实际注册的 shortcode 和 alias 进行扫描。
四、重新同步生产数据,而不是继续使用旧快照
由于之前的历史迁移已经持续了一段时间,期间我又人工修改过不少文章,所以这次没有继续使用历史阶段保存的旧 raw 数据。
而是重新从生产 WordPress 中读取当前最新的:
post_type=postpost_status=publish- Polylang 中文文章
英文文章没有单独扫描。
原因是如果中文文章需要修改,我会直接在 WordPress 后台修改中文,然后再使用现有翻译流程覆盖同步英文文章。
最终一共重新读取:
1438 篇中文已发布文章。
整个数据同步被分成 15 页:
- 前 14 页各 100 篇
- 最后一页 38 篇
每一页都进行了远程与本地 SHA-256、记录数、字节数、JSONL scope 和 schema 等检查。
最终:
- duplicate
post_id:无 - 分页 overlap:无
- cursor 异常:无
- 所有页面均通过完整性校验
完成这次全量扫描以后,结果反而比我预计的轻很多。
五、1438 篇文章,最终只有 14 篇需要人工检查
最终 retirement audit 的统计为:
- 中文 published posts:1438
- JSONL pages:15
- 命中文章:14
- shortcode 总命中:58
- 最早命中文章:2018-09-01 17:34:44
- 最新命中文章:2026-07-21 12:36:24
真正出现的 shortcode 只有 8 种:
| Shortcode | 命中次数 | 涉及文章 |
|---|---|---|
source | 19 | 6 |
php | 10 | 2 |
go | 8 | 2 |
sql | 8 | 1 |
text | 5 | 2 |
sourcecode | 4 | 1 |
bash | 2 | 1 |
code | 2 | 1 |

这个结果非常重要。
因为它意味着,在经历前面的大量历史迁移以后,真正还需要我人工打开确认的文章只剩:
14 篇。
此时继续开发复杂的自动迁移逻辑已经没有多少意义。
直接人工逐篇检查,反而更安全,也更加高效。
六、命中 shortcode,不代表一定要修改
这次 retirement audit 和之前自动 migration detector 最大的区别,就是:
只负责找候选,不负责判断这篇文章一定有问题。
实际检查过程中,很快就遇到了一个非常典型的例子。
某篇文章正文正在介绍短代码检测问题,其中专门写了:
[sourcecode]...[/sourcecode]这本身就是文章准备展示给读者看的文本。
![【图3:文章正文中 [sourcecode]...[/sourcecode] 本身就是需要展示的示例文本】](https://media.shuijingwanwq.com/2026/08/3-48-1024x491.png)
[sourcecode]...[/sourcecode] 本身就是需要展示的示例文本】但是在当时 SyntaxHighlighter Evolved 仍然启用的情况下,前台会把它当成真正的 shortcode 执行。
结果原本应该显示:
[sourcecode]...[/sourcecode]的地方,被 SyntaxHighlighter 渲染成了一个代码区域,只剩下中间的:
...从文章语义来看,这篇文章其实完全不应该修改。
真正应该退出的是 SyntaxHighlighter 对这段文字的解析,而不是修改文章原文。
因此,这篇文章虽然被 retirement audit 命中,但最终人工判断是:
保留原文,不修改。
现在 SyntaxHighlighter Evolved 已经停用,这种本来就是为了展示 shortcode 本身的文字,也就不会再继续被插件当成代码高亮短代码处理。
这也是为什么我从一开始就没有把“shortcode 残留必须归零”当成 SyntaxHighlighter 退役条件。
有些 shortcode 外观,本来就是文章内容的一部分。
七、另一类文章则必须真正迁移
另外一篇文章就完全不同。
后台正文中保存的是:
[bash]
真正的终端输出
[/bash]这里的 [bash]...[/bash] 并不是文章为了向读者展示 shortcode 本身,而是在真正使用 SyntaxHighlighter 完成代码高亮。
![【图4:停用 SyntaxHighlighter 前,仍然依赖 [bash]...[/bash] shortcode 展示终端输出的历史文章】](https://media.shuijingwanwq.com/2026/08/4-41-1024x491.png)
[bash]...[/bash] shortcode 展示终端输出的历史文章】此前前台之所以能正常显示代码块,正是因为 SyntaxHighlighter 负责解析这段 shortcode。
如果停用插件之前不处理,那么原来的:
[bash]
...
[/bash]就会重新作为普通文本暴露出来。
因此,这一类文章必须真正迁移。
我的处理方式是:
- 新建 Code Pro 区块;
- 只复制
[bash] 与 [/bash]中间真正的代码内容;
不再保留 SyntaxHighlighter shortcode;
删除原来的简码区块;
保存中文文章;
再通过后台覆盖同步对应的英文文章。
最终 Code Pro 中保存的是实际代码,例如:
[root@server example.com]# php example.php
PHP Fatal error: ...
Stack trace:
...而不再把
[bash] 和 [/bash]保存进去。
这样代码展示就不再依赖 SyntaxHighlighter。
八、14 篇人工检查,真正需要修改的不到 5 篇
最终,我把这 14 篇候选全部人工检查了一遍。
实际真正需要修改的文章甚至不到 5 篇。
也就是说,这次最终结果大致是:
1438 篇最新中文文章
↓
14 篇 shortcode 候选
↓
全部人工检查
↓
真正修改不到 5 篇这个结果也再次说明,自动扫描和人工判断应该承担不同的职责。
自动化非常适合解决:
“我有没有漏掉什么?”
但对于:
“这个 [text] 到底是需要迁移的历史 shortcode,还是文章本来就准备展示的文字?”
人工结合文章语义判断,反而更可靠。
最终不需要强行把所有 shortcode-looking text 清理到 0。
九、Retirement audit 独立于历史迁移流程
这一次没有继续往原来的 history migration 状态机中增加逻辑。
而是单独增加了:
bin/build-syntaxhighlighter-retirement-audit.py以及对应配置:
config/syntaxhighlighter-retirement.json这样做的原因也比较明确。
历史 migration detector 的目标是:
安全地判断一篇文章是否适合自动迁移。
因此它会主动保护或屏蔽:
- Code Block Pro
- Gutenberg code block
<pre><code>- 某些代码区域中的 shortcode-looking text
而 retirement audit 的目标完全不同。
它更关注:
只要可能值得人工看一眼,就把文章列出来。
因此即使一个 shortcode 出现在 Code Block Pro、<pre>、<code> 或其他复杂区域中,也没有必要过早自动排除。
最终由人工判断即可。
这也是这次 1438 篇全量扫描最终能够缩小到 14 篇人工候选的重要原因。
十、项目代码也一起完成最终收口
完成 1438 篇文章的 retirement audit、14 篇人工检查和必要的文章修改以后,我又把这次新增的审计工具,以及最后一批历史 migration state,一起完成了 Git 收口。
最终提交:
e2fd42f提交信息:
feat: 增加 SyntaxHighlighter 退役审计这次还运行了完整自动化测试:
Ran 503 tests
OK最终历史迁移状态:
67 fixed batches
1281 fixed posts
remaining=0
integrity=okSyntaxHighlighter retirement audit:
1438 Chinese published posts
14 candidates
58 matches最终 Git 状态:
## main...origin/main工作树干净。

至此,这个持续了很长时间的 WordPress 历史文章处理阶段,终于可以真正停下来了。
十一、为什么在发布本文之前就停用了 SyntaxHighlighter Evolved
原本我的计划是:
先完成全部人工检查和修改,然后继续保持 SyntaxHighlighter Evolved 启用大约 5 天,等待缓存自然过期,最后再卸载插件。
但在真正准备本文时,我发现还有一个很现实的问题。
本文本身就需要展示大量历史 shortcode,例如:
[sourcecode]...[/sourcecode]
[bash]...[/bash]
[text]
[php]
[code]如果 SyntaxHighlighter Evolved 仍然处于启用状态,那么这些原本只是为了向读者展示的文本,就可能再次被插件当成真正的 shortcode 解析。
前面 [sourcecode]...[/sourcecode] 的实际案例已经证明,这并不是理论上的风险。
因此,在正式发布本文之前,我已经将:
SyntaxHighlighter Evolved 停用。
这样,从现在开始新生成的 WordPress 页面不再执行 SyntaxHighlighter 注册的 shortcode。
本文中用于说明历史格式的 shortcode 示例,也可以按照文章原意正常展示,而不是再次被插件解释成代码高亮内容。
十二、为什么只是停用,而不是立即彻底删除
虽然插件已经停用,但我目前还没有立即删除 SyntaxHighlighter Evolved 的插件文件。
这里主要考虑的仍然是缓存。
今天真正修改的不到 5 篇文章,在修改以前可能已经存在旧页面缓存。
那些旧缓存是在 SyntaxHighlighter 仍然启用、文章仍然依赖旧 shortcode 的状态下生成的。
我希望给这些旧页面缓存留出一个自然退出的时间窗口。
因此现在采用的是:
人工迁移完成
↓
停用 SyntaxHighlighter Evolved
↓
不主动清缓存
↓
保留插件文件约 5 天
↓
让此前生成的旧页面缓存自然过期
↓
再彻底删除 SyntaxHighlighter Evolved这里需要特别区分“停用”和“删除”。
插件停用以后,新的 WordPress 页面已经不会再执行 SyntaxHighlighter 的 PHP 逻辑,也不会再注册相关 shortcode。
但插件文件暂时仍然保留在服务器上。
这样,即使某些此前生成的缓存页面仍然引用了 SyntaxHighlighter 的 CSS 或 JavaScript 静态资源,对应插件文件暂时仍然存在,不需要立即面对资源文件被删除的问题。
等大约 5 天以后,这轮修改以前的旧缓存基本完成自然退出,我再进行最终的插件删除。
十三、这次历史文章处理终于真正结束
从最初只是想给旧文章补充摘要,到后来逐渐发现:
- Classic Editor 历史格式
- Gutenberg
- Code Block Pro
- SyntaxHighlighter
- mixed content
- shortcode 误判
<pre>/<code>- 中文与英文覆盖翻译
- 自动校验
- execution evidence
- failed recovery
- production drift
- 人工修复
整个问题最终演变成了一套相当完整的历史内容迁移流程。
好在到现在,最终状态已经非常明确:
- 67 个固定批次全部结束;
- 1281 篇固定历史文章全部处理完成;
- 1438 篇最新中文文章重新完成 SyntaxHighlighter 全量审计;
- 只有 14 篇进入人工检查;
- 真正需要修改的不到 5 篇;
- SyntaxHighlighter Evolved 已经停用;
- retirement audit 工具已经加入仓库;
- 503 项自动化测试通过;
- Git 工作树已经完全干净。
至此,SyntaxHighlighter 已经不再参与新页面的内容生成。
接下来也不再继续折腾历史文章。
现在只剩最后一个非常简单的收尾动作:
继续保留已经停用的 SyntaxHighlighter Evolved 插件文件大约 5 天,让此前的旧页面缓存自然退出,然后彻底删除插件。
等这一步完成以后,这一段持续了很久的 WordPress 历史代码格式迁移,也就真正画上句号了。
需要长期技术维护或远程问题排查?
我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。
如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:
- ✅ PHP / Laravel / Yii2 老项目无人维护
- ✅ Go / Gin 后端接口需要排查或优化
- ✅ WordPress 网站访问慢、报错或插件冲突
- ✅ Nginx / MySQL / Redis / Linux 服务器异常
- ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
- ✅ 需要长期远程技术支持或兼职维护
更多介绍请查看:关于我 & 合作
微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

发表回复