如何在侧边栏短代码的自定义筛选表单中修改WC query_vars?
实现WooCommerce产品标签多选筛选(key:value格式标签分组)
问题背景
通过短代码在侧边栏添加了自定义筛选表单,产品标签采用key:value格式,已实现拆分标签并按key分组为折叠菜单、提交时重新组合标签,但当前代码仅支持单个product_tag筛选。改成多选后,传递多个product_tag参数时,query_vars只会识别最后一个,需修改实现多选功能。
解决方案
要实现多选,需从表单字段命名、WordPress查询变量处理、表单提交逻辑三个维度修改:
1. 修改表单复选框name属性
将单个name="product_tag"改为数组格式name="product_tag[]",确保表单提交时能传递多个值:
// 原代码 <input class="ajax-checkbox" type="checkbox" value="' . $key . ':' . $argvalue . '" id="' . $id . '" name="product_tag" onChange="this.form.submit()" /> // 修改后 <input class="ajax-checkbox" type="checkbox" value="' . $key . ':' . $argvalue . '" id="' . $id . '" name="product_tag[]" onChange="handleFilterSubmit()" />
2. 用钩子处理多标签查询变量
WordPress默认不解析数组格式的查询参数,添加钩子将product_tag[]转换为query_vars可识别的格式,同时支持多标签的AND/OR逻辑(以下为AND逻辑,即同时匹配所有选中标签):
add_filter('query_vars', 'add_multiple_product_tag_var'); function add_multiple_product_tag_var($vars) { $vars[] = 'product_tag'; return $vars; } add_action('pre_get_posts', 'handle_multiple_product_tags'); function handle_multiple_product_tags($query) { if (!is_admin() && $query->is_main_query() && is_shop()) { $product_tags = isset($_GET['product_tag']) ? $_GET['product_tag'] : []; if (!empty($product_tags) && is_array($product_tags)) { // 转换为标准化标签slug $tag_slugs = array_map(function($tag) { return sanitize_title($tag); }, $product_tags); // 设置多标签查询逻辑,如需OR匹配将'AND'改为'IN' $query->set('product_tag', $tag_slugs); $query->set('tag_operator', 'AND'); } } }
3. 修复表单提交逻辑(JavaScript)
原提交方式无法正确传递数组参数,改用FormData和URLSearchParams处理参数,同时保留搜索、排序等其他查询参数:
function handleFilterSubmit() { const form = document.getElementById('myfilter'); const params = new URLSearchParams(); // 收集选中的标签 const productTags = form.querySelectorAll('input[name="product_tag[]"]:checked'); productTags.forEach(tag => { params.append('product_tag[]', tag.value); }); // 收集其他隐藏字段参数 const hiddenFields = form.querySelectorAll('input[type="hidden"]'); hiddenFields.forEach(field => { params.append(field.name, field.value); }); // 跳转到筛选后的页面 window.location.href = window.location.pathname + '?' + params.toString(); }
4. 保持复选框选中状态
渲染表单时,根据当前URL的product_tag参数,自动标记对应的复选框为选中:
// 在复选框渲染循环中添加选中判断 $tag_value = $key . ':' . $argvalue; $is_checked = in_array($tag_value, $current_tags) ? 'checked' : ''; // 将判断结果添加到input标签 <input class="ajax-checkbox" type="checkbox" value="' . $tag_value . '" id="' . $id . '" name="product_tag[]" ' . $is_checked . ' onChange="handleFilterSubmit()" />
5. 修复清空筛选功能
原清空链接无法正确重置参数,改为直接跳转到不带筛选参数的商城页面:
// 原清空链接 <a href="#" class="deselect" onChange="this.form.submit()">Clear Filter</a> // 修改后 <a href="<?php echo get_permalink( wc_get_page_id( 'shop' ) ); ?>" class="deselect">Clear Filter</a>
完整修改后的代码
function my_custom_tag_filter() { global $wp_query; $return = ''; $query_vars = $wp_query->query_vars; $current_tags = isset($_GET['product_tag']) ? $_GET['product_tag'] : []; $tags = get_terms('product_tag'); $tagsbycategory = array(); if (!empty($tags) && !is_wp_error($tags)) { foreach ($tags as $tag) { $tagcategorypair = explode(":", $tag->name); if (count($tagcategorypair) != 2) continue; if (!array_key_exists($tagcategorypair[0], $tagsbycategory)) { $tagsbycategory[$tagcategorypair[0]] = array(); } $tagsbycategory[$tagcategorypair[0]][] = $tagcategorypair[1]; } } $return .= ' <form id="myfilter"> '; $keys = array_keys($tagsbycategory); foreach ($keys as $key) { $return .= ' <button type="button" class="collapsiblefilter">' . $key . '</button> <div class="filtercontent"> '; $values = $tagsbycategory[$key]; foreach ($values as $value) { $argvalue = str_replace(' ', '-', $value); $friendlyvalue = str_replace('/','',str_replace(' ', '', $value)); $id = $key . '-' . $friendlyvalue . '-check'; $tag_value = $key . ':' . $argvalue; $is_checked = in_array($tag_value, $current_tags) ? 'checked' : ''; $return .= ' <div class="filtercheckdiv"> <label for="' . $id . '"><input class="ajax-checkbox" type="checkbox" value="' . $tag_value . '" id="' . $id . '" name="product_tag[]" ' . $is_checked . ' onChange="handleFilterSubmit()" /> ' . $value . '</label> </div> '; } $return .= ' </div> '; } if ($query_vars != null) { if (array_key_exists("s", $query_vars)) { $return .= '<input type="hidden" name="s" value="' . $query_vars["s"] . '">'; } if (array_key_exists("orderby", $query_vars)) { $return .= '<input type="hidden" name="orderby" value="' . $query_vars["orderby"] . '">'; } if (array_key_exists("order", $query_vars)) { $return .= '<input type="hidden" name="order" value="' . $query_vars["order"] . '">'; } } $return .= ' <div class="small"><a href="' . get_permalink( wc_get_page_id( 'shop' ) ) . '" class="deselect">Clear Filter</a> </form> <script> function handleFilterSubmit() { const form = document.getElementById("myfilter"); const params = new URLSearchParams(); // 收集选中的标签参数 const productTags = form.querySelectorAll("input[name=\'product_tag[]\']:checked"); productTags.forEach(tag => { params.append("product_tag[]", tag.value); }); // 收集其他隐藏字段参数 const hiddenFields = form.querySelectorAll("input[type=\'hidden\']"); hiddenFields.forEach(field => { params.append(field.name, field.value); }); // 跳转至筛选页面 window.location.href = window.location.pathname + "?" + params.toString(); } </script> '; return $return; } add_shortcode('my_custom_filter', 'my_custom_tag_filter'); // 注册多标签查询变量 add_filter('query_vars', 'add_multiple_product_tag_var'); function add_multiple_product_tag_var($vars) { $vars[] = 'product_tag'; return $vars; } // 处理多标签查询逻辑 add_action('pre_get_posts', 'handle_multiple_product_tags'); function handle_multiple_product_tags($query) { if (!is_admin() && $query->is_main_query() && is_shop()) { $product_tags = isset($_GET['product_tag']) ? $_GET['product_tag'] : []; if (!empty($product_tags) && is_array($product_tags)) { // 转换为标准化标签slug $tag_slugs = array_map(function($tag) { return sanitize_title($tag); }, $product_tags); // 设置多标签AND匹配逻辑,如需OR匹配将'AND'改为'IN' $query->set('product_tag', $tag_slugs); $query->set('tag_operator', 'AND'); } } }
内容的提问来源于stack exchange,提问作者Venk Reddy
相关产品推荐
相关产品推荐

