WooCommerce AJAX筛选怎么做?
学完这篇,你能给 WooCommerce 商城加上一个不用刷新页面就能筛选商品的功能——无论是用插件 10 分钟搞定,还是自己写 AJAX 接口完全可控。
第一步:先决定走插件还是走代码
这一步要确认你的技术路线,因为两条路成本差很多。
- 只想快速上线、筛选维度就是分类/属性/价格/库存:用插件,推荐 YITH WooCommerce Ajax Product Filter 免费版。
- 需要自定义筛选逻辑(比如按自定义字段、按会员等级、按多条件组合),或者主题已经有筛选表单只想接 AJAX:走代码路线,看第三步。
注意:插件路线和代码路线不要混着加。两套筛选同时输出,用户会看到两个筛选框,商品的
ul.products结构也容易被替换两次导致分页错乱。
第二步:插件路线(后台操作到出效果)
这一步做完,侧边栏就会出现能实时筛选的控件。
- 后台 → 插件 → 安装插件,搜索
YITH WooCommerce Ajax Product Filter,点「立即安装」再点「启用」。 - 进入 外观 → 小工具(区块主题走 外观 → 编辑器 → 模板 → 侧边栏),把「YITH WooCommerce Ajax Product Filter」小工具拖进侧边栏。
- 在小工具设置里勾选要展示的筛选项:Categories、Tags、Attributes、Price、Stock、Order By。
- 保存后打开商城页面,勾一个属性,商品列表应该原地刷新,URL 不变。
如果不想用小工具,直接在页面里放短代码:[yith_wcan_filters slug="preset-slug"],preset 在 后台 → YITH → Ajax Product Filter → 预设 里创建。
注意:如果勾选后整页刷新而不是局部刷新,先关掉 WP Rocket / LiteSpeed Cache 的「合并 JS」和「延迟 JS 执行」再试,这两个选项经常打断插件的 AJAX 初始化。
第三步:代码路线——输出筛选表单
这一步你得到一个普通 GET 表单,即使 JS 挂了也能正常提交刷新。
在产品列表模板(或者用短代码挂进页面)里写:
<form id="wcf-filter" action="<?php echo esc_url( get_permalink( wc_get_page_id('shop') ) ); ?>" method="get">
<select name="product_cat">
<option value="">全部分类</option>
<?php foreach ( get_terms('product_cat', ['hide_empty' => true]) as $t ) : ?>
<option value="<?php echo esc_attr($t->slug); ?>"><?php echo esc_html($t->name); ?></option>
<?php endforeach; ?>
</select>
<input type="number" name="min_price" placeholder="最低价">
<input type="number" name="max_price" placeholder="最高价">
<button type="submit">筛选</button>
</form>
<div id="wcf-results"></div>
wcf-results 就是后面被 JS 替换掉的商品区域。
注意:属性的分类法名一定带
pa_前缀,比如颜色是pa_color。这个前缀必须在 产品 → 属性 里先建好属性并「配置术语」,否则表单里拿不到值。
第四步:注册 AJAX 接口并构造查询
这一步做完,你有了一个能返回商品 HTML 的后端接口。
add_action('wp_ajax_wcf_filter', 'wcf_filter_handler');
add_action('wp_ajax_nopriv_wcf_filter', 'wcf_filter_handler'); // 游客也要能用
function wcf_filter_handler() {
check_ajax_referer('wcf_nonce', 'nonce');
$args = [
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => 12,
'paged' => max(1, absint($_POST['paged'] ?? 1)),
'tax_query' => ['relation' => 'AND'],
'meta_query' => ['relation' => 'AND'],
];
if (!empty($_POST['product_cat'])) {
$args['tax_query'][] = ['taxonomy'=>'product_cat','field'=>'slug',
'terms'=>sanitize_text_field($_POST['product_cat'])];
}
if (!empty($_POST['pa_color'])) {
$args['tax_query'][] = ['taxonomy'=>'pa_color','field'=>'slug',
'terms'=>array_map('sanitize_title', (array)$_POST['pa_color'])];
}
$min = (float) ($_POST['min_price'] ?? 0);
$max = (float) ($_POST['max_price'] ?? 0);
if ($min > 0 || $max > 0) {
$args['meta_query'][] = ['key'=>'_price','type'=>'NUMERIC','compare'=>'BETWEEN',
'value'=>[$min ?: 0, $max ?: PHP_INT_MAX]];
}
$q = new WP_Query($args);
ob_start();
if ($q->have_posts()) {
woocommerce_product_loop_start();
while ($q->have_posts()) { $q->the_post(); wc_get_template_part('content','product'); }
woocommerce_product_loop_end();
} else { echo '<p>没有匹配的商品</p>'; }
wp_reset_postdata();
wp_send_json_success(['html'=>ob_get_clean(),'found'=>$q->found_posts]);
}
注意:
woocommerce_product_loop_start()必须保留,它输出的ul.products类名是主题样式的挂钩点,去掉后商品会变成没排版的堆叠列表。
第五步:前端发请求并替换列表
这一步做完,点筛选就不再刷新页面了。
const form = document.getElementById('wcf-filter');
const box = document.getElementById('wcf-results');
async function wcfLoad(page = 1) {
box.style.opacity = .5;
const fd = new FormData(form);
fd.append('action', 'wcf_filter');
fd.append('nonce', wcfVars.nonce);
fd.append('paged', page);
const r = await fetch(wcfVars.ajaxUrl, { method: 'POST', body: fd });
const j = await r.json();
if (j.success) box.innerHTML = j.data.html;
box.style.opacity = 1;
}
form.addEventListener('submit', e => { e.preventDefault(); wcfLoad(1); });
form.addEventListener('change', () => wcfLoad(1));
用 wp_enqueue_script 加 wp_localize_script 把 wcfVars.ajaxUrl(admin_url('admin-ajax.php'))和 wcfVars.nonce(wp_create_nonce('wcf_nonce'))传给 JS。
注意:分页按钮也要走
wcfLoad(page),否则翻页会整页跳转,用户刚选的筛选条件全丢。同时用history.pushState把参数写回地址栏,用户刷新和分享链接才不会回到初始状态。
小结
- 筛选维度简单就用 YITH WooCommerce Ajax Product Filter,小工具或短代码挂上去即可。
- 自己写就三件事:表单输出可用 GET 参数、
admin-ajax.php注册wp_ajax_nopriv接口返回商品 HTML、JS 拦截提交替换#wcf-results。 - 属性筛选的 taxonomy 名必须带
pa_前缀,且要先在产品属性里建好。 - 分页、URL 同步、缓存插件排除
admin-ajax.php这三件事不做,功能上线后一定出问题。
原文链接:https://www.gj0.com/thread-742.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。