WooCommerce商品多属性批量选择加购功能实现咨询
WooCommerce 选色后多尺码批量加购实现方案
需求说明
- 目标功能:用户先选定商品颜色,再自主勾选44、46、48等需要的尺码,一次性将选中的多规格商品加入购物车
- 现有参考代码基于原生WooCommerce环境编写,原逻辑为全尺码一键加购,未做适配调整无法直接使用
现有参考代码问题梳理
现有代码为全尺码加购的半成品,核心逻辑是加载时读取商品所有变体ID,勾选全选框后通过AJAX把所有变体传入后端循环加购,存在以下问题导致无法运行、不符合需求:
- 文件命名错误:主题函数文件标准命名为
functions.php,代码标注为function.php,容易放错位置导致代码不生效 - 脚本挂载错误:
wp_localize_script将AJAX请求所需的全局变量挂载到了bootstrap脚本句柄下,实际AJAX逻辑写在自定义JS文件中,会导致前端报ajax_object is not defined的JS错误 - 变体未做属性关联:直接读取商品下所有变体,没有和用户选中的颜色做绑定,会把其他颜色的尺码变体也加入购物车
- 缺少单尺码勾选能力:仅提供全选复选框,没有单个尺码的勾选入口,不符合调整后的交互要求
- 后端无校验逻辑:没有做请求合法性校验、变体归属校验、库存校验,容易出现加购失败、恶意请求问题
- 交互体验生硬:加购成功后直接整页刷新,没有原生WooCommerce的加购提示、购物车局部更新效果
修正后实现代码
1. 主题functions.php代码
将以下代码加入当前主题/子主题的functions.php文件中:
// 加载前端所需脚本 function custom_bulk_cart_scripts() { // 如主题已加载bootstrap、popper可删除以下两行enqueue代码,避免重复加载 wp_enqueue_script( 'popper-js', 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js', array( 'jquery' ), '1.14.7', true ); wp_enqueue_script( 'bootstrap-js', 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js', array( 'jquery' ), '4.3.1', true ); // 替换为你主题实际的JS文件存放路径 wp_enqueue_script( 'custom-bulk-add-cart', get_stylesheet_directory_uri() . '/js/ajax_add_to_cart.js', array( 'jquery', 'wc-add-to-cart-variation' ), '1.0.0', true ); // 传递AJAX请求所需参数到前端 wp_localize_script( 'custom-bulk-add-cart', 'custom_ajax', array( 'url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('bulk_add_cart_nonce') ) ); } add_action( 'wp_enqueue_scripts', 'custom_bulk_cart_scripts' ); // 在可变商品加购按钮前渲染尺码勾选区域 add_action( 'woocommerce_before_add_to_cart_button', 'custom_size_checkbox_render', 10 ); function custom_size_checkbox_render() { global $product; if( !$product->is_type('variable') ) return; $available_variations = $product->get_available_variations(); $grouped_variations = []; // 按颜色属性分组整理变体数据,供前端匹配 foreach( $available_variations as $variation ) { // 如站点自定义了颜色/尺码属性slug,替换pa_color、pa_size为实际值 $color = $variation['attributes']['attribute_pa_color']; $size = $variation['attributes']['attribute_pa_size']; $grouped_variations[$color][$size] = [ 'variation_id' => $variation['variation_id'], 'is_in_stock' => $variation['is_in_stock'], 'max_qty' => $variation['max_qty'] ]; } ?> <div class="custom-size-select-warp" data-variations='<?php echo wp_json_encode($grouped_variations); ?>'> <div class="size-checkbox-list" style="display:none;margin:15px 0;"></div> <div class="size-bulk-action" style="display:none;margin:10px 0;"> <label style="margin-right:15px;"> <input type="checkbox" class="check-all-size"> 全选当前颜色所有尺码 </label> <button type="button" class="button bulk-add-to-cart-btn" disabled>批量加入购物车</button> </div> </div> <?php } // 批量加购AJAX处理接口 add_action('wp_ajax_custom_bulk_add_to_cart', 'custom_bulk_add_to_cart_handler' ); add_action('wp_ajax_nopriv_custom_bulk_add_to_cart', 'custom_bulk_add_to_cart_handler' ); function custom_bulk_add_to_cart_handler() { if( !isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'bulk_add_cart_nonce') ) { wp_send_json_error(['msg' => '非法请求']); } $product_id = intval($_POST['product_id']); $variation_ids = array_map('intval', explode(',', $_POST['variation_ids'])); $qty = intval($_POST['qty']); if( !$product_id || !$variation_ids || $qty < 1 ) { wp_send_json_error(['msg' => '参数错误']); } $product = wc_get_product($product_id); if( !$product || !$product->is_type('variable') ) { wp_send_json_error(['msg' => '商品不存在']); } $available_variation_ids = $product->get_children(); $added_count = 0; foreach( $variation_ids as $vid ) { if( !in_array($vid, $available_variation_ids) ) continue; $variation = wc_get_product($vid); if( !$variation->is_in_stock() ) continue; if( WC()->cart->add_to_cart($vid, $qty) ) { $added_count++; } } if( $added_count === 0 ) { wp_send_json_error(['msg' => '所选尺码无可用库存,加购失败']); } // 返回购物车碎片供前端局部更新 ob_start(); woocommerce_mini_cart(); $mini_cart = ob_get_clean(); $data = [ 'success' => true, 'msg' => sprintf('成功将%d个尺码的商品加入购物车', $added_count), 'fragments' => [ 'div.widget_shopping_cart_content' => '<div class="widget_shopping_cart_content">' . $mini_cart . '</div>' ] ]; wp_send_json($data); }
2. 前端JS代码(ajax_add_to_cart.js)
在主题目录下新建js/ajax_add_to_cart.js文件,写入以下代码:
jQuery(document).ready(function($){ const $variationForm = $('.variations_form'); const $sizeWarp = $('.custom-size-select-warp'); const $sizeList = $sizeWarp.find('.size-checkbox-list'); const $bulkAction = $sizeWarp.find('.size-bulk-action'); const $checkAll = $bulkAction.find('.check-all-size'); const $bulkBtn = $bulkAction.find('.bulk-add-to-cart-btn'); const groupedVariations = $sizeWarp.data('variations'); let currentColor = ''; // 监听颜色选择完成事件 $variationForm.on('found_variation', function(){ // 替换#pa_color为站点实际的颜色选择器ID currentColor = $('select#pa_color').val(); if( !currentColor || !groupedVariations[currentColor] ) { $sizeList.hide().empty(); $bulkAction.hide(); return; } // 渲染当前颜色下的可选尺码 $sizeList.empty().show(); const currentSizeGroup = groupedVariations[currentColor]; $.each(currentSizeGroup, function(size, data){ const disabled = data.is_in_stock ? '' : 'disabled'; const stockTip = data.is_in_stock ? '' : '(无库存)'; $sizeList.append(` <label style="margin-right:12px;${disabled?'color:#ccc;':''}"> <input type="checkbox" class="size-checkbox" value="${data.variation_id}" ${disabled}> ${size} ${stockTip} </label> `); }); $bulkAction.show(); resetSelectStatus(); }); // 重置选择状态 function resetSelectStatus(){ $checkAll.prop('checked', false); $sizeList.find('.size-checkbox').prop('checked', false); $bulkBtn.prop('disabled', true); } // 单个尺码勾选事件 $sizeList.on('change', '.size-checkbox', function(){ const checkedCount = $sizeList.find('.size-checkbox:checked').length; $bulkBtn.prop('disabled', checkedCount === 0); const availableCount = $sizeList.find('.size-checkbox:not(:disabled)').length; $checkAll.prop('checked', checkedCount === availableCount); }); // 全选逻辑 $checkAll.on('change', function(){ const isChecked = $(this).prop('checked'); $sizeList.find('.size-checkbox:not(:disabled)').prop('checked', isChecked); $bulkBtn.prop('disabled', !isChecked); }); // 批量加购提交 $bulkBtn.on('click', function(){ const checkedVids = []; $sizeList.find('.size-checkbox:checked').each(function(){ checkedVids.push($(this).val()); }); if( checkedVids.length === 0 ) return; const qty = $('.quantity .input-text.qty').val() || 1; const productId = $variationForm.data('product_id'); $.ajax({ url: custom_ajax.url, type: 'POST', dataType: 'json', data: { action: 'custom_bulk_add_to_cart', nonce: custom_ajax.nonce, product_id: productId, variation_ids: checkedVids.join(','), qty: qty }, beforeSend: function(){ $bulkBtn.prop('disabled', true).text('加购中...'); }, success: function(res){ if( res.success ) { if( res.fragments ) { $.each(res.fragments, function(selector, content){ $(selector).replaceWith(content); }); } $(document.body).trigger('added_to_cart', [res.fragments, null, null]); alert(res.msg); resetSelectStatus(); } else { alert(res.msg); } }, complete: function(){ $bulkBtn.text('批量加入购物车'); const checkedCount = $sizeList.find('.size-checkbox:checked').length; $bulkBtn.prop('disabled', checkedCount === 0); } }) }); // 变体选择重置时隐藏尺码区域 $variationForm.on('reset_data', function(){ $sizeList.hide().empty(); $bulkAction.hide(); currentColor = ''; }) })
部署注意事项
- 代码中
pa_color、pa_size为WooCommerce默认颜色、尺码属性的slug,如站点自定义过属性slug,需替换为实际值 - JS文件路径需和
wp_enqueue_script中配置的路径一致,否则脚本无法加载 - 可根据主题实际样式调整复选框、按钮的CSS,适配页面视觉效果
- 如主题已加载bootstrap、popper资源,删除functions.php中对应的重复加载代码
内容的提问来源于stack exchange,提问作者Benchmark Alchakov
相关产品推荐
相关产品推荐

