WooCommerce排除折扣满额免邮逻辑异常(负手续费计算问题)
问题与解决方案
问题
需要实现:当购物车**不含任何折扣(优惠券、手续费类折扣)的原始总额(含税)**≥750时,将指定运费设置为0。但使用负手续费实现商品数量≥6时15%折扣的场景下,免邮逻辑失效——即使原始总额未达750,运费仍被设为0。
当前代码在无折扣或用优惠券折扣时正常,但负手续费场景下,无法正确排除折扣计算免邮阈值。
问题原因
原代码中计算阈值判断的逻辑错误:
$cart_total = $subtotal_incl_tax - $fee_incl_tax - $discount_incl_tax;
当使用负手续费(即$fee_incl_tax为负数)时,减去负数等价于加上折扣金额,导致$cart_total被放大,即使原始商品总额未达750,也会满足$cart_total >= $min_amount的条件,错误触发免邮。
而核心需求是基于未扣除任何折扣的原始商品总额判断免邮,因此不需要减去折扣或手续费。
修正方案
1. 修正免邮逻辑代码
直接使用商品原始含税小计作为阈值判断依据,去掉错误的折扣/手续费扣除逻辑:
add_filter('woocommerce_package_rates', 'null_shipping_costs_conditionally', 10, 2 ); function null_shipping_costs_conditionally( $rates, $package ){ // 指定要修改的运费方式ID $methodprice_key_ids = array('flat_rate:4'); $found = false; $min_amount = 750; // 免邮阈值 // 获取不含任何折扣的原始商品含税总额 $subtotal_excl_tax = WC()->cart->get_subtotal(); $subtotal_tax = WC()->cart->get_subtotal_tax(); $original_cart_total_incl_tax = $subtotal_excl_tax + $subtotal_tax; // 判断原始总额是否达标 if( $original_cart_total_incl_tax >= $min_amount) { $found = true; } if( $found ) { foreach( $rates as $rate_key => $rate ) { if( in_array($rate_key, $methodprice_key_ids) ) { // 设置运费为0 $rates[$rate_key]->cost = 0; // 添加"免费"标签 $rates[$rate_key]->label .= ' ' . __( '- gratis', 'woocommerce' ); // 同步设置运费税费为0(如果有) $taxes = array(); $has_taxes = false; foreach ($rates[$rate_key]->taxes as $key => $tax){ if( $tax > 0 ){ $taxes[$key] = 0; $has_taxes = true; } } if( $has_taxes ) { $rates[$rate_key]->taxes = $taxes; } } } } return $rates; }
2. 优化折扣实现方式(可选)
用负手续费实现折扣并非WooCommerce的标准用法,推荐改用woocommerce_cart_calculate_fees钩子添加折扣,同时确保折扣金额计算正确:
add_action('woocommerce_cart_calculate_fees', 'add_mix_match_discount'); function add_mix_match_discount() { if ( !WC()->cart->is_empty() ) { $items_count = WC()->cart->get_cart_contents_count(); $items_subtotal = WC()->cart->get_subtotal(); if ($items_count >= 6) { $percent = 15; $discount_amount = $items_subtotal * $percent / 100; // 添加负数费用实现折扣(第二个参数为负数) WC()->cart->add_fee( __('Mix & Match rabat', 'woocommerce') . " - {$percent}%", -$discount_amount, // 直接传负数,无需额外计算 true, // 是否含税 '' // 税类(留空使用默认) ); } } }
注:此优化不影响免邮逻辑,但能让折扣计算更清晰,避免原代码中$discount -= ...可能导致的变量初始化问题。
关键说明
- 免邮判断的核心是原始商品总额,即
get_subtotal()(不含税商品小计)加get_subtotal_tax()(商品税费),这两个值不会受优惠券、手续费的影响,完全符合需求。 - 若后续需求改为“扣除折扣后的实付总额达标免邮”,则需重新调整计算逻辑,但当前需求明确是基于无折扣的原始总额,因此上述修正完全适用。
内容的提问来源于stack exchange,提问作者Richard
相关产品推荐
相关产品推荐

