如何正确整合WooCommerce筛选与无限加载两个Ajax请求(无插件)
问题根源分析
筛选功能生效后,无限加载的Ajax请求没有携带当前的筛选条件(尺寸、颜色、排序方式),后端PHP接收到的还是初始默认查询参数,所以返回未筛选的分页数据。另外,筛选后商品总数可能变化,无限加载的终止条件(是否还有更多页)也需要同步更新。
解决思路
- 用全局变量存储筛选参数和分页状态,每次无限加载时携带这些参数
- 筛选完成后重置无限加载的页码、是否还有更多数据的状态
- 后端PHP统一处理筛选和无限加载的参数,生成一致的查询逻辑
代码实现
前端JS部分
// 全局存储筛选参数与分页状态 let filterParams = { size: '', color: '', orderby: 'date', order: 'desc', paged: 1 }; let hasMore = true; let isLoading = false; // 筛选表单提交逻辑 document.querySelector('.filter-form').addEventListener('submit', function(e) { e.preventDefault(); // 捕获当前筛选参数 filterParams.size = document.querySelector('#size-filter').value; filterParams.color = document.querySelector('#color-filter').value; filterParams.orderby = document.querySelector('#orderby-filter').value; filterParams.order = document.querySelector('#order-filter').value; filterParams.paged = 1; // 筛选后重置页码为第一页 hasMore = true; isLoading = false; // 发起筛选请求 fetch('/wp-admin/admin-ajax.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ action: 'filter_products', ...filterParams }) }) .then(response => response.text()) .then(html => { // 替换商品列表容器内容 document.querySelector('.products-container').innerHTML = html; // 更新是否还有更多页的状态 const totalPages = parseInt(document.querySelector('#total-pages').value); hasMore = filterParams.paged < totalPages; }) .catch(error => console.error('筛选请求失败:', error)); }); // 滚动触发无限加载 window.addEventListener('scroll', function() { if (!hasMore || isLoading) return; // 滚动到页面底部200px内时触发加载 if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 200) { loadMoreProducts(); } }); // 加载更多商品逻辑 function loadMoreProducts() { isLoading = true; filterParams.paged++; // 页码自增 fetch('/wp-admin/admin-ajax.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ action: 'load_more_products', ...filterParams }) }) .then(response => response.text()) .then(html => { // 追加商品到列表容器 document.querySelector('.products-container').insertAdjacentHTML('beforeend', html); // 更新加载状态 const totalPages = parseInt(document.querySelector('#total-pages').value); hasMore = filterParams.paged < totalPages; isLoading = false; }) .catch(error => { console.error('加载更多失败:', error); isLoading = false; }); }
后端PHP部分(添加到主题functions.php)
// 筛选商品的Ajax回调 add_action('wp_ajax_filter_products', 'filter_products_callback'); add_action('wp_ajax_nopriv_filter_products', 'filter_products_callback'); function filter_products_callback() { $args = array( 'post_type' => 'product', 'posts_per_page' => 6, 'paged' => isset($_POST['paged']) ? intval($_POST['paged']) : 1, 'orderby' => isset($_POST['orderby']) ? sanitize_text_field($_POST['orderby']) : 'date', 'order' => isset($_POST['order']) ? sanitize_text_field($_POST['order']) : 'desc', 'tax_query' => array(), ); // 处理尺寸筛选(替换为你的尺寸分类法slug) if (!empty($_POST['size'])) { $args['tax_query'][] = array( 'taxonomy' => 'product_size', 'field' => 'slug', 'terms' => sanitize_text_field($_POST['size']), ); } // 处理颜色筛选(替换为你的颜色分类法slug) if (!empty($_POST['color'])) { $args['tax_query'][] = array( 'taxonomy' => 'product_color', 'field' => 'slug', 'terms' => sanitize_text_field($_POST['color']), ); } // 多分类筛选时设置关系为AND if (count($args['tax_query']) > 1) { $args['tax_query']['relation'] = 'AND'; } $query = new WP_Query($args); if ($query->have_posts()) { while ($query->have_posts()) { $query->the_post(); // 输出商品模板(可替换为你的商品模板代码) echo '<div class="product-item">'; the_title('<h3 class="product-title">', '</h3>'); the_post_thumbnail('medium', ['class' => 'product-thumb']); echo '</div>'; } // 输出总页数隐藏标记,供前端判断是否还有更多数据 echo '<input type="hidden" id="total-pages" value="' . $query->max_num_pages . '">'; } else { echo '<p class="no-products">没有找到匹配的商品</p>'; echo '<input type="hidden" id="total-pages" value="1">'; } wp_reset_postdata(); wp_die(); } // 无限加载商品的Ajax回调,直接复用筛选逻辑 add_action('wp_ajax_load_more_products', 'load_more_products_callback'); add_action('wp_ajax_nopriv_load_more_products', 'load_more_products_callback'); function load_more_products_callback() { filter_products_callback(); }
关键说明
- 参数同步:全局变量
filterParams统一存储所有筛选和分页参数,确保筛选、无限加载的请求参数完全一致。 - 状态重置:每次筛选后重置页码为1,更新
hasMore状态,避免无限加载从之前的页码继续。 - 后端逻辑复用:无限加载的回调直接调用筛选的查询逻辑,减少重复代码,保证两次查询规则一致。
- 终止条件:后端返回总页数,前端通过对比当前页码和总页数,判断是否还有更多数据可加载。
内容的提问来源于stack exchange,提问作者libertarian
相关产品推荐
相关产品推荐

