没有不值得去解决的问题,也没有不值得去学习的技术!

W3 Total Cache 明明设置了 4 天缓存,为什么每天都会失效?一次 Polylang 与 Yoast SEO 联合排查记录

W3TC 缓存为什么每天失效?

作者:

WordPress 性能优化手记

如 如图1 所示,站点健康直接提示这是一个可能对性能或安全性产生重大影响的问题,需要优先解决。

(1) 从站点健康警告到全绿通关

PHP Fatal error: Uncaught RedisException: OOM command not allowed when used memory > 'maxmemory'. in /data/wwwroot/.../wp-content/plugins/w3-total-cache/Cache_Redis.php:150

(2) 解决 WordPress + Polylang 批量处理标签时遇到的 Redis OOM 错误

采用 ondemand 模式,适合 1 核小内存机器,空闲时释放进程。最终配置如下:如图4

(3) 一次WordPress站点504错误的排查与优化实录

优化前最终基准数据:历史累计504错误129条(6月3日峰值126条,为爬虫批量爬标签导致)。

(4) 从单日126次504超时到彻底稳定:WordPress 1核2G服务器极限优化全记录(附全部实操命令)

WebPageTest 核心指标

(5) WordPress性能基准测试与CDN选型实录:从国内拨测到海外WebPageTest,1核2G服务器如何面向全球

页面底部提示“此响应不是合法的 JSON 响应”。

(6) WordPress 标签保存失败?Nginx 限流规则惹的祸 —— 一次完整的 429 问题排查与解决

表示页面仍然是动态生成,没有缓存命中。

(7) WordPress + Nginx + W3 Total Cache 缓存未生效排查全过程(OneinStack 实战)

图7:带 Query String 后,W3TC 显示 Requested URI contains query

(8) WordPress CPU 再次满载:动态参数如何穿透 CDN 与 W3TC 页面缓存

图1:阿里云 ECS 在 14:33~14:42 期间 CPU 使用率持续接近 100%,而内存使用率整体较为稳定

(9) WordPress 服务器 CPU 再次满载:从 Nginx 499、PHP-FPM、Redis 到 W3TC 冷缓存的完整排查

图4:W3TC 最终使用 300 秒 × 7 页,并切换到中英文联合 Sitemap

(10) 从 CPU 告警到双域名预缓存:W3 Total Cache、EdgeOne 与 Cloudflare 96 小时缓存优化实战

WordPress 所有归档模板中使用 Language Visibility 和 WPCode Shortcode 添加中英文 Adsterra 广告

(11) WordPress 三域名架构再次踩坑:Adsterra 归档广告不生效,最终定位到 W3TC Object Cache

WordPress 多语言多域名缓存排查:修复 Polylang + W3 Total Cache 跨 Host 缓存失效问题

(12) WordPress 多语言多域名缓存排查:修复 Polylang + W3 Total Cache 跨 Host 缓存失效问题

WordPress 多域名环境下中文文章详情页未显示 Polylang 语言切换器

(13) WordPress 多域名下 Polylang 语言切换器延迟:W3TC Redis 跨 Host 缓存排查记录

图8:选择 2 核 4 GiB 后显示的实际补差价、2 Mbps 带宽和重启选项

(14) 从 CPU 再次告警到 ECS 升配:WordPress 服务器从 1 核 2G 升级到 2 核 4G 实录

**Alt:** WordPress 生产环境完成 PHP 8.5.9 升级,终端显示 OPcache、Imagick、Redis、Nginx、WordPress 版本及中英文站和后台域名均正常返回 HTTP 200

(15) OneinStack 生产环境将 PHP 8.1.19 升级到 PHP 8.5.9:Imagick 编译失败与 WordPress 多域名缓存验收

阿里云 OneinStack 服务器升级完成,终端显示 Nginx 1.30.4、OpenSSL 3.5.7、PCRE 8.45 和 PHP 8.5.9,Nginx 配置检查成功

(16) 阿里云 OneinStack 实战:将 Nginx 1.24.0 升级到 1.30.4,并同步升级 OpenSSL 3.5.7

阿里云 OneinStack 服务器 Redis 从 7.0.11 升级到 8.10.0 后的版本与运行状态对比截图

(17) 阿里云 OneinStack 实战:将 Redis 7.0.11 升级到 8.10.0,并完成内核优化与回滚保护

GitHub 上为 PublishPress Series 提交 PHP 8.5 SplObjectStorage 弃用警告 Issue 的页面

(18) WordPress 升级 PHP 8.5 后的插件兼容性排查:该修的修,该停的停,该等上游的等

WordPress Post Views Counter 热门文章排行榜区块及浏览量设置界面,用于排查首页查询性能问题

(19) WordPress 动态首页从 19 秒降到 1 秒以内:Post Views Counter 热门文章查询性能问题排查与 MU Plugin 优化实战

WordPress 撰写设置中已开启可能影响网站性能的 Gutenberg 实时协作功能

(20) WordPress 7.0 + PHP 8.5 服务器配置全面审计:PHP-FPM、OPcache、Redis、RDS 与 WordPress 调优实战

【图 1:8 月 6 日提交的 PublishPress Series PHP 8.5 兼容性 Issue #1163 已由上游关闭】

(21) PublishPress Series 3.1.3 升级实录:PHP 8.5 Issue 已修复,却又遇到 Gutenberg 系列编号回归

图 6:为 www 域名单独启用适中的自适应频控和流量防盗刷,处置方式均采用 JavaScript 挑战

(22) WordPress 再次出现 CPU 告警:从 EdgeOne 异常流量到自适应频控与 JavaScript 挑战

图 3:PHP-FPM 日志出现 Allowed memory size of 268435456 bytes exhausted

(23) WordPress CPU 告警继续排查:Yoast Sitemap 500、PHP 256M OOM 与 W3TC 预热失效

图 2:新的 PHP 进程通过 get_option("cron") 读取不到 Probe,但数据库中明确存在

(24) W3TC 定时任务为何创建后又消失?排查 WP-Cron 与 Redis alloptions 陈旧缓存

W3TC 缓存为什么每天失效?

(25) W3 Total Cache 明明设置了 4 天缓存,为什么每天都会失效?一次 Polylang 与 Yoast SEO 联合排查记录

最近一段时间,我一直在排查 WordPress 多语言网站中的缓存问题。

网站目前采用的是:

  • WordPress
  • Polylang
  • W3 Total Cache
  • W3TC Page Cache:Disk Enhanced
  • W3TC Object Cache:Redis
  • 中文站:www.shuijingwanwq.com
  • 英文站:en.shuijingwanwq.com
  • 后台域名:admin.shuijingwanwq.com
  • 中文站 CDN:EdgeOne
  • 英文站 CDN:Cloudflare

W3 Total Cache 的 Page Cache 生命周期设置为:

Plaintext
345600 秒

也就是:

Plaintext
4 天

理论上,只要页面没有被主动清理,一个已经生成的 Page Cache 文件应该可以继续存在几天。

但实际观察到的情况却完全不是这样。

我多次检查后发现,缓存文件基本活不过一天。即使没有执行 W3TC 后台的 Purge All Caches,大量 Page Cache 仍然会突然统一失效。

这篇文章记录的,就是这次从现象、文件系统证据、WordPress Hook,到最后定位出 Polylang 标签同步Yoast SEO Cron 两条全量 Page Cache flush 路径的完整过程。


一、最开始的问题:4 天 TTL 实际上没有意义

W3TC 当前配置中:

Plaintext
pgcache.lifetime = 345600

也就是 4 天。

但在检查 Page Cache 文件时,我发现最老的缓存通常都不到一天。

真正应该关注的,其实不是“W3TC 配置里写了几天”,而是:

Plaintext
实际缓存寿命
=
min(
    配置 TTL,
    下一次提前发生的全量 purge 时间
)

如果每天都有某个 WordPress Hook 调用了全量 Page Cache flush,那么即使 TTL 设置成 4 天、7 天甚至更长,也没有实际意义。

所以后续排查的重点变成了:

到底是谁在提前清理 Page Cache?


二、先确认 W3TC 的“全量清理”到底长什么样

W3TC 当前使用的是 Disk Enhanced Page Cache。

缓存目录位于:

Plaintext
/data/wwwroot/www.shuijingwanwq.com/wp-content/cache/page_enhanced/

开始排查时,我发现一个非常重要的细节:

W3TC 执行全量 Page Cache flush 时,并不是立即把缓存文件全部 rm 掉,而是先把文件改名成:

Plaintext
*_old

例如:

Plaintext
_index_slash_ssl.html

会变成:

Plaintext
_index_slash_ssl.html_old

gzip 文件也是如此。

这意味着:

_old 文件的 ctime,可以作为“什么时候发生了 Page Cache 失效”的重要证据。

这个细节后来非常关键。


三、第一次抓到全量 Page Cache 失效

一次现场检查中,我发现大量缓存文件在极短时间内统一变成了 _old

当时的规模大约是:

Plaintext
www:906
en:742

总计:

Plaintext
1648

而且这些文件在不到 0.1 秒的时间窗口内被连续处理。

这已经基本可以排除:

  • 正常用户访问;
  • Prime;
  • 单个文章更新;
  • 普通 TTL 过期;
  • CDN;
  • 浏览器缓存。

这种特征更符合 W3TC 自己的:

Plaintext
Cache_File_Generic::flush()

也就是整棵 Page Cache 目录的全量处理。


四、第一条根因:Polylang 标签同步触发 edited_term

当时我刚运行过一个自己长期使用的标签同步脚本:

Bash
php polylang-batch-zh-to-en-tags.php

这个脚本的用途是:

  1. 扫描中文标签;
  2. 查找是否已经存在对应英文标签;
  3. 如果不存在,则创建英文语言标签;
  4. 建立 Polylang 的中英文标签翻译关系;
  5. 后续再到后台把新生成的英文标签名称改成真正的英文。

某次实际运行结果是:

Plaintext
源语言标签总数: 9451
已处理新标签: 2
已跳过已有翻译: 9449

看起来只新增了两个标签。

但这两个标签却触发了整个 Page Cache 的失效。

继续追踪后,调用链逐渐清晰。


五、问题并不只是 wp_insert_term()

最开始容易怀疑的是“新建标签”本身。

但 W3 Total Cache 2.10.6 在当前环境下,对 taxonomy 的相关 Hook 主要是:

Plaintext
edited_term
delete_term

它们都直接绑定:

Plaintext
w3tc_flush_posts()

w3tc_flush_posts() 在当前 Disk Enhanced Page Cache 配置下,并不是“清理相关文章”,而是最终进入:

Plaintext
PgCache_Flush::flush()

然后执行整个 Page Cache 的全量 flush。

问题在于:

W3TC 并没有判断当前修改的 taxonomy 到底是什么。

也就是说:

Plaintext
修改文章标签
修改分类
修改 Polylang 内部 term translation taxonomy

对 W3TC 来说,都可能被当成:

Plaintext
全部文章缓存都应该失效

这对我的网站并不合理。


六、Polylang 翻译关系让问题变得更隐蔽

这次并不是简单的:

Plaintext
创建一个 post_tag
→ 全量 flush

真正的流程还包含 Polylang 自己维护的 taxonomy 翻译关系。

生产运行时确认,Polylang 当前用于 term 翻译关系的 taxonomy 是:

Plaintext
term_translations

标签同步脚本创建英文标签后,会继续更新 Polylang 翻译组。

其中包括:

Plaintext
save_translations()

后续会进入:

Plaintext
wp_update_term()

从而触发:

Plaintext
edited_term

而 W3TC 在 edited_term 上直接执行:

Plaintext
w3tc_flush_posts()

另外,清理某些临时翻译关系时还可能进入:

Plaintext
delete_term

同样会再次执行:

Plaintext
w3tc_flush_posts()

因此,表面上只是:

Plaintext
新增两个英文标签

背后实际上可能已经发起了多次全量 Page Cache flush 请求。


七、为什么这类标签修改不值得清空全站缓存

这里需要先明确业务需求。

我的网站标签数量很多,标签和分类的修改对前台实时一致性的要求并不高。

即使某个标签名称修改以后,极少数已经缓存的页面继续显示几小时甚至几天旧内容,我也可以接受。

相比之下,更重要的是:

不要因为一次很小的 taxonomy 操作,把几千个已经生成好的 Page Cache 全部清掉。

因为当前源站并不是高配服务器。

正常情况下访问链路最好是:

Plaintext
CDN HIT

如果 CDN MISS,则:

Plaintext
CDN MISS
→ W3TC Page Cache HIT
→ 不进入 PHP

而如果 W3TC Page Cache 被整体清空,则会变成:

Plaintext
CDN MISS
→ W3TC MISS
→ PHP
→ WordPress
→ Redis
→ 数据库

在较大访问量下,这种缓存冷启动明显更容易造成 CPU 波动。

因此,我最终决定:

category、post_tag 和 Polylang term translation taxonomy 的修改,不再触发 W3TC 全量 Page Cache flush。


八、第一项修复:taxonomy-aware W3TC flush

没有修改 W3 Total Cache 源码,也没有修改 Polylang 源码。

而是继续使用 MU Plugin。

核心思路是:

先移除 W3TC 原来的:

PHP
remove_action( 'edited_term', 'w3tc_flush_posts', 0 );
remove_action( 'delete_term', 'w3tc_flush_posts', 0 );

再注册自己的 wrapper。

wrapper 根据 taxonomy 判断:

Plaintext
category
post_tag
term_translations

对于这些 taxonomy:

Plaintext
不执行全量 w3tc_flush_posts()

对于其他 taxonomy,则继续调用 W3TC 原始行为。

这样做的目的不是“禁止所有 term 缓存刷新”,而是:

只缩小已经确认不需要全站 purge 的 taxonomy 范围。


九、没有直接宣布修复成功,而是做真实生产流程验证

代码部署以后,我没有马上为了测试而批量创建数据,而是直接用日常博客发布流程验证。

为了能够客观观察缓存,我另外增加了一个只读工具:

Plaintext
page-cache-snapshot

它会统计每个 Host 的:

  • Active HTML 数量;
  • <1 天
  • 1~2 天
  • 2~3 天
  • 3~4 天
  • >=4 天
  • 最老活跃缓存时间;
  • _old 文件数量;
  • 最近 5 / 15 / 60 分钟新出现的 _old

另外还部署了一个临时 tracer:

Plaintext
w3tc-full-flush-tracer.php

只要发生:

Plaintext
w3tc_flush_posts

或者:

Plaintext
w3tc_flush_all

就记录调用栈。


十、完整跑了一次真实双语博客发布流程

随后我完整发布了一篇中英文博客。

验证过程包括:

1. 新建中文文章

操作包括:

  • 新建文章;
  • 编辑正文;
  • 设置分类;
  • 设置标签;
  • 保存草稿。

结果:

Plaintext
没有发生全量 Page Cache flush

2. 发布中文文章

发布以后,出现了少量 _old

主要是:

Plaintext
首页
Feed
部分分页

但最老的历史缓存仍然存在。

Tracer:

Plaintext
0

说明这是正常的 URL 级精确失效,而不是全量 purge。


3. 再次运行标签同步脚本

这一次脚本仍然新增了两个标签:

Plaintext
Crawler Hints
网站收录

统计:

Plaintext
源语言标签总数: 9453
已处理新标签: 2
已跳过已有翻译: 9451

但 Page Cache 前后:

Plaintext
www OLD_COUNT:710 → 710
en  OLD_COUNT:618 → 618

最老缓存时间完全没变。

Tracer:

Plaintext
0

这说明第一次 taxonomy 修复已经在真实生产流程中生效。


十一、后台修改英文标签也没有再清空 Page Cache

随后我把:

Plaintext
网站收录

修改成:

Plaintext
Website Indexing

这个动作会触发:

Plaintext
wp_update_term()
→ edited_term

也正是之前 W3TC 会执行全量 purge 的路径。

修改以后:

Plaintext
www OLD_CTIME_5M = 0
en  OLD_CTIME_5M = 0

Tracer:

Plaintext
0

最老缓存仍然保留。

至此,可以确认:

post_tag 后台修改同样不会再把整个 Page Cache 清空。


十二、继续验证英文文章生成和发布

后续又继续走完整的英文翻译流程。

SlyTranslate 创建英文草稿

英文文章 ID:

Plaintext
27481

创建英文草稿以后:

Plaintext
www 最老缓存不变
en 最老缓存不变
Tracer = 0

没有全量 purge。


正式发布英文文章

发布英文文章后,只出现了极少量 _old

Plaintext
www:
feed

en:
首页

对应普通文件和 gzip 文件,总共只有 4 个。

Tracer 仍然:

Plaintext
0

这说明英文文章正式发布也仍然走的是小范围 URL purge。


十三、本以为问题解决了,第二天缓存还是没活过 24 小时

到这里,我一度以为问题已经解决。

但我没有立刻下结论,而是继续保留 tracer。

第二天再次检查时发现:

Plaintext
AGE_1_TO_2D = 0

最老缓存又变成了前一天 17:30 左右。

更夸张的是:

Plaintext
www OLD_COUNT = 11466
en  OLD_COUNT = 7620

显然,又发生了一次全量 flush。

但是这次终于有 tracer 了。


十四、第二个根因:Yoast SEO 的每日 Cron

Tracer 记录到了两次:

Plaintext
w3tc_flush_posts

时间分别是:

Plaintext
17:30:05.175
17:30:05.189

两个调用栈完全指向同一条路径:

Plaintext
wpseo_detect_default_seo_data

Default_SEO_Data_Cron_Callback_Integration

Options_Helper->set()

WPSEO_Options::save_option()

update_option_wpseo

WPSEO_Utils::clear_cache()

w3tc_flush_posts()

W3TC 全量 Page Cache flush

至此,第二条根因已经非常明确。


十五、Yoast 到底更新了什么?

生产环境当前 Yoast SEO 版本是:

Plaintext
28.4

进一步检查源码后发现,这个 Cron 只更新两个字段:

Plaintext
default_seo_title
default_seo_meta_desc

当时数据库中的值是:

Plaintext
default_seo_title=[27481,27474,27472,27465,27463]

default_seo_meta_desc=[27481,27474,27472,27465,27463]

这些数据保存的是:

最近几篇文章中,哪些文章仍然使用默认 SEO title 或 meta description。

它们主要用于 Yoast 后台编辑器里的提醒。

并不会直接改变:

  • 前台 SEO title;
  • meta description;
  • canonical;
  • schema;
  • sitemap;
  • post 内容;
  • post meta;
  • indexable。

所以为了这两个后台提醒字段:

Plaintext
清空 www + en + admin 的整个 Page Cache

明显没有必要。


十六、为什么 Yoast 会触发 W3TC 全量 flush?

Yoast SEO 28.4 中:

PHP
WPSEO_Utils::clear_cache()

的相关逻辑非常简单:

PHP
if ( function_exists( 'w3tc_flush_posts' ) ) {
    w3tc_flush_posts();
}
elseif ( function_exists( 'wp_cache_clear_cache' ) ) {
    wp_cache_clear_cache();
}

也就是说,只要检测到 W3TC:

Plaintext
Yoast option 更新
→ WPSEO_Utils::clear_cache()
→ w3tc_flush_posts()

它没有进一步判断:

  • 到底改的是哪个 wpseo 字段;
  • 是否发生在 Cron;
  • 字段是否影响前端;
  • 是否真的需要清空所有页面。

十七、Yoast 自己其实也会主动绕过这次 cache flush

这里还发现了一个很有意思的细节。

Yoast 28.4 自己在另一处内部流程中,也使用了类似逻辑:

PHP
remove_action(
    'update_option_wpseo',
    [ 'WPSEO_Utils', 'clear_cache' ]
);

$this->options_helper->set( ... );

add_action(
    'update_option_wpseo',
    [ 'WPSEO_Utils', 'clear_cache' ]
);

也就是说:

Yoast 自己也知道,并不是每一次内部 wpseo option 更新,都值得触发 W3TC 全量 cache flush。

这给后续兼容方案提供了很好的实现依据。


十八、第二项修复:只在这个 Yoast Cron 中暂时移除 callback

最终我没有去修改:

Plaintext
WPSEO_Utils::clear_cache()

也没有去动 W3TC 内部 Page Cache callback。

而是新增了一个独立 MU Plugin:

Plaintext
yoast-w3tc-cache-compat.php

只处理:

Plaintext
wpseo_detect_default_seo_data

这个 Cron。

设计是:

Plaintext
priority 1
→ 临时移除 WPSEO_Utils::clear_cache

priority 10
→ Yoast 正常执行 default SEO data Cron

priority 999
→ 恢复 WPSEO_Utils::clear_cache

因此 suppression 只存在于:

Plaintext
wpseo_detect_default_seo_data

这一轮 action 内。

不会一直持续到整个:

Plaintext
wp-cron.php

请求结束。

这样即使同一个 PHP Cron 请求后面还有其他事件,也不会受影响。


十九、还专门处理了 W3TC 不存在的情况

Yoast 的 clear_cache() 还有 fallback:

PHP
wp_cache_clear_cache()

因此 MU Plugin 不能在 W3TC 没有加载时仍然把整个 Yoast callback 移除。

最终增加了条件:

PHP
function_exists( 'w3tc_flush_posts' )

只有确认 W3TC 当前实际存在时才进行 suppression。

这样:

Plaintext
Yoast Cron + W3TC 存在
→ 临时抑制 WPSEO_Utils::clear_cache

而:

Plaintext
Yoast Cron + W3TC 不存在
→ 完全不干预 Yoast

这样不会意外破坏 Yoast 对其他缓存插件的 fallback。


二十、部署后的 Hook 状态

部署后实际运行时检查:

Plaintext
wpseo_detect_default_seo_data

1
yoast_w3tc_cache_compat_begin_default_seo_data_cron

10
Default_SEO_Data_Cron_Callback_Integration
->detect_default_seo_data_in_recent

999
yoast_w3tc_cache_compat_end_default_seo_data_cron

正常请求下:

Plaintext
update_option_wpseo

10 | WPSEO_Options::clear_cache
10 | WPSEO_Utils::clear_cache
10 | 其他 Yoast watchers

这说明:

MU Plugin 并没有在 WordPress 加载阶段就删除 Yoast 原有 callback。

只有真正进入目标 Cron 时才会临时处理。


二十一、终于第一次看到 Page Cache 活过 24 小时

2026 年 9 月 8 日晚上再次检查。

这次出现了一个之前一直没有出现过的结果。

中文站:

Plaintext
AGE_LT_1D=6989
AGE_1_TO_2D=181

英文站:

Plaintext
AGE_LT_1D=4785
AGE_1_TO_2D=147

最老缓存分别仍然是:

Plaintext
www:
2026-09-07 17:30:23

en:
2026-09-07 17:30:35

Tracer 仍然只有前一天修复前留下的:

Plaintext
2

没有任何新记录。

这也是这次排查以来第一次真正看到:

Plaintext
AGE_1_TO_2D > 0

换句话说:

Page Cache 终于第一次真实跨过了 24 小时生命周期。

这说明至少之前每天提前清理 Page Cache 的两条主要路径,已经不再继续把缓存每天重置。


二十二、这里仍然保留一个未完全闭环的验证点

虽然这次 Yoast Cron 的 next run 已经从:

Plaintext
2026-09-08

推进到了:

Plaintext
2026-09-09

说明当天 Cron 已经正常执行。

Tracer 也没有新增记录。

但这次:

Plaintext
default_seo_title
default_seo_meta_desc

两个数组刚好没有变化。

仍然是:

Plaintext
[27481,27474,27472,27465,27463]

WordPress 的:

PHP
update_option()

如果新旧值完全一样,就不会真正执行数据库更新,也不会触发:

Plaintext
update_option_wpseo

所以目前最严谨的结论是:

Yoast Cron 兼容 MU Plugin 已通过部署稳定性和自然 Cron 回归测试,Page Cache 也首次存活超过 24 小时。

但还缺最后一块最强证据:

Plaintext
default_seo_* 值发生变化

update_option_wpseo 真正执行

WPSEO_Utils::clear_cache 被临时抑制

Tracer 仍然不增加

Page Cache 继续存活

这一步我没有通过手工修改数据库去制造测试条件。

我更倾向于继续等待真实内容更新自然触发。


二十三、这次排查最大的收获:不要只盯着 TTL

这次最值得记住的,其实不是某一段 MU Plugin 代码。

而是:

配置的缓存生命周期,并不等于真实缓存生命周期。

例如:

Plaintext
W3TC Page Cache TTL = 4 天

只说明:

Plaintext
缓存最长允许活 4 天

并不意味着它真的能够活 4 天。

如果:

Plaintext
第 1 天 Polylang edited_term
→ 全量 flush

第 2 天 Yoast Cron
→ 全量 flush

那么实际缓存寿命可能只有:

Plaintext
不到 24 小时

这时候继续调大 TTL 是没有意义的。

真正应该查的是:

Plaintext
谁在提前清缓存?

二十四、Page Cache、Object Cache 和 CDN 必须分层判断

这次排查也再次说明,缓存问题不能简单归因于“Redis”或者“W3TC”。

至少要区分:

Plaintext
浏览器缓存
CDN
W3TC Page Cache
W3TC Object Cache / Redis
WordPress PHP Runtime
Polylang
Nginx

这次两个问题都属于:

Plaintext
W3TC Page Cache 主动失效

而不是:

Plaintext
Redis Object Cache 数据污染

也不是:

Plaintext
CDN 节点缓存错误

如果最开始只是看到“页面又变慢了”,然后直接清 Redis、清 CDN、Purge All Caches,就永远很难知道真正是谁造成了问题。


二十五、目前的两个兼容层保持独立

最终我没有把所有兼容代码都塞进一个 MU Plugin。

现在分别是:

Plaintext
polylang-w3tc-cache-compat.php

负责:

Plaintext
Polylang taxonomy

W3 Total Cache

以及:

Plaintext
yoast-w3tc-cache-compat.php

负责:

Plaintext
Yoast SEO default SEO data Cron

W3 Total Cache

这样做有几个好处:

  • 职责单一;
  • 容易单独停用;
  • 容易回滚;
  • 升级某个插件时可以单独复核;
  • 出现新问题时,不会把不同兼容逻辑混在一起。

二十六、后续还要继续观察

目前并不能因此认为:

Plaintext
以后绝对不会再出现任何 W3TC 全量 Page Cache flush

更准确的说法是:

已经确认并修复了两条真实发生过的主要提前失效路径。

我暂时仍然保留:

Plaintext
w3tc-full-flush-tracer.php

继续观察:

Plaintext
w3tc_flush_posts
w3tc_flush_all

如果后续还有其他插件、Cron 或后台操作触发全量 flush,就可以继续通过调用栈定位。

另外还要继续观察:

Plaintext
AGE_1_TO_2D
AGE_2_TO_3D
AGE_3_TO_4D

最终目标是确认正常页面缓存确实能够逐步接近当前配置的:

Plaintext
4 天 TTL

而不是再次被其他隐藏路径提前清掉。


二十七、下一轮验证就用这篇文章本身

这篇文章发布以后,我准备直接把它作为下一轮生产测试对象。

后续如果需要补充新的验证结果,就正常编辑并更新这篇已经发布的文章。

然后继续观察:

Plaintext
文章更新

W3TC 是否只做相关 URL 精确 purge

其他旧 Page Cache 是否继续存活

同时,这篇文章发布以后,也会改变最近文章集合。

下一次:

Plaintext
wpseo_detect_default_seo_data

自然 Cron 再运行时:

Plaintext
default_seo_title
default_seo_meta_desc

就更有可能发生真实变化。

如果届时:

Plaintext
option 正常更新
Tracer 仍然没有新增 w3tc_flush_posts
历史 Page Cache 仍然存在

那么 Yoast 这条兼容修复就可以完成最后一块真实生产闭环。


总结

这次问题表面上是:

W3 Total Cache 设置了 4 天 Page Cache,但缓存为什么总是活不过一天?

最终却发现并不是 TTL 配置错误,而是至少存在两条提前失效路径:

第一条:

Plaintext
Polylang 标签/分类翻译关系
→ edited_term / delete_term
→ W3TC w3tc_flush_posts()
→ 全量 Page Cache flush

第二条:

Plaintext
Yoast SEO
wpseo_detect_default_seo_data Cron
→ update_option_wpseo
→ WPSEO_Utils::clear_cache()
→ w3tc_flush_posts()
→ 全量 Page Cache flush

两个问题分别通过独立 MU Plugin 进行了最小范围兼容。

在修复后,真实双语博客发布流程中的:

  • 中文草稿;
  • 中文发布;
  • 标签同步;
  • 标签重命名;
  • 英文翻译草稿;
  • 英文正式发布;

都没有再触发异常的全量 Page Cache flush。

随后 Page Cache 也第一次真正出现:

Plaintext
AGE_1_TO_2D > 0

对于生产环境中的缓存问题,我现在越来越倾向于采用一种比较慢、但更可靠的方法:

Plaintext
先留下证据
→ 确认是哪一层缓存
→ 找到真实 Hook
→ 做最小修改
→ 用真实业务流程验证
→ 再继续观察

而不是一看到旧内容、CPU 波动或者缓存异常,就直接:

Plaintext
Purge All Caches
清 Redis
清 CDN

后者可能暂时让问题消失,却很容易把真正的根因一起清掉。

W3TC 定时任务为何创建后又消失?排查 WP-Cron 与 Redis alloptions 陈旧缓存

WordPress 网站维护、性能优化与博客运营咨询

本站已持续运营超过 10 年,累计发布 1000+ 篇原创技术文章,长期实践 WordPress 网站建设、CDN / Cloudflare 配置、缓存优化、Google SEO、广告变现和多语言网站运营。

如果你的 WordPress 网站遇到访问慢、缓存异常、插件冲突、广告不显示、SEO 基础结构混乱、CDN 配置不确定等问题,可以联系我做一次远程技术排查。

适合以下用户:
✅ 个人博客站长
✅ WordPress 网站运营者
✅ 独立开发者与内容创作者
✅ SaaS 产品官网运营团队
✅ 希望优化网站速度与稳定性的站点

服务内容:
✅ WordPress 速度优化
✅ Cloudflare / CDN / 缓存配置排查
✅ 插件冲突与页面异常排查
✅ AdSense 广告显示问题排查
✅ SEO 基础结构检查
✅ 博客运营与商业化咨询

如需了解方案或交流相关问题,请直接联系我,并注明:WordPress 维护咨询

联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com