插件冲突的排查,顺序比工具重要。同样是停插件,有人停两小时,有人十分钟就锁定了。
下面这套顺序按「先取证、再缩小、最后动线上」排,能照着做,也能直接交给同事执行。
1. 先定性:是不是插件冲突
白屏和 500 只有一部分是插件引起的。先按现象分个类,能省掉一半无效操作。
| 现象 | 先查什么 |
|---|---|
| 整站白屏 / 直接 500 | 错误日志里最后一个 PHP Fatal error 的文件路径 |
| 只有一个页面 500 | 这个页面挂的短代码、区块、模板 |
| 前台正常、后台某页 500 | 该后台页面的 hook 和它触发的 AJAX 请求 |
| 前台慢、后台正常 | 前端 enqueue 的脚本、站外请求 |
| 表单提交后 500 | admin-ajax.php 或 REST 路由的处理函数 |
| 定时任务不按时跑 | WP-Cron 是否被禁用,某个 hook 是否抛异常 |
| 某次更新后才出现 | 那次更新涉及的插件和主题,先回退再查 |
定性阶段只看两样:错误日志里的文件路径、请求的触发点。这个阶段不要改任何代码。
2. 开日志:要看的就这几份
wp-config.php 里加四行:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true ); // 默认写到 wp-content/debug.log
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
WP_DEBUG_DISPLAY 必须是 false。错误打到页面上不只是信息泄露,还会污染 AJAX 和 REST 的 JSON 响应,让问题看起来更乱。
要查的日志就这几份:
wp-content/debug.log:PHP notice / warning / fatal,插件抛的异常基本都在这里- PHP 自己的
error_log(php.ini 或 php-fpm pool 里配的那份):内存超限、执行超时、进程被杀在这 - Nginx / Apache 的 error log:502、504、upstream timeout 在这,这类通常不是插件冲突,是进程或超时
- 数据库慢查询日志:页面卡在 SQL 上的时候用
- 浏览器 Console 和 Network:哪个请求 500、哪个脚本报错
- 访问日志:定位是哪个请求触发的,尤其是只在特定 URL 上复现的问题
# 最近的致命错误
grep -n 'PHP Fatal error' wp-content/debug.log | tail -20
# 只看最后 100 行
tail -n 100 wp-content/debug.log
3. 栈里有文件路径就别二分
fatal error 的栈里通常直接写着 wp-content/plugins/xxx/...。有路径,就地锁定那个插件,跳到第 8 步验证,别浪费时间二分。
如果栈里全是 wp-includes/,说明是核心的函数被插件调用了。往上翻一两层,找到插件里的函数名,然后反查:
grep -rn 'function_name_from_stack' wp-content/plugins/ wp-content/themes/
4. 没有路径:二分停用,不要一个个停
前提:文件和数据库都已经备份。
顺序是这样的:
- 全停插件,先确认问题在插件层。 问题消失 → 继续;没消失 → 问题在主题、核心、服务器或缓存,回第 1 步重新定性。
- 一次启用一半。 复现了,问题在这一半里;没复现,在另一半里。
- 对那一半继续对半。 N 个插件最多 log2(N) 轮。
- 缩到单个插件后,再交叉主题验证一次(第 5 步),别急着下结论。
WP-CLI:
# 当前启用的插件,按目录名列出
wp plugin list --field=name --status=active
# 全停
wp plugin deactivate --all
# 启用一批
wp plugin activate plugin-a plugin-b plugin-c
批次写成文件更好管,也方便留记录:
printf '%s\n' plugin-a plugin-b plugin-c > /tmp/batch1.txt
wp plugin activate $(cat /tmp/batch1.txt)
网络激活的多站点要加 --network:
wp plugin deactivate --all --network
停用时的三个注意点:
- 先看这个插件管不管数据。 停用一般不删数据,但订单通知、支付回调、队列消费会中断。有交易在跑的站,先挑低峰期。
- 停用后清缓存再测。 对象缓存和页面缓存不清,你会看到「停用了还是坏的」或者「没启用就好了」这种假象。
- 恢复时按相反顺序逐个启用。 一次性全开回去,等于把前面的定位结果作废。
5. 交叉主题:这一步别省
插件单独启用没问题、整套启用就出问题,很可能是插件和主题共用了一段逻辑。切到核心自带的默认主题,把同一套插件再测一遍:
# 先看现在用的是哪个主题
wp theme list --status=active --field=name
# 换成站上已安装的默认主题目录名
default_theme=twentytwentyfour
wp theme activate "$default_theme"
测完记得切回去。主题目录名用 wp theme list 里看到的那个,不要凭记忆写。
6. 线上不能全停的时候
三种做法,侵入性从小到大:
a) 只对自己停用。 核心的站点健康(Site Health)里有排查模式,可以在只影响当前登录账号的情况下停掉全部插件,访客看到的还是正常站点。适合先验证「到底是不是插件问题」。
b) 用 WP-CLI 的 skip 参数单次验证。 不影响任何线上请求,只影响你这一条命令:
wp --skip-plugins=plugin-a plugin list
wp --skip-themes=theme-x option get siteurl
c) 维护模式 + 时间窗。 在站点根目录放一个 .maintenance 文件,内容一行:
<?php $upgrading = time();
访客会看到维护页。排查完立刻删掉这个文件,不要留着过夜。
不管用哪种做法,动手前先做两件事:备份文件、备份数据库;在群里或工单里写一句「现在开始停 X,预计 N 分钟」。出问题时你才知道从哪回滚。
7. 想更快定位:谁加载慢、谁抢了 handle
加载耗时。 下面这段放进 wp-content/mu-plugins/(目录不存在就新建),随便访问一次页面,看 debug.log:
<?php
// wp-content/mu-plugins/plugin-load-timing.php
add_action( 'plugin_loaded', function ( $plugin ) {
static $last = null;
$now = microtime( true );
if ( null !== $last ) {
error_log( sprintf( '[plugin-load] %s %.1f ms', $last, ( $now - $last ) * 1000 ) );
}
$last = $plugin;
}, 10 );
它记录的是「上一个插件加载完」到「这个插件加载完」的间隔,近似等于当前插件自身的加载耗时。数值受 opcache 和机器状态影响,只用来看哪个明显偏大,不要拿去当性能结论。日志里出现 [plugin-load] 行就说明生效了;没有就换个访问路径再试一次。
前端冲突。 两个插件注册同一个 script handle 时,后注册的会被忽略,表现是「某个插件的效果不生效」。打印当前页面实际 enqueue 了什么:
add_action( 'wp_print_scripts', function () {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
global $wp_scripts;
foreach ( (array) $wp_scripts->queue as $handle ) {
$src = isset( $wp_scripts->registered[ $handle ]->src ) ? $wp_scripts->registered[ $handle ]->src : '';
error_log( sprintf( '[script] %s -> %s', $handle, $src ) );
}
}, 999 );
样式同理:钩子换成 wp_print_styles,全局变量换成 $wp_styles。
8. 恢复上线:按清单走,不凭感觉
每启用一个插件,跑一遍关键路径:
- 首页和一个内页能打开
- 登录、退出正常
- 站内表单能提交,能收到通知
- 有电商的话:加购、结账、支付回调
- 搜索能用
- 后台能进,插件自己的设置页能打开
顺序上:先恢复跟钱、跟表单相关的,再恢复展示类的。每恢复一个,记一行「时间 / 插件 / 结果」。
9. 常见的误判
- 只停了插件没换主题,结论下早了
- 缓存没清,看到的不是当前状态
- 测试环境和线上的 PHP 版本、扩展不一致,本地复现不了
- 网络激活和站点激活混着看,插件列表对不上
- 插件目录名和插件 slug 不同,命令里写错,等于什么都没停
- 停用期间定时任务和队列积压,恢复后一次性跑起来把机器打满
- 排查完忘了把
WP_DEBUG关回去
10. 可以直接抄的顺序表
- 备份文件 + 数据库
- 开
WP_DEBUG_LOG,WP_DEBUG_DISPLAY设 false - 看 debug.log / PHP error log / Web 服务器 error log,找文件路径
- 有路径 → 直接定位到插件,跳到第 8 步
- 没路径 → 全停插件确认层级 → 对半启用 → 缩到单个
- 交叉默认主题再验一次
- 前端问题:打印实际 enqueue 的 handle
- 恢复:按相反顺序逐个启用,每步跑一遍关键路径
- 清理:删掉 mu-plugin 里的临时日志代码,关掉
WP_DEBUG,清缓存
我们自己也维护几个 WordPress 插件,排查时用的就是这套顺序。如果你接手的是一个陌生的老站,动手前先花五分钟跑一遍基础项自检,很多问题根本不在插件里:站点自检。