7

I am really new to WordPress programming and I am not even sure if this feature exists. What I am trying to do is send an email to users (not admin) when an admin changes their password/email?

At present when I add a new user, an email is sent to them but no email is sent to them when I change their password/email.

I will really appreciate any assistance here.

12

Here's one way to add this feature using the following flowline :

The admin updates the user option page:

   -> edit_user_profile_update or personal_options_update hooks activated
   -> edit_user() function is called
   -> wp_update_user() function is called within edit_user()
   -> wp_insert_user() function is called within wp_update_user()
   -> profile_update hook activated within wp_insert_user() 
      for user updates, not user inserts
   -> wp_redirect() function called on successful user updates
   -> wp_redirect filter activated
   -> The page reloads
   -> admin_notices hook activated

Step #1 - The HTML checkbox:

First we add the Send a notification checkbox above the password text fields and it's only visible to the administrator:

Checkbox

by hijacking the show_password_fields filter:

add_filter( 'show_password_fields', 'wpse_notification_html' );

function wpse_notification_html( $show )
{
    if( current_user_can( 'manage_options' ) ):
?>
    <tr>
        <th scope="row">
            <label for="wpse_send_notification"><?php _e('Send a notification?') ?></label>
        </th>
    <td>
            <label for="wpse_send_notification">
                <input type="checkbox" name="wpse_send_notification" id="wpse_send_notification" value="1" />
                <?php _e( 'Send an email to user and notify that the password has changed.' ); ?>
            </label>
        </td>
    </tr>
<?php
    endif;
    return $show;
}

Step #2 - The main controller:

Next we want to hook into the profile_update from the user options page:

add_action( 'edit_user_profile_update', 'wpse_user_update' );
add_action( 'personal_options_update',  'wpse_user_update' );

function wpse_user_update( $user_id )
{
    if( current_user_can( 'manage_options' ) )
        add_action( 'profile_update', 'wpse_controller', 10, 2 );
}

where the main logic is in the wpse_controller() function:

function wpse_controller( $user_id, $old_user_data )
{
    // Input:
    $pass1  = filter_input( INPUT_POST, 'pass1' );
    $pass2  = filter_input( INPUT_POST, 'pass2' );
    $send   = filter_input( INPUT_POST, 'wpse_send_notification', FILTER_SANITIZE_NUMBER_INT );

    // Run this action only once:
    remove_action( current_action(), __FUNCTION__ );

    // Send the notification:
    if( 1 == $send )
    {
       if( ! empty( $pass1 )
           && $pass1 === $pass2
           && sanitize_text_field( $pass1 ) === $pass1
       ):
            if( wpse_user_password_notification( $user_id, wp_unslash( sanitize_text_field( $pass1 ) ) ) )
                add_filter( 'wp_redirect', 'wpse_redirect_notification_success' );
            else
                add_filter( 'wp_redirect', 'wpse_redirect_notification_error' );
       else:
                add_filter( 'wp_redirect', 'wpse_redirect_pass_validation_error' );
       endif;
    }
}

because then all the validations have taken place.

It's a little bit tricky to display error/success messages, because WordPress uses a redirect when the user options page is updated. Therefore we use a trick with the wp_redirect filter to add the relevant query variable so we can determine the message from the admin_notices hook:

function wpse_redirect_notification_success( $location )
{
    return add_query_arg( 'wpse_notification', 'mail_success', $location );
}

function wpse_redirect_notification_error( $location )
{
    return add_query_arg( 'wpse_notification', 'mail_error', $location );
}

function wpse_redirect_pass_validation_error( $location )
{
    return add_query_arg( 'wpse_notification', 'pass_validation_error', $location );
}

Step #3 - Send the email:

We use a modification of the core wp_new_user_notification() function to send the email:

function wpse_user_password_notification( $user_id, $plaintext_pass = '' )
{
    if ( empty( $plaintext_pass ) )
       return false;

    $user = get_userdata( $user_id );
    $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
    $message  = sprintf( __( 'Username: %s' ),     $user->user_login ) . "\r\n";
    $message .= sprintf( __( 'New Password: %s' ), $plaintext_pass   ) . "\r\n";
    $message .= wp_login_url() . "\r\n";
    return wp_mail( $user->user_email, sprintf(__('[%s] Your username and new password'), $blogname), $message );
}

Step #4 - Admin notices for success or errors:

We use the following admin notices, determined by the wp_notices query variable added in the wp_redirect filter:

Success Error 1 Error 2

add_action( 'admin_notices', 'wpse_admin_notices' );

function wpse_admin_notices()
{
    $status = filter_input( INPUT_GET, 'wpse_notification', FILTER_SANITIZE_STRING );

    switch ( $status )
    {
        case 'mail_success':
            ?><div id="message" class="updated"><p><strong>Notification Sent!</strong>: Notification email successfully sent to the user</p></div><?php
            break;  
        case 'mail_error':
            ?><div class="error"><p><strong>ERROR</strong>: Notification email not sent to the user</p></div><?php
            break;
        case 'pass_validation_error':
            ?><div class="error"><p><strong>ERROR</strong>: Notification email not sent to the user, because of symbol chars in the password </p></div><?php
            break;
    } // end switch
}

How to sanitize the password?

Notice that I use the sanitize_text_field() to sanitize the password in the email. I'm not sure what's the best way to do it. At least I didn't want to send it raw in the email. That's the reason for this extra error message:

Error 1

just so we can handle the case where the password contains some characters that get stripped by the sanitize_text_field() function. Any other ideas are welcomed.

PS: This is experimental and might need some adjustments. The code above is all procedural and without any anonymous functions. It might get much simpler by smearing some OOP butter on it ;-)

  • You're welcome, hopefully you can extend it to your needs. Maybe this would be a nice plugin idea ;-) – birgire Sep 10 '14 at 18:34
  • Ya I am thinking exactly the same – Baig Sep 10 '14 at 18:56
  • Rather puts my answer to shame! I'm amazed this isn't already a plugin! – Sol Sep 12 '14 at 12:26
  • @Sol I like #1 on your list, I guess that's very overlooked option ;-) I haven't checked if there already exists plugins for this feature, but if I got some time I might work on it and maybe you guys can join in and test it, if that happens? – birgire Sep 12 '14 at 13:01
  • 1
    This is one of the best written and most complete responses I've seen here in a while -- Just enough info to be a solid response, while still leaving it to the reader to understand and implement many details on his own. Well done. – TonyG Mar 13 '17 at 21:27
2

There are a few ways to accomplish this;

1) [easy] Send your user to the login screen and have them initiate the forgot password process

2) [moderate] Plugins (there are a few) free WordPress plugins, this looks useful, or you could search http://wordpress.org/plugins/search.php?q=reset+password and probably lots of commercial ones, but here is one

3) [hard] Custom write a function in your own plugin - for that you can refer to the WordPress Codex and also here seems a reasonable tutorial

1

Since WordPress 4.3.0, there is a filter for this (located in user.php):

add_filter('send_password_change_email', function( $send, $user, $userdata ){
  // bail early if $send is false
  if( !$send ) {
    return $send;
  }
  // Your custom email logic
  // ...

  // tell wordpress not to send the built-in email
  return false;
}, 10, 3);
  • Not sure this helps. This filter hook is meant to define weather to send the password change email or not. It now sends it by default. As reminder, the problem is "At present when I add a new user an email is sent to them which is great but no email is sent to them when I change their password/email." – ClemC Aug 23 '17 at 13:49
  • It does help, I am using this in a production project. The filter returns false to wordpress, so the built-in email doesn't get send. Instead, you can send your own email before the last return statement. – rassoh Aug 23 '17 at 18:25
  • Yes, that's an interesting use of a filter which you make it act like an action also. But that would be helpful if the OP wanted to change the built-in email and it's not mentionned anywhere in the question. My point is that it's a little bit off-topic... – ClemC Aug 24 '17 at 18:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.