WooCommerce 8.6.1:特定配送区域改配送类代码无效果排查
WooCommerce 8.6.1 配送类修改代码无效问题排查与修复
问题背景
需求为:结账时,若客户处于指定配送区域(ID 29),且购物车中至少有2个属于特定配送类(ID 343)的商品,需将这些商品的配送类改为ID 344。提供的代码未产生预期效果,已排除插件、其他代码片段、主题兼容性问题。
原代码:
// Custom function to change shipping class if conditions are met function adjust_shipping_class_based_on_quantity() { // Get the current cart contents $cart = WC()->cart->get_cart(); // Check if the cart contains items and the first item has a destination if ( ! empty( $cart ) && isset( $cart[0]['destination'] ) && is_array( $cart[0]['destination'] ) ) { // Get the shipping zone ID $zone_id = WC_Shipping_Zones::get_zone_matching_package( array( 'contents' => $cart ) )->get_id(); // Check if the shipping zone ID is 29 if ( $zone_id == 29 ) { // Initialize variables to count 'Letter box' items $letter_box_count = 0; // Loop through cart items to count 'Letter box' items foreach( $cart as $item ) { if ( isset( $item['data'] ) && $item['data']->get_shipping_class_id() == 343 ) { // Increment count for each 'Letter box' item $letter_box_count += $item['quantity']; } } // If there are at least 2 'Letter box' items, change shipping class of all 'Letter box' items to 344 if ( $letter_box_count >= 2 ) { // Loop through cart items again to change shipping class if shipping class ID is 343 foreach( $cart as $key => $item ) { if ( isset( $item['data'] ) && $item['data']->get_shipping_class_id() == 343 ) { // Change the shipping class of the item to 'regular-package' $cart[$key]['data']->set_shipping_class_id(344); } } } // Set the modified cart contents WC()->cart->set_cart( $cart ); } } } add_action( 'woocommerce_cart_loaded_from_session', 'adjust_shipping_class_based_on_quantity' );
问题根源分析
配送区域获取逻辑错误
- 购物车项(cart item)中不存在
destination键,原代码通过$cart[0]['destination']判断配送地址存在的逻辑不成立,配送地址信息存储在会话的配送包裹数据中。 - 调用
WC_Shipping_Zones::get_zone_matching_package时,传入的参数缺少destination字段,导致无法正确匹配配送区域。
- 购物车项(cart item)中不存在
钩子时机不合适
woocommerce_cart_loaded_from_session仅在购物车从会话加载时触发,无法响应结账过程中用户修改收货地址的场景,导致条件判断无法实时更新。
购物车数据更新逻辑错误
- 修改商品配送类后,调用
WC()->cart->set_cart($cart)属于冗余操作,且未触发购物车重新计算,导致修改后的配送类无法生效。
- 修改商品配送类后,调用
修复后的代码
function adjust_shipping_class_based_on_shipping_zone_and_quantity() { // 确保WC Cart对象存在且非空 if ( ! WC()->cart || WC()->cart->is_empty() ) { return; } // 获取完整的配送包裹信息 $shipping_package = WC()->cart->get_shipping_packages()[0] ?? null; if ( ! $shipping_package || empty( $shipping_package['destination'] ) ) { return; } // 匹配当前配送区域,捕获异常避免未设置地址时报错 try { $shipping_zone = WC_Shipping_Zones::get_zone_matching_package( $shipping_package ); $zone_id = $shipping_zone->get_id(); } catch ( Exception $e ) { return; } // 检查是否为目标配送区域ID 29 if ( $zone_id != 29 ) { return; } // 统计目标配送类(ID 343)的商品总数量 $target_class_count = 0; foreach ( WC()->cart->get_cart() as $item ) { if ( isset( $item['data'] ) && $item['data']->get_shipping_class_id() == 343 ) { $target_class_count += $item['quantity']; } } // 数量不足2则终止 if ( $target_class_count < 2 ) { return; } // 修改符合条件的商品配送类为ID 344 foreach ( WC()->cart->get_cart() as $key => $item ) { if ( isset( $item['data'] ) && $item['data']->get_shipping_class_id() == 343 ) { $item['data']->set_shipping_class_id(344); // 标记购物车内容已变更 WC()->cart->cart_contents_changed = true; } } // 触发购物车重新计算,确保变更生效 WC()->cart->calculate_totals(); } // 在购物车计算前和结账配送方式更新时触发,覆盖全场景 add_action( 'woocommerce_before_calculate_totals', 'adjust_shipping_class_based_on_shipping_zone_and_quantity', 20 ); add_action( 'woocommerce_checkout_update_shipping_method', 'adjust_shipping_class_based_on_shipping_zone_and_quantity' );
代码说明
- 正确获取配送区域:通过
WC()->cart->get_shipping_packages()获取包含配送地址的完整包裹数据,确保get_zone_matching_package能准确匹配配送区域。 - 覆盖全场景钩子:使用
woocommerce_before_calculate_totals和woocommerce_checkout_update_shipping_method两个钩子,覆盖购物车修改、结账地址变更等所有需要触发逻辑的场景。 - 确保变更生效:标记购物车内容变更并调用
calculate_totals(),强制WooCommerce重新计算购物车数据,使修改的配送类生效。
内容的提问来源于stack exchange,提问作者chalcopterus
相关产品推荐
相关产品推荐

