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

WooCommerce自定义价格失效:COD订单提交后价格重置问题求助

嘿,搞定COD订单价格重置的问题!

我一眼就看到了两个核心问题导致你的逻辑在提交订单后失效:

问题根源

  1. 全局变量“断档”:你用的$allFreeItems是全局变量,在购物车/结账页的浏览请求里是有效的,但用户提交COD订单时,这是一个全新的POST请求,全局变量会被清空,根本匹配不到需要免费的商品key,订单项自然就回到了产品原始价格。
  2. 订单创建时的价格“回溯”:哪怕你在购物车里改了价格,WooCommerce创建订单的时候,默认会从数据库里重新拉取产品的原始价格,不会直接沿用购物车的修改——除非你在订单生成的关键节点主动插手。

另外,woocommerce_after_checkout_form这个钩子完全没用,它只是在结账表单显示完之后触发,对实际创建订单的流程半毛钱影响都没有,直接删掉就行。

解决方案代码

我们改用WooCommerce自带的会话(WC_Session)来存需要免费的商品key,这样跨请求也能拿到数据,同时在订单创建的钩子里同步修改价格:

// 处理购物车价格,同时把免费商品key存到会话里
function apply_free_item_discount( $cart_obj ) {
    // 防止钩子重复触发导致异常
    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) {
        return;
    }

    // 这里替换成你生成$allFreeItems的逻辑,确保能正确拿到数据
    global $allFreeItems;
    $free_item_keys = array();

    if ( !empty( $allFreeItems ) ) {
        foreach ($allFreeItems as $item) {
            $free_item_keys[] = $item[1]; // 提取要免费的商品key
        }
    }

    // 把免费key存入WooCommerce会话,跨请求也能拿到
    WC()->session->set( 'free_item_keys', $free_item_keys );

    // 修改购物车对应商品的价格
    foreach ( $cart_obj->get_cart() as $cart_item ) {
        $product_key = $cart_item['key'];
        if ( in_array( $product_key, $free_item_keys ) ) {
            $cart_item['data']->set_price( 0.00 );
        }
    }
}
add_action( 'woocommerce_before_calculate_totals', 'apply_free_item_discount', 10, 1 );

// 在创建订单订单项时,同步设置免费价格
function set_free_item_price_in_order( $item, $cart_item_key, $values, $order ) {
    // 从会话里取出免费商品key
    $free_item_keys = WC()->session->get( 'free_item_keys', array() );

    if ( in_array( $cart_item_key, $free_item_keys ) ) {
        $item->set_subtotal( 0.00 );
        $item->set_total( 0.00 );
        // 如果需要处理税费,也可以加下面两行
        // $item->set_subtotal_tax( 0.00 );
        // $item->set_total_tax( 0.00 );
    }
}
add_action( 'woocommerce_checkout_create_order_line_item', 'set_free_item_price_in_order', 10, 4 );

// 订单完成后清理会话数据(可选,但推荐)
function clear_free_item_session_data( $order_id ) {
    WC()->session->__unset( 'free_item_keys' );
}
add_action( 'woocommerce_checkout_order_processed', 'clear_free_item_session_data', 10, 1 );

关键修改说明

  1. 用WC_Session替代全局变量:WooCommerce会话会跟着用户的整个购物流程走,不管是浏览还是提交订单,都能正确获取到需要免费的商品key,彻底解决全局变量失效的问题。
  2. 新增订单订单项钩子:woocommerce_checkout_create_order_line_item是WooCommerce创建订单项的核心节点,在这里改价格会直接写入订单数据库,确保订单显示的是实际结算的0元。
  3. 移除无效钩子:删掉没用的woocommerce_after_checkout_form,减少不必要的代码。
  4. 防重复触发:加入了重复触发判断,避免某些场景下钩子多次执行导致的价格混乱。

额外提醒

  • 确保你的$allFreeItems生成逻辑是正确的,而且执行时机要早于woocommerce_before_calculate_totals,不然会拿不到数据。
  • 如果你的“买一送一”涉及可变产品、库存扣减这些复杂场景,可能还要额外调整,但当前代码已经解决了COD订单价格重置的核心问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:52:37