WordPress自定义文章类型产品按两个ACF价格字段排序
自定义文章类型按ACF价格(含促销价)排序解决方案
嘿,我明白你想要实现的效果:让自定义文章类型的产品按照「实际售卖价格」排序——也就是有促销价(price_sale)的用促销价排,没有的就用原价(price)排。你的现有查询参数没法直接搞定这个,因为WordPress默认的orderby不支持动态从两个meta字段里选一个作为排序依据,咱们得用点SQL技巧来实现。
下面是一步步的实现方法:
1. 调整WP_Query的基础参数
首先,你的meta_query不用强制同时匹配price和price_sale(毕竟不是所有产品都有促销价对吧)。我们只需要确保price字段存在,price_sale是可选的。调整后的参数如下:
$args = array( 'post_type' => 'your_custom_post_type', // 替换成你的自定义文章类型slug 'tax_query' => array( // 替换成你的分类筛选逻辑 array( 'taxonomy' => 'categories', 'field' => 'slug', 'terms' => 'sofas', ), ), 'meta_query' => array( 'relation' => 'OR', // 匹配有促销价的产品 array( 'key' => 'price_sale', 'compare' => 'EXISTS', 'type' => 'NUMERIC', ), // 匹配只有原价的产品(确保原价存在) array( 'key' => 'price', 'compare' => 'EXISTS', 'type' => 'NUMERIC', ), ), // 先填一个占位的orderby,后面会用过滤器修改 'orderby' => 'meta_value_num', 'order' => 'ASC', );
2. 用posts_orderby过滤器自定义排序逻辑
WordPress允许我们通过posts_orderby过滤器修改查询的排序SQL,这正是我们需要的。我们可以用SQL的CASE语句来动态选择排序的价格字段:
add_filter('posts_orderby', 'custom_price_sort_order', 10, 2); function custom_price_sort_order($orderby, $query) { // 只针对我们的目标查询生效,别影响其他查询 if (!isset($query->query['post_type']) || $query->query['post_type'] !== 'your_custom_post_type') { return $orderby; } global $wpdb; // 核心逻辑:如果有有效的price_sale,用它;否则用price,然后升序排列 $orderby = " CASE WHEN (SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = {$wpdb->posts}.ID AND meta_key = 'price_sale') > 0 THEN (SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = {$wpdb->posts}.ID AND meta_key = 'price_sale') ELSE (SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = {$wpdb->posts}.ID AND meta_key = 'price') END ASC "; return $orderby; }
3. 执行查询并清理过滤器
执行查询后,记得移除这个过滤器,避免干扰后续的WordPress查询:
$products_query = new WP_Query($args); // 移除过滤器,防止影响其他查询 remove_filter('posts_orderby', 'custom_price_sort_order'); // 循环输出结果 if ($products_query->have_posts()) { while ($products_query->have_posts()) { $products_query->the_post(); $price = get_field('price'); $sale_price = get_field('price_sale'); $display_price = !empty($sale_price) && $sale_price > 0 ? $sale_price : $price; echo get_the_title() . ' - ' . $display_price . '$<br>'; } wp_reset_postdata(); }
一些细节调整:
- 如果你的
price_sale字段允许为空字符串(而不是0),可以把CASE里的判断改成WHEN (SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = {$wpdb->posts}.ID AND meta_key = 'price_sale') != '' - 如果你想按降序排序,把
END ASC改成END DESC就可以了
这样设置后,所有产品都会按照各自的实际售卖价格(促销价优先,原价兜底)升序排列,完全符合你想要的排序逻辑。
内容的提问来源于stack exchange,提问作者Plikard
相关产品推荐
相关产品推荐

