WooCommerce按支付方式触发自定义邮件通知问题求助
WooCommerce按支付方式触发自定义邮件问题解决方案
需求
在WooCommerce中配置两种专属邮件通知:
- 预支付邮件:对应WooCommerce内置的BACS银行转账支付方式
- 发票支付邮件:用Cheque支票支付网关替代原生无的发票支付场景
实现基础
基于自定义插件搭建,目录结构如下:
custom-wc-email/ ├── custom-wc-email.php ├── emails/ │ ├── class-wc-custom-invoice-email.php │ └── class-wc-custom-prepayment-email.php └── templates/ ├── emails/ │ ├── wc-custom-invoice-email.php │ └── wc-custom-prepayment-email.php └── plain/ ├── wc-custom-invoice-email.php └── wc-custom-prepayment-email.php
遇到的问题
- 用默认取消状态钩子能正常发送自定义模板邮件,但无法按支付方式触发;
- 替换为
woocommerce_thankyou_bacs等网关专属钩子后,仅发送WooCommerce默认通知,自定义邮件无响应; - 使用
woocommerce_order_status_pending_to_processing等状态变更钩子时,收到的邮件是自定义模板与默认通知的混合内容; - 发票支付对应的
class-wc-custom-invoice-email.php绑定状态钩子后,下单时触发内部服务器错误。
问题根源
woocommerce_thankyou_{gateway}钩子失效:该钩子仅在订单感谢页加载时触发,此时WooCommerce默认邮件已完成调度,自定义邮件类若未正确绑定到邮件初始化流程,直接调用会因对象未实例化而失败。- 状态钩子导致内容混合:状态变更钩子会自动触发WooCommerce默认的状态邮件,若未禁用对应默认通知,会出现自定义邮件与默认邮件同时发送(或模板逻辑冲突导致内容叠加)的情况。
- 发票支付类内部错误:大概率是类文件存在语法错误、未正确继承
WC_Email基类、构造函数初始化参数缺失,或钩子回调中未做支付方式判断就执行邮件发送,导致调用未定义方法/变量。
正确实现方案
1. 确保自定义邮件类正确注册
在插件主文件custom-wc-email.php中,通过woocommerce_email_classes过滤器注册自定义邮件类,确保WooCommerce邮件系统能识别它们:
add_filter( 'woocommerce_email_classes', 'register_custom_wc_emails' ); function register_custom_wc_emails( $email_classes ) { // 引入邮件类文件 require_once plugin_dir_path( __FILE__ ) . 'emails/class-wc-custom-prepayment-email.php'; require_once plugin_dir_path( __FILE__ ) . 'emails/class-wc-custom-invoice-email.php'; // 实例化并注册 $email_classes['WC_Custom_Prepayment_Email'] = new WC_Custom_Prepayment_Email(); $email_classes['WC_Custom_Invoice_Email'] = new WC_Custom_Invoice_Email(); return $email_classes; }
2. 用统一状态钩子实现支付方式触发
放弃网关专属钩子,改用woocommerce_order_status_changed钩子,在回调中判断支付方式和订单状态,触发对应自定义邮件并禁用默认通知:
add_action( 'woocommerce_order_status_changed', 'trigger_payment_specific_emails', 10, 4 ); function trigger_payment_specific_emails( $order_id, $old_status, $new_status, $order ) { $payment_method = $order->get_payment_method(); // 预支付(BACS):订单创建后默认状态为pending,此时触发 if ( $payment_method === 'bacs' && $new_status === 'pending' ) { // 禁用默认新订单邮件 add_filter( 'woocommerce_email_enabled_new_order', '__return_false', 20 ); // 获取并触发自定义预支付邮件 $email = WC()->mailer()->get_emails()['WC_Custom_Prepayment_Email']; $email->trigger( $order_id ); } // 发票支付(Cheque):订单创建后默认状态为on-hold,此时触发 if ( $payment_method === 'cheque' && $new_status === 'on-hold' ) { // 禁用默认新订单邮件 add_filter( 'woocommerce_email_enabled_new_order', '__return_false', 20 ); // 获取并触发自定义发票邮件 $email = WC()->mailer()->get_emails()['WC_Custom_Invoice_Email']; $email->trigger( $order_id ); } }
3. 修复自定义邮件类的核心方法
确保每个邮件类的trigger方法正确初始化订单对象和邮件变量,示例(以预支付邮件类为例):
class WC_Custom_Prepayment_Email extends WC_Email { public function __construct() { // 邮件基础配置 $this->id = 'custom_prepayment_email'; $this->title = '预支付通知'; $this->description = '客户选择BACS预支付时发送的专属通知'; $this->customer_email = true; // 模板路径设置 $this->template_base = plugin_dir_path( __FILE__ ) . '../templates/'; $this->template_html = 'emails/wc-custom-prepayment-email.php'; $this->template_plain = 'plain/wc-custom-prepayment-email.php'; parent::__construct(); } public function trigger( $order_id ) { $this->setup_locale(); if ( $order_id && is_numeric( $order_id ) ) { $this->object = wc_get_order( $order_id ); $this->recipient = $this->object->get_billing_email(); // 模板变量替换 $this->find['order-date'] = '{order_date}'; $this->find['order-number'] = '{order_number}'; $this->replace['order-date'] = wc_format_datetime( $this->object->get_date_created() ); $this->replace['order-number'] = $this->object->get_order_number(); } if ( $this->is_enabled() && $this->get_recipient() ) { $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); } $this->restore_locale(); } }
4. 修复发票支付类的内部错误
检查class-wc-custom-invoice-email.php:
- 确认类名与文件名匹配(驼峰命名,如
WC_Custom_Invoice_Email); - 确认正确继承
WC_Email,构造函数中完整初始化id、title、description及模板路径; - 检查
trigger方法中是否存在未定义变量或语法错误,比如未判断订单对象是否存在就调用其方法。
5. 验证测试
- 分别用BACS和Cheque支付方式下单;
- 检查收件箱,确认仅收到对应自定义邮件,无默认邮件或混合内容;
- 查看服务器错误日志,确认无内部错误记录。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

