Add a PHP Email Template to Your WordPress Theme

I have always wondered why WordPress does not include a way to include a PHP template for all emails by default. It has always baffled me that this is a complex thing to do in WordPress. Plugins exist to help, but none seem to be a magic solution for developers who wish to create their own HTML email templates. Here is a way that I have found to create an email HTML template within your theme file that WordPress will use for most sends.

Steps to Add An HTML Email Template to Your WordPress Theme

Step 1: Create A Custom Email Template

Create an HTML email template with placeholders for the subject line and content and upload this to your theme as a PHP file. I have included an example here to get started. Add this file into the root of your theme with the filename email-template.php.

<?php
/**
 * Custom HTML Email Template
 * {email_subject} will be replaced with the email subject
 * {email_content} will be replaced with the email content
 */
?>

<!DOCTYPE html>
<html>
<head>
    <title>{email_subject}</title>
</head>
<body>
    <h1>{email_subject}</h1>
    {email_content}
</body>
</html>

Step 2: Add a Filter to Modify Email Sends

WordPress includes a number of hooks and filters that can be used to modify email sends. For this example, we will use a filter to modify data passed into wp_mail. Add the following function to the functions.php file in your theme.

/**
 * Use an HTML Email Template for All Sends
 * Add this file to functions.php
 */
function your_email_template($args) {
    
    if (!is_array($args)) {
        return $args;
    }
    
    if (isset($args["message"]) && isset($args["subject"]) && isset($args["headers"])) {
        
        // Test that this is not already an HTML email
        // Test that this message does not already include an <html> or <body> tag. This seems to add compatibility for most plugins
        if ( !str_contains($args["message"], '<html') && !str_contains($args["message"], '<HTML') && !str_contains($args["message"], '<body') ) {
        
            // Automatically add spacing
            $message = wpautop($args["message"]);
            $subject = $args["subject"];
            
            // Load your custom email template file
            ob_start();
            include(get_template_directory() . '/email-template.php');
            $email_template = ob_get_clean();
            
            // Replace placeholders with actual content
            $email_template = str_replace('{email_subject}', $subject, $email_template);
            $email_template = str_replace('{email_content}', $message, $email_template);
            
            $args["message"] = $email_template;
            
            // If the headers are not set then update them so that this is sent as an HTML email instead of plain text
            if ( !is_array($args["headers"]) && $args["headers"] === '' ) {
                $args["headers"] = 'Content-Type: text/html; charset=UTF-8';
            }
            
        }
        
    }
    
    return $args;
    
}
add_filter('wp_mail', 'your_email_template', 10, 1);

That’s it! Make sure to test this in a staging environment before you add it to a live website.

Compatibility

These instructions are meant to be used by a developer. This has been tested and is compatible with core WordPress email notifications and several plugins that I use. This function may need to be modified if conflicts are found with other plugins. Compatibility with all plugins is not guaranteed.

The following has been tested and work well with this function:

  • WordPress email notifications (password reset, etc.)
  • WooCommerce (WooCommerce email template is used instead)
  • Ninja Forms
  • Mailgun