折扣商品自定义过滤器失效:页面刷新而非AJAX加载
修复折扣商品过滤器的排序与AJAX加载问题
一、解决商品显示与排序错误问题
你的代码存在两个核心问题:未筛选真正有折扣的商品、排序逻辑错误(按现价排序≠按折扣高低排序)。以下是修正后的代码:
function filter_products_by_discount( $query ) { // 仅对前台产品归档主查询生效 if ( ! is_admin() && $query->is_main_query() && is_post_type_archive('product') && isset( $_GET['discount_filter'] ) && ! empty( $_GET['discount_filter'] ) ) { // 筛选有折扣的商品:现价>0且小于原价 $meta_query = $query->get('meta_query'); $meta_query[] = array( 'relation' => 'AND', array( 'key' => '_sale_price', 'value' => 0, 'compare' => '>', 'type' => 'NUMERIC' ), array( 'key' => '_regular_price', 'value' => '_sale_price', 'compare' => '>', 'type' => 'NUMERIC' ) ); $query->set('meta_query', $meta_query); $discount_filter = $_GET['discount_filter']; if ( $discount_filter === 'highest' ) { add_filter( 'posts_orderby', 'orderby_discount_highest' ); // 用完即移除过滤器,避免影响其他查询 add_filter( 'posts_orderby', function() { remove_filter( current_filter(), __FUNCTION__ ); remove_filter( current_filter(), 'orderby_discount_highest' ); }); } elseif ( $discount_filter === 'lowest' ) { add_filter( 'posts_orderby', 'orderby_discount_lowest' ); add_filter( 'posts_orderby', function() { remove_filter( current_filter(), __FUNCTION__ ); remove_filter( current_filter(), 'orderby_discount_lowest' ); }); } } } add_action( 'pre_get_posts', 'filter_products_by_discount' ); // 按折扣率从高到低排序:(原价-现价)/原价 降序 function orderby_discount_highest( $orderby ) { global $wpdb; return "(({$wpdb->postmeta}.meta_value - (SELECT meta_value FROM {$wpdb->postmeta} AS pm WHERE pm.post_id = {$wpdb->posts}.ID AND pm.meta_key = '_sale_price')) / {$wpdb->postmeta}.meta_value) DESC"; } // 按折扣率从低到高排序 function orderby_discount_lowest( $orderby ) { global $wpdb; return "(({$wpdb->postmeta}.meta_value - (SELECT meta_value FROM {$wpdb->postmeta} AS pm WHERE pm.post_id = {$wpdb->posts}.ID AND pm.meta_key = '_sale_price')) / {$wpdb->postmeta}.meta_value) ASC"; }
关键改动说明
- 新增
meta_query筛选逻辑,确保只显示真正有折扣的商品 - 调整排序规则为基于「折扣率」计算,而非直接按现价排序
- 添加过滤器自动移除逻辑,避免干扰其他页面查询
二、实现AJAX动态加载(取消页面刷新)
替换原表单提交逻辑,改用AJAX请求更新内容:
1. 修改短代码HTML结构
function discount_filter_shortcode() { ob_start(); ?> <div class="discount-filter-wrap"> <select id="discount-filter" name="discount_filter"> <option value="">折扣筛选</option> <option value="highest" <?php echo ( isset($_GET['discount_filter']) && $_GET['discount_filter'] == 'highest' ) ? 'selected' : ''; ?>>最高折扣</option> <option value="lowest" <?php echo ( isset($_GET['discount_filter']) && $_GET['discount_filter'] == 'lowest' ) ? 'selected' : ''; ?>>最低折扣</option> </select> </div> <!-- 产品列表容器,确保ID唯一 --> <div id="products-list"> <?php if (is_post_type_archive('product')) { woocommerce_product_loop_start(); if (have_posts()) : while (have_posts()) : the_post(); wc_get_template_part('content', 'product'); endwhile; endif; woocommerce_product_loop_end(); } ?> </div> <?php return ob_get_clean(); } add_shortcode( 'discount_filter', 'discount_filter_shortcode' );
2. 添加AJAX处理PHP代码
// 注册AJAX动作,支持前台未登录用户访问 add_action('wp_ajax_filter_discount_products', 'filter_discount_products_ajax'); add_action('wp_ajax_nopriv_filter_discount_products', 'filter_discount_products_ajax'); function filter_discount_products_ajax() { $discount_filter = isset($_POST['discount_filter']) ? sanitize_text_field($_POST['discount_filter']) : ''; $paged = isset($_POST['paged']) ? intval($_POST['paged']) : 1; // 构建产品查询参数 $args = array( 'post_type' => 'product', 'posts_per_page' => get_option('posts_per_page'), 'paged' => $paged, 'meta_query' => array( 'relation' => 'AND', array( 'key' => '_sale_price', 'value' => 0, 'compare' => '>', 'type' => 'NUMERIC' ), array( 'key' => '_regular_price', 'value' => '_sale_price', 'compare' => '>', 'type' => 'NUMERIC' ) ) ); // 设置排序规则 if ($discount_filter === 'highest') { add_filter('posts_orderby', 'orderby_discount_highest'); } elseif ($discount_filter === 'lowest') { add_filter('posts_orderby', 'orderby_discount_lowest'); } $products_query = new WP_Query($args); // 输出产品HTML ob_start(); if ($products_query->have_posts()) : woocommerce_product_loop_start(); while ($products_query->have_posts()) : $products_query->the_post(); wc_get_template_part('content', 'product'); endwhile; woocommerce_product_loop_end(); woocommerce_pagination(); else : echo '<p>暂无折扣商品</p>'; endif; wp_reset_postdata(); // 移除过滤器 remove_filter('posts_orderby', 'orderby_discount_highest'); remove_filter('posts_orderby', 'orderby_discount_lowest'); echo ob_get_clean(); wp_die(); // 必须终止AJAX请求 }
3. 添加JavaScript逻辑
在主题目录创建js/discount-filter.js文件,内容如下:
jQuery(document).ready(function($) { $('#discount-filter').on('change', function() { var filterVal = $(this).val(); var $productContainer = $('#products-list'); var currentPage = $('.page-numbers.current').text() || 1; // 显示加载状态 $productContainer.addClass('loading').html('<p>加载中...</p>'); // 发送AJAX请求 $.ajax({ url: discountFilterAjax.ajax_url, type: 'POST', data: { action: 'filter_discount_products', discount_filter: filterVal, paged: currentPage }, success: function(res) { $productContainer.removeClass('loading').html(res); // 更新URL参数,保持浏览器历史记录 var newUrl = new URL(window.location.href); if (filterVal) { newUrl.searchParams.set('discount_filter', filterVal); } else { newUrl.searchParams.delete('discount_filter'); } window.history.pushState({path: newUrl.href}, '', newUrl.href); }, error: function() { $productContainer.removeClass('loading').html('<p>加载失败,请重试</p>'); } }); }); });
4. 注册并加载JS文件
在主题functions.php中添加:
function discount_filter_enqueue_scripts() { if (is_post_type_archive('product') || has_shortcode(get_post()->post_content, 'discount_filter')) { wp_enqueue_script('discount-filter-js', get_stylesheet_directory_uri() . '/js/discount-filter.js', array('jquery'), '1.0', true); wp_localize_script('discount-filter-js', 'discountFilterAjax', array( 'ajax_url' => admin_url('admin-ajax.php') )); } } add_action('wp_enqueue_scripts', 'discount_filter_enqueue_scripts');
内容的提问来源于stack exchange,提问作者user22774038
相关产品推荐
相关产品推荐

