WooCommerce自定义价格失效:COD订单提交后价格重置问题求助
嘿,搞定COD订单价格重置的问题!
我一眼就看到了两个核心问题导致你的逻辑在提交订单后失效:
问题根源
- 全局变量“断档”:你用的
$allFreeItems是全局变量,在购物车/结账页的浏览请求里是有效的,但用户提交COD订单时,这是一个全新的POST请求,全局变量会被清空,根本匹配不到需要免费的商品key,订单项自然就回到了产品原始价格。 - 订单创建时的价格“回溯”:哪怕你在购物车里改了价格,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 );
关键修改说明
- 用WC_Session替代全局变量:WooCommerce会话会跟着用户的整个购物流程走,不管是浏览还是提交订单,都能正确获取到需要免费的商品key,彻底解决全局变量失效的问题。
- 新增订单订单项钩子:
woocommerce_checkout_create_order_line_item是WooCommerce创建订单项的核心节点,在这里改价格会直接写入订单数据库,确保订单显示的是实际结算的0元。 - 移除无效钩子:删掉没用的
woocommerce_after_checkout_form,减少不必要的代码。 - 防重复触发:加入了重复触发判断,避免某些场景下钩子多次执行导致的价格混乱。
额外提醒
- 确保你的
$allFreeItems生成逻辑是正确的,而且执行时机要早于woocommerce_before_calculate_totals,不然会拿不到数据。 - 如果你的“买一送一”涉及可变产品、库存扣减这些复杂场景,可能还要额外调整,但当前代码已经解决了COD订单价格重置的核心问题。
内容的提问来源于stack exchange,提问作者Veeble
相关产品推荐
相关产品推荐

