站点升到 PHP 8.4 之后整个前台变白,或者后台弹出「此站点遇到了严重错误」,先别慌着改代码——这种故障几乎不是 WordPress 核心的问题。核心从 6.7 起就跑得动 8.4,真正炸掉的是某个几年没更新的插件或主题,撞上了 PHP 8.4 三类破坏性变更中的一条。正确顺序是:先把 PHP 版本切回去让站点活过来,再开 debug.log 精确指出是哪个文件在报 Fatal error,最后决定修还是换。
第一步:切回旧版本,先让站点能开
白屏状态下你连后台都进不去,任何「装个插件扫一下」的建议都是空话。有面板的直接进 cPanel → MultiPHP Manager(或宝塔的「网站 → PHP 版本」),把该站点切回 8.2 或 8.3,刷新前台。
只有 SSH 的话,用 WP-CLI 先确认核心版本没被误伤:
wp core version --allow-root
wp core verify-checksums --allow-root
checksums 全部通过,就说明核心文件没被改动,问题百分百在 wp-content 里。如果站点切回 8.3 后正常了,这条判断就锁死了:不是 PHP 装坏,是有代码不兼容。别跳过这一步就去逐个禁插件,白屏时你根本看不到反馈。
PHP 8.4 到底改了什么:三类破坏性变更
把这张表存下来,看 debug.log 时直接对号入座。
| 变更类型 | 日志里长什么样 | 8.4 的严重程度 |
|---|---|---|
| 隐式可空参数 | Implicitly marking parameter $x as nullable is deprecated | Deprecated(8.5 会升级为致命) |
| 动态属性赋值 | Creation of dynamic property Foo::$bar | 报错,可能中断渲染 |
| 函数被彻底移除 | Call to undefined function utf8_encode() | Fatal error,直接白屏 |
| 扩展没跟着装 | Call to undefined function imagecreate() | 缩略图生成失败、上传报错 |
被移除的函数里,utf8_encode()、utf8_decode()、create_function() 是老插件的重灾区。最后一类容易被漏掉:换 PHP 版本等于换了一整套编译产物,GD、Imagick、intl、zip 这些扩展不一定跟着开,站点看着能开但一上传图片就崩。
用 debug.log 把凶手指出来
猜没有意义,日志会直接给你文件路径和行号。编辑 wp-config.php,插在 /* That's all, stop editing! */ 上面:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
WP_DEBUG_DISPLAY 必须关掉。开着的话报错会混进 AJAX 和 REST 响应体,把区块编辑器一起搞坏,你会以为多了一个新故障。
然后把 PHP 切回 8.4,复现一次白屏,再看日志:
tail -n 100 wp-content/debug.log | grep -E "Fatal error|TypeError|undefined function"
# 只看是哪些插件目录在报,出现次数从多到少
grep -oE "wp-content/(plugins|themes)/[^/]+" wp-content/debug.log | sort | uniq -c | sort -rn
只盯 Fatal error 和 TypeError 两行。Deprecated 一屏一屏地刷是正常的,它不会导致白屏,别被吓住。
拿到目录名之后,最快的临时止血是改名让 WordPress 自动停用它:
mv wp-content/plugins/old-slider wp-content/plugins/old-slider_off
改名比在后台点「停用」可靠——后台都进不去的时候,这是唯一能用的开关。
踩坑实录
去年帮人处理过一次,日志里 Fatal 指向 wp-content/plugins/wp-smushit/core/class-modules.php,我以为是这个图片插件本体不兼容,直接换成了另一个压缩插件。结果切回 8.4 白屏照旧。回头把 debug.log 从头往下翻,才发现真正第一条报错在 12 行之前,来自主题的 inc/widgets.php:一个继承 WP_Widget 的自定义小工具在构造函数里写 $this->cache_key = ...,动态属性赋值。给类里补一行 public $cache_key;,白屏立刻消失。教训是 tail 看到的最后一条往往是连锁反应,要 grep -n "Fatal error" debug.log | head -1 找最早那条。
修代码还是换插件
先看插件最近一次更新时间。半年内有更新的,八成升级到最新版就好了,先跑 wp plugin update --all --allow-root。
超过两年没动过的,别浪费时间改它源码——下一次核心更新或插件自动更新会把你的补丁覆盖掉。这时候只有两条路:换维护中的替代品,或者这个站点先停在 8.3 上。
如果是自己写的主题或私有插件,改动量通常很小。动态属性有两种改法:
// 推荐:显式声明
class My_Widget extends WP_Widget {
public string $cache_key;
}
// 只在实在改不动的遗留代码上用
#[\AllowDynamicProperties]
class Legacy_Widget extends WP_Widget {}
还有一点值得注意:PHP 8.5 会把 8.4 里一大批 Deprecated 直接升为 Fatal error。所以现在别只满足于「白屏没了」,顺手把 grep -c "Deprecated" debug.log 的数量记下来,那是你下一次升级的账单。跳过 8.4 直接上 8.5,等着你的是翻倍的工作量。
常见问题
问:直接把 WP_DEBUG 关掉,白屏会好吗?
不会。关掉 debug 只是不再记录,Fatal error 该崩还是崩。能靠关 debug「解决」的,只有报错信息污染 REST 响应那类问题。
问:插件页面写着「未测试与你的 PHP 版本兼容」,还能用吗?
这只是作者没更新 tested-up-to 标记,不等于一定坏。判断标准看最近发布日期:一年内有版本的基本没事,长期停更的风险实打实。稳妥做法是克隆一份到测试子域名,只把那个子域名切到 8.4,跑一遍再看 debug.log。
问:升完 PHP 后缩略图不生成了,也是插件问题?
更可能是新版本 PHP 没启用 GD 或 Imagick。执行 php -m | grep -E "gd|imagick" 确认,缺了就让主机商在对应 PHP 版本里开启,而不是去翻插件代码。
如果你的 debug.log 里出现了上面没覆盖到的报错,把那一行贴到 fenij.com 的评论区,我看到会一起分析。