You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:58:10