Ecommerce Shopify WordPress Discussion

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();
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.

December 29, 2023

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'), 'email1@email.com' => __('Store one', 'woocommerce'), 'email2@email.com' => __('Store two', 'woocommerce'), 'email3@email.com' => __('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 . "\r\n"; } return $headers; } } $checkout = new CustomCheckout(); Code goes in functions.php file of your child theme (or in a plugin). Tested and works.

December 29, 2023

TurboCommerce make the better internet purchasing globaly

Turbo Multi-language Translator

Make the better internet purchasing globaly

Turbosify SEO Speed Booster

5.0 (7) Free plan available
Get better conversions by improving store loading speed Installed

Turbo Multi-language Chat - AI Customer service in one hand

TurboCommerce make the better internet purchasing globaly
Our products

The help you need, when you need it

App by Turbo Engine

3 apps • 5.0 average rating

Turbosify Speed Booster

5.0 (7)
Get better conversions by optimizing shopify store Google page speed Installed

Turbosify Translator for Wordpress Woocommerce

5.0 (74) Free Wordpress Woocommerce Plugin
Translate your wordpress website to multiple language within 1 click, no configuration needed, no No technical required

Grow your business here

Whether you want to sell products down the street or around the world, we have all the tools you need.