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

Woocommerce实现BOGO活动:购物车复制商品而非增数量

解决WooCommerce买赠(BOGO)活动:新增免费商品项而非合并数量

问题分析

你当前的代码使用WC()->cart->add_to_cart()时,WooCommerce默认会将同商品的购物项合并,导致无法生成独立的免费商品项。另外,代码没有处理重复添加的问题(比如用户多次更新购物车时会重复添加免费项),也没设置免费项的价格为0。

修正后的完整代码

// 监听购物车更新事件,添加免费商品项
add_filter('woocommerce_update_cart_action_cart_updated', 'add_free_bogo_item_on_cart_update');
add_action('woocommerce_cart_loaded_from_session', 'add_free_bogo_item_on_cart_update');

function add_free_bogo_item_on_cart_update() {
    if (!WC()->cart) return;

    $cart_items = WC()->cart->get_cart();
    $added_free_items = [];

    // 先记录已存在的免费项,避免重复添加
    foreach ($cart_items as $key => $item) {
        if (isset($item['free_bogo_item']) && $item['free_bogo_item'] === true) {
            $added_free_items[$item['product_id']] = true;
        }
    }

    // 遍历购物车项,添加对应免费商品
    foreach ($cart_items as $key => $item) {
        $product_id = $item['product_id'];
        $quantity = $item['quantity'];

        // 跳过免费项本身,且仅当数量≥5且未添加过对应免费项时执行
        if (isset($item['free_bogo_item']) || $quantity < 5 || isset($added_free_items[$product_id])) {
            continue;
        }

        // 添加免费商品,标记为免费项
        WC()->cart->add_to_cart(
            $product_id,
            1,
            $item['variation_id'],
            $item['variation'],
            ['free_bogo_item' => true] // 自定义元数据标记免费项
        );

        // 标记已添加,防止重复
        $added_free_items[$product_id] = true;
    }

    WC()->cart->calculate_totals();
}

// 修改免费项的价格显示为FREE,小计为0
add_filter('woocommerce_cart_item_subtotal', 'set_bogo_free_item_price', 10, 3);
add_filter('woocommerce_cart_item_price', 'set_bogo_free_item_price', 10, 3);

function set_bogo_free_item_price($price, $cart_item, $cart_item_key) {
    if (isset($cart_item['free_bogo_item']) && $cart_item['free_bogo_item'] === true) {
        return '<span class="free-bogo-item">FREE</span>';
    }
    return $price;
}

// 确保免费项的实际价格为0(不影响订单计算)
add_action('woocommerce_before_calculate_totals', 'set_bogo_free_item_actual_price');

function set_bogo_free_item_actual_price($cart) {
    if (is_admin() && !defined('DOING_AJAX')) return;
    if (did_action('woocommerce_before_calculate_totals') >= 2) return;

    foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
        if (isset($cart_item['free_bogo_item']) && $cart_item['free_bogo_item'] === true) {
            $cart_item['data']->set_price(0);
        }
    }
}

代码说明

  1. 覆盖全场景:同时使用woocommerce_update_cart_action_cart_updated和woocommerce_cart_loaded_from_session钩子,覆盖用户添加商品到购物车、更新购物车数量两种触发场景。
  2. 防止重复添加:先遍历购物车记录已存在的免费项,避免用户多次更新购物车时重复生成免费商品。
  3. 标记免费项:通过自定义元数据free_bogo_item标记免费商品,方便后续识别并修改价格。
  4. 价格双处理:
    • 用woocommerce_cart_item_subtotal和woocommerce_cart_item_price钩子修改前端显示为"FREE",匹配你需要的展示效果。
    • 用woocommerce_before_calculate_totals钩子设置免费项的实际价格为0,确保订单金额计算正确。

使用注意事项

  • 将代码添加到你的主题functions.php文件或自定义插件中。
  • 若需针对特定商品生效,可在判断条件中添加商品ID白名单,比如if ($product_id !== 123) continue;(替换123为目标商品ID)。
  • 测试前清空购物车缓存,确保代码正常生效。

内容的提问来源于stack exchange,提问作者Nymul Islam Moon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:43:27