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

WooCommerce Per Product Shipping插件仅收最高运费代码报错求助

问题:WooCommerce Per Product Shipping插件实现仅收取最高产品运费时触发致命错误

我使用WooCommerce Per Product Shipping插件按产品设置运费,该插件无内置功能实现类似WooCommerce核心平邮的计算逻辑——仅收取整单中运费最高的产品的运费。我尝试用AI生成的代码实现,但操作后始终触发致命错误。

插件与产品设置说明

  • 插件设置:税务状态为应税;未设置默认产品运费、单产品或整单手续费;未勾选「忽略其他配送方式」;未启用其他配送方式
  • 产品设置:已启用按产品配送;为美国本土、夏威夷、阿拉斯加三个地区分别添加了运费条目

原AI生成代码(触发错误)

/**
 * Retrieve shipping costs for a WooCommerce product.
 *
 * @param int $product_id The ID of the WooCommerce product.
 * @return float|null Shipping cost for the product, or null if not found.
 */
function get_shipping_cost_for_product( $product_id ) {
    $shipping_methods = WC()->shipping->get_packages();
    
    foreach ( $shipping_methods as $package ) {
        foreach ( $package['rates'] as $rate ) {
            // Check if the shipping rate is applicable to the product.
            if ( $rate->method_id === '11' && $rate->get_instance_id() === 0 ) {
                // Retrieve the shipping cost for the product.
                return $rate->cost;
            }
        }
    }
    
    return null; // Shipping cost not found.
}

/**
 * Custom function to calculate shipping costs for WooCommerce Per Product Shipping.
 *
 * @param array $package Shipping package.
 * @return void
 */
function custom_per_product_shipping_cost( $package ) {
    if ( ! is_array( $package['contents'] ) ) {
        return;
    }

    // Initialize variables to keep track of the highest shipping cost.
    $highest_shipping_cost = 0;
    
    // Loop through each item in the cart.
    foreach ( $package['contents'] as $item_id => $item ) {
        $product_id = $item['product_id'];
        
        // Get the shipping cost for the current product.
        $shipping_cost = get_shipping_cost_for_product( $product_id );
        
        // Compare with the highest shipping cost found so far.
        if ( $shipping_cost > $highest_shipping_cost ) {
            $highest_shipping_cost = $shipping_cost;
        }
    }
    
    // Set the calculated highest shipping cost for the entire order.
    $package['contents_cost'] = $highest_shipping_cost;
    
    // Update the package shipping costs.
    WC()->cart->shipping_total      = $highest_shipping_cost;
    WC()->cart->shipping_tax_total  = 0; // You may need to adjust tax calculation.
    WC()->cart->shipping_taxes      = array();
    WC()->cart->shipping_methods    = array();
    
    // Recalculate cart totals.
    WC()->cart->calculate_totals();
}

// Hook into the shipping calculation process.
add_action( 'woocommerce_cart_shipping_packages', 'custom_per_product_shipping_cost' );

问题分析

  1. 钩子使用错误:woocommerce_cart_shipping_packages是过滤器(需返回修改后的数据),原代码用动作钩子且未返回包裹数组,导致循环计算触发致命错误
  2. 运费获取逻辑失效:硬编码method_id === '11'不通用,且依赖未完成计算的包裹费率,无法准确读取产品运费设置
  3. 直接修改购物车属性:调用WC()->cart->calculate_totals()会重新触发运费计算,造成无限循环

修正后的代码

/**
 * 获取指定产品对应配送区域的运费(适配WooCommerce Per Product Shipping插件)
 *
 * @param int $product_id 产品ID
 * @param array $package 配送包裹(包含用户地址信息)
 * @return float 产品运费
 */
function get_per_product_shipping_cost( $product_id, $package ) {
    $shipping_cost = 0;
    $shipping_zones = WC_Shipping_Zones::get_zones();
    $customer_location = $package['destination'];
    
    // 匹配用户所在配送区域
    foreach ( $shipping_zones as $zone ) {
        $is_match = WC_Shipping_Zones::location_matches_zone( $customer_location, $zone['zone_locations'] );
        
        if ( $is_match ) {
            $product_shipping = get_post_meta( $product_id, '_per_product_shipping', true );
            if ( is_array( $product_shipping ) && isset( $product_shipping[ $zone['zone_id'] ] ) ) {
                $shipping_cost = (float) $product_shipping[ $zone['zone_id'] ]['cost'];
                break;
            }
        }
    }
    
    // 匹配默认区域运费
    if ( $shipping_cost === 0 ) {
        $product_shipping = get_post_meta( $product_id, '_per_product_shipping', true );
        if ( is_array( $product_shipping ) && isset( $product_shipping[0] ) ) {
            $shipping_cost = (float) $product_shipping[0]['cost'];
        }
    }
    
    return $shipping_cost;
}

/**
 * 定制Per Product Shipping计算逻辑:仅收取最高产品运费
 *
 * @param array $packages 配送包裹数组
 * @return array 修改后的包裹数组
 */
function custom_per_product_shipping_highest_cost( $packages ) {
    if ( empty( $packages ) ) return $packages;
    
    $highest_shipping_cost = 0;
    
    // 遍历包裹商品,找出最高运费
    foreach ( $packages as &$package ) {
        if ( empty( $package['contents'] ) ) continue;
        
        foreach ( $package['contents'] as $item ) {
            $item_shipping_cost = get_per_product_shipping_cost( $item['product_id'], $package );
            if ( $item_shipping_cost > $highest_shipping_cost ) {
                $highest_shipping_cost = $item_shipping_cost;
            }
        }
        
        // 更新Per Product Shipping费率为最高运费
        if ( $highest_shipping_cost > 0 ) {
            foreach ( $package['rates'] as $rate_id => $rate ) {
                if ( $rate->method_id === 'per_product' ) {
                    $package['rates'][ $rate_id ]->cost = $highest_shipping_cost;
                    // 同步计算运费税费
                    $taxes = WC_Tax::calc_shipping_tax( $highest_shipping_cost, WC()->tax()->get_shipping_tax_rates() );
                    $package['rates'][ $rate_id ]->taxes = $taxes;
                }
            }
        }
    }
    
    return $packages;
}
add_filter( 'woocommerce_cart_shipping_packages', 'custom_per_product_shipping_highest_cost' );

代码关键改进

  • 使用过滤器钩子并正确返回包裹数组,避免循环计算
  • 直接读取插件存储的产品元数据运费,逻辑更稳定可靠
  • 自动匹配用户所在配送区域的运费设置,覆盖默认区域场景
  • 修改现有费率成本而非直接操作购物车属性,避免冲突
  • 保留税费计算逻辑,适配插件应税设置

内容的提问来源于stack exchange,提问作者Janna Hartley

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 09:16:01