Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Shop emails

WooCommerce sends emails on order events by itself: order received and order completed to the customer, new order to the administrator. Every email is a separate class with its own ID, settings and template. Texts are changed in the admin panel, and content is extended with hooks.

Emails in the admin panel

The list of emails is in WooCommerce → Settings → Emails. Each has a Manage button: there you enable the email and change the subject, the heading and the additional content. The bottom of the page holds the common look: the logo, colors, footer text.

IDTo whomWhen
new_orderThe administratorA new order is created
customer_on_hold_orderThe customerThe order is on hold
customer_processing_orderThe customerThe order is paid
customer_completed_orderThe customerThe order is completed
customer_refunded_orderThe customerA refund
customer_noteThe customerA note to the customer was added
customer_new_accountThe customerAn account was created

Where to write the code

Create the includes/emails.php file and include it in acme-shop.php.

The email subject

// wp-content/plugins/acme-shop/includes/emails.php
add_filter('woocommerce_email_subject_customer_processing_order', function (string $subject, $order): string {
    if (!$order instanceof WC_Order) {
        return $subject;
    }
 
    return sprintf('Order #%s is in progress', $order->get_order_number());
}, 10, 2);

The filter name is woocommerce_email_subject_ plus the email ID. Place an order: the customer's email arrives with the subject Order #1024 is in progress. The heading inside the email is changed the same way, with the woocommerce_email_heading_ filter and the same ID.

Adding content

// wp-content/plugins/acme-shop/includes/emails.php
add_action('woocommerce_email_before_order_table', function (WC_Order $order, bool $sentToAdmin, bool $plainText, $email) {
    if ($email->id !== 'customer_completed_order') {
        return;
    }
 
    $tracking = $order->get_meta('_acme_tracking');
 
    if ($tracking !== '') {
        echo '<p>Parcel tracking number: <strong>' . esc_html($tracking) . '</strong></p>';
    }
}, 10, 4);

The hook fires in every email with an order table, so the function checks the email ID. In the Completed order email the tracking number from the previous lesson appears above the product table.

Email hooks

HookWhere in the email
woocommerce_email_headerThe header
woocommerce_email_before_order_tableBefore the order table
woocommerce_email_after_order_tableAfter the order table
woocommerce_email_order_metaAdditional order details
woocommerce_email_customer_detailsThe addresses block
woocommerce_email_footerThe footer

The four hooks around the order receive the same arguments: the order, a sent-to-admin flag, a plain-text flag and the email object.

Testing without an order

To avoid placing an order for every email, open an order in the admin panel, choose Send order details to customer or a resend of the needed notification in the Order actions box and press the arrow button. On a local server emails are convenient to catch with Mailpit.

Overriding a template

The email markup is changed with a template copy, as in the lesson on templates:

Source file in woocommerce/templates/Copy in the theme
emails/customer-completed-order.phpacme-child/woocommerce/emails/customer-completed-order.php
emails/email-header.phpacme-child/woocommerce/emails/email-header.php
emails/email-styles.phpacme-child/woocommerce/emails/email-styles.php

The email-styles.php file holds the CSS of all emails. Email copies go out of date just like other templates — watch the Templates section on the WooCommerce → Status page.

Disabling an email in code

// wp-content/plugins/acme-shop/includes/emails.php
add_filter('woocommerce_email_enabled_customer_completed_order', function (bool $enabled, $order): bool {
    return $order instanceof WC_Order && $order->get_shipping_method() === '' ? false : $enabled;
}, 10, 2);

The Completed order email is not sent for orders without shipping — for example, a pickup placed without a shipping method.

Common mistake

Emails do not arrive, and the cause is sought in the code. WooCommerce passes an email to wp_mail(), which hands it to the server's mail service — on hosting it is often missing or its mail lands in spam. Set up sending through SMTP with a separate plugin and check delivery before changing templates.

Thanks for reading!

Donate to the site — we work hard for you.