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

WooCommerce自定义订单状态邮件无法触发的排查求助

WooCommerce自定义订单状态邮件无法触发排查

我开发的插件里注册了自定义订单状态,但切换到/从这些状态(包括和processing、completed等核心状态互转)时,邮件触发不了。我已经注册了所有能想到的动作组合(业务场景排除了on-hold和pending),请问哪里漏了?


初始类代码

<?php
/**
 * @author BAKKBONE Australia
 * @package Bkf_WC_Email
 * @license GNU General Public License (GPL) 3.0
**/

if ( ! defined( 'ABSPATH' ) ) {
    return;
}

/**
 * Class Bkf_WC_Email
 */
class Bkf_WC_Email {

    /**
     * Bkf_WC_Email constructor.
     */
    public function __construct() {
        add_action( 'woocommerce_email_classes', array( $this, 'bkf_register_email' ), 90, 1 );
        define( 'CUSTOM_WC_EMAIL_PATH', plugin_dir_path( __FILE__ ) );
        add_filter('woocommerce_email_actions', array($this, 'bkf_woocommerce_email_actions'), 10, 1);
    }

    /**
     * @param array $emails
     *
     * @return array
     */
    public function bkf_register_email( $emails ) {
        $emails['WC_Email_Customer_Scheduled_Order'] = include __DIR__ . 'emails/class-wc-customer-scheduled-order.php';
        $emails['WC_Email_Customer_Prepared_Order'] = include __DIR__ . 'emails/class-wc-customer-made-order.php';
        $emails['WC_Email_Customer_Out_for_Delivery_Order'] = include __DIR__ . 'emails/class-wc-customer-out-order.php';

        return $emails;
    }

    public function bkf_woocommerce_email_actions($actions)
    {
$actions[] = 'woocommerce_order_status_scheduled';
$actions[] = 'woocommerce_order_status_made';
$actions[] = 'woocommerce_order_status_out';
$actions[] = 'woocommerce_order_status_relay';
$actions[] = 'woocommerce_order_status_processing';
$actions[] = 'woocommerce_order_status_completed';
$actions[] = 'woocommerce_order_status_scheduled_to_made';
$actions[] = 'woocommerce_order_status_scheduled_to_out';
$actions[] = 'woocommerce_order_status_scheduled_to_relay';
$actions[] = 'woocommerce_order_status_scheduled_to_processing';
$actions[] = 'woocommerce_order_status_scheduled_to_completed';
$actions[] = 'woocommerce_order_status_made_to_scheduled';
$actions[] = 'woocommerce_order_status_made_to_out';
$actions[] = 'woocommerce_order_status_made_to_relay';
$actions[] = 'woocommerce_order_status_made_to_processing';
$actions[] = 'woocommerce_order_status_made_to_completed';
$actions[] = 'woocommerce_order_status_out_to_scheduled';
$actions[] = 'woocommerce_order_status_out_to_made';
$actions[] = 'woocommerce_order_status_out_to_relay';
$actions[] = 'woocommerce_order_status_out_to_processing';
$actions[] = 'woocommerce_order_status_out_to_completed';
$actions[] = 'woocommerce_order_status_relay_to_scheduled';
$actions[] = 'woocommerce_order_status_relay_to_made';
$actions[] = 'woocommerce_order_status_relay_to_out';
$actions[] = 'woocommerce_order_status_relay_to_processing';
$actions[] = 'woocommerce_order_status_relay_to_completed';
$actions[] = 'woocommerce_order_status_processing_to_scheduled';
$actions[] = 'woocommerce_order_status_processing_to_made';
$actions[] = 'woocommerce_order_status_processing_to_out';
$actions[] = 'woocommerce_order_status_processing_to_relay';
$actions[] = 'woocommerce_order_status_processing_to_completed';
$actions[] = 'woocommerce_order_status_completed_to_scheduled';
$actions[] = 'woocommerce_order_status_completed_to_made';
$actions[] = 'woocommerce_order_status_completed_to_out';
$actions[] = 'woocommerce_order_status_completed_to_relay';
$actions[] = 'woocommerce_order_status_completed_to_processing';
        $bkfoptions = get_option("bkf_options_setting");
        if($bkfoptions["bkf_petals"] == "1") {
$actions[] = 'woocommerce_order_status_new';
$actions[] = 'woocommerce_order_status_accept';
$actions[] = 'woocommerce_order_status_reject';
$actions[] = 'woocommerce_order_status_scheduled_to_new';
$actions[] = 'woocommerce_order_status_scheduled_to_accept';
$actions[] = 'woocommerce_order_status_scheduled_to_reject';
$actions[] = 'woocommerce_order_status_made_to_new';
$actions[] = 'woocommerce_order_status_made_to_accept';
$actions[] = 'woocommerce_order_status_made_to_reject';
$actions[] = 'woocommerce_order_status_out_to_new';
$actions[] = 'woocommerce_order_status_out_to_accept';
$actions[] = 'woocommerce_order_status_out_to_reject';
$actions[] = 'woocommerce_order_status_relay_to_new';
$actions[] = 'woocommerce_order_status_relay_to_accept';
$actions[] = 'woocommerce_order_status_relay_to_reject';
$actions[] = 'woocommerce_order_status_processing_to_new';
$actions[] = 'woocommerce_order_status_processing_to_accept';
$actions[] = 'woocommerce_order_status_processing_to_reject';
$actions[] = 'woocommerce_order_status_completed_to_new';
$actions[] = 'woocommerce_order_status_completed_to_accept';
$actions[] = 'woocommerce_order_status_completed_to_reject';
$actions[] = 'woocommerce_order_status_new_to_scheduled';
$actions[] = 'woocommerce_order_status_new_to_made';
$actions[] = 'woocommerce_order_status_new_to_out';
$actions[] = 'woocommerce_order_status_new_to_relay';
$actions[] = 'woocommerce_order_status_new_to_processing';
$actions[] = 'woocommerce_order_status_new_to_completed';
$actions[] = 'woocommerce_order_status_new_to_accept';
$actions[] = 'woocommerce_order_status_new_to_reject';
$actions[] = 'woocommerce_order_status_accept_to_scheduled';
$actions[] = 'woocommerce_order_status_accept_to_made';
$actions[] = 'woocommerce_order_status_accept_to_out';
$actions[] = 'woocommerce_order_status_accept_to_relay';
$actions[] = 'woocommerce_order_status_accept_to_processing';
$actions[] = 'woocommerce_order_status_accept_to_completed';
$actions[] = 'woocommerce_order_status_accept_to_new';
$actions[] = 'woocommerce_order_status_accept_to_reject';
$actions[] = 'woocommerce_order_status_reject_to_scheduled';
$actions[] = 'woocommerce_order_status_reject_to_made';
$actions[] = 'woocommerce_order_status_reject_to_out';
$actions[] = 'woocommerce_order_status_reject_to_relay';
$actions[] = 'woocommerce_order_status_reject_to_processing';
$actions[] = 'woocommerce_order_status_reject_to_completed';
$actions[] = 'woocommerce_order_status_reject_to_new';
$actions[] = 'woocommerce_order_status_reject_to_accept';
        }
        return $actions;
    }
  
}

new Bkf_WC_Email();

特定邮件类代码

<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

if ( ! class_exists( 'WC_Email' ) ) {
    return;
}

/**
 * Class WC_Email_Customer_Out_for_Delivery_Order
 */
class WC_Email_Customer_Out_for_Delivery_Order extends WC_Email {

    /**
     * Create an instance of the class.
     *
     * @access public
     * @return void
     */
    function __construct() {

        $this->id          = 'customer_out_order';
        $this->title       = __( 'Order Out for Delivery', 'woocommerce' );
        $this->description = __( 'An email sent to the customer when an order is out for delivery.', 'woocommerce' );
        $this->customer_email = true;
        $this->heading     = __( 'Order Out for Delivery', 'woocommerce' );
        $this->subject     = sprintf( _x( '[%s] Order Out for Delivery', 'default email subject for out for delivery emails', 'woocommerce' ), '{blogname}' );

        $this->template_html  = 'emails/customer-out-order.php';
        $this->template_plain = 'emails/plain/customer-out-order.php';
        $this->template_base  = CUSTOM_WC_EMAIL_PATH . 'templates/';

        add_action( 'woocommerce_order_status_out', array( $this, 'trigger' ) );

        parent::__construct();
    }

    /**
     * Trigger Function that will send this email to the customer.
     *
     * @access public
     * @return void
     */
    function trigger( $order_id ) {
        $this->object = wc_get_order( $order_id );

        if ( version_compare( '3.0.0', WC()->version, '>' ) ) {
            $order_email = $this->object->billing_email;
        } else {
            $order_email = $this->object->get_billing_email();
        }

        $this->recipient = $order_email;


        if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
            return;
        }

        $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
    }

    /**
     * Get content html.
     *
     * @access public
     * @return string
     */
    public function get_content_html() {
        return wc_get_template_html( $this->template_html, array(
            'order'         => $this->object,
            'email_heading' => $this->get_heading(),
            'additional_content' => $this->get_additional_content(),
            'sent_to_admin' => false,
            'plain_text'    => false,
            'email'         => $this
        ), '', $this->template_base );
    }

    /**
     * Get content plain.
     *
     * @return string
     */
    public function get_content_plain() {
        return wc_get_template_html( $this->template_plain, array(
            'order'         => $this->object,
            'email_heading' => $this->get_heading(),
            'additional_content' => $this->get_additional_content(),
            'sent_to_admin' => false,
            'plain_text'    => true,
            'email'         => $this
        ), '', $this->template_base );
    }

}

return new WC_Email_Customer_Out_for_Delivery_Order();

排查思路

  • 自定义状态注册是否合规:确保自定义状态(如scheduled、made等)注册时,public属性设置为true,否则WooCommerce不会触发对应的状态切换钩子。示例注册代码:

    add_action('init', 'register_custom_order_statuses');
    function register_custom_order_statuses() {
        register_post_status('wc-out', array(
            'label'                     => __('Out for Delivery', 'text-domain'),
            'public'                    => true, // 必须为true
            'show_in_admin_status_list' => true,
            'label_count'               => _n_noop('Out for Delivery <span class="count">(%s)</span>', 'Out for Delivery <span class="count">(%s)</span>', 'text-domain')
        ));
    }
    add_filter('woocommerce_order_statuses', 'add_custom_status_to_list');
    function add_custom_status_to_list($statuses) {
        $statuses['wc-out'] = __('Out for Delivery', 'text-domain');
        return $statuses;
    }
    
  • 邮件触发钩子不完整:当前邮件类只绑定了woocommerce_order_status_out钩子,但状态切换时还需要绑定woocommerce_order_status_{from}_to_out系列钩子。比如在WC_Email_Customer_Out_for_Delivery_Order的构造函数里补充:

    // 基础进入状态钩子
    add_action( 'woocommerce_order_status_out', array( $this, 'trigger' ) );
    // 所有切换到out状态的钩子
    add_action( 'woocommerce_order_status_scheduled_to_out', array( $this, 'trigger' ) );
    add_action( 'woocommerce_order_status_made_to_out', array( $this, 'trigger' ) );
    add_action( 'woocommerce_order_status_processing_to_out', array( $this, 'trigger' ) );
    add_action( 'woocommerce_order_status_completed_to_out', array( $this, 'trigger' ) );
    // petals选项对应的状态切换钩子
    $bkfoptions = get_option("bkf_options_setting");
    if($bkfoptions["bkf_petals"] == "1") {
        add_action( 'woocommerce_order_status_new_to_out', array( $this, 'trigger' ) );
        add_action( 'woocommerce_order_status_accept_to_out', array( $this, 'trigger' ) );
    }
    
  • 检查后台邮件启用状态:在WooCommerce后台「设置-邮件」中,确认你的自定义邮件(如"Order Out for Delivery")处于启用状态,$this->is_enabled()会读取这个配置判断是否发送邮件。

  • 调试trigger函数:在trigger函数开头添加日志,验证钩子是否触发:

    error_log('Out for Delivery email trigger fired for order ID: ' . $order_id);
    

    然后查看服务器错误日志,确认是否进入了触发逻辑。

  • 版本兼容性优化:当前代码中获取订单邮箱的版本判断冗余,直接使用$this->object->get_billing_email()即可适配新版WooCommerce。


内容的提问来源于stack exchange,提问作者Scott L

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 16:10:33