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

WordPress 英文站出现横向滚动条:排查 Polylang 多域名下 W3TC Object Cache 缓存旧 CSS 的问题

【图 7,数据库原始内容与 get_post() 返回内容不一致】

WordPress CDN 与全球加速实战

图16:浏览器访问正常,网站全球访问成功

(1) 从阿里云 DNS 到 Cloudflare 全球加速的完整迁移实战记录

这一套规则遵循 Cloudflare + WordPress 标准 CDN 架构:

(2) Cloudflare SSL/TLS 与 Cache Rules 配置实战

图12:评论实时生效

(3) WordPress + Cloudflare 推荐配置与 Cache Rules 实战优化(SSL / API / 缓存闭环完整记录)

CDN上线后的boce数据

(4) CDN 上线前后性能对比实测:WordPress 缓存误判修正与真实加速效果验证

【图9:boce 测试 cn-test,灰云直连阿里云 ECS,平均响应 0.478s】

(5) Cloudflare 免费版适合中国大陆 WordPress 主站吗?从缓存 HIT 到灰云直连阿里云 ECS 的实测复盘

【图1:腾讯云 EdgeOne 产品页,选择“立即使用”】

(6) 从 Cloudflare Free 迁移到腾讯云 EdgeOne:一次 WordPress 主站国内外加速实战

【图2:EdgeOne 上线后 boce 第二次测试,平均响应 0.354s,不可访问 2 个】

(7) Cloudflare Free 迁移到 EdgeOne 后到底快了多少?WordPress CDN 三阶段 boce 与 WebPageTest 实测对比

[图2,EdgeOne 昨日 L7 访问流量,显示 6.56 GB]

(8) EdgeOne 流量成本排查:将 WordPress uploads 静态资源迁移到 Cloudflare media 子域名

【图3,EdgeOne 301 请求的 URL Path 排行,集中在 /wp-content/uploads/ 图片路径】

(9) WordPress 图片迁移到 media 子域名后,EdgeOne 仍然出现大量 301 的排查与处理记录

图4:Cloudflare Edge TTL 配置、Cloudflare Browser TTL 配置

(10) WordPress Media CDN 迁移后的 Cloudflare Cache Rules 调整记录

[图4:EdgeOne 按 URL path 开始于 /en/ 筛选后的流量截图]

(11) EdgeOne 流量成本控制决策:是否将英文站从 /en/ 迁移到 en.shuijingwanwq.com

[图3:执行核心升级时返回 524 No Reason Phrase]

(12) WordPress 核心升级反复 524 与“另一更新正在进行”的排查记录

【图 10:新证书 SAN 信息截图,显示已经包含 en.shuijingwanwq.com】

(13) OneinStack 现有 Nginx 虚拟主机追加域名并重签 SSL 证书的一次实操记录

【图 8,curl 验证 www 与 en 的 html lang、canonical 均正确】

(14) WordPress Polylang 英文站从 /en/ 迁移到 en 子域名:W3TC 与 Redis 缓存问题排查

【图 14,最终回归验证:en 首页和文章页 Cloudflare HIT,lang 与 canonical 正确】

(15) 将 Polylang 英文子域名接入 Cloudflare:HTML 缓存、登录绕过与后台入口收敛

【图1:浏览器开发者工具中,旧 /en/ 首页返回 301,随后成功加载 en 子域名英文首页】

(16) WordPress 英文站从 /en/ 迁移到 en 子域名:兼容数千条 Nginx 旧规则并避免二次 301

【图 7,数据库原始内容与 get_post() 返回内容不一致】

(17) WordPress 英文站出现横向滚动条:排查 Polylang 多域名下 W3TC Object Cache 缓存旧 CSS 的问题

这篇文章是此前 Polylang 多域名迁移排查的后续记录。

上一篇文章:

Plaintext
https://www.shuijingwanwq.com/2026/07/10/19280/

在上一篇文章中,我将英文站从原来的 /en/ 路径迁移到了独立子域名:

Plaintext
中文站:https://www.shuijingwanwq.com/
英文站:https://en.shuijingwanwq.com/

迁移过程中,我已经遇到过两类与缓存有关的问题:

  1. W3 Total Cache Page Cache 将 Polylang 的英文语言域名识别成 foreign domain,导致 en 被 301 跳回 www
  2. 301 问题解决后,W3 Total Cache Object Cache 中仍然保留旧的 Polylang 配置,导致英文子域名运行时继续被识别成中文站。

这一次,最初遇到的只是一个看起来很普通的前端问题:英文文章页面底部出现了横向滚动条。

但排查到最后发现,除了真实存在的 CSS 布局问题之外,W3 Total Cache Object Cache 使用 Redis 保存的旧对象,也导致新 CSS 长时间无法在英文站生效。


一、当前网站结构

当前 WordPress 使用 Polylang 的多域名模式:

Plaintext
中文站:www.shuijingwanwq.com
英文站:en.shuijingwanwq.com
WordPress 后台:www.shuijingwanwq.com/wp-admin/

两个域名指向同一个 WordPress 根目录,并共享:

Plaintext
同一套 WordPress 程序
同一个数据库
同一套 Twenty Twenty-Five 主题
同一套插件
同一个 Redis 实例

当前启用的缓存组合包括:

Plaintext
W3 Total Cache Page Cache
W3 Total Cache Object Cache
Redis
Cloudflare

这里需要明确一下:

本站使用的是 W3 Total Cache 提供的 Object Cache 功能,Redis 是对象缓存的存储后端。

因此,本文后续统一使用:

Plaintext
W3TC Object Cache(Redis 后端)

而不是把它描述成一个独立的 Redis Object Cache 插件。


二、问题现象:只有英文文章出现横向滚动条

出现问题的英文文章是:

Plaintext
https://en.shuijingwanwq.com/2026/07/11/19327/

其对应的中文文章是:

Plaintext
https://www.shuijingwanwq.com/2026/07/11/19309/

中文文章显示正常,但英文页面底部出现了一条横向滚动条。

【图 1,英文文章页面底部出现横向滚动条】
【图 1,英文文章页面底部出现横向滚动条】

由于两个页面使用的是同一个主题和同一套模板,最开始怀疑的对象包括:

Plaintext
英文长标题
超长 URL
代码块
表格
AdSense iframe
搜索框
语言切换器
额外 CSS

单纯通过肉眼观察,很难确定究竟是哪一个元素把页面撑宽了。


三、通过 JavaScript 找出超出视口的元素

我先打开英文文章页面,按 F12 进入浏览器开发者工具,然后在“控制台”中执行下面的代码:

JavaScript
(() => {
    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;
})();

检测结果显示:

Plaintext
viewportWidth: 1405
pageScrollWidth: 1422
overflowWidth: 17

也就是说,页面总宽度比浏览器可视区域多出了 17px。

在检测结果中,最右侧的元素是:

Plaintext
nav.tepll-pll-language-switcher
【图 2,控制台检测到语言切换器超出视口 17px】
【图 2,控制台检测到语言切换器超出视口 17px】

四、语言切换器只是最右侧元素,不一定是根因

为了验证语言切换器是否就是问题来源,我临时在控制台中把它向左移动了 17px:

JavaScript
const el = document.querySelector(
    'nav.tepll-pll-language-switcher'
);

el.style.setProperty(
    'transform',
    'translateX(-17px)',
    'important'
);

执行后,页面底部的横向滚动条立即消失。

不过,这只能说明语言切换器是页面中最靠右的元素。

它并不能证明语言切换器本身就是导致布局溢出的根因。

如果直接把下面的代码加入正式 CSS:

CSS
transform: translateX(-17px);

虽然可以让滚动条消失,但本质上只是使用固定偏移量补偿布局错误。

因此,我没有把这种方式作为最终修复方案。


五、检查语言切换器及其父级容器

接下来,我检查了语言切换器及其父级元素的实际宽度。

控制台结果显示,语言切换器所在的 Flex 父容器:

Plaintext
clientWidth: 397px
scrollWidth: 429px

也就是说:

Plaintext
父容器可用宽度:397px
内部元素所需宽度:429px
内部溢出宽度:约 32px
【图 3,父容器 clientWidth 为 397、scrollWidth 为 429】
【图 3,父容器 clientWidth 为 397、scrollWidth 为 429】

查看当时的额外 CSS,可以发现页头搜索框使用了:

CSS
.wp-block-search {
    flex: 3 1 0;
    min-width: 250px;
    margin: 0 10px;
}

语言切换器本身大约需要:

Plaintext
160px

搜索框和语言切换器最低占用空间大约是:

Plaintext
搜索框最小宽度:250px
搜索框左边距:10px
搜索框右边距:10px
语言切换器宽度:160px

合计:430px

而它们所在的父容器实际只有:

Plaintext
397px

这与控制台检测到的:

Plaintext
scrollWidth: 429px

基本吻合。

因此,真实的 CSS 布局问题是:

搜索框设置了 min-width: 250px,导致 Flex 空间不足时搜索框无法继续缩小,最终把英文语言切换器推出了父容器。

英文单词 English 占用的宽度比中文语言名称更大,所以英文页面更容易暴露这个问题。


六、修改页头搜索框的最小宽度

我将原来的规则:

CSS
.wp-block-search {
    flex: 3 1 0;
    min-width: 250px;
    margin: 0 10px;
}

调整为:

CSS
@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. 允许搜索框继续收缩

原来是:

CSS
min-width: 250px;

修改为:

CSS
min-width: 0;

这样,当 Flex 父容器空间不足时,搜索框可以继续缩小,不会强制占用至少 250px。

2. 将作用范围限制在页头

原来的选择器:

CSS
.wp-block-search

会影响网站中的所有搜索区块。

修改后:

CSS
header.wp-block-template-part .wp-block-search

只会影响页头中的搜索框,不会干扰侧边栏、正文或其他模板中的搜索区块。

正常情况下,保存额外 CSS 后,英文页面的横向滚动条应该立即消失。

但实际保存后,页面仍然没有发生变化。


七、后台已经保存新 CSS,英文页面却仍输出旧规则

查看英文页面源代码后,我发现前台仍然输出旧规则:

CSS
.wp-block-search {
    flex: 3 1 0;
    min-width: 250px;
    margin: 0 10px;
}

但 WordPress 后台保存的内容已经是:

CSS
header.wp-block-template-part .wp-block-search {
    flex: 3 1 0;
    min-width: 0;
    margin: 0 10px;
}

也就是说:

Plaintext
后台已经保存新 CSS
数据库内容已经更新
英文前台仍然输出旧 CSS
【图 4,后台额外 CSS 已修改,但英文源代码仍显示 min-width: 250px】
【图 4,后台额外 CSS 已修改,但英文源代码仍显示 min-width: 250px】

到这里,问题已经不再只是 CSS 布局本身,而是:

为什么 WordPress 前台没有读取到数据库中已经保存的新 CSS?


八、后台清除 W3TC 缓存后,英文页面仍未更新

当前 WordPress 后台统一使用:

Plaintext
https://www.shuijingwanwq.com/wp-admin/

为了收敛后台入口,访问:

Plaintext
https://en.shuijingwanwq.com/wp-admin/

时,会被 301 跳转到主域名后台。

我在 www 后台执行了 W3 Total Cache 的“清除全部缓存”,但英文页面仍然输出旧 CSS。

这时最初怀疑:

Polylang 使用不同域名后,从主域名后台执行 W3TC 缓存清理,可能没有完整更新英文语言域名的缓存。

不过,后续排查证明,这次真正残留的不是 Cloudflare 边缘缓存,而是 W3TC Object Cache 中的旧对象。


九、排除 Cloudflare 边缘缓存

为了排除 Cloudflare 缓存,我给英文文章 URL 添加了随机查询参数,并检查响应头:

Bash
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:"

返回结果:

Plaintext
HTTP/2 200
server: cloudflare
cache-control: max-age=14400
cf-cache-status: MISS

其中:

Plaintext
cf-cache-status: MISS

说明这次请求没有直接命中 Cloudflare 边缘节点中的旧缓存,而是重新向源站获取了页面。

但返回的 HTML 中仍然包含:

CSS
min-width: 250px;

因此可以确认:

Plaintext
浏览器缓存不是根因
Cloudflare 边缘缓存也不是根因
源站返回的内容本身就是旧 CSS
【图 5,Cloudflare 返回 MISS,但 HTML 中仍然包含旧 CSS】
【图 5,Cloudflare 返回 MISS,但 HTML 中仍然包含旧 CSS】

十、检查 W3TC 的多域名页面缓存目录

W3 Total Cache Page Cache 会在下面的目录中保存页面缓存:

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

进入该目录后,可以看到两个语言域名对应的独立目录:

Plaintext
en.shuijingwanwq.com
www.shuijingwanwq.com

英文域名目录中也有完整的缓存结构:

Plaintext
2014
2018
2019
2021
2025
2026
category
series
tag
【图 6,page_enhanced 下同时存在 en 和 www 缓存目录】
【图 6,page_enhanced 下同时存在 en 和 www 缓存目录】

这说明 W3TC Page Cache 会按照请求 Host 分别保存两个域名的 HTML 页面缓存。

不过,在英文缓存目录中,没有找到直接以文章 ID 19327 命名的缓存路径。

因此,这次不能简单通过删除某个 19327 目录来解决问题。

后续直接绕过 Cloudflare访问源站,返回的仍然是旧 CSS,也说明问题已经进入 WordPress 运行时和对象缓存层。


十一、绕过 Cloudflare,直接请求源站

为了确认旧 CSS 是否来自源站,我在服务器中使用 --resolve,让英文域名直接解析到本机 Nginx:

Bash
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:

Bash
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

输出:

Plaintext
===== 直接访问源站 =====
包含 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; }

这一步证明:

Plaintext
Cloudflare 返回的是旧 CSS
直接访问源站同样返回旧 CSS

因此,问题位于 WordPress 运行时,而不是 Cloudflare。


十二、查询数据库中的 wp_global_styles

Twenty Twenty-Five 是区块主题。

通过站点编辑器保存的全局样式和额外 CSS,会保存在 wp_global_styles 类型的文章记录中。

我使用下面的 PHP 脚本查询数据库:

Bash
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

输出:

Plaintext
ID=17390
type=wp_global_styles
status=publish
name=wp-global-styles-twentytwentyfive
title=Custom Styles
old250=NO
new0=YES

这说明数据库中的 wp_global_styles 已经是新版本:

Plaintext
min-width: 0

数据库中也没有另一条仍然包含 min-width: 250px 的 Twenty Twenty-Five 全局样式记录。

因此,问题不是 CSS 没有保存,也不是数据库中存在两份新旧全局样式。


十三、WordPress 运行时仍然生成旧 CSS

接下来,我通过 PHP 直接加载 WordPress,并模拟英文域名请求:

Bash
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

输出:

Plaintext
CSS length: 39474
包含 min-width: 0:NO
包含 min-width: 250px:YES

匹配到的搜索框规则:
.wp-block-search { flex: 3 1 0; min-width: 250px; margin: 0 10px; }

这时已经可以确认:

Plaintext
数据库里是新版 CSS
WordPress 运行时仍然生成旧版 CSS

由于当前站点启用了 W3 Total Cache Object Cache,并使用 Redis 作为缓存后端,因此接下来重点检查 W3TC Object Cache 返回的对象内容。


十四、对比数据库原始值与 get_post() 返回值

为了确认对象缓存是否陈旧,我继续对比:

  1. 直接通过 SQL 读取数据库;
  2. 通过 WordPress get_post() 读取;
  3. 当前是否正在使用外部对象缓存。

执行:

Bash
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

输出:

Plaintext
使用外部对象缓存:YES

===== 数据库原始内容 =====
长度:17407
min-width: 0:YES
min-width: 250px:NO

===== get_post() 返回内容 =====
长度:17317
min-width: 0:NO
min-width: 250px:YES

这个结果已经可以明确说明:

Plaintext
数据库中的 wp_global_styles 已经更新

W3TC Object Cache 中仍然保存旧的 post 对象

get_post(17390) 返回旧内容

WordPress 运行时继续生成旧 CSS
【图 7,数据库原始内容与 get_post() 返回内容不一致】
【图 7,数据库原始内容与 get_post() 返回内容不一致】

这里已经不需要继续猜测 Cloudflare、Nginx 或浏览器缓存。

数据库原始内容与 get_post() 返回内容不一致,而清理对象缓存后恢复正常,这已经直接证明问题发生在 WordPress 对象缓存层。


十五、精确清理 wp_global_styles 对象缓存

由于已经确认出现问题的是:

Plaintext
wp_global_styles ID:17390

所以这一次没有直接执行:

Bash
redis-cli FLUSHALL

而是通过 WordPress API,只清理这条文章对象缓存以及 Theme JSON 相关缓存:

Bash
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

输出:

Plaintext
已清理对象缓存。
get_post() 包含 min-width: 0:YES
get_post() 包含 min-width: 250px:NO

这说明 W3TC Object Cache 中旧的 wp_global_styles 文章对象已经被清理,WordPress 重新读取到了数据库中的新内容。

【图 8,执行 clean_post_cache 后 get_post() 已读取新版 CSS】
【图 8,执行 clean_post_cache 后 get_post() 已读取新版 CSS】

需要注意:

Plaintext
17390

只是我当前网站中对应的 wp_global_styles 记录 ID。

其他网站不能直接照搬这个 ID,必须先查询自己站点数据库中的实际记录。


十六、再次验证公网英文页面

最后,在本地电脑中重新请求英文页面:

Bash
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)
'

输出:

Plaintext
包含 min-width: 0:True
包含 min-width: 250px:False

重新打开英文文章页面后,底部的横向滚动条已经消失。

【图 9,英文文章横向滚动条消失,页面恢复正常】
【图 9,英文文章横向滚动条消失,页面恢复正常】

十七、这次问题实际包含两层原因

这次故障不能简单归结为语言切换器样式,也不能简单归结为缓存没有清理。

它实际上包含两层相互叠加的问题。

第一层:CSS 布局确实存在问题

页头搜索框原来设置了:

CSS
min-width: 250px;

在父级 Flex 容器空间不足时,搜索框无法继续缩小,最终把英文语言切换器推出页面。

正确修复方式是:

CSS
min-width: 0;

而不是使用:

CSS
transform: translateX(-17px);

强行把语言切换器向左移动。

第二层:W3TC Object Cache 仍然返回旧 CSS 对象

虽然后台已经保存了新的额外 CSS,数据库中的 wp_global_styles 也已经更新,但 W3TC Object Cache 仍然保存着旧的文章对象。

因此:

Plaintext
CSS 已经修改正确

数据库已经更新

get_post() 仍然返回旧对象

WordPress 继续生成旧 CSS

英文前台仍然存在横向滚动条

只有执行:

PHP
clean_post_cache(17390);

清理对应的对象缓存后,真正的 CSS 修复才开始生效。


十八、与上一篇 Polylang 多域名迁移问题的联系

这并不是我第一次在 Polylang 多域名模式下遇到 W3TC 缓存异常。

上一篇文章记录的迁移过程中,实际上连续出现了两个问题。

第一个问题:W3TC Page Cache 将英文域名识别成 foreign domain

当时访问:

Plaintext
https://en.shuijingwanwq.com/

会被 301 跳转回:

Plaintext
https://www.shuijingwanwq.com/

最终确认跳转来自:

Plaintext
W3TC\PgCache_Plugin->redirect_on_foreign_domain

也就是说,W3 Total Cache Page Cache 按照 WordPress 主站域名判断请求,没有正确把 Polylang 配置的英文语言域名视为合法域名。

最终,我通过一个 mu-plugin,为 Polylang 已配置的语言域名移除了这项 foreign domain 跳转。

修复后:

Plaintext
en.shuijingwanwq.com

不再跳回:

Plaintext
www.shuijingwanwq.com

第二个问题:W3TC Object Cache 缓存了旧的 Polylang 配置

301 问题解决后,访问英文子域名时又出现了另一个问题:

HTML
<html lang="zh-CN">

Canonical 也仍然指向:

Plaintext
https://www.shuijingwanwq.com/

这说明请求虽然已经进入:

Plaintext
en.shuijingwanwq.com

但 WordPress 运行时仍然把它识别成中文主站。

数据库中的 Polylang 配置已经更新为:

Plaintext
force_lang = 3
domains[en] = https://en.shuijingwanwq.com
domains[zh] = https://www.shuijingwanwq.com

但 WordPress 运行时读取到的仍然是旧配置:

Plaintext
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。

当时我直接执行:

Bash
redis-cli FLUSHALL

输出:

Plaintext
OK

清理后,WordPress 运行时才恢复为正确配置:

Plaintext
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 网站,对其他业务的影响可控。


十九、两次故障的准确关系

因此,不能把两次故障简单概括为:

Plaintext
第一次:Page Cache 问题
第二次:Object Cache 问题

更准确的关系是:

Plaintext
第一次迁移过程中:

1. W3TC Page Cache
   将 Polylang 英文域名识别成 foreign domain。

2. W3TC Object Cache
   保留了旧的 Polylang option。


这一次横向滚动条问题:

3. W3TC Object Cache
   保留了旧的 wp_global_styles post 对象。

两次 W3TC Object Cache 异常影响的是不同类型的数据:

Plaintext
第一次:
Polylang option

这一次:
wp_global_styles post object

但它们的证据链高度相似:

Plaintext
数据库原始内容已经更新

WordPress API 运行时仍然返回旧内容

清理 W3TC Object Cache 后恢复正常

第一次导致的是:

Plaintext
英文域名识别错误
<html lang> 错误
Canonical 错误
英文首页 URL 错误

这一次导致的是:

Plaintext
全局 CSS 继续使用旧版本
搜索框 min-width 修改不生效
英文文章持续出现横向滚动条

二十、当前能够确认的 W3TC 缓存问题

结合前后两次排查,目前已经能够确认三个具体问题。

1. Page Cache 对 Polylang 语言域名识别异常

Plaintext
en.shuijingwanwq.com

redirect_on_foreign_domain

www.shuijingwanwq.com

该问题最终通过 mu-plugin 补丁解决。

2. Object Cache 保留旧的 Polylang option

Plaintext
数据库:
force_lang = 3

WordPress 运行时:
force_lang = 1

清理 Redis 后:
force_lang = 3

3. Object Cache 保留旧的 wp_global_styles 对象

Plaintext
数据库 post_content:
min-width: 0

get_post(17390):
min-width: 250px

clean_post_cache(17390) 后:
min-width: 0

这里不再需要继续假设 Redis 缓存键是否包含 Host,也不需要把问题归因于独立的 Redis Object Cache 插件。

当前站点启用的是:

Plaintext
W3 Total Cache Object Cache

Redis 是其缓存后端。

而这两次对象缓存问题的共同事实是:

WordPress 数据库已经更新,但 W3TC Object Cache 仍然返回旧的 option 或 post 对象。

至于为什么正常保存操作没有让对应对象及时失效,仍然需要结合 W3TC 的对象缓存实现继续分析。

但对于这次故障的定位和修复来说,证据已经足够完整。


二十一、排查这类问题时的建议顺序

以后如果再次遇到“后台已经修改,但前台始终不更新”的问题,可以按照下面的顺序排查。

1. 先确认真实的前端问题

不要一开始就用:

CSS
overflow-x: hidden;

或者:

CSS
transform: translateX(...);

掩盖布局问题。

应该先通过浏览器控制台找到真正超出视口的元素及其父级容器。

2. 查看前台实际输出的源代码

确认浏览器当前拿到的是旧 CSS,还是新 CSS。

3. 排除 CDN 边缘缓存

查看:

Plaintext
cf-cache-status
age
cache-control

必要时添加随机查询参数。

4. 直接请求源站

使用:

Bash
curl --resolve

区分 CDN 问题与源站问题。

5. 对比数据库和 WordPress API 返回值

例如:

Plaintext
数据库 SQL 原始值
get_option() 返回值
get_post() 返回值
wp_get_global_stylesheet() 返回值

如果数据库是新值,但 WordPress API 返回旧值,就应该重点检查 Object Cache。

6. 优先精确清理对象

已知具体文章 ID 时,可以使用:

PHP
clean_post_cache($id);

而不是直接执行:

Bash
redis-cli FLUSHALL

只有在无法确定具体缓存对象,并且 Redis 实例影响范围可控时,才考虑清空整个 Redis。


总结

这次英文文章横向滚动条问题的完整链路是:

Plaintext
页头搜索框 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 多域名迁移排查,目前已经遇到:

Plaintext
W3TC Page Cache 多域名识别问题
W3TC Object Cache 缓存旧 Polylang option
W3TC Object Cache 缓存旧 wp_global_styles post

这也说明,在 WordPress 多域名环境中,看到前台内容没有更新时,不能只检查:

Plaintext
浏览器缓存
Cloudflare 缓存
Nginx 缓存
W3TC Page Cache

还应该继续比较:

Plaintext
数据库原始内容
get_option() 返回内容
get_post() 返回内容
wp_get_global_stylesheet() 生成内容
W3TC Object Cache 中的对象

尤其是在下面这种架构中:

Plaintext
后台固定使用主域名
不同语言使用独立域名
多个域名共享同一个 WordPress
多个域名共享同一个数据库
多个域名共享同一个 W3TC Object Cache

“数据库已经更新”和“所有语言页面运行时都已经读取到新数据”,并不是同一件事。

WordPress 英文站从 /en/ 迁移到 en 子域名:兼容数千条 Nginx 旧规则并避免二次 301

需要长期技术维护或远程问题排查?

我是拥有 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

评论

发表回复

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

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