WooCommerce订单完成时自定义邮箱字段邮件发送失败排查
WooCommerce自定义邮箱收件人邮件发送失败排查
问题背景
根据购物车中虚拟商品的数量,在WooCommerce结账流程注册了参与者姓名、邮箱、头衔、生日的自定义字段,且已成功保存至后台订单详情。订单完成时需向order_email_ucastnika字段中的所有收件人发送含Zoom链接的邮件,使用账单邮箱时功能正常,切换为自定义邮箱后邮件无法发送。
相关代码
注册自定义结账字段代码
function cart_has_virtual_product() { if ( ! is_a( WC()->cart, 'WC_Cart' ) ) { return 0; } $virtual_product_count = 0; foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { $product = $cart_item['data']; if ( $product->is_virtual() ) { $virtual_product_count += $cart_item['quantity']; } } return $virtual_product_count; } add_filter('woocommerce_form_field', 'addHeadingsInBetweenFormFields', 10, 4); function addHeadingsInBetweenFormFields($field, $key, $args, $value = null) { // 修正逻辑与运算符,原代码位运算符&可能导致判断异常 if (is_checkout() && $key === 'order_jmeno_ucastnika') { $a = '<h3>Údaje o účastníkovi kurzu</h3>'; return $a . $field; } return $field; } function add_custom_checkout_fields( $fields ) { $virtual_product_count = cart_has_virtual_product(); for ( $i = 1; $i <= $virtual_product_count; $i++ ) { $fields['order']['order_jmeno_ucastnika' . $i] = array( 'label' => 'Jméno účastníka ' . $i, 'placeholder' => 'Jméno Příjmení', 'required' => true, 'class' => array( 'form-row-wide' ), 'clear' => true ); $fields['order']['order_email_ucastnika' . $i] = array( 'type' => 'email', 'label' => 'E-mail účastníka ' . $i, 'placeholder' => '', 'required' => true, 'class' => array( 'form-row-wide' ), 'clear' => true ); $fields['order']['order_title' . $i] = array( 'label' => 'Titul/y' . $i, 'placeholder' => 'Titul/y', 'required' => false, 'class' => array( 'form-row-wide' ), 'clear' => true ); $fields['order']['order_birthdate' . $i] = array( 'type' => 'date', 'label' => 'Datum narození' . $i, 'placeholder' => 'DD.MM.RRRR', 'required' => true, 'class' => array( 'form-row-wide' ), 'clear' => true ); } return $fields; }
保存自定义字段至订单详情代码
function save_custom_checkout_fields( $order_id, $posted_data ) { $virtual_product_count = cart_has_virtual_product(); for ( $i = 1; $i <= $virtual_product_count; $i++ ) { if ( isset( $_POST['order_jmeno_ucastnika' . $i] ) ) { update_post_meta( $order_id, 'order_jmeno_ucastnika' . $i, sanitize_text_field( $_POST['order_jmeno_ucastnika' . $i] ) ); } if ( isset( $_POST['order_email_ucastnika' . $i] ) ) { update_post_meta( $order_id, 'order_email_ucastnika' . $i, sanitize_email( $_POST['order_email_ucastnika' . $i] ) ); } if ( isset( $_POST['order_title' . $i] ) ) { update_post_meta( $order_id, 'order_title' . $i, sanitize_text_field( $_POST['order_title' . $i] ) ); } if ( isset( $_POST['order_birthdate' . $i] ) ) { update_post_meta( $order_id, 'order_birthdate' . $i, sanitize_text_field( $_POST['order_birthdate' . $i] ) ); } } } add_action( 'woocommerce_checkout_update_order_meta', 'save_custom_checkout_fields', 10, 2 );
原订单完成发送邮件代码
function send_zoom_link_on_order_complete( $order_id ) { $order = wc_get_order( $order_id ); $items = $order->get_items(); $virtual_product_count = cart_has_virtual_product(); foreach ( $items as $item ) { $product_id = $item->get_product_id(); $zoom_link = get_post_meta( $product_id, 'zoom_link', true ); $custom_info = get_post_meta( $product_id, 'custom_info', true ); if ( $zoom_link ) { for ( $i = 1; $i <= $virtual_product_count; $i++ ) { $to = get_post_meta( $order_id, 'order_email_ucastnika' . $i, true ); $subject = 'my subject ' . $item->get_name(); $message = 'link: ' . $zoom_link . $custom_info; $headers = array( 'From: mysite.com <orders@mysite.com>', 'Content-Type: text/html; charset=UTF-8' ); wp_mail( $to, $subject, $message, $headers ); } } } } add_action('woocommerce_order_status_completed', 'send_zoom_link_on_order_complete');
问题排查与修复
1. 核心问题:订单完成时购物车不可用
cart_has_virtual_product()函数依赖WC()->cart获取虚拟商品数量,但订单完成触发woocommerce_order_status_completed钩子时,购物车通常已被清空或销毁,导致virtual_product_count返回0,循环无法执行,邮件根本不会发送。
2. 语法错误:循环闭合不完整
原发送邮件函数中,for循环缺少闭合的},导致代码结构错误,函数无法正常运行。
3. 修复后的发送邮件函数
function send_zoom_link_on_order_complete( $order_id ) { $order = wc_get_order( $order_id ); $items = $order->get_items(); // 从订单元数据中统计参与者数量,不再依赖购物车 $participant_count = 0; while ( get_post_meta( $order_id, 'order_email_ucastnika' . ( $participant_count + 1 ), true ) ) { $participant_count++; } foreach ( $items as $item ) { $product_id = $item->get_product_id(); $zoom_link = get_post_meta( $product_id, 'zoom_link', true ); $custom_info = get_post_meta( $product_id, 'custom_info', true ); if ( $zoom_link && $participant_count > 0 ) { for ( $i = 1; $i <= $participant_count; $i++ ) { $to = get_post_meta( $order_id, 'order_email_ucastnika' . $i, true ); // 验证邮箱有效性,跳过无效地址 if ( ! is_email( $to ) ) { error_log( '订单ID ' . $order_id . ': 无效邮箱地址 - ' . $to ); continue; } $subject = '我的主题 ' . $item->get_name(); $message = '链接:' . $zoom_link . $custom_info; $headers = array( 'From: mysite.com <orders@mysite.com>', 'Content-Type: text/html; charset=UTF-8' ); // 发送邮件并记录日志便于调试 $mail_result = wp_mail( $to, $subject, $message, $headers ); if ( $mail_result ) { error_log( '订单ID ' . $order_id . ': 邮件成功发送至 - ' . $to ); } else { error_log( '订单ID ' . $order_id . ': 邮件发送失败至 - ' . $to ); } } } } } add_action('woocommerce_order_status_completed', 'send_zoom_link_on_order_complete');
4. 额外优化点
- 原
addHeadingsInBetweenFormFields函数中使用位运算符&,改为逻辑与&&避免判断异常。 - 添加邮箱有效性验证,跳过无效地址。
- 增加日志记录,便于排查邮件发送失败的具体原因。
内容的提问来源于stack exchange,提问作者JohnK
相关产品推荐
相关产品推荐

