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

如何覆盖已被woocommerce_product_get_price过滤的WooCommerce购物车商品价格?

WooCommerce定价冲突解决方案:同时实现用户专属价与免费赠品

问题背景

开发WooCommerce扩展时,遇到两个功能的冲突:

  • 全店范围内根据用户和商品信息动态设置专属价格
  • 强制指定部分购物车商品为免费(赠品)

两个功能单独运行正常,但同时启用后,免费商品的0价格会被专属定价函数覆盖。

用户专属定价代码(简化版)

add_filter('woocommerce_product_get_price', 'wcds_custom_price', 10, 2);
function wcds_custom_price($price, $product)
{
    if (did_action('woocommerce_product_get_price') >= 2) {
        return;
    }
    // 获取用户与商品对应的专属价格
    $user_id = get_current_user_id();
    $price = wcds_get_price($product, $user_id); // 此功能正常
    return $price;
}

免费赠品定价代码(简化版)

add_filter('woocommerce_before_calculate_totals', 'wcds_apply_giveaway_pricing', 999, 1);
function wcds_apply_giveaway_pricing($cart)
{

    // 不在后台修改价格
    if (is_admin()) {
        return;
    }

    if (did_action('woocommerce_before_calculate_totals') >= 2) {
        return;
    }

    // $giveaway_products示例(实际为动态设置)
    $giveaway_products = array(
        '107964' => array
        (
            'qty' => '2',
            'giveaway_post_id' => '127753'
        )
    );


    // $total_quantities示例(实际从购物车内容动态获取)
    $total_quantities = array(
        '107964' => '5'
    );


    $to_add = array();

    // 遍历购物车商品并拆分赠品
    foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
        $product_id = $cart_item['product_id'];

        if (array_key_exists($product_id, $giveaway_products)) {
            $total_quantity = $total_quantities[$product_id];
            $free_quantity = $giveaway_products[$product_id]['qty'];
            $free_quantity = min($total_quantity, $free_quantity);
            $paid_quantity = max($total_quantity - $free_quantity, 0);

            $to_add[$product_id] = [
                'paid' => $paid_quantity,
                'free' => $free_quantity,
                'giveaway_post_id' => $giveaway_products[$product_id]['giveaway_post_id'],
            ];

            $cart->remove_cart_item($cart_item_key); // 删除赠品商品的原始订单项
        } else {
            unset($cart_item['giveaway']); // 若不在赠品列表则移除赠品标记
        }
    }

    // 添加调整数量后的赠品商品到购物车
    foreach ($to_add as $product_id => $data) {
        // 添加付费商品到购物车
        if ($data['paid'] > 0) {
            $cart->add_to_cart($product_id, $data['paid']);
        }

        // 添加免费赠品商品到购物车
        if ($data['free'] > 0) {
            $giveaway_id = $data['giveaway_post_id'];
            $cart_item_key = $cart->add_to_cart($product_id, $data['free'], '', '', [
                'giveaway' => true,
                'giveaway_id' => $giveaway_id,
            ]);
            // 调整赠品商品价格
            $cart_item = $cart->get_cart_item($cart_item_key);
            $cart_item['data']->set_price(0);
            $cart_item['data']->set_name('FREE: ' . $cart_item['data']->get_name()); // 可选:修改赠品名称
        }
    }

}

冲突核心:woocommerce_product_get_price过滤器会在woocommerce_before_calculate_totals之后多次触发,覆盖通过set_price()设置的0价格。


解决方案

方案1:在专属定价函数中排除赠品

修改用户专属定价函数,判断当前商品是否为购物车中的赠品,若是则跳过价格修改逻辑:

add_filter('woocommerce_product_get_price', 'wcds_custom_price', 10, 2);
function wcds_custom_price($price, $product)
{
    if (did_action('woocommerce_product_get_price') >= 2) {
        return $price;
    }

    // 检查当前商品是否为购物车中的赠品
    global $woocommerce;
    if (isset($woocommerce->cart)) {
        foreach ($woocommerce->cart->get_cart() as $cart_item) {
            if ($cart_item['product_id'] === $product->get_id() && isset($cart_item['giveaway']) && $cart_item['giveaway'] === true) {
                return $price; // 保留已设置的0价格
            }
        }
    }

    // 获取用户与商品对应的专属价格
    $user_id = get_current_user_id();
    $price = wcds_get_price($product, $user_id); // 此功能正常
    return $price;
}

方案2:直接锁定购物车项的价格

在设置赠品价格时,直接修改购物车项的小计和总计,绕过后续价格计算:

修改免费赠品代码中的价格设置部分:

// 添加免费赠品商品到购物车
if ($data['free'] > 0) {
    $giveaway_id = $data['giveaway_post_id'];
    $cart_item_key = $cart->add_to_cart($product_id, $data['free'], '', '', [
        'giveaway' => true,
        'giveaway_id' => $giveaway_id,
    ]);
    // 调整赠品商品价格
    $cart_item = $cart->get_cart_item($cart_item_key);
    $cart_item['data']->set_price(0);
    // 直接设置购物车项的小计和总计
    $cart_item['line_subtotal'] = 0;
    $cart_item['line_total'] = 0;
    $cart_item['data']->set_name('FREE: ' . $cart_item['data']->get_name()); // 可选:修改赠品名称
    // 保存修改后的购物车项
    $cart->cart_contents[$cart_item_key] = $cart_item;
}

原理说明

  • 方案1通过识别购物车项的giveaway标记,让专属定价逻辑跳过赠品商品,保留已设置的0价格。
  • 方案2直接修改购物车项的line_subtotal和line_total,强制锁定价格为0,避免后续过滤器覆盖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:45:03