skip to Main Content

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',
                    '[email protected]' => 'Value 1',
                    '[email protected]' => 'Value 2',
                    '[email protected]' => '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();

2

Answers


  1. 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.

    Login or Signup to reply.
  2. The correct hook to be used is not woocommerce_thankyou but woocommerce_new_order to avoid multiple email notifications…

    For email debugging, you can use WP Mail Catcher plugin…

    In the code below, I have added some functions to validate and save the custom checkout field values… When the order is submitted, the order is auto-completed, and an email notification is sent to the selected store as CC…

    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_filter( 'woocommerce_cart_needs_payment', '__return_false' );
            # 
            add_action( 'woocommerce_after_checkout_validation', array( $this, 'custom_checkout_fields_validation'), 10, 2 );
            # 
            add_action( 'woocommerce_checkout_create_order', array( $this, 'save_order_meta_checkout_fields_values'), 10, 2 );
            # 
            add_action( 'woocommerce_checkout_update_customer', array( $this, 'save_customer_meta_checkout_field_value'), 10, 2 );
    
            add_action( 'woocommerce_new_order', array( $this, 'auto_complete_new_order'), 10, 2 );
    
            add_filter( 'woocommerce_email_headers', array( $this, 'additional_cc_recipient'), 10, 3 );
        }
            
        #
        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( 'withdrawal_point', array(
                'type' => 'select',
                'required' => true,
                'class' => array('form-row-first'),
                'label' => __('Withdrawal point', 'woocommerce'),
                'options' => array(
                    ''                 => __('Select a store', 'woocommerce'),
                    '[email protected]' => __('Store one', 'woocommerce'),
                    '[email protected]' => __('Store two', 'woocommerce'),
                    '[email protected]' => __('Store three', 'woocommerce'),
                ) 
            ), $checkout->get_value( 'withdrawal_point' ) );
    
            #
            woocommerce_form_field( 'booking_day', array(
                'type' => 'date',
                'required' => true,
                'class' => array('form-row-last'),
                'label' => 'Booking day'
            ), $checkout->get_value('booking_day') );
        
            #
            woocommerce_form_field( 'booking_hour', array(
                'type' => 'time',
                'required' => true,
                'class' => array('form-row-last'),
                'label' => 'Booking hour'
            ), $checkout->get_value('booking_hour') );
        }
    
        # Save custom checkout fields values as customer metadata
        public function custom_checkout_fields_validation( $data, $errors ) {
            if ( isset($_POST['withdrawal_point']) && empty($_POST['withdrawal_point']) ) {
                $errors->add( 'pos_error', __( '<strong>Withdrawal point</strong> is a required field.', 'woocommerce' ), 'error' );
            }
            if ( isset($_POST['booking_day']) && empty($_POST['booking_day']) ) {
                $errors->add( 'pos_error', __( '<strong>Booking day</strong> is a required field.', 'woocommerce' ), 'error' );
            }
            if ( isset($_POST['booking_hour']) && empty($_POST['booking_hour']) ) {
                $errors->add( 'pos_error', __( '<strong>Booking hour</strong> is a required field.', 'woocommerce' ), 'error' );
            }
        }
    
        # Save custom checkout fields values as order metadata
        public function save_order_meta_checkout_fields_values( $order, $data ) {
            if ( isset($_POST['withdrawal_point']) && ! empty($_POST['withdrawal_point']) ) {
                $order->update_meta_data('withdrawal_point', sanitize_email($_POST['withdrawal_point']));
            }
            if ( isset($_POST['booking_day']) && ! empty($_POST['booking_day']) ) {
                $order->update_meta_data('booking_day', esc_attr($_POST['booking_day']));
            }
            if ( isset($_POST['booking_hour']) && ! empty($_POST['booking_hour']) ) {
                $order->update_meta_data('booking_hour', esc_attr($_POST['booking_hour']));
            }
        }
    
        # Save custom checkout fields values as customer metadata
        public function save_customer_meta_checkout_field_value( $customer, $data ) {
            if ( isset($_POST['withdrawal_point']) && ! empty($_POST['withdrawal_point']) ) {
                $customer->update_meta_data('withdrawal_point', sanitize_email($_POST['withdrawal_point']));
            }
        }
    
        # Change order status, send new order email to admin and selected store
        # Send email customer completed order email to customer
        public function auto_complete_new_order( $order_id, $order ) {
            $order->update_status('wc-completed');
        }
    
        # Add selected store as CC recipient to "new order email"
        public function additional_cc_recipient( $headers, $email_id, $order ) {
            if ( $email_id === 'new_order' && ( $pos_email = $order->get_meta('withdrawal_point') ) ) {
                $headers .= "Cc: " . $pos_email . "rn";
            }
            return $headers;
        }
    }
    
    $checkout = new CustomCheckout();
    

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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search