WooCommerce结账逻辑修改:将商品追加至Processing状态现有订单而非创建新订单的实现及钩子适配问题
解决WooCommerce结账时追加商品到现有Processing订单的问题
首先直接回答你的钩子选择问题:应该使用woocommerce_create_order过滤器,而非woocommerce_new_order动作。原因很直白:
woocommerce_new_order是在新订单已经创建完成后触发的,这时候再干预已经晚了——新订单已经生成,你没法阻止它的创建;- 而
woocommerce_create_order是在订单创建之前触发的,它允许你替换默认要创建的订单对象,完美匹配你“有Processing订单就复用,没有就新建”的需求。
接下来,你的原代码存在几个需要修正的细节问题,我会一步步帮你完善并整合到WooCommerce的默认逻辑中:
原代码的问题点
$user_id未定义,导致WC_Customer实例化失败;- 只取用户的最后一个订单,但可能最后一个订单状态不是Processing,而用户还有其他有效的Processing订单;
- 获取购物车商品数量时错误使用了
$product->get_quantity()(这是商品的库存数量),应该用购物车项自带的$cart_item['quantity']; - 缺少订单保存和购物车清空的逻辑,导致追加商品后订单不会更新,购物车商品依然残留;
- 用户角色判断逻辑不够健壮(如果用户有多个角色,
roles[0]不一定是管理员)。
修正后的完整代码
add_filter('woocommerce_create_order', 'custom_append_to_processing_order', 10, 2); function custom_append_to_processing_order($order, $data) { // 仅针对登录用户处理,未登录用户无法关联已有订单 if (!is_user_logged_in()) { return $order; // 返回默认订单对象,走正常创建流程 } $user_id = get_current_user_id(); $current_user = wp_get_current_user(); // 仅针对管理员角色处理(如果需要扩展到其他角色,修改这里的角色名即可) if (!in_array('administrator', $current_user->roles)) { return $order; } // 查询用户最新的Processing状态订单 $processing_orders = wc_get_orders(array( 'customer_id' => $user_id, 'status' => 'processing', 'limit' => 1, 'orderby' => 'date', 'order' => 'DESC', )); // 如果存在有效的Processing订单 if (!empty($processing_orders)) { $existing_order = reset($processing_orders); // 遍历购物车中的商品,逐个追加到现有订单 foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) { $product = $cart_item['data']; $quantity = $cart_item['quantity']; // 添加商品到现有订单 $existing_order->add_product($product, $quantity); } // 保存订单更新,确保追加的商品生效 $existing_order->save(); // 清空购物车,避免用户结账后购物车仍有商品残留 WC()->cart->empty_cart(); // 返回现有订单对象,WooCommerce会直接使用它,不再创建新订单 return $existing_order; } // 不存在Processing订单,返回默认订单对象,走正常创建流程 return $order; }
代码逻辑说明
- 登录与角色校验:先判断用户是否登录,再校验是否为管理员角色,不符合条件直接放行默认流程;
- 查询有效Processing订单:通过
wc_get_orders精准查询用户最新的Processing状态订单,确保拿到的是有效的未完成订单; - 追加商品与更新订单:遍历购物车商品,逐个添加到现有订单,然后保存订单确保修改生效;
- 清空购物车:追加完成后清空购物车,避免用户后续操作出现混淆;
- 订单对象返回:如果找到Processing订单,返回该订单对象,WooCommerce会直接复用它;如果没找到,返回默认的
$order对象,继续执行默认的订单创建流程。
使用方法
将上述代码添加到你的WordPress主题的functions.php文件中,或者创建一个自定义插件来存放这段代码(更推荐后者,避免主题更新导致代码丢失)。
内容的提问来源于stack exchange,提问作者checkm
相关产品推荐
相关产品推荐

