You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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); 

修复说明

  1. 重构了免费配送字段的判断逻辑,适配ACF复选框可能返回的数组、字符串、布尔值等多种格式,确保准确识别是否启用了免费配送
  2. 当确认免费配送启用时,直接跳过后续的运费计算逻辑,避免误加运费
  3. 增加了对应的错误日志输出,方便调试排查

内容的提问来源于stack exchange,提问作者Ashley Young

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 19:13:18