基于可配送商品最低小计的免运费设置及进度条实现问题
WooCommerce购物车免运费提示与商品类型过滤优化方案
需求梳理
需要实现以下逻辑判断:
- 仅含**预约(APPOINTMENT)**或虚拟商品时,显示感谢语
- 购物车仅含实体商品且小计≤50欧元:不显示免运费差额进度条
- 购物车包含实体商品+预约/虚拟商品,且小计<50欧元:显示免运费差额进度条
- 购物车有普通商品(可变/简单类型)且小计≥50欧元:显示“免运费可用”
优化后的代码实现
// 判断购物车是否仅含预约/虚拟商品 function has_only_virtual_or_appointment() { $has_physical = false; foreach ( WC()->cart->get_cart() as $item ) { // 检查商品是否为实体商品(可配送) if ( $item['data']->is_shipping_required() ) { $has_physical = true; break; } } return !$has_physical; } // 判断购物车是否仅含实体商品 function has_only_physical_products() { $has_virtual_or_appointment = false; foreach ( WC()->cart->get_cart() as $item ) { // 检查商品是否为虚拟/预约类型(不可配送) if ( !$item['data']->is_shipping_required() ) { $has_virtual_or_appointment = true; break; } } return !$has_virtual_or_appointment; } // 判断购物车是否混合了实体与虚拟/预约商品 function has_mixed_products() { $has_physical = false; $has_virtual = false; foreach ( WC()->cart->get_cart() as $item ) { if ( $item['data']->is_shipping_required() ) { $has_physical = true; } else { $has_virtual = true; } // 两种类型都找到就提前终止循环 if ( $has_physical && $has_virtual ) break; } return $has_physical && $has_virtual; } // 过滤配送方式 add_filter( 'woocommerce_package_rates', 'ecommercehints_free_shipping_for_specific_products', 10, 2 ); function ecommercehints_free_shipping_for_specific_products( $rates, $package ) { // 仅含虚拟/预约商品时,保留原有配送方式 if( has_only_virtual_or_appointment() ){ return $rates; } // 实体商品小计不足50时,移除指定免运费方式 if ( WC()->cart->get_subtotal() < 50 ) { unset( $rates['free_shipping:21'] ); // 替换为你的免运费方式ID } return $rates; } // 结账页显示免运费提示/进度条 add_action( 'woocommerce_checkout_before_order_review', 'ecommercehints_checkout_page_progress_bar', 10 ); function ecommercehints_checkout_page_progress_bar() { $subtotal = WC()->cart->get_subtotal(); // 仅含虚拟/预约商品:显示感谢语 if( has_only_virtual_or_appointment() ){ echo __("感谢您的订单", "woocommerce"); } // 小计≥50:显示免运费可用 elseif ( $subtotal >= 50 ) { echo __("免运费可用", "woocommerce"); } // 小计<50的情况:判断是否混合商品,是则显示进度条;仅实体则不显示 elseif ( $subtotal < 50 ) { if ( has_mixed_products() ) { printf( __('再消费 %s 即可享受免运费!', 'woocommerce'), wc_price( 50 - $subtotal ) ); printf('<br><progress id="freeshippingprogress" max="50" value="%d"></progress>', intval($subtotal) ); } // 仅实体商品时,此处什么都不输出 } }
代码说明
- 商品类型判断函数:通过
is_shipping_required()来区分实体/非实体商品,比直接判断商品类型更通用,兼容预约、虚拟等各类无需配送的商品 - 配送方式过滤:仅当存在实体商品且小计不足50时,移除免运费选项
- 结账页提示逻辑:严格按照需求分支判断,确保每种场景的输出符合预期
内容的提问来源于stack exchange,提问作者Marco Crisgod
相关产品推荐
相关产品推荐

