启用Redis对象缓存后get_terms的hide_empty参数失效问题
问题原因
核心触发点是Redis对象缓存的get_terms查询缓存键生成逻辑存在缺陷,和WordPress默认参数补全逻辑不兼容:
- 你的代码中没有显式传入
hide_empty参数,WordPress执行查询时会自动补全该参数的默认值true,但绝大多数Redis对象缓存插件生成terms查询缓存键时,仅识别代码中手动传入的参数,不会将WordPress自动补全的默认参数纳入缓存键计算维度。 - 站点内任意位置(包括后台渲染、其他插件/主题的自定义查询)只要曾经以
hide_empty=false的配置查询过相同父ID、相同分类法(product_cat)的分类列表,Redis就会把包含空分类的结果集写入缓存。后续你当前的查询因为没有显式传hide_empty,生成的缓存键和前述查询完全一致,会直接读取到包含空分类的错误缓存结果,常规刷新缓存的操作无法避免这个缓存键冲突问题,刷新后依然可能被其他请求提前写入错误缓存。 - 少数旧版本场景下,WooCommerce产品上下架、删除时没有同步更新Redis中存储的term计数缓存,会导致
hide_empty判断时读取到错误的分类关联产品数,把实际无关联产品的空分类判定为非空分类返回。
修复方案
按优先级依次尝试即可:
- 最稳妥的方案是不要依赖函数默认参数,在查询时显式声明所有核心参数,修改
$args数组明确传入hide_empty => true,让缓存插件能正确识别参数差异,生成独立的缓存键,避免和其他查询的缓存串用,修改后的代码如下:
$parentid = 182; $args = array( 'parent' => $parentid, 'hide_empty' => true, // 显式声明参数,规避缓存键冲突 ); $terms = get_terms( 'product_cat', $args ); if ( $terms ) { echo '<ul>'; foreach ( $terms as $term ) { echo '<li>'; echo '<a href="' . esc_url( get_term_link( $term ) ) . '" class="' . $term->slug . '">'; echo $term->name; echo '</a>'; echo '</li>'; } echo '</ul>'; }
- 如果显式传参后问题依然存在,先升级Redis对象缓存插件到最新版本,修复已知的缓存键生成bug;也可以将
terms缓存组配置为不持久化存储,避免跨请求的缓存污染。 - 兜底兼容方案:获取到terms列表后手动过滤空分类,不依赖
hide_empty的内置判断:
// 获取terms后增加过滤逻辑 foreach ( $terms as $index => $term ) { if ( (int) $term->count <= 0 ) { unset( $terms[$index] ); } }
内容的提问来源于stack exchange,提问作者Blue Li
相关产品推荐
相关产品推荐

