这个场景我遇到过不止一次:改完 functions.php,刷新页面,还是老样子。再刷,还是老样子。开始怀疑自己是不是改错了文件、是不是没保存、是不是改的那个是备份。
最后发现是缓存。改的代码是对的,只是没被执行。
这件事的要害不是”记得清缓存”,而是要理解:缓存把”每次请求都跑一遍 PHP”变成了”直接吐一份 HTML”。 你的模板代码压根没运行。
先分清层次,不然永远在瞎清。
| 层 | 存在哪 | 管什么 | 怎么清 |
|---|---|---|---|
| 浏览器缓存 | 访客的电脑/手机 | CSS、JS、图片 | 访客自己 Ctrl+F5 |
| 页面缓存 | 服务器磁盘 | 整页 HTML | 插件里点”清空所有缓存” |
| 对象缓存 | 内存(Redis/Memcached) | 数据库查询结果 | 重启服务或清 key |
我改完代码看不到效果,99% 是页面缓存。因为我改的是 PHP,而页面缓存里存的是一份已经渲染好的 HTML——它不会因为你改了 PHP 就自动失效。
这里有个概念必须先建立:
页面缓存生效时,你的
header.php、single.php、functions.php一行都不会执行。
不是”执行了但没效果”,是根本不执行。服务器直接找到那份 HTML 文件,发出去,完事。
所以,凡是”每次请求都该不一样”的逻辑,放在模板里就是错的。举几个例子:
is_user_logged_in() 判断显示”你好,某某”——缓存后,未登录的访客会看到别人的名字;这些不是”缓存插件的 bug”,是主题的写法跟缓存机制冲突了。
WordPress 有个标准常量,缓存插件都认:
define( 'DONOTCACHEPAGE', true );
在需要动态输出的页面里定义它,页面缓存插件就会跳过这一页。
典型用法是挂在 template_redirect 上(这时已经知道是哪个页面了,但还没开始输出):
add_action( 'template_redirect', function () {
if ( is_user_logged_in() ) {
define( 'DONOTCACHEPAGE', true );
}
} );
这句话的意思是:登录用户看到的页面,永远不缓存。 访客看到的照常缓存,两边都合理。
另一条路是把动态部分挪走:页面主体照常缓存,那几块”会变”的内容用 AJAX 单独请求。这是大型站点的标准做法,但复杂度高一个量级,小站不值得。
这个案例值得单独讲,因为它暴露了”缓存插件不认识非 HTML 内容”这个问题。
WordPress 自带一个站点地图 /wp-sitemap.xml。它由 PHP 动态生成,正常情况下响应头是:
Content-Type: application/xml
但我这边实测是:
Content-Type: text/html
结果就是:浏览器打开那个地址,看到的是一片空白。因为浏览器拿到”XML 内容 + HTML 身份”,按 HTML 去解析,把 <?xml 当成看不懂的注释直接跳过,后面整段全忽略。
我一开始以为是文件坏了,反复清缓存、反复刷,没用。后来加了个随机参数绕开缓存,立刻正常:
https://www.caogenbj.com/wp-sitemap.xml?abc=123
这一个测试就把问题定性了:不是内容错,是缓存层把响应头写死了。
为什么?因为页面缓存插件的设计目标是”缓存 HTML 页面”。它抓到一份响应,按 HTML 存下来,再吐出去的时候也按 HTML 标注。它不管你这个 URL 原本是什么类型。
解法有两个:
一、让插件别碰这个地址。在缓存插件的”永不缓存以下页面”里填:
wp-sitemap
二、在主题里定义常量。如果你能改到主题,更彻底:
if ( isset( $_SERVER['REQUEST_URI'] )
&& strpos( $_SERVER['REQUEST_URI'], 'wp-sitemap' ) !== false ) {
define( 'DONOTCACHEPAGE', true );
}
这段要放在 functions.php 最顶部,不要包进 add_action 里——因为缓存插件判断”要不要缓存”的时间点很早,你得赶在它前面。
对象缓存缓存的是”数据库查询结果”。比如 get_option() 查一次,结果存内存,下次直接从内存拿。
对主题作者来说,能用上的场景不多。但有一个原则要遵守:
别在模板里写”每次都重新查库”的代码。
比如我在卷一讲过的:为了在一个页面上取两次同样的数据,用两次 WP_Query。第二次完全可以复用第一次的结果。对象缓存能救一部分,但它不是免费的。
第一种情况:改的是 PHP。清页面缓存就行,插件后台那个”清空所有缓存”的大按钮。
第二种情况:改的是 CSS/JS。清完页面缓存还不够,因为访客浏览器里那份旧的还在。这时候要在文件地址后面带版本号,WordPress 的 wp_enqueue_style 第四个参数就是干这个的:
wp_enqueue_style( 'my-style', get_stylesheet_uri(), array(), '1.0.3' );
改一次样式,把 1.0.3 改成 1.0.4,浏览器就会当成新文件重新下载。这比让访客按 Ctrl+F5 靠谱得多,因为他不会按。
第三种情况:改完还是不对。加个随机参数试试(?nc=123)。能正常就说明是缓存,不能正常才是代码问题。
这个”加参数”的动作,是我排查缓存问题的第一招,几乎每次都灵。
一句话记住:页面缓存生效时,你的 PHP 一行都不跑。所以”每次都该变”的东西不能写在模板里;改完看不到效果,先加参数验证是不是缓存。
下一篇聊多语言——不是为了翻译,是为了把散落各处的文字收拢到一处。