WooCommerce使用woocommerce_new_order发邮件缺商品信息如何加延迟
问题根因
你的判断完全准确:woocommerce_new_order 钩子触发时,仅完成了订单主记录的创建,订单项、商品元数据、订单状态等关联数据还未写入数据库,此时调用wc_get_order()自然拿不到商品信息。存量订单因为所有数据早已落库,所以跑代码能正常取到内容。
注意不要在回调函数里直接用sleep()加同步延迟,这种写法会阻塞订单提交流程,极易触发PHP超时、支付回调失败,高并发下会严重影响站点稳定性。
可行实现方案
方案1:替换为数据全量写入后触发的钩子(零延迟,实现简单)
WooCommerce在订单所有关联数据(商品、税费、运费、元数据)全部落库后,会触发woocommerce_checkout_order_processed钩子,直接把业务逻辑挂载到这个钩子上即可,不需要额外加等待。
以下代码修正了原代码的几个已知问题:未定义$status变量、多商品循环覆盖变量、重复挂载邮件格式过滤器、无订单有效性判断:
// 单独挂载邮件内容类型过滤器,避免重复挂载 add_filter('wp_mail_content_type', function( $content_type ) { return 'text/html'; }); add_action( 'woocommerce_checkout_order_processed', 'extra_mail_after_new_order', 20, 1 ); function extra_mail_after_new_order( $order_id ) { $order = wc_get_order( $order_id ); if (!$order) return; // 订单不存在直接退出,避免报错 $items = $order->get_items(); $product_names = []; $product_info = []; foreach ( $items as $item ) { $product_name = $item->get_name(); $product_id = $item->get_product_id(); $product = wc_get_product($product_id); $product_variation_id = $item->get_variation_id(); $product_data = $product ? $product->get_meta('extra_email') : ''; $product_names[] = $product_name; $product_info[] = "商品名:{$product_name},商品ID:{$product_id},自定义元数据:{$product_data}"; } $status = $order->get_status(); $to = 'mail.mail@gmail.com'; $subject = implode(',', $product_names) . ' 新订单通知!'; $message = "订单ID: {$order_id}<br />"; $message .= "订单状态: {$status}<br />"; $message .= "商品明细:<br />" . implode('<br />', $product_info); wp_mail( $to, $subject, $message ); }
方案2:异步延迟执行(稳定性最高,不阻塞主流程)
如果站点安装了较多会修改订单数据的插件,担心钩子触发时还有后续逻辑没执行完,可以借助WP自带的定时任务功能,把发邮件的动作延迟10-30秒异步执行,完全不占用订单创建的请求进程,也不会出现数据取不全的问题。
代码示例:
// 注册自定义定时任务钩子 add_action( 'send_extra_order_notice', 'extra_mail_after_new_order' ); add_filter('wp_mail_content_type', function( $content_type ) { return 'text/html'; }); // 订单创建后挂载延迟任务 add_action( 'woocommerce_new_order', function( $order_id ) { // 延迟20秒执行发邮件任务,可根据自身需求调整时间 wp_schedule_single_event( time() + 20, 'send_extra_order_notice', [ $order_id ] ); }, 10, 1 ); function extra_mail_after_new_order( $order_id ) { $order = wc_get_order( $order_id ); if (!$order) return; $items = $order->get_items(); $product_names = []; $product_info = []; foreach ( $items as $item ) { $product_name = $item->get_name(); $product_id = $item->get_product_id(); $product = wc_get_product($product_id); $product_data = $product ? $product->get_meta('extra_email') : ''; $product_names[] = $product_name; $product_info[] = "商品名:{$product_name},商品ID:{$product_id},自定义元数据:{$product_data}"; } $status = $order->get_status(); $to = 'mail.mail@gmail.com'; $subject = implode(',', $product_names) . ' 新订单通知!'; $message = "订单ID: {$order_id}<br />"; $message .= "订单状态: {$status}<br />"; $message .= "商品明细:<br />" . implode('<br />', $product_info); wp_mail( $to, $subject, $message ); }
注意:如果站点安装了缓存类插件禁用了WP-Cron异步运行,需要在服务器侧配置定时任务触发WP-Cron,才能保证延迟邮件正常发送。
内容的提问来源于stack exchange,提问作者Ville
相关产品推荐
相关产品推荐

