WooCommerce Email Subject Line Generator

Rewrite WooCommerce email subject lines and headings in code, with the placeholders each email supports and the filter names that match.

Live output

Enable JavaScript to customise; default output below.

Emails

One entry per email. The filter name is built from the email ID, so it has to match exactly.

Live preview email-subjects.php
<?php
/**
 * WooCommerce email subjects and headings.
 *
 * The filter name carries the email ID, so a typo there is a filter that
 * never runs rather than an error.
 */

/**
 * Subject for the customer_processing_order email.
 *
 * @param string   $subject Current subject.
 * @param WC_Order $object  The order, or the user for account emails.
 * @param WC_Email $email   The email object.
 * @return string
 */
function my_store_customer_processing_order_subject( $subject, $object, $email ) {
	$text = __( 'Thanks {customer_first_name}, order #{order_number} is on its way', 'my-store' );

	// format_string() is what turns {order_number} into the number.
	return $email->format_string( $text );
}
add_filter( 'woocommerce_email_subject_customer_processing_order', 'my_store_customer_processing_order_subject', 10, 3 );

/**
 * Heading for the customer_processing_order email.
 *
 * @param string   $heading Current heading.
 * @param WC_Order $object  The order, or the user for account emails.
 * @param WC_Email $email   The email object.
 * @return string
 */
function my_store_customer_processing_order_heading( $heading, $object, $email ) {
	$text = __( 'Order received', 'my-store' );

	return $email->format_string( $text );
}
add_filter( 'woocommerce_email_heading_customer_processing_order', 'my_store_customer_processing_order_heading', 10, 3 );

Output is valid and updates as you type.

Rewrite the subject line and heading of any WooCommerce email in code, with the placeholders still working and the filter names built correctly from the email ID.

How to use

  1. Pick the email by its ID. The filter name is woocommerce_email_subject_<id>, so customer_processing_order and processing_order are not the same thing.
  2. Write the subject with placeholders: {site_title}, {order_number}, {order_date}, {customer_first_name} and {customer_full_name} on order emails.
  3. Keep placeholder replacement on. It runs the string through the email’s own format_string(), which is what turns {order_number} into the number.
  4. Change the heading too where it makes sense. The subject is what people see in the inbox; the heading is the first line inside the email.
  5. Put the snippet in a site specific plugin. Email wording should survive a theme change.

Example

function acme_customer_processing_order_subject( $subject, $object, $email ) {
	$text = __( 'Thanks {customer_first_name}, order #{order_number} is on its way', 'acme' );

	// format_string() is what turns {order_number} into the number.
	return $email->format_string( $text );
}
add_filter( 'woocommerce_email_subject_customer_processing_order', 'acme_customer_processing_order_subject', 10, 3 );

Without format_string() the customer receives an email whose subject literally reads {order_number}, which is the most common report about this filter.

Pitfalls

  • The placeholders are per email. {customer_first_name} exists on order emails and not on the password reset, where the object is a user rather than an order.
  • The old {blogname} placeholder still works but is deprecated in favour of {site_title}.
  • Subject filters run for the admin emails too. new_order goes to the shop manager, not the customer, and wording written for a customer reads oddly there.
  • These filters do not change emails that a plugin sends itself. Subscriptions, bookings and memberships each add their own email classes with their own IDs.
  • Settings in WooCommerce, Emails already allow a subject per email. A filter overrides that, and the person editing the setting will not know why it has no effect.
  • A very long subject is truncated by mail clients at around 60 characters on desktop and fewer on mobile. Put the useful part first.
  • format_string() needs the $email argument, which means registering the filter with three arguments. With the default one, $email is null and the call is a fatal.
  • Emails are sent during checkout. An error in this filter takes the order confirmation down with it.

Compatibility

woocommerce_email_subject_<id> and woocommerce_email_heading_<id> have been stable since WooCommerce 2.x and still apply in WooCommerce 8 and 9. WC_Email::format_string() and the woocommerce_email_format_string filter have been available since 3.0. Email IDs are the ones in WC_Emails::init_transactional_emails(). The generated code targets PHP 7.0 and up, and the tool runs entirely in your browser.

Frequently asked questions

Which placeholders can I use?
{site_title}, {site_address}, {order_date}, {order_number}, {customer_first_name}, {customer_last_name} and {customer_full_name} on order emails. Account emails have fewer.
Why is my placeholder printing literally?
The string was not passed through format_string(), or the filter was registered without the $email argument.
Can I just use the settings screen?
Yes, and for a single store that is simpler. Code is for a theme or plugin that ships the wording with it.
How do I add my own placeholder?
Filter woocommerce_email_format_string and replace your token. The generated snippet includes that option.
Does this work for plugin emails?
Only for emails registered through WooCommerce’s own email system, using their own IDs. Check the plugin’s email class.

From the people who built this tool

WP Adminify

The WordPress admin, rebuilt: a dashboard worth looking at, menu and column control, a real file manager and the login page your client sees.

See WP Adminify Free version on WordPress.org

Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.