一句话总结:一次被 LiteSpeed Cache 坑惨的 WooCommerce 分类。

最近折腾一个 WooCommerce 商店页时,遇到了一个看起来很简单、实际特别折磨人的问题。

商店首页顶部有一组商品分类入口,点击某个分类后会进入对应的商品分类页。正常来说,这组分类导航应该一直保留,方便用户继续切换其他分类。

问题偏偏就出在这里:

Shop 首页显示正常,一进入商品分类页,顶部分类导航就消失了。

更离谱的是,后来改完以后大部分分类恢复正常,唯独其中一个分类死活不显示,而且 PC、移动端一起出问题。

前前后后查了不少东西,最后发现真正把排查方向搅乱的,居然是 LiteSpeed Cache

把整个过程记下来,免得以后再踩一次。


一开始以为是分类页模板的问题

最开始看到的现象很直观:

在 Shop 页面:

  • 顶部 5 个分类正常
  • 图片正常
  • 点击正常

进入某个 Product Category 页面以后:

  • 商品列表正常
  • 筛选正常
  • 页面标题正常
  • 但顶部那组分类没了

第一反应自然是去主题设置里找。

于是把产品归档、Page Title、Product Categories 相关设置翻了一遍。

像什么:

  • 显示商品分类
  • 显示当前分类祖先
  • 隐藏空分类
  • 分类层级
  • 分类邻居

基本都试了一轮。

结果没什么用。

这时候其实已经开始有点不对劲了:后台设置看起来都是对的,但前台行为和设置完全对不上。


DevTools 反而把问题范围缩小了

后面没有继续盲点设置,而是直接用浏览器 DevTools 看页面到底生成了什么。

先在正常的 Shop 页面检查分类元素。

结果很明确:

category-grid-item = 5

也就是说,5 个分类都真实存在于 DOM 里。

继续往父级结构看,可以看到它们属于类似这样的结构:

category-grid-item
→ carousel item
→ product categories
→ column
→ row

这时就能确认一件事:

顶部这组东西不是简单的菜单,而是 Product Categories 动态区块。

然后再去异常的商品分类页跑同样的检查。

结果变成:

category-grid-item = 0

更关键的是,对应位置的外层 Column 还在:

children = 0
htmlLength = 0

这一下基本把 CSS 排除了。

如果只是:

display: none;

或者:

visibility: hidden;

元素应该还在 DOM 里。

现在是里面压根没有生成内容。

所以问题已经从:

“为什么这个分类导航看不见?”

缩小成了:

“为什么 Product Categories 动态区块在分类归档页没有输出?”

这比盲猜 CSS、响应式、图片加载靠谱得多。


真正的问题在 Product Archive Layout

继续往下查,发现网站实际上使用的是一个 Product Archive Layout。

这个 Layout 同时控制:

  • Shop
  • Product Category
  • 商品归档页

而顶部分类,就是 Layout 里的一个:

Product Categories Block

打开这个区块以后,看到一个很关键的选项:

Data source

原来使用的是:

WooCommerce Query

这里就开始说得通了。

WooCommerce Query 会根据当前归档页面的上下文动态查询。

在 Shop 首页时,没有具体的当前分类,于是它可以正常列出一级分类。

但进入某个具体 Product Category 后,查询上下文发生变化,最终可能拿不到想要的那组一级分类。

于是就出现:

Shop
→ 有分类

Product Category
→ 分类为空

对于“固定显示几个一级分类入口”这种需求,其实根本没必要让它跟着当前分类上下文跑。

于是改成:

Custom Query

并设置:

Count: 5
Order by: Menu order
Hide empty: Off

保存以后,大部分分类立刻恢复正常。

到这里本来以为结束了。

结果新的坑来了。


最诡异的一幕:只有一个分类还是坏的

改成 Custom Query 后:

  • Shop 正常
  • 分类 A 正常
  • 分类 B 正常
  • 分类 C 正常
  • 分类 D 正常
  • 唯独分类 E 还是不显示

这种情况特别容易让人怀疑:

  • 这个分类是不是父级不一样?
  • 是不是空分类?
  • 是不是 Display Type 不一样?
  • 是不是有独立 Layout?
  • 是不是 taxonomy metadata 有问题?

于是又把正常分类和异常分类逐项对比了一遍。

结果:

Parent = 0
Count = 1
Display type = Default

全部正常。

连分类层级都一样。

DevTools 再看一次:

正常分类页:

categoryItems: 5
catBlockExists: true

异常分类页:

categoryItems: 0
catBlockExists: false

又开始往 Gutenberg Block attributes、隐藏设置这些方向查。

甚至把区块真实保存的 attributes 都翻出来看了。

这里其实已经明显开始“查深了”。

最后才想起来一个最朴素的问题:

缓存清了吗?


最后发现:LiteSpeed Cache 一直在给旧页面续命

网站开着 LiteSpeed Cache。

之前异常分类页已经被访问过,所以 LiteSpeed 把那个“分类区块为空”的旧 HTML 缓存下来了。

之后虽然 Layout 已经改成 Custom Query:

旧配置
WooCommerce Query

↓

新配置
Custom Query

但那个分类 URL 仍然命中服务器缓存。

于是就出现一个极其迷惑的状态:

新访问的分类
→ 第一次生成
→ 使用新 Layout
→ 正常

之前访问过的异常分类
→ 命中旧缓存
→ 继续输出旧 HTML
→ 永远不正常

更坑的是:

Ctrl + F5 没用。

因为 Ctrl + F5 主要解决的是浏览器缓存。

LiteSpeed Cache 是服务器端页面缓存。

浏览器就算刷新一百遍,服务器还是可能把之前缓存好的 HTML 原样扔回来。

最后去:

LiteSpeed Cache
→ Toolbox
→ Purge
→ Purge All LSCache

清掉缓存。

再刷新。

好了。

PC 正常。

移动端正常。

所有分类都正常。

折腾半天,最后卡在缓存。


这次最值得记住的不是“清缓存”

如果只是总结成一句:

WordPress 出问题先清缓存。

那其实没什么价值。

真正有用的是排查顺序。

以后遇到类似:

后台已经改了,但前台行为很奇怪

可以先按下面这个顺序来。

1. 先看 DOM 到底有没有生成

不要第一时间改 CSS。

先确认:

元素存在,只是不可见

还是:

元素压根没有生成

这是两个完全不同的问题。

前者查:

  • CSS
  • JS
  • responsive state

后者查:

  • PHP
  • query
  • dynamic block
  • archive context
  • template condition

2. 动态区块一定要考虑“当前页面上下文”

尤其是 WooCommerce 归档页。

Shop 和 Product Category 看起来很像,但查询上下文根本不是一回事。

类似:

WooCommerce Query
Current Query
Current Taxonomy
Current Category

这种选项都意味着:

同一个 Block 在不同 URL 下可能得到完全不同的结果。

如果需求只是:

永远显示固定的几个一级分类

那 Custom Query 往往比自动跟随当前页面上下文更可控。


3. 一个页面异常、其他同类页面正常时,优先怀疑缓存

这是这次最容易忽略的信号。

假设有 5 个结构完全相同的分类:

4 个正常
1 个异常

并且:

  • Layout 一样
  • 分类配置一样
  • 数据一样
  • 页面结构理论上一样

这时候不要立刻往“这个分类是不是有什么神秘配置”上钻。

先问一句:

这个 URL 有没有可能缓存过旧版本?

尤其用了:

  • LiteSpeed Cache
  • Cloudflare
  • WP Rocket
  • Nginx FastCGI Cache
  • CDN Page Cache

这种东西时。


4. Ctrl + F5 不等于清服务器缓存

这次最大的认知坑就是这个。

简单说:

Ctrl + F5
≈ 浏览器别用本地旧资源

而:

Purge LiteSpeed Cache
≈ 服务器别再给我旧页面

根本不是一个层级。

以后改:

  • WooCommerce 分类
  • Archive Layout
  • Gutenberg 动态区块
  • 商品筛选
  • 模板条件
  • 页面 Builder

最好养成一个习惯:

保存
→ Purge LSCache
→ Ctrl + F5
→ 再测试

开发阶段甚至可以考虑暂时减少页面缓存干扰,等结构稳定以后再正式开启。


最后的方案

最终没有:

  • 改主题源码
  • 写 PHP
  • 注入 JS
  • 写 CSS Hack
  • 重做分类导航
  • 加额外插件

只用了原本就有的:

Product Archive Layout
→ Product Categories
→ Custom Query

然后把 LiteSpeed 的旧缓存清掉。

这也是我比较满意的结果。

遇到 WordPress 这类成熟系统时,能用主题和插件本身提供的能力解决,尽量别急着往源码上打补丁。

因为很多时候并不是功能做不到。

只是:

你改的是现在,缓存给你看的还是过去。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐