WooCommerce 3.0 was rolled out with lots of exciting features for end-users as well as developers. Several advancements including use of CRUD classes and others were introduced with this release to make WooCommerce more performance-friendly.
This also lead to changes in the way interaction between post types, taxonomies and related data happens. In one of our previous articles we showed you how could you (without using any plugin) add and send custom WooCommerce emails. And as we continually receive comments and requests about modifying the code to also make it compatible with WooCommerce 3.0+, I decided to quickly (yeah, I know this is very late 🙁 ) get onto this.
This tutorial has been tested to work with WooCommerce 3.0+. So, if you are looking to add and send custom emails in WooCommerce 3.0+, follow the instructions below.
First things first!
It is highly recommended that any customization be kept separate from the theme. A plugin like WP Designer could come in handy if you want to add such a customization. This example requires you to FTP into your website and create custom directories and files inside wp-content > uploads
directory. Following is a list of directories and files that need to be created:
- Create directory
crwc-custom-emails
insidewp-content > uploads
. - Create file
crwc-email-functions.php
in the root ofcrwc-custom-emails
directory (crwc-custom-emails > crwc-email-functions.php
). - Create file
class-crwc-welcome-email.php
in the root ofcrwc-custom-emails
directory (crwc-custom-emails > class-crwc-welcome-email.php
). - Create a sub-directory
emails
insidecrwc-custom-emails
directory. - Create a new file
crwc-welcome-email.php
inside theemails
directory (crwc-custom-emails > emails > crwc-welcome-email.php
). - You can also choose to create a sub-directory
plain
insideemails
directory and then createcrwc-welcome-email.php
file insideplain
directory (crwc-custom-emails > emails > plain > crwc-welcome-email.php
). This will be used in case emails use plain content-type.
Building custom email class
The custom email class that we create would actually define the email trigger plus the email content. We can extend the default WC_Email
class and hence make use of all of the parent email class methods & members that are available. This makes life really easy 😉
Add the following code to class-crwc-welcome-email.php
file.
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly if ( class_exists( 'WC_Email' ) ) : class CRWC_Welcome_Email extends WC_Email { /** * Set email defaults */ public function __construct() { // Unique ID for custom email $this->id = 'crwc_welcome_email'; // Is a customer email $this->customer_email = true; // Title field in WooCommerce Email settings $this->title = __( 'Welcome Email', 'woocommerce' ); // Description field in WooCommerce email settings $this->description = __( 'Welcome email is sent when an online training program account is created for the customer after the purchase of the online course.', 'woocommerce' ); // these define the locations of the templates that this email should use, we'll just use the new order template since this email is similar $upload_dir = wp_upload_dir(); $this->template_base = WPD_BASE_DIR . '/wc-emails/'; // Fix the template base lookup for use on admin screen template path display $this->template_html = 'emails/crwc-welcome-email.php'; $this->template_plain = 'emails/plain/crwc-welcome-email.php'; $this->placeholders = array( '{site_title}' => $this->get_blogname(), '{order_date}' => '', '{order_number}' => '', ); // Trigger email when payment is complete add_action( 'woocommerce_payment_complete', array( $this, 'trigger' ) ); add_action( 'woocommerce_order_status_on-hold_to_processing_notification', array( $this, 'trigger' ) ); add_action( 'woocommerce_order_status_on-hold_to_completed_notification', array( $this, 'trigger' ) ); add_action( 'woocommerce_order_status_failed_to_processing_notification', array( $this, 'trigger' ) ); add_action( 'woocommerce_order_status_failed_to_completed_notification', array( $this, 'trigger' ) ); add_action( 'woocommerce_order_status_pending_to_processing_notification', array( $this, 'trigger' ) ); // Call parent constructor to load any other defaults not explicity defined here parent::__construct(); } /** * Get email subject. * * @since 3.1.0 * @return string */ public function get_default_subject() { return __( 'XYZ Online Training Program', 'woocommerce' ); } /** * Get email heading. * * @since 3.1.0 * @return string */ public function get_default_heading() { return __( 'Welcome to Online Training Program', 'woocommerce' ); } /** * Prepares email content and triggers the email * * @param int $order_id */ public function trigger( $order_id, $order = false ) { if ( $order_id && ! is_a( $order, 'WC_Order' ) ) { $order = wc_get_order( $order_id ); } if ( is_a( $order, 'WC_Order' ) ) { $this->object = $order; $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() ); $this->placeholders['{order_number}'] = $this->object->get_order_number(); //* Maybe include an additional check to make sure that the online training program account was created /* Uncomment and add your own conditional check $online_training_account_created = get_post_meta( $order_id, '_crwc_user_account_created', 1 ); if ( ! empty( $online_training_account_created ) && false === $online_training_account_created ) { return; } */ /* Proceed with sending email */ $this->recipient = $this->object->get_billing_email(); } // Send welcome email only once and not on every order status change if ( get_post_meta( $order_id, '_crwc_welcome_email_sent', true ) ) { return; } if ( ! $this->is_enabled() || ! $this->get_recipient() ) { return; } // All well, send the email $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() ); // add order note about the same $this->object->add_order_note( sprintf( __( '%s email sent to the customer.', 'woocommerce' ), $this->get_title() ) ); // Set order meta to indicate that the welcome email was sent update_post_meta( $order_id, '_crwc_welcome_email_sent', 1 ); } /** * get_content_html function. * * @return string */ public function get_content_html() { return wc_get_template_html( $this->template_html, array( 'order' => $this->object, 'email_heading' => $this->get_heading(), 'sent_to_admin' => false, 'plain_text' => false, 'email' => $this ) ); } /** * get_content_plain function. * * @return string */ public function get_content_plain() { return wc_get_template_html( $this->template_plain, array( 'order' => $this->object, 'email_heading' => $this->get_heading(), 'sent_to_admin' => false, 'plain_text' => true, 'email' => $this ) ); } /** * Initialize settings form fields */ public function init_form_fields() { $this->form_fields = array( 'enabled' => array( 'title' => __( 'Enable/Disable', 'woocommerce' ), 'type' => 'checkbox', 'label' => 'Enable this email notification', 'default' => 'yes' ), 'subject' => array( 'title' => __( 'Subject', 'woocommerce' ), 'type' => 'text', 'desc_tip' => true, 'description' => sprintf( 'This controls the email subject line. Leave blank to use the default subject: <code>%s</code>.', $this->get_subject() ), 'placeholder' => $this->get_default_subject(), 'default' => '' ), 'heading' => array( 'title' => __( 'Email Heading', 'woocommerce' ), 'type' => 'text', 'desc_tip' => true, 'description' => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: <code>%s</code>.' ), $this->get_heading() ), 'placeholder' => $this->get_default_heading(), 'default' => '' ), 'email_type' => array( 'title' => __( 'Email type', 'woocommerce' ), 'type' => 'select', 'description' => __( 'Choose which format of email to send.', 'woocommerce' ), 'default' => 'html', 'class' => 'email_type wc-enhanced-select', 'options' => $this->get_email_type_options(), 'desc_tip' => true, ) ); } } endif;
Viewing custom email settings
The code mentioned above will help us to create custom class with all settings and triggers. However, to be able to see the custom email settings that we created along with the default emails on WooCommerce Emails screen under WooCommerce > Settings > Emails
, we’ll need to add this class to the default email classes in WooCommerce. In order to do that, we’ll make use of the woocommerce_email_classes
filter to include custom email class to the default classes.
Add the following code to crwc-email-functions.php
file (inside crwc-custom-emails
directory).
add_filter( 'woocommerce_email_classes', 'crwc_custom_woocommerce_emails' ); function crwc_custom_woocommerce_emails( $email_classes ) { //* Custom welcome email to customer when purchasing online training program $upload_dir = wp_upload_dir(); include_once( $upload_dir['basedir'] . '/crwc-custom-emails/class-crwc-welcome-email.php' ); $email_classes['CRWC_Welcome_Email'] = new CRWC_Welcome_Email(); // add to the list of email classes that WooCommerce loads return $email_classes; }
Now, when you navigate to WooCommerce > Settings > Emails
, you should be able to see the custom email Welcome Email that we added to the list of emails on that page. If you click on the Configure button, you will find settings screen that allows you to enable/disable the email, edit/update the email subject and heading and choose the email content type since we added these settings in the custom class we created above.
Creating custom email template
Until this point, we have been able to create email class that helps create email trigger and set-up email content and we have also been able to add our custom email to the WooCommerce Emails screen. We still need to define the email template that will be used for the email content. The paths to the email content templates have already been defined in the custom email class we created above. Let’s add the actual content that will be used by the welcome email we send out to customers.
Add the following code to crwc-welcome-email.php
file (inside emails
directory).
<?php /** * * Welcome email content template * * The file is prone to modifications after plugin upgrade or alike; customizations are advised via hooks/filters * */ if ( ! defined( 'ABSPATH' ) ) { exit; } /** * @hooked WC_Emails::email_header() Output the email header */ do_action( 'woocommerce_email_header', $email_heading, $email ); ?> <p><?php _e( 'Thank you for your purchase of Online training course. Your account has been successfully created over the Online Training Program portal.', 'woocommerce' ); ?></p> <p><?php _e( 'Use the following credentials to login to the portal:', 'woocommerce' ); ?></p> <p> <strong><?php __( 'Login URL: ', 'woocommerce' ) ?></strong><?php _e( 'https://example.com' ); ?><br /> <strong><?php __( 'Username: ', 'woocommerce' ) ?></strong><?php echo make_clickable( esc_attr( $order->get_billing_email() ) ); ?><br /> </p> <p><?php _e( 'Below are the order details for your reference.' ) ?></p> <?php /** * @hooked WC_Emails::order_details() Shows the order details table. * @hooked WC_Emails::order_schema_markup() Adds Schema.org markup. * @since 2.5.0 */ do_action( 'woocommerce_email_order_details', $order, $sent_to_admin, $plain_text, $email ); /** * @hooked WC_Emails::order_meta() Shows order meta data. */ do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email ); /** * @hooked WC_Emails::customer_details() Shows customer details * @hooked WC_Emails::email_address() Shows email address */ do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email ); /** * @hooked WC_Emails::email_footer() Output the email footer */ do_action( 'woocommerce_email_footer', $email );
You can modify the email content template as required based on your specific requirements and accordingly, the details that you’d need to send out to your customers.
Start making Custom WooCommerce email work
We’re almost there with starting to send custom WooCommerce emails to the customers. All we need to do is to trigger our code. The filter we added to include our custom email class to list of default email classes is placed in crwc-email-functions.php
, but hey!, wait a sec.. did we actually include it so that it is executed by WordPress? No, not yet. Let’s do that.
In order to do so, you can just add the following code to your theme’s functions.php
:
$upload_dir = wp_upload_dir(); include_once( $upload_dir['basedir'] . '/crwc-custom-emails/crwc-email-functions.php' );
That’s it! Now on, when a customer purchases an online training product from your store, he would receive a welcome email with his credentials. Cheers!
hi, we can send different email based on specific product variation? ex. trigger a specific template mail only when a product variation is purchased?
Hi Luigi,
Sure, feel free to add in necessary conditional checks in the
trigger()
method inclass-crwc-welcome-email.php
file as required. Based on the condition you specify it will only be sent out once that is met. Hope that helps.Hi Aniket,
could you be a little more specific? I would also like to trigger a mail template that will be sent when the order status is completed, depending on the product variations ordered. (If several products were ordered in different variations, a separate mail should be sent for each variation.)
Unfortunately I don’t know anything about coding, so I can’t do much with the hint to adjust the trigger() function as needed :/
Hi,
Can you please update this for WooCommerce version: 3.8.1 with WordPress version: 5.3.2 and PHP version: 7.3.3
I am seeing the following error:
PHP Warning: Use of undefined constant WPD_BASE_DIR – assumed ‘WPD_BASE_DIR’ (this will throw an Error in a future version of PHP) in [path]\wp-content\uploads\crwc-custom-emails\class-crwc-welcome-email.php on line 29
Thanks.
Change WPD_BASE_DIR with the following.
$this->template_base = WC()->plugin_path() . ‘/templates/wc-emails/’;
Hey, thanks for the tutorial, but it doesn’t seems to work for me.
Nothing appeared in the woocommerce -> Settings ->e-mail 🙁
I mean, I can’t see the new line.
You probably had it solved by now, but anyway the reason for not showing up in Emails section, might be if you didn’t included this in functions.php :
$upload_dir = wp_upload_dir();
include_once( $upload_dir[‘basedir’] . ‘/crwc-custom-emails/crwc-email-functions.php’ );
Should this work on WC 4.0.1?
I didn’t get any email with this only the regular Order waiting -email.
Excellent tutorial
When i click on manage button in email list, it say html template file not found. Can you please help me with that ?
HTML template
File was not found.
What should I do so he can read my template.
Hi there,
Thanks for the code. I can’t see the settings under Email section in woocommerce.
1) Used this for template base path: $this->template_base = WC()-
>plugin_path() . ‘/templates/wc-emails/’;
2) Already put the upload in functions.php.
Still not showing. Is there anything I’m missing?
Have a nice day.
Regards & Thanks
For correcting the path of the template in the admin of WooCommerce -> Settings -> Emails.
We need to override the same email template files into the themes WooCommerce override template. woocommerce -> email -> crwc-welcome-email.php.
Hi.
Your recommendations made it easy to create a letter.
Thank you so much for your work.
Please tell me how I can implement the trigger in accordance with my needs:
There are only 4 uncategorized products in my store. I want the customer to receive different emails when buying each of them, depending on the ID of the product, or any other way.
And how do you disable Woocommerce standard emails while doing this?
Sure,
It would only involve creating 4 different email templates and putting them inside the
emails
directory, like the defaultcrwc-welcome-email.php
in the tutorial above.All you need to do is load the template files conditionally inside the
trigger
function somewhere after line number 115. You should have the product ID to compare with at that point in the code (or any other condition as you may like). Supply the path to email templates conditionally and assign to the variable$this->template_html
to load those when specific condition is met.Let me know if this helps.
Hi,
I want to send a custom email after completing purchase. Only if user have not used any coupon code. Is there any possibility to achieve this?
Looking forward to hearing from you. please suggest.
Warmest Regards
Deepak
Sure, you could add any condition to check against the products in the order, coupon code or any other data the order object may contain inside the
trigger
function. Based on the condition, you should be able to send out the custom email as described in the tutorial above.Let me know how that goes for you.
Hi mate,
Amazing tutorial, thanks a lot!!
Im developing a gift card system for a client and wondering if possible to send emails to someone who didn’t purchased the product. In this case would send to the gifted instead of the one who is buying.
Another question is if possible to schedule a mail trigger.
Thank you so much