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

解决Woocommerce woocommerce_email_footer钩子递归与实例丢失问题

解决WooCommerce邮件内容捕获的递归与漏触发问题

我明白你遇到的困境:用woocommerce_email_footer钩子捕获邮件内容时,调用$email->get_content()会触发无限递归导致内存错误,而临时移除钩子又可能让其他并发的邮件请求错过你的自定义逻辑。下面给你两个更优的解决方案,完全满足你的需求:

方案1:用静态变量阻止递归(兼容现有钩子)

如果想继续使用woocommerce_email_footer钩子,可以通过静态变量标记当前是否正在处理函数,避免递归调用,同时无需移除钩子,也就不会有漏触发的风险:

// Capture the contents of the Emails sent and save into local files
// These Local files are used for further messaging through different channels
function Save_Email_Contents_into_Local_File( $email ) {
    // 静态变量标记是否正在处理,防止递归
    static $is_processing = false;

    // 如果已经在处理中,直接返回,避免递归
    if ( $is_processing ) {
        return;
    }

    // 定义需要捕获的邮件ID列表,后续扩展只需添加新ID
    $target_email_ids = [
        'customer_processing_order',
        'customer_completed_order',
        'customer_on_hold_order'
    ];

    if ( in_array( $email->id, $target_email_ids ) ) {
        $is_processing = true;

        // 给文件名加上邮件ID,区分不同场景的邮件
        $target_filename = '/home/users/....../Sent_Mail_' . $email->id . '.html';
        $html_message = $email->get_content();
        $formatted_message = $email->style_inline( $html_message );
        file_put_contents( $target_filename, $formatted_message );

        $is_processing = false;
    }
};
add_action( 'woocommerce_email_footer', 'Save_Email_Contents_into_Local_File', 20, 1 );

原理说明

静态变量$is_processing在函数首次执行时设为true,当$email->get_content()渲染模板触发woocommerce_email_footer钩子再次调用该函数时,检测到$is_processing为true就直接返回,中断递归。处理完成后再将其重置为false,不影响后续其他邮件请求。

方案2:使用更合适的钩子(推荐)

WooCommerce提供了woocommerce_email_send_before钩子,这个钩子在邮件即将发送前触发,此时邮件内容已经完成渲染和内联样式处理,完全不需要调用$email->get_content(),从根源上避免了递归问题,代码更简洁安全:

// Capture the contents of the Emails sent and save into local files
// These Local files are used for further messaging through different channels
function Save_Email_Contents_into_Local_File( $email, $to, $subject, $message, $headers, $attachments ) {
    // 定义需要捕获的邮件ID列表
    $target_email_ids = [
        'customer_processing_order',
        'customer_completed_order',
        'customer_on_hold_order'
    ];

    if ( in_array( $email->id, $target_email_ids ) ) {
        $target_filename = '/home/users/....../Sent_Mail_' . $email->id . '.html';
        // 直接保存已经处理好的邮件内容
        file_put_contents( $target_filename, $message );
    }
};
// 注意这个钩子的优先级和参数个数,这里需要6个参数
add_action( 'woocommerce_email_send_before', 'Save_Email_Contents_into_Local_File', 10, 6 );

为什么推荐这个方案?

  • 完全规避递归:$message参数已经是WooCommerce处理好的最终HTML内容(包含内联样式),不需要我们再调用任何会触发钩子的方法。
  • 无漏触发风险:每个邮件发送请求都会触发这个钩子,不需要临时移除/重新添加动作,不会出现并发场景下的逻辑丢失。
  • 代码更简洁:省去了手动调用get_content()和style_inline()的步骤,直接使用现成的处理结果。

扩展提示

不管用哪个方案,你只需要在$target_email_ids数组中添加对应的邮件ID(比如customer_refunded_order、admin_new_order等),就能轻松扩展到其他邮件场景。

内容的提问来源于stack exchange,提问作者Sreenivasa Hosamane

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:52:58