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

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

作者:

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 英文站从原来的 /en/ 路径迁移到了独立子域名。当前中文站是 https://www.shuijingwanwq.com,英文站是 https://en.shuijingwanwq.com,WordPress 后台通过 https://admin.shuijingwanwq.com 访问。

多语言继续使用 Polylang;Page Cache 使用 W3 Total Cache;Object Cache 由 W3 Total Cache 通过 Redis 保存;中文站 CDN 使用 EdgeOne,英文站 CDN 使用 Cloudflare。

英文站还在 /en/ 路径时,中英文虽然 URL 不同,但共用 www.shuijingwanwq.com 这个 Host。迁移到独立英文子域后,同一个 WordPress 安装开始同时运行在 wwwenadmin 三个 Host 下,以前不明显的缓存失效问题也随之暴露。

这次排查主要解决的是 Origin,也就是 WordPress、Polylang、W3 Total Cache 和 Redis 这一层的缓存一致性问题。最终确认了两个需要补偿的场景:英文文章从独立后台域名保存时,W3 Total Cache 原生流程没有覆盖英文首页 Page Cache;同时,Redis Object Cache 中同一类 Post 对象可能存在于不同 Host 对应的缓存空间,需要一个跨 Host 的失效机制。

本文暂不处理 EdgeOne 和 Cloudflare CDN 缓存失效。CDN 属于下一层问题,会在后续单独处理。


一、从 /en/ 迁移到独立域名以后发生了什么

迁移以前,中文首页是 https://www.shuijingwanwq.com/,英文内容位于 https://www.shuijingwanwq.com/en/。两种语言都在同一个 Host 下。

迁移以后,中文站改为 www.shuijingwanwq.com,英文站改为 en.shuijingwanwq.com,后台则使用 admin.shuijingwanwq.com。Polylang 使用不同域名识别中文和英文,而文章的发布、更新发生在独立后台 Host。

这意味着一次英文文章保存,会同时涉及 admin Host 下的 WordPress 保存流程、en Host 对应的文章和首页缓存、www Host 下 W3 Total Cache 默认生成的一部分 URL,以及 Redis 中不同 Host 对应的对象缓存。

因此,迁移后已经不能再把它简单理解成“同一个站点,只多了一个 /en/ 路径”。


二、先确认问题到底在哪一层

网站当前同时存在浏览器缓存、CDN、Nginx、W3 Total Cache Page Cache、WordPress/Polylang、W3 Total Cache Object Cache 和 Redis。排查时如果直接 Purge All Caches 或清空 Redis,即使页面恢复,也很难知道真正起作用的是哪一层。

浏览器
↓
CDN
↓
Nginx
↓
W3 Total Cache Page Cache
↓
WordPress / Polylang
↓
W3 Total Cache Object Cache
↓
Redis

因此这次把问题拆成两个阶段:第一阶段只确认 Origin 缓存一致性;第二阶段再处理 EdgeOne 与 Cloudflare CDN Cache Invalidation。本文记录的是第一阶段。


三、W3 Total Cache 原生文章保存流程并不是完全失效

继续检查 W3 Total Cache 的文章保存流程后,我确认它在多域名环境下并不是完全不知道如何处理 Polylang。

对于具体文章自己的 URL,Polylang 仍然能够根据文章语言返回正确域名。英文文章 permalink 会落到 en.shuijingwanwq.com,中文文章 permalink 会落到 www.shuijingwanwq.com,因此文章自身 Page Cache 并不是主要问题。

真正的问题出现在首页这类依赖当前请求上下文生成 URL 的页面。文章从 admin.shuijingwanwq.com 保存时,W3 Total Cache 原生流程能够处理文章自身的 Page Cache,也会处理默认站点的 www 首页等目标,但不会自动再补一次 https://en.shuijingwanwq.com/ 的首页清理。

因此保存英文文章以后,原生流程可以覆盖英文文章自身 Page Cache 和默认站点相关目标,但英文首页 Page Cache 缺少对应清理。这就是第一个需要补偿的地方。


四、Redis Object Cache 还有另一层 Host 隔离

Page Cache 之外,还需要考虑 W3 Total Cache Object Cache。进一步检查当前 Redis 缓存键后发现,具体对象缓存键会受到当前 Host 影响。

也就是说,同一个 WordPress 安装通过 www.shuijingwanwq.comen.shuijingwanwq.comadmin.shuijingwanwq.com 启动时,同一个 Post 对象可能存在于不同 Host 对应的缓存空间。

后台更新文章时,WordPress Core 本身会执行精确的 clean_post_cache()。但这次保存请求发生在 admin Host,仅依赖当前请求中的单对象删除,并不足以证明 wwwen 下已经存在的旧 Post 对象也会立即失效。

当前 W3 Total Cache 实现中,具体对象键虽然存在 Host 隔离,但 posts group 使用的 generation/version 是共享的。因此不需要遍历 wwwenadmin,也不需要模拟不同 HTTP_HOST,更不需要清空整个 Redis。

公共版最终保留的关键判断和 group flush API 是:

PHP
wp_cache_supports( 'flush_group' );
wp_cache_flush_group( 'posts' );

实际逻辑会先确认当前 Object Cache 支持 group flush,再对 posts group 做有限失效。这样可以推进共享 generation/version,使不同 Host 下旧 generation 的 posts 对象统一失效。


五、最终方案其实很小

确认两个缺口以后,并不需要重新实现一套缓存系统。最终只补两个动作:

  1. 根据文章本身确定 Polylang 语言,并得到该语言首页;
  2. 精确清理该语言首页的 W3 Total Cache Page Cache;
  3. 在 Object Cache 支持 group flush 时,刷新 posts Object Cache group;
  4. 同一个 PHP 请求内只主动执行一次 posts group flush,避免重复工作。

整体流程可以简化为:

在 admin 后台保存英文文章
        ↓
W3 Total Cache 原生处理
        ├─ 清理英文文章自身 Page Cache
        └─ 处理 www 首页等原生目标

MU Plugin 补充处理
        ├─ 清理 en 英文首页 Page Cache
        └─ 刷新 posts Object Cache group
                    ↓
             www / en / admin
           旧 posts 对象统一失效

v0.1 只处理当前已经确认存在问题的普通 post。没有加入 options、category、tag、taxonomy、menu、wp_templatewp_template_part、Global Styles、Theme JSON 或 CDN 清理。


六、为什么没有直接清整个 Redis

最简单粗暴的做法当然是文章一更新就清空 Redis,再清空全部 Page Cache。这样很可能也能看到最新内容,但并不适合作为生产方案。

  • 大量与当前文章无关的对象会同时失效;
  • 后续请求更容易集中回源数据库;
  • 可能制造额外的 CPU 与数据库负载尖峰;
  • Object Cache 的收益也会被削弱。

因此这里选择的是有限的 posts group 失效,而不是全局 Object Cache flush。

PHP
wp_cache_flush_group( 'posts' );

没有采用 wp_cache_flush(),更没有直接执行 Redis 的 FLUSHDB。目标不是“把缓存清得越干净越好”,而是只让已经确认可能陈旧的对象失效。


七、第一次生产验证出现了一个误判

公共版 MU Plugin 完成后,我第一次进行了生产验证。英文首页 Page Cache 部分很顺利:保存文章以后,在发起新的 Origin GET 之前,对应的英文首页缓存文件已经不存在,说明英文首页 Page Cache 补偿逻辑确实执行成功。

但 Object Cache 验证出现了 posts group version:812 → 812。表面看起来像 wp_cache_flush_group( 'posts' ) 没有生效,因此当时公共版被自动回滚到原生产插件。

这一步后来证明是一次测试方法造成的假阴性,而不是插件本身失效。


八、真正的问题不是插件,而是测试方法

继续比较生产版与公共版以后发现,两份代码中的 Object Cache 核心逻辑没有关键差异:都检查 wp_cache_supports( 'flush_group' ),都调用 wp_cache_flush_group( 'posts' ),Hook priority、参数数量、普通 post 判断和 request 内去重逻辑也一致。

最后发现真正的问题在于:第一次验证通过 WP-CLI 模拟保存文章,而该上下文加载的是 Core WP_Object_Cache fallback,不是真实后台 HTTP 请求所使用的 W3 Total Cache Redis Object Cache drop-in。

因此 WP-CLI 测试里的 812 → 812 不能证明公共版插件失效,只能说明当前 WP-CLI 上下文不适合验证真实后台请求中的 W3TC Redis group flush。

这个结论对后续排查很重要:至少在当前环境中,不能简单把 wp post update 当成 WordPress 后台点击“更新”的完全等价验证。


九、重新使用真实后台 Update 验证

确认测试方法有问题以后,我重新部署公共 v0.1。部署完成后,www Origin 返回 HTTP 200,en Origin 返回 HTTP 200,admin 返回正常的 HTTP 302 登录重定向。

随后建立更新前基线。Redis posts group version 为 813。英文首页 Page Cache 文件已经存在,mtime 为 2026-07-31 14:18:41.458486060 +0800,大小为 283002 bytes,SHA256 为 72e91f22a546dac51e928771e46cf1e85b26e4f9cb42e9004fa9e13cf80d2e33

接着从 admin.shuijingwanwq.com 打开英文文章 21022,不修改文章内容,直接点击一次“更新”。这一次没有使用 WP-CLI 模拟。


十、真实后台验证结果

这次结果和第一次完全不同。真实后台 Update 后,Redis posts group version 从 813 推进到 815,说明 Object Cache group flush 已经真实发生。

与此同时,在 Update 完成之后、发起下一次 Origin GET 之前,英文首页 Page Cache 文件已经不存在,说明英文首页 Page Cache 的精确清理也再次成功。

随后首次访问英文 Origin,首页缓存重新生成。新缓存 mtime 为 2026-07-31 14:38:43.320046857 +0800,大小为 283011 bytes,SHA256 为 54d5b3bd10a0e2df3d1e71d499e394fcf412e828f5c5f53b305b8ca892a1e237

重新生成后,wwwen Origin 都返回 HTTP 200,admin 仍是正常 HTTP 302 登录重定向。英文首页第一篇文章为 21022,页面 HTML 中也包含 21022

因此可以确认:公共 v0.1 已经通过真实生产环境的 WordPress 后台 Update 验证,并继续留在生产环境运行。


十一、这次修复以后,Origin 层发生了什么变化

对于目前已经验证的普通英文文章发布/更新场景,保存完成后,文章自身 Page Cache 会失效;W3 Total Cache 原生流程继续处理默认站点相关目标;MU Plugin 补充清理英文语言首页;同时 posts Object Cache group version 推进,让 wwwenadmin 下旧 generation 的 Post 对象失效。

下一次 Origin 请求到来时,就会基于最新对象重新生成页面。因此中文首页和英文首页不再需要等待 Origin 层旧缓存自然过期以后才能看到新文章。


十二、修复以后为什么浏览器仍然可能看到旧首页

Origin 修复完成以后,我又在浏览器隐私窗口中测试中文和英文首页。英文首页已经显示最新文章 21022,但中文首页直接访问时仍没有显示最新文章 21018

随后访问带新查询参数的中文首页 https://www.shuijingwanwq.com/?swq_home_test=20260731150601,页面立即显示最新文章 21018

由于此前已经确认 Origin 本身是最新内容,而改变 CDN cache key 后马上拿到最新页面,因此当前剩余问题可以继续缩小到 EdgeOne CDN 中原中文首页 URL 的旧缓存。

也就是说,这次修复解决的是 Origin 缓存一致性,但并没有自动清理 EdgeOne 或 Cloudflare 已经存在的旧 HTML。CDN 需要作为下一阶段单独处理。


十三、从“可能叠加两层陈旧”变成主要只剩 CDN

修复以前,如果 Origin 缓存本身没有及时失效,而 CDN 又继续缓存 Origin 返回的旧页面,两层陈旧时间存在叠加的可能。按照当前大约 4 天的 CDN 缓存周期理解,极端情况下可能近似出现 Origin 旧缓存约 4 天,再叠加 CDN 约 4 天,最终接近 8 天的陈旧窗口。

这里并不是说每篇文章一定会旧 8 天,而是多层缓存都依赖自然过期时,陈旧时间可能继续向后叠加。

现在普通文章保存后,Origin 旧 Page Cache 会主动失效,posts Object Cache group 也会推进,因此 Origin 不再额外贡献几天的陈旧时间。用户侧当前剩余的主要风险来自 CDN,按现有周期理解,最长陈旧窗口可以从两层叠加的极端情况压缩到主要剩 CDN 的约 4 天。

下一阶段如果再实现文章保存后精确 Purge EdgeOne 和 Cloudflare 对应首页缓存,用户侧首页更新才会进一步接近“保存后立即可见”。


十四、没有继续扩大 v0.1 的功能范围

这次修复完成以后,我没有继续顺手加入分类、标签、菜单、Theme JSON 等缓存清理。当前 v0.1 只解决已经真实确认的两个问题:对应语言首页 Page Cache 精确失效,以及 posts Object Cache group 跨 Host 失效。

后续如果 category、tag、menu、wp_template、Global Styles 或 Theme JSON 真的出现缓存问题,再根据实际证据补充,而不是提前把插件做成一个“文章一保存就清所有缓存”的工具。

目前更适合这套生产环境的方式仍然是:遇到真实问题,先收集证据,确认属于哪一层缓存,再做最小修改并立即验证。


十五、将修复整理成独立的开源 MU Plugin

生产验证通过后,我把这部分逻辑从原有站点专用 MU Plugin 中提取出来,整理成独立项目 wordpress-polylang-w3tc-cache-compat

GitHub 仓库:https://github.com/shuijingwan/wordpress-polylang-w3tc-cache-compat

当前版本采用 MIT License。v0.1 的范围非常明确:为 Polylang 独立语言域名 + W3 Total Cache + Redis + 独立后台 Host 环境补充已经确认的普通文章缓存失效场景,而不是做一个通用的全缓存清理插件。


十六、当前阶段结论

  1. Polylang 使用独立语言域名以后,具体文章 URL 仍然能够按文章语言生成正确域名,但从独立后台 Host 保存文章时,W3 Total Cache 原生首页清理不会完整覆盖英文语言首页。
  2. W3 Total Cache Redis Object Cache 中,具体对象存在 Host 隔离,但共享的 posts group generation/version 可以用于跨 Host 统一失效。
  3. 不需要为了修复这个问题清空整个 Redis,也不需要对 wwwenadmin 分别模拟请求删除对象。
  4. WP-CLI 的 Object Cache 运行环境不能默认当成真实后台 HTTP 请求环境;第一次 812 → 812 最终证明是测试方法造成的假阴性。
  5. 真实后台 Update 已经验证 posts group version:813 → 815,同时英文首页 Page Cache 会在文章更新后立即被删除,并在下一次 Origin 请求时重新生成。

因此目前可以确认:普通文章更新以后,WordPress Origin 层的中英文首页缓存一致性问题已经得到处理。

但整个缓存链路还没有结束。浏览器实际测试已经确认:英文首页能够显示最新文章,而中文首页原 URL 仍可能由 EdgeOne 返回旧内容;增加新的查询参数后则立即显示最新文章。

所以下一阶段的目标已经非常明确:处理 EdgeOne 和 Cloudflare CDN 层的精确缓存失效。这部分将单独继续排查并整理成下一篇文章。

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

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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理