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

WooCommerce禁止免费与付费商品一同购买的代码优化咨询

WooCommerce 免费与付费商品互斥购物功能优化

需求明确

要实现:购物车中存在免费(0定价)商品时,自动移除所有付费商品;反之,购物车有付费商品时,自动移除所有免费商品,两者无法同时下单。

原代码的问题

  1. 价格判断错误:用WC()->cart->get_product_price()获取的是带货币符号的格式化字符串(比如"$0.00"),直接和数字0比较会失效。
  2. 移除不彻底:移除付费商品时用了break,只会删掉第一个付费商品,不是全部。
  3. 逻辑不完整:只处理了「存在免费商品时移除付费商品」的情况,没处理「存在付费商品时移除免费商品」的反向逻辑。
  4. 钩子时机不合适:template_redirect钩子会在页面跳转时触发,不如专门处理购物车计算的woocommerce_before_calculate_totals精准高效。

优化后的代码

add_action( 'woocommerce_before_calculate_totals', 'exclude_free_paid_products_in_cart', 10, 1 );
function exclude_free_paid_products_in_cart( $cart ) {
    // 避免重复执行(该钩子可能触发多次)
    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) {
        return;
    }

    $has_free_items = false;
    $has_paid_items = false;

    // 遍历购物车,标记是否存在免费/付费商品
    foreach ( $cart->get_cart() as $cart_item ) {
        $product_price = (float) $cart_item['data']->get_price();
        
        if ( $product_price <= 0 ) {
            $has_free_items = true;
        } else {
            $has_paid_items = true;
        }
    }

    // 两者同时存在时执行移除逻辑
    if ( $has_free_items && $has_paid_items ) {
        // 移除所有付费商品(优先保留免费商品)
        foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
            $product_price = (float) $cart_item['data']->get_price();
            if ( $product_price > 0 ) {
                $cart->remove_cart_item( $cart_item_key );
                wc_add_notice( '免费商品与付费商品无法同时购买,已移除购物车中的付费商品', 'notice' );
            }
        }
        // 若需要优先保留付费商品,可替换为下面的逻辑:
        // foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        //     $product_price = (float) $cart_item['data']->get_price();
        //     if ( $product_price <= 0 ) {
        //         $cart->remove_cart_item( $cart_item_key );
        //         wc_add_notice( '付费商品与免费商品无法同时购买,已移除购物车中的免费商品', 'notice' );
        //     }
        // }
    }
}

优化点说明

  • 用get_price()获取原始价格:直接获取商品的数值价格,转成float类型后比较,避免字符串匹配错误。
  • 完整的互斥逻辑:覆盖两种共存场景,确保只要两者同时存在就执行对应移除操作。
  • 彻底移除对应商品:遍历所有购物车商品,移除符合条件的全部商品,而非单个。
  • 合适的钩子:woocommerce_before_calculate_totals是购物车操作的专用钩子,触发时机精准,还通过did_action避免重复执行。
  • 添加用户提示:用wc_add_notice告知用户商品被移除的原因,提升购物体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 00:54:18