woocommerce_new_order钩子中get_items('fee')无法获取fee_lines内的负额分销商折扣
根因定位
- 钩子时序错位:
woocommerce_new_order触发时机为订单主记录刚写入数据库的瞬间,此时费项、商品行等关联行项目数据尚未完成同步写入,调用$order->get_items('fee')会返回空数组,导致循环不执行。 - 序列化对象解析误区:调试时看到的
fee_lines是WooCommerce订单CR对象的动态缓存属性,不是数据库原生存储字段,直接将订单对象序列化后json_decode解析,无法获取实时存储的费项值。 - 取值逻辑错配:
get_total_discount()仅返回官方优惠券产生的折扣金额,和自定义添加的负费项折扣属于独立逻辑,永远无法取到你通过购物车钩子添加的分销商折扣值。
可直接落地的解决方案
1. 调整钩子挂载位置
将原挂载在woocommerce_new_order的回调,替换为所有订单行项目全部写入完成后才触发的woocommerce_checkout_order_created钩子,从根源上解决时序问题。
2. 标准取值代码实现
无需重复通过wc_get_order初始化对象,回调会直接传入已完成数据加载的$order实例,可直接通过官方方法遍历匹配目标费项:
add_action( 'woocommerce_checkout_order_created', 'insert_distributor_discount' ); function insert_distributor_discount( $order ) { $target_fee_value = 0; // 遍历订单所有费项 foreach( $order->get_items( 'fee' ) as $fee ) { // 匹配和购物车中定义完全一致的费项名称 if ( $fee->get_name() === 'Distributor Discount' ) { // 获取费项不含税总金额,即你看到的-500这个值 $target_fee_value = $fee->get_total(); // 如需获取费项税额,可调用 $fee->get_total_tax() } } // 执行自定义数据库插入逻辑,将$target_fee_value写入指定表 }
3. 排查调试方案
如果遍历后未匹配到目标费项,可临时增加调试日志,确认费项实际存储的名称和值:
add_action( 'woocommerce_checkout_order_created', function( $order ) { foreach( $order->get_items( 'fee' ) as $fee ) { // 输出到服务端调试日志,核对费项信息 error_log( "费项名称:{$fee->get_name()} | 费项值:{$fee->get_total()}" ); } });
排查时注意确认费项名称是否存在大小写不匹配、前后带空格的问题。
注意事项
- 禁止直接读取
$order->fee_lines动态属性:该属性为本地缓存值,存在缓存未刷新导致取空的风险,必须通过get_items('fee')官方方法获取,该方法会主动校验数据有效性。 - 不要依赖JSON解析订单对象的方式取值:WooCommerce序列化的对象结构存在动态属性,解析后拿到的
fee_lines为非结构化数组,数据可靠性远低于官方取值方法。
内容的提问来源于stack exchange,提问作者Ako Si
相关产品推荐
相关产品推荐

