admin管理员组

文章数量:1195151

Is there a way to change the content type for only the password reset email?

I have a custom HTML template for it, and have set wp_mail_content_type to text/html and am applying the template with a filter on retrieve_password_message. That all works fine and I get an HTML email for it, but I’m having a hard time figuring out where/how to reset wp_mail_content_type since I’m not actually calling wp_mail() anywhere.

Any help would be greatly appreciated.

EDIT - here’s the code I’m using.

This is the function that changes the content type:

function xxx_wp_email_content_type() {
    return 'text/html';
}
add_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' );

And here’s the function that changes the email itself:

function xxx_wp_retrieve_password_message( $content, $key ) {
    ob_start();

    $email_subject = xxx_wp_retrieve_password_title();

    include( 'templates/email_header.php' );
    include( 'templates/lost_password_email.php' );
    include( 'templates/email_footer.php' );

    $message = ob_get_contents();
    ob_end_clean();

    return $message;
}
add_filter( 'retrieve_password_message', 'xxx_wp_retrieve_password_message', 10, 2 );

Typically I’d add a remove_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' ); after a call to wp_mail(), but there isn’t one here.

Is there a way to change the content type for only the password reset email?

I have a custom HTML template for it, and have set wp_mail_content_type to text/html and am applying the template with a filter on retrieve_password_message. That all works fine and I get an HTML email for it, but I’m having a hard time figuring out where/how to reset wp_mail_content_type since I’m not actually calling wp_mail() anywhere.

Any help would be greatly appreciated.

EDIT - here’s the code I’m using.

This is the function that changes the content type:

function xxx_wp_email_content_type() {
    return 'text/html';
}
add_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' );

And here’s the function that changes the email itself:

function xxx_wp_retrieve_password_message( $content, $key ) {
    ob_start();

    $email_subject = xxx_wp_retrieve_password_title();

    include( 'templates/email_header.php' );
    include( 'templates/lost_password_email.php' );
    include( 'templates/email_footer.php' );

    $message = ob_get_contents();
    ob_end_clean();

    return $message;
}
add_filter( 'retrieve_password_message', 'xxx_wp_retrieve_password_message', 10, 2 );

Typically I’d add a remove_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' ); after a call to wp_mail(), but there isn’t one here.

Share Improve this question edited Dec 8, 2017 at 21:45 jmock asked Dec 8, 2017 at 18:40 jmockjmock 231 silver badge4 bronze badges 4
  • Can you provide an example of your code and how you're using the filters? – phatskat Commented Dec 8, 2017 at 19:18
  • Did not quite follow. Why do you need to reset the wp_mail_content_type, is it because you want other emails to send as text only? – signal2013 Commented Dec 8, 2017 at 19:27
  • @signal2013 Yes, the only one I want to send as HTML is the password reset email. – jmock Commented Dec 8, 2017 at 21:35
  • @phatskat Code has been added. – jmock Commented Dec 8, 2017 at 21:45
Add a comment  | 

4 Answers 4

Reset to default 2

I suspect you implemented the hook something like this:

function wp_set_html_mail_content_type() {
    return 'text/html';
}
add_filter( 'wp_mail_content_type', 'wp_set_html_mail_content_type' );

More info: https://codex.wordpress.org/Plugin_API/Filter_Reference/wp_mail_content_type

Did you need to reset the content type at a later point?


** UPDATE: try intercept it with a global variable:

function xxx_wp_email_content_type() {
    if($GLOBALS["use_html_content_type"]){
        return 'text/html';
    }else{
        return 'text/plain';
    }
}
add_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' );

function xxx_wp_retrieve_password_message( $content, $key ) {
    ob_start();

    $GLOBALS["use_html_content_type"] = TRUE;

    $email_subject = xxx_wp_retrieve_password_title();

    include( 'templates/email_header.php' );
    include( 'templates/lost_password_email.php' );
    include( 'templates/email_footer.php' );

    $message = ob_get_contents();
    ob_end_clean();

    return $message;
}
add_filter( 'retrieve_password_message', 'xxx_wp_retrieve_password_message', 10, 2 );

This way works for me without setting a $GLOBAL:

function xxx_wp_email_content_type() {
    return 'text/html';
}

function xxx_wp_retrieve_password_message( $content, $key ) {
    add_filter( 'wp_mail_content_type', 'xxx_wp_email_content_type' );

    ob_start();

    $email_subject = xxx_wp_retrieve_password_title();

    include( 'templates/email_header.php' );
    include( 'templates/lost_password_email.php' );
    include( 'templates/email_footer.php' );

    $message = ob_get_contents();
    ob_end_clean();

    return $message;
}
add_filter( 'retrieve_password_message', 'xxx_wp_retrieve_password_message', 10, 2 );

Since Wordpress 6.0 you can use the retrieve_password_notification_email to access (among other things) the headers for only the lost password email:

function set_lost_password_email_content_type(array $defaults, string $key, string $user_login, WP_User $user_data): array
{
    if (!isset($defaults['headers'])) {
        $defaults['headers'] = [];
    }

    $defaults['headers'] = (array) $defaults['headers'];

    $defaults['headers'][] = 'Content-Type: text/html';

    return $defaults;
}

add_filter(
    'retrieve_password_notification_email',
    'set_lost_password_email_content_type',
    10,
    4
);

The filter is called in wp-includes/user.php:

/**
 * Filters the contents of the reset password notification email sent to the user.
 *
 * @since 6.0.0
 *
 * @param array $defaults {
 *     The default notification email arguments. Used to build wp_mail().
 *
 *     @type string $to      The intended recipient - user email address.
 *     @type string $subject The subject of the email.
 *     @type string $message The body of the email.
 *     @type string $headers The headers of the email.
 * }
 * @type string  $key        The activation key.
 * @type string  $user_login The username for the user.
 * @type WP_User $user_data  WP_User object.
 */
$notification_email = apply_filters( 'retrieve_password_notification_email', $defaults, $key, $user_login, $user_data );

This doesn't technically answer the question - but more the question behind the question. The reason you might want to set the content type only for the password reset email is that setting all system emails to text/html will break the default password reset email.

I suggest using the retrieve_password_message filter in combination with the wp_mail_content_type filter to make the password reset email compatible with the HTML format:

<?php
// adding support for html emails
// this converts ALL wp_mail emails to HTML, which messes up the password reset
add_filter( 'wp_mail_content_type','squarecandy_set_content_type' );
function squarecandy_set_content_type() {
        return "text/html";
}

// add this filter too
// this will make the password reset email compatible with the HTML format
add_filter( 'retrieve_password_message', 'squarecandy_retrieve_password_message', 10, 1 );
function squarecandy_retrieve_password_message( $message ) {
    // Revise the message content to make it HTML email compatible
    $message = str_replace('<','',$message);
    $message = str_replace('>','',$message);
    $message = str_replace("\n",'<br>',$message);
    // make any additional modifications to the message here...
    return $message;
}

Otherwise, if you only want to set individual emails to text/html, the $GLOBALS method in the answer from @signal2013 also works, but might be better applied to target your custom email instead of to the default password reset email (leave this as the default text/plain).

本文标签: Set content type to HTML for lost password email only