WooCommerce:如何将默认排序改为先按产品标签再按日期?
问题分析与解决方法
你的代码存在的问题
- 钩子使用错误:
woocommerce_default_catalog_orderby仅用于设置WooCommerce默认的排序选项(比如默认选择“最新”“价格”这类内置选项),无法自定义全新的复合排序规则,因此没法实现「先按产品标签、再按日期」的排序需求。 - 逻辑不符合需求:你的代码仅判断当前是否处于
my-tag标签页面时返回按日期排序,和你要的「所有商品分类下都先按标签排序、再按日期排序」的目标完全不匹配。
正确实现方案
要实现复合排序,需要直接修改WordPress查询的SQL子句,通过关联产品标签的数据库表来实现按标签排序,同时处理多标签商品的重复问题。
方案1:强制所有商品分类页面使用该排序规则
如果希望所有商品分类页面默认就采用「先按产品标签名称升序、再按发布日期降序」的排序,添加以下代码到主题的functions.php文件或自定义插件中:
// 强制商品分类页面商品按「标签名称+日期」排序 add_filter( 'posts_clauses', 'custom_category_product_sort', 10, 2 ); function custom_category_product_sort( $clauses, $query ) { // 仅在前端商品分类主查询中生效 if ( ! is_admin() && $query->is_main_query() && is_product_category() ) { global $wpdb; // 关联产品标签相关表,获取标签名称 $clauses['join'] .= " LEFT JOIN {$wpdb->term_relationships} tr ON {$wpdb->posts}.ID = tr.object_id"; $clauses['join'] .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id"; $clauses['join'] .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id = t.term_id"; // 去重:避免单个商品关联多个标签导致查询结果重复 $clauses['distinct'] = 'DISTINCT'; // 设置排序规则:先按标签名称升序,再按发布日期降序(可按需修改ASC/DESC) $clauses['orderby'] = "t.name ASC, {$wpdb->posts}.post_date DESC"; } return $clauses; }
方案2:添加自定义排序选项供用户选择
如果希望保留原有排序选项,同时新增「先按标签、再按日期」的选项让用户自行选择,可使用以下代码:
// 1. 向排序下拉菜单添加自定义选项 add_filter( 'woocommerce_catalog_orderby', 'add_tag_date_sort_option' ); function add_tag_date_sort_option( $options ) { $options['tag_then_date'] = '先按产品标签,再按日期'; return $options; } // 2. 当用户选择自定义选项时,应用对应的排序规则 add_filter( 'woocommerce_get_catalog_ordering_args', 'apply_tag_date_sort', 10, 1 ); function apply_tag_date_sort( $args ) { if ( isset( $_GET['orderby'] ) && 'tag_then_date' === $_GET['orderby'] ) { add_filter( 'posts_clauses', 'tag_date_sort_clauses', 10, 2 ); } return $args; } // 3. 定义排序对应的SQL子句修改逻辑 function tag_date_sort_clauses( $clauses, $query ) { if ( ! is_admin() && $query->is_main_query() ) { global $wpdb; $clauses['join'] .= " LEFT JOIN {$wpdb->term_relationships} tr ON {$wpdb->posts}.ID = tr.object_id"; $clauses['join'] .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id"; $clauses['join'] .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id = t.term_id"; $clauses['distinct'] = 'DISTINCT'; $clauses['orderby'] = "t.name ASC, {$wpdb->posts}.post_date DESC"; } return $clauses; }
说明
- 代码中的
ASC(升序)和DESC(降序)可根据需求调整,比如要按标签名称降序排序,就把t.name ASC改成t.name DESC。 - 由于单个商品可能关联多个标签,代码中添加了
DISTINCT去重,避免同一件商品多次出现在列表中。
内容的提问来源于stack exchange,提问作者Jan Radosta
相关产品推荐
相关产品推荐

