Woocommerce 3中通过GET变量设置购物车商品自定义价格异常
解决Woocommerce 3.3.5+自定义支付金额加载后重置为0的问题
我之前升级WC到3.3版本后也碰到过一模一样的坑,你的代码逻辑本身没毛病,但新版本对购物车数据的处理和钩子触发机制有了变化,才导致价格被莫名重置。核心问题出在这两点:
woocommerce_before_calculate_totals钩子在结账页会多次触发,第一次加载时能拿到URL里的$_GET['amount'],但后续触发时这个参数就不存在了,此时$payment_value为空,直接把商品价格设成了0;- 新版WC里直接修改
$cart_item['data']->set_price(),没有把值同步到持久化的购物车会话中,后续页面刷新就会丢失自定义价格。
修复后的代码
add_action( 'woocommerce_before_calculate_totals', 'pay_custom_amount', 99 ); function pay_custom_amount() { // 避免钩子重复执行,减少不必要的计算开销 if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return; // 先处理URL参数,存入WC会话,确保后续钩子触发也能拿到值 if ( isset( $_GET['amount'] ) && is_numeric( $_GET['amount'] ) && $_GET['amount'] > 0 ) { WC()->session->set( 'custom_payment_amount', floatval( $_GET['amount'] ) ); } // 从会话中获取自定义金额 $payment_value = WC()->session->get( 'custom_payment_amount' ); // 只有拿到有效金额时才修改价格 if ( $payment_value ) { foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { // 目标商品ID,这里对应你的商品ID 21 $target_product_id = 21; // 新版WC要用get_id()方法获取商品ID,别直接访问id属性(旧写法已被弃用) if ( $cart_item['data']->get_id() === $target_product_id ) { $cart_item['data']->set_price( $payment_value ); // 强制同步购物车数据到会话,确保价格不会丢失 WC()->cart->set_session(); } } } }
几个关键的改进说明
- 会话存储金额:把URL里的金额存到Woocommerce的session中,这样不管钩子触发多少次,都能拿到正确的数值,不会因为后续没有GET参数就清空价格;
- 参数有效性检查:确保
amount是正数数值,防止非法值(比如空字符串、负数)导致的异常; - 新版WC兼容:用
get_id()代替直接访问id属性,这是WC 3.0+推荐的标准写法,避免属性访问报错; - 限制钩子执行次数:通过
did_action让钩子只执行一次,减少重复循环处理购物车项的开销。
另外,如果你想在用户移除目标商品或者清空购物车时清除会话里的金额,可以加这段代码:
add_action( 'woocommerce_cart_item_removed', 'clear_custom_payment_session' ); add_action( 'woocommerce_cart_emptied', 'clear_custom_payment_session' ); function clear_custom_payment_session() { WC()->session->__unset( 'custom_payment_amount' ); }
这样就能避免残留的会话值影响其他订单啦。
内容的提问来源于stack exchange,提问作者Robert Papworth
相关产品推荐
相关产品推荐

