改完 functions.php,保存,刷新——整站白屏。没有报错,没有提示,就一片白。
这是 WordPress 主题开发里最让人慌的时刻,因为你看不到任何线索。
原因很简单:PHP 默认在正式环境里不显示错误(display_errors 关掉了),出错时直接中断,页面就剩下已经输出的那部分——如果错误发生在输出之前,就是全白。
我在另一个站上就撞过一次。那次报错是这样的(后来打开日志才看到):
Parse error: Unmatched '}' in .../functions.php on line 96
多了一个 }。整整花了我十分钟才找到——因为白屏什么也不告诉我。
打开 wp-config.php,找到这一行:
define( 'WP_DEBUG', false );
改成:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
三个常量,各管一件事:
| 常量 | 作用 |
|---|---|
WP_DEBUG |
总开关,打开后 PHP 的 notice / warning 都会报 |
WP_DEBUG_LOG |
把错误写进 wp-content/debug.log |
WP_DEBUG_DISPLAY |
是否在页面上显示错误 |
注意我把 WP_DEBUG_DISPLAY 设成了 false。为什么?
因为如果设成 true,错误会直接印在页面上,访客也能看到——包括文件路径、数据库查询语句。那是给攻击者送情报。
正确的组合是:错误写进日志,页面上不显示。 我去看日志。
日志文件在 wp-content/debug.log。用宝塔的文件管理器打开,或者:
tail -50 wp-content/debug.log
那次的 Unmatched '}' 就是这么看到的。
顺序很重要。我现在的习惯是:
为什么?因为站点挂着的每一分钟都在损失。先止血,再治病。
所以有一条硬规矩:改任何 PHP 文件之前,先复制一份 functions.php.bak。 宝塔的文件管理器有”复制”按钮,两秒钟的事。
如果要更稳,把整个主题目录打包下载一份到本地。我这次就是这么干的——出问题时,把修好的单个文件传上去就恢复了。
不是白屏,是”能打开但不对”。比如:
这类问题通常是多余的输出造成的。
我自己遇到的那个:functions.php 末尾写了一个 ?>,后面跟了 8 个空行。
remove_action( 'wp_head', 'rest_output_link_wp_head' );
}
?>
PHP 的规则是:?> 之后的内容,原样输出。那 8 个空行就被打到了每一个响应的最前面。
对 HTML 页面:浏览器忽略空白,你看不出来(只是源码开头有几行空的)。
对 XML:致命。 因为 XML 规定 <?xml 必须是文件的第一个字节,前面多一个换行都不合法。我的站点地图就因为前面多这 8 个换行,一直解析失败。
检测方法很直接,看文件末尾:
tail -5 functions.php | cat -A
cat -A 会把行尾显示成 $,空白行一目了然。
修法有两条:
一、纯 PHP 文件不写 ?>。 这是 WordPress 官方编码规范的建议。文件整个都是 PHP,没有要输出的 HTML,就不需要”出”这个动作。
二、如果一定要保留,?> 后面不能有第二个换行。 PHP 有个专门处理:?> 后面紧跟的那一个换行会被自动吃掉。第二个开始,就照常输出了。
这类问题最容易被误判,因为我踩过。
我给站点发布文章的时候,一直收到这个错误:
not well-formed (invalid token): line 1, column 0
第一反应:内容里有非法字符,去查内容。查了半天,内容没问题。
真相是:服务器返回的响应是 gzip 压缩的,而我的客户端没解压。 拿一堆二进制去当 XML 解析,当然报”格式不对”。
这个教训很通用:看到”格式错误”,先确认”我拿到的是不是原始内容”。
排查方法:把响应的前几十个字节打印出来看。如果是 \x1f\x8b 开头,那是 gzip 魔数,说明数据是被压缩的。
同一类问题还有”内容是对的,但类型不对”。我的站点地图就遇到过:XML 内容完全合法,但响应头写的是 Content-Type: text/html,浏览器按 HTML 解析,页面一片空白。内容正确 + 类型错误 = 看起来坏掉。
上面说的都是”出错了怎么查”。但更多时候,问题是”没出错,但慢 / 但不对”。
这时候装一个插件:Query Monitor。
它在页面底部(或工具栏)加一个面板,告诉你这个页面:
add_action 挂在这个页面上了;我拿它查过一次”页面变慢”:发现同一个页面跑了 60 多条 SQL,其中一半是同一个查询重复跑。原因就是循环里调了会查库的函数。
这类问题靠”看代码”是看不出来的,必须靠工具。
注意:Query Monitor 只在登录状态下生效,访客看不到。所以可以常开着,不用管。
最后说三条我给自己定的规矩:
一、调试信息不要留在线上。
var_dump()、print_r()、error_log()——查完就删。尤其是 var_dump($post) 这种,会把整个对象的内容印在页面上,访客能看见全部字段。
二、查完把 WP_DEBUG 关掉。
开着的代价是:每个 notice 都要写日志,日志文件会越长越大;而且开着 debug 时,有些插件的严格模式会被触发,行为跟正式环境不一致。
三、一次只改一个地方。
这条最难做到,但最重要。同时改五个文件,出问题时你不知道是哪个引起的,只能一个个回退。改一个、刷一次、确认没问题、再改下一个。
一句话记住:白屏先换回备份止血,再打开 WP_DEBUG_LOG 看日志;页面”能开但不对”先查多余输出;”格式错误”先确认拿到的数据是不是原始内容。
下一篇聊一个更功利的话题:如果你的主题想提交到 WordPress 官方目录,要过哪些关。