这是一篇可直接发布或再加工的排障记录。文中保留了关键命令、输出、报错和修复过程。为了便于复现,我尽量把每一步都写成可执行的操作。
背景
这次的目标很简单:把一个旧插件 WP-Markdown 安装到运行在 Docker 中的 WordPress 里,并完成启用。
插件安装包是 wp-markdown.1.6.1.zip,WordPress 容器使用的是 wordpress:6.7.2,容器里的 PHP 版本是 8.2.28。
最初的安装步骤参考的是插件官方说明:
- 上传
wp-markdown文件夹到 WordPress 的wp-content/plugins/目录。 - 在后台插件页启用插件。
- 到 Settings > Writing 里打开 Markdown 相关选项。
但实际执行后,第二步失败了:插件一启用就触发了 fatal error。
环境信息
- 主机环境:Linux
- WordPress 容器:
wordpress_ygtb-wordpress_yGTB-1 - WordPress 镜像:
wordpress:6.7.2 - PHP 版本:
8.2.28 - 插件压缩包:
/root/wp-markdown.1.6.1.zip
第一步:确认压缩包和容器状态
先确认插件压缩包确实存在,并找到正在运行的 WordPress 容器。
pwd && ls -la
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
输出中能看到 WordPress 容器:
wordpress_ygtb-wordpress_yGTB-1 wordpress:6.7.2 Up 12 days 0.0.0.0:39005->80/tcp
这一步的结论是:容器在跑,而且可以通过 39005 端口访问 WordPress。
第二步:确认插件压缩包结构
在把文件塞进容器之前,先确认压缩包顶层目录是不是 wp-markdown/。
unzip -l /root/wp-markdown.1.6.1.zip | head -n 20
输出显示压缩包的顶层目录确实是:
wp-markdown/
wp-markdown/CHANGELOG.md
wp-markdown/css/
wp-markdown/js/
wp-markdown/wp-markdown.php
这意味着可以直接把整个 wp-markdown 文件夹复制到 WordPress 的插件目录。
第三步:安装插件到 Docker 里的 WordPress
先解压,再用 docker cp 复制到容器的 wp-content/plugins/。
rm -rf /tmp/wp-markdown && unzip -q /root/wp-markdown.1.6.1.zip -d /tmp
docker cp /tmp/wp-markdown wordpress_ygtb-wordpress_yGTB-1:/var/www/html/wp-content/plugins/
复制后检查容器内目录:
docker exec wordpress_ygtb-wordpress_yGTB-1 sh -lc 'ls -la /var/www/html/wp-content/plugins/wp-markdown | head -n 20'
能看到这些文件:
wp-markdown.php
markdown-extra.php
CHANGELOG.md
readme.md
css/
js/
languages/
到这一步,插件文件已经进了容器,但还没有真正启用。
第四步:第一次启用失败,出现 fatal error
我尝试直接激活插件,但 WordPress 报了致命错误。
激活时的现象是:
无法启用插件,因为它引起了一个致命错误(fatal error)。
接下来就进入排障阶段。
第五步:先看 PHP 版本,再看错误日志
先确认容器里的 PHP 版本:
docker exec wordpress_ygtb-wordpress_yGTB-1 php -v
结果是:
PHP 8.2.28
这个信息非常关键。因为很多老插件在 PHP 8 下会因为旧语法直接挂掉。
然后我看了插件主文件和错误日志。
docker exec wordpress_ygtb-wordpress_yGTB-1 sh -lc 'php -l /var/www/html/wp-content/plugins/wp-markdown/wp-markdown.php && php -l /var/www/html/wp-content/plugins/wp-markdown/markdown-extra.php'
输出里,主入口文件没有语法问题,但 markdown-extra.php 直接报了 fatal:
Errors parsing /var/www/html/wp-content/plugins/wp-markdown/markdown-extra.php
[31-May-2026 13:27:12 UTC] PHP Fatal error: Array and string offset access syntax with curly braces is no longer supported in /var/www/html/wp-content/plugins/wp-markdown/markdown-extra.php on line 846
这就是根因。
第六步:定位根因
我用 grep 搜索了 markdown-extra.php 里所有可疑的花括号字符串下标写法。
grep -nE '\\{[0-9]+\\}' /var/www/html/wp-content/plugins/wp-markdown/markdown-extra.php
最开始扫出来的可疑位置很多,包括:
846
1142
1167
1507
1730
1995
2004
2166
2548
2866
这些位置大多是 PHP 5 / PHP 7 时代常见的老写法,比如:
$level = $matches[2]{0} == '=' ? 1 : 2;
而 PHP 8 里,这种写法已经被移除,必须改成方括号:
$level = $matches[2][0] == '=' ? 1 : 2;
第七步:修复策略
我的处理思路不是只修报错行,而是一次性把同类语法都清掉。
原因很直接:
- 这类 fatal error 往往不止一个点。
- 只修当前行,插件后面很可能在另一个页面或另一段解析逻辑里再次崩溃。
- 老插件移植到 PHP 8,最稳妥的办法是先把“语法级问题”一次性清理掉,再验证功能。
第八步:修复代码
我把容器里的插件目录拷回工作区,先在本地文件中修补,再同步回容器。
关键修改是把所有字符串下标的花括号写法改成方括号写法,例如:
$matches[2]{0} -> $matches[2][0]
$token{0} -> $token[0]
$tag{1} -> $tag[1]
$tag{strlen($tag)-2} -> $tag[strlen($tag)-2]
修复覆盖了这些位置:
- 标题解析
- 强调/加粗标记处理
- HTML tag 处理
- 代码块和内联代码解析
- 类名处理
这类改动本质上是“兼容新 PHP 版本”,没有改变插件的功能逻辑。
第九步:验证修复是否成功
先在修复后的文件上做 lint,再同步回容器做一次最终验证。
本地文件里已经不再残留这类语法:
grep -nE '\\$[A-Za-z_][A-Za-z0-9_]*\\{[^}]+\\}' /root/wp-markdown-fix/markdown-extra.php
结果为空,说明旧语法已经清理干净。
然后同步回容器,并在容器里 lint:
docker cp /root/wp-markdown-fix/. wordpress_ygtb-wordpress_yGTB-1:/var/www/html/wp-content/plugins/wp-markdown/
docker exec wordpress_ygtb-wordpress_yGTB-1 sh -lc 'php -l /var/www/html/wp-content/plugins/wp-markdown/markdown-extra.php && php -l /var/www/html/wp-content/plugins/wp-markdown/wp-markdown.php'
最终结果:
No syntax errors detected in /var/www/html/wp-content/plugins/wp-markdown/markdown-extra.php
No syntax errors detected in /var/www/html/wp-content/plugins/wp-markdown/wp-markdown.php
第十步:重新激活插件
插件语法修复完成后,再执行激活。
docker exec wordpress_ygtb-wordpress_yGTB-1 sh -lc 'php -r "require \"/var/www/html/wp-load.php\"; include_once ABSPATH . \"wp-admin/includes/plugin.php\"; include_once ABSPATH . \"wp-admin/includes/file.php\"; $result = activate_plugin(\"wp-markdown/wp-markdown.php\"); if (is_wp_error($result)) { fwrite(STDERR, $result->get_error_message() . PHP_EOL); exit(1); } echo \"activated\\n\";"'
返回结果是:
activated
这说明插件已经可以在当前 WordPress + PHP 8.2 环境下正常启用。
顺手发现的非致命警告
激活时还出现了一个警告,但它不是 fatal error,所以不会阻止插件启用:
[31-May-2026 13:34:16 UTC] PHP Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /var/www/html/wp-content/plugins/wp-markdown/markdownify/markdownify.php on line 299
这个警告说明插件内部还有更老的 PHP 代码风格,但它目前不是阻断性问题。
最终结论
WP-Markdown 本身可以安装到 Docker 里的 WordPress,但它的老版本代码不完全兼容 PHP 8.2。真正导致无法启用的原因不是 WordPress 安装过程,而是插件内部的旧语法:
Array and string offset access syntax with curly braces is no longer supported
只要把这些旧式字符串下标全部改成方括号形式,插件就能正常加载并激活。
可复现的命令清单
下面把整个过程按顺序整理成一套可复现命令:
# 1. 查看容器
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
# 2. 确认压缩包结构
unzip -l /root/wp-markdown.1.6.1.zip | head -n 20
# 3. 解压并复制到容器
rm -rf /tmp/wp-markdown && unzip -q /root/wp-markdown.1.6.1.zip -d /tmp
docker cp /tmp/wp-markdown wordpress_ygtb-wordpress_yGTB-1:/var/www/html/wp-content/plugins/
# 4. 查看 PHP 版本
docker exec wordpress_ygtb-wordpress_yGTB-1 php -v
# 5. lint 检查
docker exec wordpress_ygtb-wordpress_yGTB-1 sh -lc 'php -l /var/www/html/wp-content/plugins/wp-markdown/wp-markdown.php && php -l /var/www/html/wp-content/plugins/wp-markdown/markdown-extra.php'
# 6. 激活插件
docker exec wordpress_ygtb-wordpress_yGTB-1 sh -lc 'php -r "require \"/var/www/html/wp-load.php\"; include_once ABSPATH . \"wp-admin/includes/plugin.php\"; include_once ABSPATH . \"wp-admin/includes/file.php\"; $result = activate_plugin(\"wp-markdown/wp-markdown.php\"); if (is_wp_error($result)) { fwrite(STDERR, $result->get_error_message() . PHP_EOL); exit(1); } echo \"activated\\n\";"'
适合写在博客里的“排障方法论”
如果你想把这件事写成一篇技术博客,可以把核心思路概括为下面三句话:
- 先确认环境,而不是先改代码。PHP 版本决定了很多插件是否还活着。
- 遇到 fatal error,优先看日志和 lint,不要凭感觉猜。
- 老插件迁移到新 PHP 时,先处理语法级兼容问题,再看功能级问题。