Woocommerce 8.x.x相关产品自定义问题:缓存与主类别筛选失效
WooCommerce相关产品自定义问题解决方案
问题1:强制存储自定义查询结果以降低服务器负载
要避免每次页面请求都执行自定义查询,可利用WordPress的Transient缓存机制持久化存储查询结果,具体实现如下:
- 缓存查询结果:根据当前产品ID、主类别及语言生成唯一缓存键,先检查是否存在对应缓存。若缓存有效,直接返回缓存的产品ID列表;若不存在,执行自定义查询后将结果存入Transient,设置合理过期时间(如24小时)。
- 缓存失效机制:在产品更新、类别调整时,通过
save_post_product、edited_term等钩子清除对应缓存,保证数据时效性。
示例代码片段(结合你的业务逻辑):
function custom_related_products_query( $query, $product_id ) { global $wpdb; // 生成唯一缓存键(包含语言标识适配多语言场景) $cache_key = 'related_products_main_cat_' . $product_id . '_' . get_locale(); $cached_ids = get_transient( $cache_key ); if ( $cached_ids ) { // 直接使用缓存构建查询结构 $query['fields'] = "SELECT DISTINCT ID FROM {$wpdb->posts} p WHERE p.ID IN (" . implode(',', $cached_ids) . ")"; $query['join'] = ''; $query['where'] = " AND p.post_status = 'publish' AND p.post_type = 'product'"; return $query; } // 获取产品主类别(使用WooCommerce官方方法) $main_category_id = wc_get_product_term_id( $product_id, 'product_cat' ); $main_category = get_term( $main_category_id, 'product_cat' ); if ( ! $main_category || is_wp_error( $main_category ) ) { return $query; } // 执行自定义查询获取相关产品ID $related_ids = $wpdb->get_col( "SELECT DISTINCT p.ID FROM {$wpdb->posts} p INNER JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE p.post_status = 'publish' AND p.post_type = 'product' AND p.ID != {$product_id} AND tt.taxonomy = 'product_cat' AND tt.term_id = {$main_category->term_id}" ); // 存储缓存,24小时后过期 set_transient( $cache_key, $related_ids, 24 * HOUR_IN_SECONDS ); // 构建最终查询结构返回 $query['fields'] = "SELECT DISTINCT ID FROM {$wpdb->posts} p WHERE p.ID IN (" . implode(',', $related_ids) . ")"; $query['join'] = ''; $query['where'] = " AND p.post_status = 'publish' AND p.post_type = 'product'"; return $query; } add_filter( 'woocommerce_product_related_posts_query', 'custom_related_products_query', 99, 2 );
问题2:强制相关产品取自同一主类别无效的排查思路
结合你提供的$query数组和代码,从以下维度排查:
1. 主类别获取逻辑错误
你当前通过$category->parent == 0判断顶级类别作为主类别,但WooCommerce中产品的主类别是用户在产品编辑页手动选择的(可能是子类别),而非默认顶级类别。应改用官方函数获取真正的主类别:
// 替换原有的主类别遍历逻辑 $main_category_id = wc_get_product_term_id( $product_id, 'product_cat' ); $main_category = get_term( $main_category_id, 'product_cat' );
2. 重复JOIN导致关联冲突
你的代码中追加了INNER JOIN {$wpdb->term_relationships}和INNER JOIN {$wpdb->term_taxonomy},但原$query的join字段已包含这些表的关联(从你提供的$query数组可见),重复关联会导致SQL逻辑错误,甚至返回空结果。建议直接修改原查询的WHERE条件,而非追加JOIN。
3. 钩子优先级被覆盖
你设置的钩子优先级为10,可能被其他插件或主题的同钩子逻辑覆盖。将优先级调高(如99),确保你的修改最后执行:
add_filter( 'woocommerce_product_related_posts_query', 'custom_related_products_query', 99, 2 );
4. 调试验证步骤
- 在函数中添加
var_dump($main_category),确认主类别是否正确获取; - 将最终生成的SQL语句(拼接
$query['fields'] + $query['join'] + $query['where'] + $query['limits'])复制到数据库管理工具执行,查看返回结果是否符合预期; - 检查多语言插件(如WPML,你的$query中包含
icl_translations表)干扰,确认语言过滤条件icl.language_code = 'fr'是否影响主类别下的产品筛选。
修改后的核心代码
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) { function custom_related_products_query( $query, $product_id ) { global $wpdb; $categories = get_the_terms( $product_id, 'product_cat' ); if ( empty( $categories ) || is_wp_error( $categories ) ) { return $query; } // 获取WooCommerce官方认定的主类别 $main_category_id = wc_get_product_term_id( $product_id, 'product_cat' ); $main_category = get_term( $main_category_id, 'product_cat' ); if ( ! $main_category || is_wp_error( $main_category ) ) { return $query; } // 清理原查询中多余的类别条件,添加主类别过滤 $query['where'] = preg_replace( '/AND WCCP_term_taxonomy\.term_id = \d+/', '', $query['where'] ); $query['where'] .= " AND {$wpdb->term_taxonomy}.taxonomy = 'product_cat' AND {$wpdb->term_taxonomy}.term_id = {$main_category->term_id}"; return $query; } // 提高优先级确保最后执行 add_filter( 'woocommerce_product_related_posts_query', 'custom_related_products_query', 99, 2 ); function custom_related_products_orderby( $orderby ) { return "p.ID DESC"; } add_filter( 'woocommerce_product_related_posts_orderby', 'custom_related_products_orderby', 10, 1 ); }
内容的提问来源于stack exchange,提问作者Teal_cfr
相关产品推荐
相关产品推荐

