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

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

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

作者:

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 缓存排查记录

最近在继续验证 WordPress 多语言、多域名缓存兼容性时,我发现一个新的问题:

英文译文已经发布,Polylang 中的中英文文章关系也已经建立,但对应的中文文章详情页仍然没有显示语言切换器,页面中的英文 hreflang 也没有出现。

这次排查最终确认,问题并不是简单的 W3 Total Cache Page Cache 没有清理,而是 Polylang 翻译关系对应的 Object Cache 在 wwwenadmin 三个 Host 之间没有同步失效。

不过,考虑到这个问题目前主要导致语言切换器和 hreflang 延迟出现,而要实现真正可靠的跨 Host 精确清理需要进一步依赖 W3TC 内部机制,因此这一阶段没有继续增加生产修复逻辑。

这篇文章记录已经确认的现象、根因和暂时的取舍,方便以后需要继续优化时直接接着排查。


一、问题出现在英文译文发布以后

这次测试的中文文章是 21027,英文译文是 21034

英文文章已经正常发布,而且通过 WP-CLI 查询,Polylang 关系也是正确的:

21027 → 21034

因此最开始可以排除一种情况:英文文章并不是因为没有建立翻译关系而缺少语言切换器。

一开始我怀疑的是中文文章详情页 Page Cache。

因为中文文章通常先发布,此时英文译文还不存在。如果详情页已经生成缓存,那么 HTML 中自然不会包含英文语言切换器。后来英文译文发布,如果这份 Page Cache 没有失效,看起来就会一直像“没有英文版”。

但实际检查很快排除了这个判断。


二、没有 Page Cache 时,Origin 仍然输出错误

检查 21027 对应的 W3TC Page Cache 文件时,第一次发现缓存文件并不存在。

随后直接绕过 CDN 请求本机 Origin,页面返回 HTTP 200,但 HTML 中:

  • 英文文章 21034 的 URL 出现次数为 0;
  • hreflang 出现次数为 0。

这意味着问题已经发生在 Page Cache 生成之前。

也就是说:

WordPress 动态生成中文文章页面时,本身就没有识别到对应英文译文。

公网请求当时同样返回 eo-cache-status: MISS,输出结果也一样,因此 EdgeOne 旧缓存也不是这次问题的来源。

问题范围由此缩小到了 WordPress、Polylang 和 Object Cache。


三、正常旧文章与异常新文章形成了明显对照

为了确认不是语言切换器本身失效,我又找了一篇能够正常显示语言切换器的旧文章 20612,对应英文文章为 20617

正常文章的 Origin HTML 中:

  • 对应英文文章 URL 出现 2 次;
  • hreflang 出现 3 次;
  • 页面能够正常输出 20617 的英文链接。

而异常文章 21027

  • 对应 21034 URL 为 0;
  • hreflang 为 0。

随后又发现,最近十余篇中文文章存在类似情况。

这说明整个 Polylang 输出机制并没有失效,更像是近期新建立的翻译关系没有被某一层缓存及时感知。


四、真正的关键证据:WP-CLI 正常,www HTTP Runtime 错误

WP-CLI 中查询 21027 时,可以正常获得:

21027 → 21034

但 WP-CLI 和真实 PHP-FPM HTTP 请求不一定使用完全相同的 Object Cache 运行环境,因此我又通过真实 www Origin HTTP 请求调用了 pll_get_post()

运行环境确认使用的是 W3 Total Cache Redis Object Cache:

W3TC\ObjectCache_WpObjectCache

正常旧文章仍然得到:

20612 → 20617

但异常文章却得到:

21027 → NONE

这一步基本确定了问题:

数据库中的 Polylang 翻译关系已经正确,但 www Host 的持久化 Object Cache 仍然保存着“21027 没有英文译文”的旧结果。


五、精确清理 relationship cache 后立即恢复

随后没有清空 Redis,也没有执行全局 Object Cache Flush,而是在真实 www HTTP Runtime 中对关联文章执行了 clean_object_term_cache()

执行前:

pll_get_post( 21027, 'en' ) = 0

执行以后:

pll_get_post( 21027, 'en' ) = 21034

为了进一步缩小范围,又使用另一组异常文章 21018 → 21022 做了精确测试,只删除对应的 post_translations_relationships 缓存:

PHP
wp_cache_delete(
    21018,
    'post_translations_relationships'
);

wp_cache_delete(
    21022,
    'post_translations_relationships'
);

结果同样从:

before: 0

恢复到:

after: 21022

因此已经能够确认,真正陈旧的是:

post_translations_relationships

也就是 Polylang Post 翻译关系对应的 Object Cache。


六、为什么最终还会表现成页面长期没有语言切换器

Object Cache 只是第一层。

www Runtime 从旧的 post_translations_relationships 中读到“没有英文译文”以后,会生成一份没有英文语言切换器和 hreflang 的 HTML。

如果 W3TC Page Cache 随后缓存了这份 HTML,即使 Object Cache 后来已经自然过期,用户仍然可能继续看到错误页面,直到 Page Cache 自己过期或被清理。

这次在清理 relationship cache 后,又精确清除了 21027 的详情页 Page Cache。

重新生成 Origin 页面以后:

  • 21034 URL 出现 2 次;
  • hreflang 出现 3 次;
  • 中英文 alternate 链接恢复正常。

因此完整链路已经确认:

旧的 Polylang relationship Object Cache → pll_get_post() 返回无译文 → 生成缺少语言切换器的 HTML → W3TC Page Cache 再缓存这份 HTML。


七、为什么迁移到三个 Host 后才明显出现

以前英文站位于 www.shuijingwanwq.com/en/

中英文虽然路径不同,但都运行在 www.shuijingwanwq.com 这个 Host 下。

现在则变成:

  • 中文:www.shuijingwanwq.com
  • 英文:en.shuijingwanwq.com
  • 后台:admin.shuijingwanwq.com

英文译文通常从 admin Host 创建和保存翻译关系,而 W3 Total Cache Redis Object Cache 又会让具体缓存项受到 Host namespace 的影响。

于是就可能出现:

中文文章还没有英文译文时,www 已经缓存了“无翻译”关系;随后 admin 创建英文译文并更新数据库,但 www 中原来的 relationship cache 没有同步失效。

这也解释了为什么以前单 Host 环境没有明显问题,迁移到多域名后才集中暴露。


八、为什么没有直接加入跨 Host 修复

确认根因以后,我让 Codex进一步检查了当前 W3TC 2.10.3 是否存在适合的 Host-aware Object Cache API。

结果没有找到一个公开、稳定的接口,可以从 admin 请求中指定:

“删除 www Host 下某个 post_translations_relationships key”。

实验也证明,在 admin Host 执行 wp_cache_flush_group( 'post_translations_relationships' ) 后,admin 自己可以读取新关系,但 www 仍然读取旧数据。

因此不能简单照搬此前 posts group 的处理方案。

理论上可以继续依赖 W3TC 内部 Redis key 构造规则,实现跨 Host 精确删除,但这会把 MU Plugin 与 W3TC 2.10.3 的私有实现绑定在一起。

为了解决一个语言切换器延迟问题,我认为这种维护成本和风险目前并不值得。


九、也没有为了这个问题修改 Object Cache 策略

当前 W3TC 实际配置是:

Object Cache 使用 Redis,lifetime 为 86400 秒,也就是 24 小时。

Page Cache 使用 file_generic,lifetime 为 345600 秒,也就是 4 天。

这意味着旧翻译关系可能在 Redis 中保留较长时间,而错误生成的详情页 HTML 还可能继续由 Page Cache 保存。

曾考虑过几个方案:

缩短 Object Cache TTL,可以让旧关系更快自然过期,但会影响整个 Object Cache,而不仅仅是 Polylang 翻译关系。

post_translations_relationships 设置成 non-persistent,可以彻底避开 Redis 中的跨 Host 旧关系,但意味着这类翻译关系以后会更频繁重新读取数据库。

把 Object Cache TTL 延长到 2 天或 4 天,可以降低自然过期频率,但也会让这类没有正确失效的旧数据保留更久。

综合来看,目前都没有必要。

因此继续保持:

Object Cache TTL = 1 天

Page Cache TTL = 4 天


十、当前为什么选择接受自然过期

这个问题确实存在,但影响范围需要和修复成本一起考虑。

目前更重要的是保证文章发布以后:

  • 中文和英文首页能够及时更新;
  • Sitemap 能够及时反映新内容;
  • 文章正文正确;
  • 页面语言正确;
  • canonical 正确;
  • 不因为缓存长期展示旧文章内容。

相比之下,中文文章详情页的语言切换器以及 hreflang 晚一些出现,虽然不够理想,但当前仍属于低优先级问题。

因此这一阶段选择不再继续增加生产逻辑。

不使用 W3TC 私有 Redis API,不直接拼 physical key,不执行 Redis DEL,也不改变整个 relationship group 的持久化策略。

先让现有缓存自然过期。


十一、这次排查留下的几个重要经验

这次最有价值的并不是最终有没有写一个 MU Plugin 修复,而是进一步确认了多 Host Object Cache 排查时的一些边界。

数据库已经更新,不代表所有 Host 的 PHP Runtime 都已经看到最新结果。

WP-CLI 返回正确,也不能直接证明真实 HTTP Runtime 正确。

同一个 WordPress 安装可能出现:

admin 正确、en 正确,但 www 仍然读取旧 Object Cache。

另外,全量清空 Object Cache 虽然很容易让问题暂时消失,却会同时删除故障现场,也可能产生明显的冷缓存阶段。

当天曾经执行过全量 Object Cache 清理,随后又出现几次 CPU 告警。目前还没有足够证据证明两者存在直接因果关系,因此没有因此修改 TTL。

以后再遇到类似问题,更适合先保留现场,从具体 Host、具体文章、具体 group 或 key 开始确认,而不是直接 Purge All Caches。


十二、当前阶段结论

这次已经确认:

Polylang 在数据库中已经建立中英文文章关系,但在多域名环境下,W3 Total Cache Redis Object Cache 中的 post_translations_relationships 可能在不同 Host 下留下不同状态。

英文译文从独立后台域名建立以后,www Host 中此前缓存的“没有英文译文”关系可能继续存在。

这会导致中文文章动态生成时不输出英文语言切换器和 hreflang,随后 W3TC Page Cache 又可能继续保存这份 HTML。

实际测试已经证明,在对应 www Runtime 中精确删除 post_translations_relationships 后,pll_get_post() 会立即恢复;再清理文章详情页 Page Cache,语言切换器和 hreflang 也能够恢复。

因此根因已经明确。

只是目前没有找到一个足够简单、稳定,而且不依赖 W3TC 私有内部实现的跨 Host 精确删除方案。

考虑到这个问题实际影响有限,当前决定暂时不继续修改生产环境,保持 Object Cache 1 天、Page Cache 4 天的现有配置,让语言切换器自然恢复。

如果以后这个问题变得更重要,可以直接从 post_translations_relationships 的跨 Host 精确失效继续研究,不需要重新从头排查。

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

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 来减少垃圾评论。了解你的评论数据如何被处理