WooCommerce结账时免费配送启用后仍计算运费的问题排查
问题:WooCommerce免费配送启用后仍计算运费的修复
我为WooCommerce的每个产品设置了以下自定义字段:
shipping_national_free_shipping:复选框,用于启用/禁用国内免费配送shipping_national_one_item_cost:数字字段,单件商品的运费shipping_national_additional_items_cost:数字字段,超出单件后的额外商品运费
当前代码在shipping_national_free_shipping禁用时,能正确计算运费并添加至产品价格;但启用该免费配送选项后,代码仍会读取另外两个运费字段的值并添加运费,不符合预期(此时应忽略运费计算)。
原代码
function kraftdeck_national_shipping_cost_logic($cart) { if (is_admin() && !defined('DOING_AJAX')) { return; } error_log('Starting national shipping cost logic...'); $customer_shipping_country_code = WC()->customer->get_shipping_country(); $customer_shipping_country = kraftdeck_get_full_country_name($customer_shipping_country_code); foreach ($cart->get_cart() as $cart_item_key => $cart_item) { $product_id = $cart_item['product_id']; $national_free_shipping = get_field('shipping_national_free_shipping', $product_id); // Check if national free shipping is enabled ('enabled' in array) if (!empty($national_free_shipping) && in_array('enabled', (array)$national_free_shipping)) { continue; } $country_of_origin = get_field('shipping_country_of_origin', $product_id); if ($customer_shipping_country === $country_of_origin) { $shipping_national_one_item_cost = get_field('shipping_national_one_item_cost', $product_id); $shipping_national_additional_items_cost = get_field('shipping_national_additional_items_cost', $product_id); $quantity = $cart_item['quantity']; $additional_shipping_cost = 0; if (is_numeric($shipping_national_one_item_cost)) { if (empty($shipping_national_additional_items_cost)) { $additional_shipping_cost = $shipping_national_one_item_cost * $quantity; } else { $additional_shipping_cost = $shipping_national_one_item_cost + $shipping_national_additional_items_cost * ($quantity - 1); } } if ($additional_shipping_cost > 0) { $base_price = $cart_item['data']->get_price(); $new_price = ($base_price * $quantity) + $additional_shipping_cost; $cart_item['data']->set_price($new_price / $quantity); } } error_log("Final Additional Shipping Cost for Product $product_id: $additional_shipping_cost"); error_log("Final Price for Product $product_id: " . $cart_item['data']->get_price()); } } add_action('woocommerce_before_calculate_totals', 'kraftdeck_national_shipping_cost_logic'); function kraftdeck_get_full_country_name($country_code) { $countries = WC()->countries->get_countries(); $full_name = isset($countries[$country_code]) ? $countries[$country_code] : ''; // Remove any parentheses and content within them $full_name_cleaned = preg_replace('/\s+(.+)$/', '', $full_name); return $full_name_cleaned; } remove_action('woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_price', 10);
问题原因及修复方案
问题根源
原代码中对shipping_national_free_shipping字段的判断逻辑存在漏洞:ACF的复选框字段如果是单选项启用,返回值可能是字符串'enabled'而非数组,此时in_array('enabled', (array)$national_free_shipping)虽然能转换为数组,但如果字段返回的是布尔值或其他格式,判断会失效,导致免费配送启用时没有跳过运费计算。
修复后的代码
function kraftdeck_national_shipping_cost_logic($cart) { if (is_admin() && !defined('DOING_AJAX')) { return; } error_log('Starting national shipping cost logic...'); $customer_shipping_country_code = WC()->customer->get_shipping_country(); $customer_shipping_country = kraftdeck_get_full_country_name($customer_shipping_country_code); foreach ($cart->get_cart() as $cart_item_key => $cart_item) { $product_id = $cart_item['product_id']; $national_free_shipping = get_field('shipping_national_free_shipping', $product_id); // 修正免费配送判断逻辑:适配ACF复选框的各种返回格式 $free_shipping_enabled = false; if (is_array($national_free_shipping)) { $free_shipping_enabled = in_array('enabled', $national_free_shipping); } elseif (is_string($national_free_shipping)) { $free_shipping_enabled = ($national_free_shipping === 'enabled'); } elseif (is_bool($national_free_shipping)) { $free_shipping_enabled = $national_free_shipping; } if ($free_shipping_enabled) { error_log("Product $product_id has free national shipping, skipping cost calculation"); continue; } $country_of_origin = get_field('shipping_country_of_origin', $product_id); if ($customer_shipping_country === $country_of_origin) { $shipping_national_one_item_cost = get_field('shipping_national_one_item_cost', $product_id); $shipping_national_additional_items_cost = get_field('shipping_national_additional_items_cost', $product_id); $quantity = $cart_item['quantity']; $additional_shipping_cost = 0; if (is_numeric($shipping_national_one_item_cost)) { if (empty($shipping_national_additional_items_cost)) { $additional_shipping_cost = $shipping_national_one_item_cost * $quantity; } else { $additional_shipping_cost = $shipping_national_one_item_cost + $shipping_national_additional_items_cost * ($quantity - 1); } } if ($additional_shipping_cost > 0) { $base_price = $cart_item['data']->get_price(); $new_price = ($base_price * $quantity) + $additional_shipping_cost; $cart_item['data']->set_price($new_price / $quantity); } } error_log("Final Additional Shipping Cost for Product $product_id: $additional_shipping_cost"); error_log("Final Price for Product $product_id: " . $cart_item['data']->get_price()); } } add_action('woocommerce_before_calculate_totals', 'kraftdeck_national_shipping_cost_logic'); function kraftdeck_get_full_country_name($country_code) { $countries = WC()->countries->get_countries(); $full_name = isset($countries[$country_code]) ? $countries[$country_code] : ''; // Remove any parentheses and content within them $full_name_cleaned = preg_replace('/\s+(.+)$/', '', $full_name); return $full_name_cleaned; } remove_action('woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_price', 10);
修复说明
- 重构了免费配送字段的判断逻辑,适配ACF复选框可能返回的数组、字符串、布尔值等多种格式,确保准确识别是否启用了免费配送
- 当确认免费配送启用时,直接跳过后续的运费计算逻辑,避免误加运费
- 增加了对应的错误日志输出,方便调试排查
内容的提问来源于stack exchange,提问作者Ashley Young
相关产品推荐
相关产品推荐

