这篇文章是此前 Polylang 多域名迁移排查的后续记录。
上一篇文章:
https://www.shuijingwanwq.com/2026/07/10/19280/
在上一篇文章中,我将英文站从原来的 /en/ 路径迁移到了独立子域名:
中文站:https://www.shuijingwanwq.com/
英文站:https://en.shuijingwanwq.com/
迁移过程中,我已经遇到过两类与缓存有关的问题:
- W3 Total Cache Page Cache 将 Polylang 的英文语言域名识别成 foreign domain,导致
en被 301 跳回www。 - 301 问题解决后,W3 Total Cache Object Cache 中仍然保留旧的 Polylang 配置,导致英文子域名运行时继续被识别成中文站。
这一次,最初遇到的只是一个看起来很普通的前端问题:英文文章页面底部出现了横向滚动条。
但排查到最后发现,除了真实存在的 CSS 布局问题之外,W3 Total Cache Object Cache 使用 Redis 保存的旧对象,也导致新 CSS 长时间无法在英文站生效。
一、当前网站结构
当前 WordPress 使用 Polylang 的多域名模式:
中文站:www.shuijingwanwq.com
英文站:en.shuijingwanwq.com
WordPress 后台:www.shuijingwanwq.com/wp-admin/
两个域名指向同一个 WordPress 根目录,并共享:
同一套 WordPress 程序
同一个数据库
同一套 Twenty Twenty-Five 主题
同一套插件
同一个 Redis 实例
当前启用的缓存组合包括:
W3 Total Cache Page Cache
W3 Total Cache Object Cache
Redis
Cloudflare
这里需要明确一下:
本站使用的是 W3 Total Cache 提供的 Object Cache 功能,Redis 是对象缓存的存储后端。
因此,本文后续统一使用:
W3TC Object Cache(Redis 后端)
而不是把它描述成一个独立的 Redis Object Cache 插件。
二、问题现象:只有英文文章出现横向滚动条
出现问题的英文文章是:
https://en.shuijingwanwq.com/2026/07/11/19327/
其对应的中文文章是:
https://www.shuijingwanwq.com/2026/07/11/19309/
中文文章显示正常,但英文页面底部出现了一条横向滚动条。

由于两个页面使用的是同一个主题和同一套模板,最开始怀疑的对象包括:
英文长标题
超长 URL
代码块
表格
AdSense iframe
搜索框
语言切换器
额外 CSS
单纯通过肉眼观察,很难确定究竟是哪一个元素把页面撑宽了。
三、通过 JavaScript 找出超出视口的元素
我先打开英文文章页面,按 F12 进入浏览器开发者工具,然后在“控制台”中执行下面的代码:
(() => {
const viewportWidth = document.documentElement.clientWidth;
const elements = [...document.querySelectorAll('body *')]
.map(el => {
const rect = el.getBoundingClientRect();
return {
element: el,
tag: el.tagName.toLowerCase(),
class: typeof el.className === 'string' ? el.className : '',
left: Math.round(rect.left),
right: Math.round(rect.right),
width: Math.round(rect.width),
scrollWidth: el.scrollWidth,
clientWidth: el.clientWidth,
text: (el.innerText || el.textContent || '')
.trim()
.replace(/\s+/g, ' ')
.slice(0, 100)
};
})
.filter(item =>
item.right > viewportWidth + 1 ||
item.left < -1
);
elements.forEach(item => {
item.element.style.outline = '3px solid red';
});
console.table(elements.map(({ element, ...item }) => item));
console.log({
viewportWidth,
pageScrollWidth: document.documentElement.scrollWidth,
overflowWidth:
document.documentElement.scrollWidth - viewportWidth,
overflowElements: elements.length
});
return elements;
})();
检测结果显示:
viewportWidth: 1405
pageScrollWidth: 1422
overflowWidth: 17
也就是说,页面总宽度比浏览器可视区域多出了 17px。
在检测结果中,最右侧的元素是:
nav.tepll-pll-language-switcher

四、语言切换器只是最右侧元素,不一定是根因
为了验证语言切换器是否就是问题来源,我临时在控制台中把它向左移动了 17px:
const el = document.querySelector(
'nav.tepll-pll-language-switcher'
);
el.style.setProperty(
'transform',
'translateX(-17px)',
'important'
);
执行后,页面底部的横向滚动条立即消失。
不过,这只能说明语言切换器是页面中最靠右的元素。
它并不能证明语言切换器本身就是导致布局溢出的根因。
如果直接把下面的代码加入正式 CSS:
transform: translateX(-17px);
虽然可以让滚动条消失,但本质上只是使用固定偏移量补偿布局错误。
因此,我没有把这种方式作为最终修复方案。
五、检查语言切换器及其父级容器
接下来,我检查了语言切换器及其父级元素的实际宽度。
控制台结果显示,语言切换器所在的 Flex 父容器:
clientWidth: 397px
scrollWidth: 429px
也就是说:
父容器可用宽度:397px
内部元素所需宽度:429px
内部溢出宽度:约 32px

查看当时的额外 CSS,可以发现页头搜索框使用了:
.wp-block-search {
flex: 3 1 0;
min-width: 250px;
margin: 0 10px;
}
语言切换器本身大约需要:
160px
搜索框和语言切换器最低占用空间大约是:
搜索框最小宽度:250px
搜索框左边距:10px
搜索框右边距:10px
语言切换器宽度:160px
合计:430px
而它们所在的父容器实际只有:
397px
这与控制台检测到的:
scrollWidth: 429px
基本吻合。
因此,真实的 CSS 布局问题是:
搜索框设置了
min-width: 250px,导致 Flex 空间不足时搜索框无法继续缩小,最终把英文语言切换器推出了父容器。
英文单词 English 占用的宽度比中文语言名称更大,所以英文页面更容易暴露这个问题。
六、修改页头搜索框的最小宽度
我将原来的规则:
.wp-block-search {
flex: 3 1 0;
min-width: 250px;
margin: 0 10px;
}
调整为:
@media (min-width: 769px) {
header.wp-block-template-part .wp-block-search {
flex: 3 1 0;
min-width: 0;
margin: 0 10px;
}
}
当前保存的额外 CSS 中,页头搜索框已经采用限定到 Header 的选择器,并将 min-width 调整为了 0。
这次修改主要包含两个部分。
1. 允许搜索框继续收缩
原来是:
min-width: 250px;
修改为:
min-width: 0;
这样,当 Flex 父容器空间不足时,搜索框可以继续缩小,不会强制占用至少 250px。
2. 将作用范围限制在页头
原来的选择器:
.wp-block-search
会影响网站中的所有搜索区块。
修改后:
header.wp-block-template-part .wp-block-search
只会影响页头中的搜索框,不会干扰侧边栏、正文或其他模板中的搜索区块。
正常情况下,保存额外 CSS 后,英文页面的横向滚动条应该立即消失。
但实际保存后,页面仍然没有发生变化。
七、后台已经保存新 CSS,英文页面却仍输出旧规则
查看英文页面源代码后,我发现前台仍然输出旧规则:
.wp-block-search {
flex: 3 1 0;
min-width: 250px;
margin: 0 10px;
}
但 WordPress 后台保存的内容已经是:
header.wp-block-template-part .wp-block-search {
flex: 3 1 0;
min-width: 0;
margin: 0 10px;
}
也就是说:
后台已经保存新 CSS
数据库内容已经更新
英文前台仍然输出旧 CSS

到这里,问题已经不再只是 CSS 布局本身,而是:
为什么 WordPress 前台没有读取到数据库中已经保存的新 CSS?
八、后台清除 W3TC 缓存后,英文页面仍未更新
当前 WordPress 后台统一使用:
https://www.shuijingwanwq.com/wp-admin/
为了收敛后台入口,访问:
https://en.shuijingwanwq.com/wp-admin/
时,会被 301 跳转到主域名后台。
我在 www 后台执行了 W3 Total Cache 的“清除全部缓存”,但英文页面仍然输出旧 CSS。
这时最初怀疑:
Polylang 使用不同域名后,从主域名后台执行 W3TC 缓存清理,可能没有完整更新英文语言域名的缓存。
不过,后续排查证明,这次真正残留的不是 Cloudflare 边缘缓存,而是 W3TC Object Cache 中的旧对象。
九、排除 Cloudflare 边缘缓存
为了排除 Cloudflare 缓存,我给英文文章 URL 添加了随机查询参数,并检查响应头:
u="https://en.shuijingwanwq.com/2026/07/11/19327/?_csscheck=$(date +%s)"
curl -sS -D - -o /dev/null "$u" \
| grep -Ei "HTTP/|server:|eo-cache-status:|cf-cache-status:|age:|cache-control:|x-cache:|via:"
返回结果:
HTTP/2 200
server: cloudflare
cache-control: max-age=14400
cf-cache-status: MISS
其中:
cf-cache-status: MISS
说明这次请求没有直接命中 Cloudflare 边缘节点中的旧缓存,而是重新向源站获取了页面。
但返回的 HTML 中仍然包含:
min-width: 250px;
因此可以确认:
浏览器缓存不是根因
Cloudflare 边缘缓存也不是根因
源站返回的内容本身就是旧 CSS

十、检查 W3TC 的多域名页面缓存目录
W3 Total Cache Page Cache 会在下面的目录中保存页面缓存:
/data/wwwroot/www.shuijingwanwq.com/wp-content/cache/page_enhanced/
进入该目录后,可以看到两个语言域名对应的独立目录:
en.shuijingwanwq.com
www.shuijingwanwq.com
英文域名目录中也有完整的缓存结构:
2014
2018
2019
2021
2025
2026
category
series
tag

这说明 W3TC Page Cache 会按照请求 Host 分别保存两个域名的 HTML 页面缓存。
不过,在英文缓存目录中,没有找到直接以文章 ID 19327 命名的缓存路径。
因此,这次不能简单通过删除某个 19327 目录来解决问题。
后续直接绕过 Cloudflare访问源站,返回的仍然是旧 CSS,也说明问题已经进入 WordPress 运行时和对象缓存层。
十一、绕过 Cloudflare,直接请求源站
为了确认旧 CSS 是否来自源站,我在服务器中使用 --resolve,让英文域名直接解析到本机 Nginx:
ts=$(date +%s)
url="/2026/07/11/19327/?origin_check=$ts"
curl -ksS \
--resolve en.shuijingwanwq.com:443:127.0.0.1 \
-H "Cache-Control: no-cache" \
"https://en.shuijingwanwq.com$url" \
-o /tmp/en-origin.html
curl -ksS \
-H "Cache-Control: no-cache" \
"https://en.shuijingwanwq.com$url" \
-o /tmp/en-public.html
然后对比源站和公网返回的 CSS:
python3 - <<'PY'
import re
for name, path in [
("直接访问源站", "/tmp/en-origin.html"),
("通过公网 Cloudflare", "/tmp/en-public.html"),
]:
with open(path, "r", encoding="utf-8", errors="ignore") as f:
html = f.read()
rules = re.findall(
r'(?:header\.wp-block-template-part\s+)?\.wp-block-search\s*\{.*?\}',
html,
flags=re.S
)
matched = [
re.sub(r'\s+', ' ', rule).strip()
for rule in rules
if "flex: 3 1 0" in rule or "min-width:" in rule
]
print(f"\n===== {name} =====")
print("包含 min-width: 0:", "min-width: 0" in html)
print("包含 min-width: 250px:", "min-width: 250px" in html)
for rule in matched[-5:]:
print(rule)
PY
输出:
===== 直接访问源站 =====
包含 min-width: 0:False
包含 min-width: 250px:True
.wp-block-search { flex: 3 1 0; min-width: 250px; margin: 0 10px; }
===== 通过公网 Cloudflare =====
包含 min-width: 0:False
包含 min-width: 250px:True
.wp-block-search { flex: 3 1 0; min-width: 250px; margin: 0 10px; }
这一步证明:
Cloudflare 返回的是旧 CSS
直接访问源站同样返回旧 CSS
因此,问题位于 WordPress 运行时,而不是 Cloudflare。
十二、查询数据库中的 wp_global_styles
Twenty Twenty-Five 是区块主题。
通过站点编辑器保存的全局样式和额外 CSS,会保存在 wp_global_styles 类型的文章记录中。
我使用下面的 PHP 脚本查询数据库:
cd /data/wwwroot/www.shuijingwanwq.com
php -d display_errors=1 <<'PHP'
<?php
require __DIR__ . '/wp-load.php';
global $wpdb;
$rows = $wpdb->get_results("
SELECT
ID,
post_type,
post_status,
post_name,
post_title,
post_modified,
post_content
FROM {$wpdb->posts}
WHERE post_type IN ('wp_global_styles', 'custom_css')
ORDER BY post_modified DESC, ID DESC
");
foreach ($rows as $row) {
$content = (string) $row->post_content;
printf(
"ID=%d | type=%s | status=%s | name=%s | title=%s | modified=%s | length=%d | old250=%s | new0=%s\n",
$row->ID,
$row->post_type,
$row->post_status,
$row->post_name,
$row->post_title,
$row->post_modified,
strlen($content),
strpos($content, 'min-width: 250px') !== false ? 'YES' : 'NO',
strpos($content, 'min-width: 0') !== false ? 'YES' : 'NO'
);
}
PHP
输出:
ID=17390
type=wp_global_styles
status=publish
name=wp-global-styles-twentytwentyfive
title=Custom Styles
old250=NO
new0=YES
这说明数据库中的 wp_global_styles 已经是新版本:
min-width: 0
数据库中也没有另一条仍然包含 min-width: 250px 的 Twenty Twenty-Five 全局样式记录。
因此,问题不是 CSS 没有保存,也不是数据库中存在两份新旧全局样式。
十三、WordPress 运行时仍然生成旧 CSS
接下来,我通过 PHP 直接加载 WordPress,并模拟英文域名请求:
cd /data/wwwroot/www.shuijingwanwq.com
php -d display_errors=1 <<'PHP'
<?php
$_SERVER['HTTP_HOST'] = 'en.shuijingwanwq.com';
$_SERVER['SERVER_NAME'] = 'en.shuijingwanwq.com';
$_SERVER['REQUEST_URI'] = '/2026/07/11/19327/';
$_SERVER['HTTPS'] = 'on';
$_SERVER['SERVER_PORT'] = '443';
$_SERVER['REQUEST_SCHEME'] = 'https';
require __DIR__ . '/wp-load.php';
$global_css = function_exists('wp_get_global_stylesheet')
? wp_get_global_stylesheet()
: '';
$custom_css = function_exists('wp_get_global_styles_custom_css')
? wp_get_global_styles_custom_css()
: '';
$css = $global_css . "\n" . $custom_css;
echo "CSS length: " . strlen($css) . PHP_EOL;
echo "包含 min-width: 0:"
. (strpos($css, 'min-width: 0') !== false ? 'YES' : 'NO')
. PHP_EOL;
echo "包含 min-width: 250px:"
. (strpos($css, 'min-width: 250px') !== false ? 'YES' : 'NO')
. PHP_EOL;
if (preg_match(
'/(?:header\.wp-block-template-part\s+)?\.wp-block-search\s*\{[^}]*\}/s',
$css,
$match
)) {
echo PHP_EOL . "匹配到的搜索框规则:" . PHP_EOL;
echo preg_replace('/\s+/', ' ', trim($match[0])) . PHP_EOL;
}
PHP
输出:
CSS length: 39474
包含 min-width: 0:NO
包含 min-width: 250px:YES
匹配到的搜索框规则:
.wp-block-search { flex: 3 1 0; min-width: 250px; margin: 0 10px; }
这时已经可以确认:
数据库里是新版 CSS
WordPress 运行时仍然生成旧版 CSS
由于当前站点启用了 W3 Total Cache Object Cache,并使用 Redis 作为缓存后端,因此接下来重点检查 W3TC Object Cache 返回的对象内容。
十四、对比数据库原始值与 get_post() 返回值
为了确认对象缓存是否陈旧,我继续对比:
- 直接通过 SQL 读取数据库;
- 通过 WordPress
get_post()读取; - 当前是否正在使用外部对象缓存。
执行:
cd /data/wwwroot/www.shuijingwanwq.com
php -d display_errors=1 <<'PHP'
<?php
$_SERVER['HTTP_HOST'] = 'en.shuijingwanwq.com';
$_SERVER['SERVER_NAME'] = 'en.shuijingwanwq.com';
$_SERVER['REQUEST_URI'] = '/2026/07/11/19327/';
$_SERVER['HTTPS'] = 'on';
$_SERVER['SERVER_PORT'] = '443';
$_SERVER['REQUEST_SCHEME'] = 'https';
require __DIR__ . '/wp-load.php';
global $wpdb;
$id = 17390;
$raw_database = (string) $wpdb->get_var(
$wpdb->prepare(
"SELECT post_content FROM {$wpdb->posts} WHERE ID = %d",
$id
)
);
$post_object = get_post($id);
$cached_post = $post_object
? (string) $post_object->post_content
: '';
$stylesheet = function_exists('wp_get_global_stylesheet')
? (string) wp_get_global_stylesheet()
: '';
function report_css($name, $content) {
echo PHP_EOL . "===== {$name} =====" . PHP_EOL;
echo "长度:" . strlen($content) . PHP_EOL;
echo "min-width: 0:"
. (strpos($content, 'min-width: 0') !== false ? 'YES' : 'NO')
. PHP_EOL;
echo "min-width: 250px:"
. (strpos($content, 'min-width: 250px') !== false ? 'YES' : 'NO')
. PHP_EOL;
}
echo "使用外部对象缓存:"
. (wp_using_ext_object_cache() ? 'YES' : 'NO')
. PHP_EOL;
report_css('数据库原始内容', $raw_database);
report_css('get_post() 返回内容', $cached_post);
report_css('wp_get_global_stylesheet() 生成结果', $stylesheet);
PHP
输出:
使用外部对象缓存:YES
===== 数据库原始内容 =====
长度:17407
min-width: 0:YES
min-width: 250px:NO
===== get_post() 返回内容 =====
长度:17317
min-width: 0:NO
min-width: 250px:YES
这个结果已经可以明确说明:
数据库中的 wp_global_styles 已经更新
↓
W3TC Object Cache 中仍然保存旧的 post 对象
↓
get_post(17390) 返回旧内容
↓
WordPress 运行时继续生成旧 CSS

这里已经不需要继续猜测 Cloudflare、Nginx 或浏览器缓存。
数据库原始内容与 get_post() 返回内容不一致,而清理对象缓存后恢复正常,这已经直接证明问题发生在 WordPress 对象缓存层。
十五、精确清理 wp_global_styles 对象缓存
由于已经确认出现问题的是:
wp_global_styles ID:17390
所以这一次没有直接执行:
redis-cli FLUSHALL
而是通过 WordPress API,只清理这条文章对象缓存以及 Theme JSON 相关缓存:
cd /data/wwwroot/www.shuijingwanwq.com
php -d display_errors=1 <<'PHP'
<?php
$_SERVER['HTTP_HOST'] = 'en.shuijingwanwq.com';
$_SERVER['SERVER_NAME'] = 'en.shuijingwanwq.com';
$_SERVER['REQUEST_URI'] = '/2026/07/11/19327/';
$_SERVER['HTTPS'] = 'on';
$_SERVER['SERVER_PORT'] = '443';
$_SERVER['REQUEST_SCHEME'] = 'https';
require __DIR__ . '/wp-load.php';
$id = 17390;
/* 清理指定 wp_global_styles 文章的对象缓存 */
clean_post_cache($id);
/* 清理 WordPress Theme JSON / 全局样式缓存 */
if (function_exists('wp_clean_theme_json_cache')) {
wp_clean_theme_json_cache();
}
/* 重新读取并验证 */
$post = get_post($id);
$content = $post ? (string) $post->post_content : '';
echo "已清理对象缓存。" . PHP_EOL;
echo "get_post() 包含 min-width: 0:"
. (strpos($content, 'min-width: 0') !== false ? 'YES' : 'NO')
. PHP_EOL;
echo "get_post() 包含 min-width: 250px:"
. (strpos($content, 'min-width: 250px') !== false ? 'YES' : 'NO')
. PHP_EOL;
PHP
输出:
已清理对象缓存。
get_post() 包含 min-width: 0:YES
get_post() 包含 min-width: 250px:NO
这说明 W3TC Object Cache 中旧的 wp_global_styles 文章对象已经被清理,WordPress 重新读取到了数据库中的新内容。

需要注意:
17390
只是我当前网站中对应的 wp_global_styles 记录 ID。
其他网站不能直接照搬这个 ID,必须先查询自己站点数据库中的实际记录。
十六、再次验证公网英文页面
最后,在本地电脑中重新请求英文页面:
u="https://en.shuijingwanwq.com/2026/07/11/19327/?_csscheck=$(date +%s)"
curl -ksS "$u" |
python3 -c '
import sys
html = sys.stdin.read()
print("包含 min-width: 0:", "min-width: 0" in html)
print("包含 min-width: 250px:", "min-width: 250px" in html)
'
输出:
包含 min-width: 0:True
包含 min-width: 250px:False
重新打开英文文章页面后,底部的横向滚动条已经消失。

十七、这次问题实际包含两层原因
这次故障不能简单归结为语言切换器样式,也不能简单归结为缓存没有清理。
它实际上包含两层相互叠加的问题。
第一层:CSS 布局确实存在问题
页头搜索框原来设置了:
min-width: 250px;
在父级 Flex 容器空间不足时,搜索框无法继续缩小,最终把英文语言切换器推出页面。
正确修复方式是:
min-width: 0;
而不是使用:
transform: translateX(-17px);
强行把语言切换器向左移动。
第二层:W3TC Object Cache 仍然返回旧 CSS 对象
虽然后台已经保存了新的额外 CSS,数据库中的 wp_global_styles 也已经更新,但 W3TC Object Cache 仍然保存着旧的文章对象。
因此:
CSS 已经修改正确
↓
数据库已经更新
↓
get_post() 仍然返回旧对象
↓
WordPress 继续生成旧 CSS
↓
英文前台仍然存在横向滚动条
只有执行:
clean_post_cache(17390);
清理对应的对象缓存后,真正的 CSS 修复才开始生效。
十八、与上一篇 Polylang 多域名迁移问题的联系
这并不是我第一次在 Polylang 多域名模式下遇到 W3TC 缓存异常。
上一篇文章记录的迁移过程中,实际上连续出现了两个问题。
第一个问题:W3TC Page Cache 将英文域名识别成 foreign domain
当时访问:
https://en.shuijingwanwq.com/
会被 301 跳转回:
https://www.shuijingwanwq.com/
最终确认跳转来自:
W3TC\PgCache_Plugin->redirect_on_foreign_domain
也就是说,W3 Total Cache Page Cache 按照 WordPress 主站域名判断请求,没有正确把 Polylang 配置的英文语言域名视为合法域名。
最终,我通过一个 mu-plugin,为 Polylang 已配置的语言域名移除了这项 foreign domain 跳转。
修复后:
en.shuijingwanwq.com
不再跳回:
www.shuijingwanwq.com
第二个问题:W3TC Object Cache 缓存了旧的 Polylang 配置
301 问题解决后,访问英文子域名时又出现了另一个问题:
<html lang="zh-CN">
Canonical 也仍然指向:
https://www.shuijingwanwq.com/
这说明请求虽然已经进入:
en.shuijingwanwq.com
但 WordPress 运行时仍然把它识别成中文主站。
数据库中的 Polylang 配置已经更新为:
force_lang = 3
domains[en] = https://en.shuijingwanwq.com
domains[zh] = https://www.shuijingwanwq.com
但 WordPress 运行时读取到的仍然是旧配置:
force_lang = 1
domains[en] =
domains[zh] = https://www.shuijingwanwq.com
pll_home_url_en = https://www.shuijingwanwq.com/en/
这说明 W3TC Object Cache 中仍然保存着旧的 Polylang option。
当时我直接执行:
redis-cli FLUSHALL
输出:
OK
清理后,WordPress 运行时才恢复为正确配置:
force_lang = 3
domains[en] = https://en.shuijingwanwq.com
domains[zh] = https://www.shuijingwanwq.com
pll_home_url_en = https://en.shuijingwanwq.com/
pll_home_url_zh = https://www.shuijingwanwq.com/
需要特别说明:
如果一个 Redis 实例同时被多个网站或多个业务使用,不建议直接执行
FLUSHALL。
FLUSHALL 会清空整个 Redis 实例中的所有数据库和缓存。
我当时这样处理,是因为该 Redis 实例主要用于当前 WordPress 网站,对其他业务的影响可控。
十九、两次故障的准确关系
因此,不能把两次故障简单概括为:
第一次:Page Cache 问题
第二次:Object Cache 问题
更准确的关系是:
第一次迁移过程中:
1. W3TC Page Cache
将 Polylang 英文域名识别成 foreign domain。
2. W3TC Object Cache
保留了旧的 Polylang option。
这一次横向滚动条问题:
3. W3TC Object Cache
保留了旧的 wp_global_styles post 对象。
两次 W3TC Object Cache 异常影响的是不同类型的数据:
第一次:
Polylang option
这一次:
wp_global_styles post object
但它们的证据链高度相似:
数据库原始内容已经更新
↓
WordPress API 运行时仍然返回旧内容
↓
清理 W3TC Object Cache 后恢复正常
第一次导致的是:
英文域名识别错误
<html lang> 错误
Canonical 错误
英文首页 URL 错误
这一次导致的是:
全局 CSS 继续使用旧版本
搜索框 min-width 修改不生效
英文文章持续出现横向滚动条
二十、当前能够确认的 W3TC 缓存问题
结合前后两次排查,目前已经能够确认三个具体问题。
1. Page Cache 对 Polylang 语言域名识别异常
en.shuijingwanwq.com
↓
redirect_on_foreign_domain
↓
www.shuijingwanwq.com
该问题最终通过 mu-plugin 补丁解决。
2. Object Cache 保留旧的 Polylang option
数据库:
force_lang = 3
WordPress 运行时:
force_lang = 1
清理 Redis 后:
force_lang = 3
3. Object Cache 保留旧的 wp_global_styles 对象
数据库 post_content:
min-width: 0
get_post(17390):
min-width: 250px
clean_post_cache(17390) 后:
min-width: 0
这里不再需要继续假设 Redis 缓存键是否包含 Host,也不需要把问题归因于独立的 Redis Object Cache 插件。
当前站点启用的是:
W3 Total Cache Object Cache
Redis 是其缓存后端。
而这两次对象缓存问题的共同事实是:
WordPress 数据库已经更新,但 W3TC Object Cache 仍然返回旧的 option 或 post 对象。
至于为什么正常保存操作没有让对应对象及时失效,仍然需要结合 W3TC 的对象缓存实现继续分析。
但对于这次故障的定位和修复来说,证据已经足够完整。
二十一、排查这类问题时的建议顺序
以后如果再次遇到“后台已经修改,但前台始终不更新”的问题,可以按照下面的顺序排查。
1. 先确认真实的前端问题
不要一开始就用:
overflow-x: hidden;
或者:
transform: translateX(...);
掩盖布局问题。
应该先通过浏览器控制台找到真正超出视口的元素及其父级容器。
2. 查看前台实际输出的源代码
确认浏览器当前拿到的是旧 CSS,还是新 CSS。
3. 排除 CDN 边缘缓存
查看:
cf-cache-status
age
cache-control
必要时添加随机查询参数。
4. 直接请求源站
使用:
curl --resolve
区分 CDN 问题与源站问题。
5. 对比数据库和 WordPress API 返回值
例如:
数据库 SQL 原始值
get_option() 返回值
get_post() 返回值
wp_get_global_stylesheet() 返回值
如果数据库是新值,但 WordPress API 返回旧值,就应该重点检查 Object Cache。
6. 优先精确清理对象
已知具体文章 ID 时,可以使用:
clean_post_cache($id);
而不是直接执行:
redis-cli FLUSHALL
只有在无法确定具体缓存对象,并且 Redis 实例影响范围可控时,才考虑清空整个 Redis。
总结
这次英文文章横向滚动条问题的完整链路是:
页头搜索框 min-width: 250px
↓
搜索框和英文语言切换器
无法同时装进父级 Flex 容器
↓
英文页面出现横向滚动条
↓
将搜索框改为 min-width: 0
↓
数据库中的 wp_global_styles 更新成功
↓
W3TC Object Cache 仍然返回旧 post 对象
↓
get_post() 继续得到 min-width: 250px
↓
英文前台继续输出旧 CSS
↓
clean_post_cache() 清理指定对象
↓
WordPress 重新读取数据库中的新 CSS
↓
英文页面横向滚动条消失
结合上一篇 Polylang 多域名迁移排查,目前已经遇到:
W3TC Page Cache 多域名识别问题
W3TC Object Cache 缓存旧 Polylang option
W3TC Object Cache 缓存旧 wp_global_styles post
这也说明,在 WordPress 多域名环境中,看到前台内容没有更新时,不能只检查:
浏览器缓存
Cloudflare 缓存
Nginx 缓存
W3TC Page Cache
还应该继续比较:
数据库原始内容
get_option() 返回内容
get_post() 返回内容
wp_get_global_stylesheet() 生成内容
W3TC Object Cache 中的对象
尤其是在下面这种架构中:
后台固定使用主域名
不同语言使用独立域名
多个域名共享同一个 WordPress
多个域名共享同一个数据库
多个域名共享同一个 W3TC Object Cache
“数据库已经更新”和“所有语言页面运行时都已经读取到新数据”,并不是同一件事。
需要长期技术维护或远程问题排查?
我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。
如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:
- ✅ PHP / Laravel / Yii2 老项目无人维护
- ✅ Go / Gin 后端接口需要排查或优化
- ✅ WordPress 网站访问慢、报错或插件冲突
- ✅ Nginx / MySQL / Redis / Linux 服务器异常
- ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
- ✅ 需要长期远程技术支持或兼职维护
更多介绍请查看:关于我 & 合作
微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

发表回复