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

WooCommerce:如何让经销商条件折扣在运费前生效

解决WooCommerce经销商折扣先于运费计算的问题

问题原因

你当前使用woocommerce_cart_calculate_fees钩子添加折扣,但这个钩子是在WooCommerce计算完运费、税费之后才触发的——这不仅会让折扣显示在运费条目之后,而且运费计算时完全不会考虑折扣后的金额。另外,add_fee方法添加的是额外费用项,不会改变购物车商品的原始总价,导致运费始终基于原价计算。

修改方案

改用woocommerce_before_calculate_totals钩子(该钩子在所有费用计算前触发),直接调整购物车商品的价格来实现折扣。这样运费计算时会基于折扣后的商品总价,同时折扣会在运费之前生效并显示。

修改后的完整代码

// 在所有费用计算前应用经销商折扣
add_action('woocommerce_before_calculate_totals', 'apply_dealer_discounts', 10, 1);

// 应用经销商自定义配送规则
add_filter('woocommerce_package_rates', 'custom_shipping_rules_dealer', 20, 2);

function apply_dealer_discounts($cart) {
    // 避免重复计算,防止钩子多次触发
    if (did_action('woocommerce_before_calculate_totals') >= 2) {
        return;
    }

    // 获取当前用户
    $current_user = wp_get_current_user();

    // 检查用户角色是否为dealer
    if (!in_array('dealer', (array) $current_user->roles)) {
        return;
    }

    $core_seasonal_discount = 0.10; // 10%折扣
    $keg_discount = 0.05; // 5%折扣
    $total_discount_rate = 0;

    // 先判断购物车内是否有符合折扣条件的商品
    $has_core_seasonal = false;
    $has_keg = false;

    foreach ($cart->get_cart() as $cart_item) {
        if (has_term(['core', 'seasonal'], 'product_cat', $cart_item['product_id'])) {
            $has_core_seasonal = true;
        }
        if (has_term('keg', 'product_cat', $cart_item['product_id'])) {
            $has_keg = true;
        }
    }

    // 计算累计折扣率
    if ($has_core_seasonal) {
        $total_discount_rate += $core_seasonal_discount;
    }
    if ($has_keg) {
        $total_discount_rate += $keg_discount;
    }

    // 对所有商品应用折扣
    if ($total_discount_rate > 0) {
        foreach ($cart->get_cart() as $cart_item) {
            $product = $cart_item['data'];
            $original_price = $product->get_price('edit');
            $discounted_price = $original_price * (1 - $total_discount_rate);
            $product->set_price($discounted_price);
        }
    }
}

function custom_shipping_rules_dealer($rates, $package) {
    // 获取当前用户
    $current_user = wp_get_current_user();

    // 检查用户角色是否为dealer
    if (!in_array('dealer', (array) $current_user->roles)) {
        return $rates;
    }

    // 初始化统计变量
    $total_core_seasonal = 0;
    $keg_count = 0;

    // 遍历购物车商品统计数量
    foreach ($package['contents'] as $item) {
        if (has_term(['core', 'seasonal'], 'product_cat', $item['product_id'])) {
            $total_core_seasonal += $item['quantity'];
        }
        if (has_term('keg', 'product_cat', $item['product_id'])) {
            $keg_count += $item['quantity'];
        }
    }

    // 获取当前配送区域
    $zone = WC_Shipping_Zones::get_zone_matching_package($package);
    $zone_name = $zone->get_zone_name();

    // 调试日志(可根据需求删除)
    error_log('配送区域: ' . $zone_name);
    error_log('Keg商品数量: ' . $keg_count);
    error_log('核心/季节商品数量: ' . $total_core_seasonal);

    // 应用配送规则
    foreach ($rates as $rate_key => $rate) {
        // 核心/季节商品配送规则
        if ($total_core_seasonal > 0) {
            if ($total_core_seasonal >= 10) {
                $rates[$rate_key]->cost = 0;
            } else {
                $rates[$rate_key]->cost = 60 * $total_core_seasonal;
            }
        }

        // Keg商品配送规则
        if ($keg_count > 0) {
            if ($zone_name === '曼谷大都会区') {
                $rates[$rate_key]->cost = 0;
            } else {
                $rates[$rate_key]->cost = 300 * $keg_count;
            }
        }
    }

    return $rates;
}

关键修改点说明

  1. 钩子替换:将折扣应用逻辑移到woocommerce_before_calculate_totals,确保在运费计算前执行。
  2. 直接修改商品价格:不再用add_fee添加折扣项,而是直接调整商品销售价格,让购物车总价实时更新为折扣后金额。
  3. 防重复计算:添加did_action判断,避免钩子重复触发导致折扣多次叠加。
  4. 逻辑优化:先统计符合折扣条件的商品类型,再计算累计折扣率统一应用,也可根据需求改为针对不同商品类型单独折扣。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:07:10