记录一次因为使用不成熟插件导致文章不显示的问题与解决过程
事故
我用ABStore下载了这个插件,TeoSeo。
启用之后,博客爆了。
- 启用 TeoSeo 插件后,网站前台文章正文完全不显示。
- 页面其他部分(页头、页脚、侧边栏、标题、评论等)全部正常。
- 关闭插件后问题依旧,文章正文仍然空白。
- 数据库中的文章数据完好无损,后台能正常看到所有文章。
不可能是我刚换的主题问题,而且在启用这个插件之前还好好的。那么问题很显然。
排查
我反复检查了后台设置,结果无济于事,索性将目光转移到代码上。
打开插件源码,看着那一堆AI味浓浓的注释,我就知道这事情变得搞笑起来。
原因出在这里:
public static function markdown(?string $text): ?string
{
if (!self::geoEnabled()) {
return null; // ← 致命错误
}
if (null === $text || false === strpos($text, '<details')) {
return null; // ← 致命错误
}
...
}Typecho的markdown是一个filter钩子,约定是传入原始Markdown文本,返回处理后的文本。当钩子返回null时,Typecho会把这个null当作最终结果传给后续渲染流程,文章正文就被“清空”了。而GEO开关默认是关闭的,所以只要插件启用,每一篇文章的正文都会被这个钩子清空。
一句话来说,就是只要启用插件,你的前台文章阅读就会全部爆掉。
那为什么关闭插件也无济于事呢?
持续原因:钩子被写进了数据库,禁用插件并不会清除。
观察Typecho数据库的options表,你会发现一个plugins字段,json格式的。页面请求时,Typecho读取数据库里的handles配置来决定调用哪些钩子。
此外,当你禁用插件,这些钩子并不会自己消失,仍然被注册,并且在每次渲染文章时被调用。
这就是为什么“关闭插件后还是没用”。
除此之外还有小问题:钩子被重复注册了两遍!
查看数据库里的plugins配置,可以看到TeoSeo的每一个钩子都出现了两份(以我的为参照):
"Widget_Abstract_Contents:markdown":{
"0":["TeoSeo_Plugin","markdown"],
"0.001":["TeoSeo_Plugin","markdown"]
}原因是插件在activate()里调用了 persistHooks(),而persistHooks()的逻辑是“读库 → 合并 → 写回”,但没有先去重。多次激活/自动更新后,同一钩子被反复追加,导致重复注册。
重复注册本身不致命,但会放大问题:只要有一份钩子存在并返回null,文章就没了。
解决方法
手动清理数据库中的残留钩子(我推荐)
编辑表把有关TeoSeo的一切都删了就可以。
修改插件代码,根治问题(如果你坚持要用这个插件)
修改Plugin.php,修复markdown()返回值:不处理时返回$text,绝不返回null。这样。
php
public static function markdown(?string $text): ?string
{
if (!self::geoEnabled()) {
return $text;
}
if (null === $text || false === strpos($text, '<details')) {
return $text;
}
...
}修复persistHooks()去重:写回数据库前先移除旧的TeoSeo钩子,再写入新的,避免重复注册。
完善deactivate():主动从options.plugins中清除TeoSeo的所有钩子,而不是只依赖Typecho自动处理。
顺从插件(GEO优化开关打开)
不过这个好像会因为某些主题不支持而根本无法打开。
结论
请各位大佬用AI写代码后自己好好把所有功能都测试一遍再发布正式版,又不费什么时间。