Search code examples
phpwoocommerceordersstatusemail-notifications

Send email notification on custom order statuses only for Woocommerce sub orders


I'm using the code below, to add a custom order satus "readytocollect" and "shipped". When the order status changes, an email is sent to the buyer notifying that his order is being assembled or delivered (it works):

// Enable custom statuses for WooCommerce Orders
add_action('init', 'register_custom_order_statuses');
function register_custom_order_statuses() {
    register_post_status('wc-shipped', array(
        'label' => __( 'shipped', 'woocommerce' ),
        'public' => true,
        'exclude_from_search' => false,
        'show_in_admin_all_list' => true,
        'show_in_admin_status_list' => true,
        'label_count' => _n_noop('shipped <span class="count">(%s)</span>', 'shipped <span class="count">(%s)</span>')
    ));
    register_post_status('wc-readytocollect', array(
        'label' => __( 'readytocollect', 'woocommerce' ),
        'public' => true,
        'exclude_from_search' => false,
        'show_in_admin_all_list' => true,
        'show_in_admin_status_list' => true,
        'label_count' => _n_noop('readytocollect <span class="count">(%s)</span>', 'readytocollect <span class="count">(%s)</span>')
    ));
}

add_action('woocommerce_order_status_changed', 'my_notification_shipped');
function my_notification_shipped ($order_id) {
   global $woocommerce;
   $order = new WC_Order( $order_id );
   if($order->status === 'shipped' ) {
      //HERE IS THE ISSUE
       $order->get_order_number();
      // Create a mailer
      $mailer = $woocommerce->mailer();
      $message_body =     "
                <html>
                    <head>
                    </head>
                    <body>
                        <h1>shipped</h1>
                        <h1></h1>
                    </body>
                    
                    </html>
                ";
      $message = $mailer->wrap_message(
      // Message head and message body.
      sprintf( __( 'order %s shipped' ), $order->get_order_number() ), $message_body );
      // Send email
      $mailer->send( $order->billing_email, sprintf( __( 'order %s shipped' ), $order->get_order_number() ), $message );
     }
}

add_action('woocommerce_order_status_changed', 'my_notification_readytocollect');
function my_notification_readytocollect ($order_id) {
   global $woocommerce;
   $order = new WC_Order( $order_id );
   if($order->status === 'readytocollect' ) {
      //HERE IS THE ISSUE
        $order->get_order_number();
      // Create a mailer
      $mailer = $woocommerce->mailer();
      $message_body =                 "
                <html>
                    <head>

 </head>
                    <body>

                        <h1>readytocollect</h1>
                        <h2></h2>
                    </body>
                    </html>
                ";
      $message = $mailer->wrap_message(
      // Message head and message body.
      sprintf( __( 'order %s readytocollect' ), $order->get_order_number() ), $message_body );
      // Send email
      $mailer->send( $order->billing_email, sprintf( __( 'order %s readytocollect' ), $order->get_order_number() ), $message );
     }
}

My problem is the following:

I use a multivendor plugin that creates its own suborder number for each order and synchronizes the suborder status with the parent order. The buyer receives 2 emails. Those 2 events occur when the order status changes, sending an email notification related to the parent order and also to the suborder.

To stop sending email related to the parent order, and send it only to a related suborder is use the following code:

add_filter( 'woocommerce_email_recipient_customer_readytocollect_order', 'disable_email_for_parent_order', 10,3 );
add_filter( 'woocommerce_email_recipient_customer_shipped_order', 'disable_email_for_parent_order', 10,3 );
function disable_email_for_parent_order( $recipient, $order, $object ){
    if( wp_get_post_parent_id( $order->get_id() ) ){
        return $recipient;
    } else{
        return;
    }
}

But unfortunately, this code does not work with my custom order statuses.

Is there a mistake in my code somewhere?

How to stop email notifications from my custom order statuses to the related parent order?

Any help is really appreciated.


Solution

  • Your code is a bit outdated, with mistakes and missing things… We can directly target suborders on order status change when we send the email notifications.

    Try the following:

    // Enable custom statuses for WooCommerce Orders
    add_action('init', 'register_custom_order_statuses');
    function register_custom_order_statuses() {
        register_post_status('wc-shipped', array(
            'label' => __( 'Shipped', 'woocommerce' ),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_admin_all_list' => true,
            'show_in_admin_status_list' => true,
            'label_count' => _n_noop('Shipped <span class="count">(%s)</span>', 'Shipped <span class="count">(%s)</span>')
        ));
        register_post_status('wc-readytocollect', array(
            'label' => __( 'Ready to collect', 'woocommerce' ),
            'public' => true,
            'exclude_from_search' => false,
            'show_in_admin_all_list' => true,
            'show_in_admin_status_list' => true,
            'label_count' => _n_noop('Ready to collect <span class="count">(%s)</span>', 'Ready to collect <span class="count">(%s)</span>')
        ));
    }
    
    // Add a custom order status to list of WC Order statuses
    add_filter('wc_order_statuses', 'add_custom_order_statuses');
    function add_custom_order_statuses($order_statuses) {
        $new_order_statuses = array();
    
        // add new order status before processing
        foreach ($order_statuses as $key => $status) {
            $new_order_statuses[$key] = $status;
            if ('wc-processing' === $key) {
                $new_order_statuses['wc-shipped']        = __('Shipped', 'woocommerce' );
                $new_order_statuses['wc-readytocollect'] = __('Ready to collect', 'woocommerce' );
            }
        }
        return $new_order_statuses;
    }
    
    // Send custom email notifications to sub orders only
    add_action( 'woocommerce_order_status_changed', 'custom_order_statuses_email_notifications', 10, 4 );
    function custom_order_statuses_email_notifications ($order_id, $from_status, $to_status, $order) {
        // Targeting sub-orders only
        if ( ! $order->get_parent_id() ) return;
    
        if ( $to_status === 'shipped' ) {
            $status_label  = __( 'shipped', 'woocommerce' );
        } 
        elseif ( $to_status === 'readytocollect' ) {
            $status_label  = __( 'Ready to collect', 'woocommerce' );
        }
    
        if ( isset($status_label) ) {
            $mailer        = WC()->mailer(); // load the mailer class.
            $email_subject = sprintf( __( 'Order %s %s' ), $order->get_order_number(), $status_label );
            $message_body  = '<html>
            <head></head>
            <body>
                <h1>'.$status_label.'</h1>
                <p></p>
            </body>
            </html>';
            $message = $mailer->wrap_message( $email_subject, $message_body );
            $mailer->send( $order->get_billing_email(), $email_subject, $message ); // Send email
        }
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.

    Related: