WooCommerce指定商品买2赠1折扣及免运费计算异常问题
问题修复方案
问题1:减免数量计算错误
原代码中$key % ($each_n_items + 1) == 1的判断逻辑,实际是按每4件减免1件执行的,和你需要的「买2赠1(每3件减免1件)」规则不符。比如9件商品时,只会触发2次减免,而非预期的3次。
修复逻辑:统计符合条件的商品总数量,按每3件为一组,每组减免1件(优先减免最便宜的商品,保证规则合理性)。
问题2:免运费门槛判断错误
WooCommerce默认使用折扣前的购物车总额判断免运费资格,通过add_fee添加的折扣不会自动修改这个判断逻辑,导致折扣后总额未达门槛却触发免运费,或反之。
修复逻辑:通过过滤器修改免费配送的判断条件,改用折扣后的购物车总额和门槛对比。
修改后的完整代码
add_action('woocommerce_cart_calculate_fees', 'buy_two_get_one_free', 10, 1 ); function buy_two_get_one_free( $cart ){ if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return; // 指定参与活动的商品ID $targeted_product_ids = array( 5745, 5741, 5734 ); $each_n_items = 3; // 每3件减免1件(买2赠1) $discount = 0; // 初始化折扣金额 $items_prices = array(); // 存储符合条件的商品单价 foreach ( $cart->get_cart() as $cart_item ) { if( in_array( $cart_item['product_id'], $targeted_product_ids ) ) { $qty = intval( $cart_item['quantity'] ); // 将每个商品的单价存入数组(对应数量循环添加) for ( $i = 0; $i < $qty; $i++ ) { $items_prices[] = floatval( $cart_item['data']->get_price() ); } } } $count_items_prices = count($items_prices); if ( $count_items_prices >= $each_n_items ) { // 计算可减免的商品数量:总数量 ÷ 3 取整数 $free_items_count = floor( $count_items_prices / $each_n_items ); // 对单价数组升序排序,优先减免最便宜的商品(可根据需求移除排序) sort( $items_prices ); // 累加减免金额 for ( $i = 0; $i < $free_items_count; $i++ ) { $discount += $items_prices[$i]; } // 保留两位小数避免精度问题 $discount = number_format( $discount, 2 ); } if ( $discount > 0 ) { wc_clear_notices(); wc_add_notice( __("买2赠1:每3件商品减免1件费用"), 'notice'); // 添加折扣(第三个参数true表示该折扣含税) $cart->add_fee( __("买2赠1折扣"), -$discount, true ); } } // 修复免运费门槛判断逻辑 add_filter( 'woocommerce_shipping_free_shipping_is_available', 'adjust_free_shipping_threshold', 20, 3 ); function adjust_free_shipping_threshold( $is_available, $package, $shipping_method ) { // 仅针对免费配送方式生效 if ( $shipping_method->id !== 'free_shipping' ) { return $is_available; } // 获取折扣后的购物车总额 $discounted_total = WC()->cart->get_total( 'edit' ); // 获取后台设置的免运费最低金额 $min_threshold = $shipping_method->get_option( 'min_amount' ); // 判断折扣后总额是否达标 return ( $discounted_total >= $min_threshold ) ? true : false; }
内容的提问来源于stack exchange,提问作者exe65
相关产品推荐
相关产品推荐

