phpwordpresswoocommercehook-woocommerceemail-notifications

Woocommerce - Change order status automatically and send email to a selected address


I'm customizing woocommerce to create a food reservation system. I've successfully removed all unnecessary checkout fields and I've disabled the payments gateway because I just need to register the order. I'm now adding some custom fields to the checkout page using elementor and a custom plugin I'm writing. I have this code ath the moment and I need to customize the checkout, when a client place a reservation (order), I will need to send an email to some custom email adresses that can be selected from the user using a custom checkout field I've added. Is possible to automatically change the order status to completed and send the email, and what is the hook to use?

class CustomCheckout {        
    
    #
    public function __construct()
    {
        # 
        add_action( 'woocommerce_checkout_fields', array( $this, 'remove_default_checkout_fields') );
        # 
        add_action( 'woocommerce_after_checkout_billing_form', array( $this, 'add_custom_checkout_fields') );
        # 
        add_action( 'phpmailer_init', array( $this, 'mailtrap') );
        # 
        add_filter( 'woocommerce_cart_needs_payment', '__return_false' );
    }

    # debug email woocommerce
    public function mailtrap( $phpmailer ) 
    {
        $phpmailer->isSMTP();
        $phpmailer->Host = 'sandbox.smtp.mailtrap.io';
        $phpmailer->SMTPAuth = true;
        $phpmailer->Port = 2525;
        $phpmailer->Username = '****';
        $phpmailer->Password = '***';
    }
        
    #
    public function remove_default_checkout_fields( $fields )
    {
        //unset( $fields['billing']['first_name'] );
        //unset( $fields['billing']['last_name'] );
        unset( $fields['billing']['billing_company'] );
        unset( $fields['billing']['billing_country'] );
        unset( $fields['billing']['billing_address_1'] );
        unset( $fields['billing']['billing_address_2'] );
        unset( $fields['billing']['billing_city'] );
        unset( $fields['billing']['billing_state'] );
        unset( $fields['billing']['billing_postcode'] );
        # Rimuovo campi spedizione
        unset( $fields['shipping']['shipping_first_name'] );
        unset( $fields['shipping']['shipping_last_name'] );
        unset( $fields['shipping']['shipping_company'] );
        unset( $fields['shipping']['shipping_country'] );
        unset( $fields['shipping']['shipping_address_1'] );
        unset( $fields['shipping']['shipping_addredd_2'] );
        unset( $fields['shipping']['shipping_city'] );
        unset( $fields['shipping']['shipping_state'] );
        unset( $fields['shipping']['shipping_postcode'] );

        #
        return $fields;
    }
    
    #
    public function add_custom_checkout_fields( $checkout )
    {
        # 
        woocommerce_form_field( 
            'pdvselector', 
            array(
                'type' => 'select',
                'required' => true,
                'class' => array('form-row-first'),
                'label' => 'Punto di ritiro',
                //'label_class'
                'options' => array(
                    '' => 'Select a store',
                    'email1@email.com' => 'Value 1',
                    'email2@email.com.com-' => 'Value 2',
                    'email3@email.com' => 'Value 3'
                )
            ),
            $checkout->get_value( 'pdvselector' )
        );

        #
        woocommerce_form_field( 
            'dateselector', 
            array(
                'type' => 'date',
                'required' => true,
                'class' => array('form-row-last'),
                'label' => 'Reservation day'
            ), 
            $checkout->get_value( 'dateselector' ) 
        );
    
        #
        woocommerce_form_field(
            'hourselector',
            array(
                'type' => 'time',
                'required' => true,
                'class' => array('form-row-last'),
                'label' => 'Reservation hour'
            ),
            $checkout->get_value( 'hourselector' )
        );
    }
  
    #
    public function send_order_status_change_email( $order_id )
    {
        #
        $order = wc_get_order( $order_id );
        //$order->update_status( '' );
        #
    }
}

$checkout = new CustomCheckout();


Solution

  • 1. Hook into the woocommerce_thankyou action:

    This action fires when an order is placed successfully, making it ideal for handling post-order tasks like status changes and email notifications.

    2. Modify your send_order_status_change_email method:

    public function send_order_status_change_email( $order_id ) {
        $order = wc_get_order( $order_id );
    
        // Get the selected email address from the custom field
        $selected_email = $order->get_meta( 'pdvselector' );
    
        // Change the order status to completed
        $order->update_status( 'completed' );
    
        // Send the email notification to the selected address
        WC()->mailer()->send( 'customer_completed_order', $order_id, $selected_email );
    }
    

    3. Add the action hook in your CustomCheckout constructor:

    public function __construct() {
    
        //add this line
        add_action( 'woocommerce_thankyou', array( $this, 'send_order_status_change_email' ), 10, 1 );
    }
    

    When a customer places an order, the send_order_status_change_email method will be triggered. It will retrieve the selected email address from the pdvselector custom field. The order status will be updated to "completed". The "customer_completed_order" email template will be sent to the selected email address, informing them of the reservation.

    EDIT 1

    You can avoid sending two emails by utilizing a different hook and making some adjustments to your code.

    1. Hook into woocommerce_order_status_changed:

    Instead of using woocommerce_thankyou, leverage the woocommerce_order_status_changed action. This fires whenever the order status changes, allowing you to capture the completion moment without relying on the checkout page completion.

    2. Refine your send_order_status_change_email method:

    Modify your existing method to check the new order status before sending the email.

    public function send_order_status_change_email( $order_id, $old_status, $new_status ) {
        if ( $new_status !== 'completed' ) {
            return; // Do not send email if not completed
        }
    
        $order = wc_get_order( $order_id );
    
        // ... Get selected email and send email logic ...
    
    }
    

    3. Register the action hook:

    Update your constructor's code to register the hook with the updated method:

    public function __construct() {
        //add this line
        add_action( 'woocommerce_order_status_changed', array( $this, 'send_order_status_change_email' ), 10, 3 );
    }
    

    With this, the email will only be sent when the order status changes to "completed," effectively preventing duplicate emails and confirming the successful order completion to the selected email address.