Develop

WordPress: Send Admin Notification when User Updates Specific Profile Fields

Background

I’ve had some requests in the past from clients who want to be notified when WordPress users change information in their user profile, easy enough for the most part. However, a recent client asked to be notified when specific information was changed, mainly, contact related info. This would include their email address, their phone number and their mailing address. No big deal, or so I thought…

Rename Post

fig 1.0 send mail

The Issue

This simple idea turned out to be not-so-straightforward. Setting up the conditions for notification on email change were easy: compare $old_user_data->user_email to $user->user_email*, if the values are not equal, send an email. Great!

*more about profile updates in the codex.

However, when using this method with the phone field and any of the address fields $old_user_data returns null. Why?! After some exhaustive searching, I found this little bit of information that explained everything:

$old_user_data is an object containing only the basic WP_User fields, but none of the additional user keys (first_name, last_name, etc. are not part of this object).

Ahhhh, ok. Well at least that explains it. So, what to do now? I thought about if for a bit, but no easy solution came to mind. I also wanted to implement a solution that was native to WordPress, without using jQuery etc. I posted the situation to the Advanced WordPress Facebook Group, which if you’re not involved in, you should be!

Within a matter of minutes I had multiple ideas coming in from awesome WordPress folks. One solution in particular stood out to me, it was a suggestion from Nick Ciske, to store the user meta in a transient, and then compare the data. A transient? I had never heard of this before so I looked it up in the codex, behold, awesome: Transient API.

I was super excited, this is what I needed! I went to bed happy knowing that I had a solution to integrate the next day. When I awoke the next morning I had a message from Nick, he had personally taken the code sample I had posted on GitHub and coded the transient portions for me! Wow…what and awesome and selfless thing to do :)

The Solution

Since this is nowhere to be found on the interwebs, below is the solution I came up with including Nick’s awesome code for setting up the transient metadata. There is an email to be sent for each of the following conditions, when they are true:

1. A user’s email is updated
2. A user’s phone number is updated
3. Any of the address related fields are updated

/* ===========================================
    Send Emails when User Profile Changes
   =============================================*/

// IF EMAIL CHANGES
function sr_user_profile_update_email( $user_id, $old_user_data ) {

  $user = get_userdata( $user_id );
  if($old_user_data->user_email != $user->user_email) {
    $admin_email = "you@yourdomain.com";
    $message = sprintf( __( 'This user has updated their profile on the SchoolRise USA Staff Member site.' ) ) . "\r\n\r\n";
    $message .= sprintf( __( 'Display Name: %s' ), $user->display_name ). "\r\n\r\n";
    $message .= sprintf( __( 'Old Email: %s' ), $old_user_data->user_email ). "\r\n\r\n";
    $message .= sprintf( __( 'New Email: %s' ), $user->user_email ). "\r\n\r\n";
    wp_mail( $admin_email, sprintf( __( '[Staff Member Site] User Profile Update' ), get_option('blogname') ), $message );
  }

}

add_action( 'profile_update', 'sr_user_profile_update_email', 10, 2 );

// IF PHONE NUMBER CHANGES
function sr_user_profile_update_phone( $user_id, $old_user_data ) {

  $old_user_data = get_transient( 'sr_old_user_data_' . $user_id );
  $user = get_userdata( $user_id );

  if($old_user_data->phone != $user->phone) {
    $admin_email = "you@yourdomain.com";
    $message = sprintf( __( 'This user has updated their profile on the SchoolRise USA Staff Member site.' ) ) . "\r\n\r\n";
    $message .= sprintf( __( 'Display Name: %s' ), $user->display_name ). "\r\n\r\n";
    $message .= sprintf( __( 'Old Phone: %s' ), $old_user_data->phone ). "\r\n\r\n";
    $message .= sprintf( __( 'New Phone: %s' ), $user->phone ). "\r\n\r\n";
    wp_mail( $admin_email, sprintf( __( '[Staff Member Site] User Profile Update' ), get_option('blogname') ), $message );
  }

}

add_action( 'profile_update', 'sr_user_profile_update_phone', 10, 2 );

// IF ADDRESS CHANGES
function sr_user_profile_update_address( $user_id, $old_user_data ) {

  $old_user_data = get_transient( 'sr_old_user_data_' . $user_id );
  $user = get_userdata( $user_id );

  if($old_user_data->street != $user->street or $old_user_data->city != $user->city or $old_user_data->state != $user->state or $old_user_data->zip != $user->zip) {

    $admin_email = "you@yourdomain.com";
    $message = sprintf( __( 'This user has updated their profile on the SchoolRise USA Staff Member site.' ) ) . "\r\n\r\n";
    $message .= sprintf( __( 'Display Name: %s' ), $user->display_name ). "\r\n\r\n";
    $message .= sprintf( __( 'Old Address: %s, %s, %s %s' ), $old_user_data->street, $old_user_data->city, $old_user_data->state, $old_user_data->zip ). "\r\n\r\n";
    $message .= sprintf( __( 'New Address: %s, %s, %s %s' ), $user->street, $user->city, $user->state, $user->zip ). "\r\n\r\n";
    wp_mail( $admin_email, sprintf( __( '[Staff Member Site] User Profile Update' ), get_option('blogname') ), $message );
  }

}

add_action( 'profile_update', 'sr_user_profile_update_address', 10, 2 );

// Save old user data and meta for later comparison for non-standard fields (phone, address etc.)
function sr_old_user_data_transient(){

  $user_id = get_current_user_id();
  $user_data = get_userdata( $user_id );
  $user_meta = get_user_meta( $user_id );

  foreach( $user_meta as $key=>$val ){
    $user_data->data->$key = current($val);
  }

  // 1 hour should be sufficient
  set_transient( 'sr_old_user_data_' . $user_id, $user_data->data, 60 * 60 );

}
add_action('show_user_profile', 'sr_old_user_data_transient');

// Cleanup when done
function sr_old_user_data_cleanup( $user_id, $old_user_data ){
  delete_transient( 'sr_old_user_data_' . $user_id );
}
add_action( 'profile_update', 'sr_old_user_data_cleanup', 1000, 2 );

Conclusion

In conclusion, code is awesome. Code that works is more awesome. And people in the WordPress community are the most awesome of them all. Thanks again, Nick!

{ 68 Comments }

  1. Dominic

    I *may* have just sent you (or your client) an update notification email or two.

    Might be worth removing the hardcoded notification email address, just in case any else is dumb enough to accidentally allow it to run before making site-specific changes (like I did).

    $admin_email = get_option( ‘admin_email’ );

    • Chris Perryman

      Ha! I totally got it ;) Thanks for the heads up, I’ll fix that. But looks like it’s working for you, yay!

    • Dominic

      Yes it’s fantastic. Exactly what I was looking for!

      The only change I’ll make is to roll the separate functions into one, so I get a single email that says: “Hey bug guy, this user changes these multiple fields.”

      Thanks heaps for sharing!

  2. scott

    Great post! Helped me with a project I’m working on. Wondering if you would know why the “\r\n” is not working in my generated emails? The output is showing in one line.

  3. Hey thanks so much for working on it Chris. You’re effort is really appreciated and now I don’t feel so bad! Be blessed.

    Wayne

  4. This looks very promising for me. We have a large membership and need to be aware when they make changes to their profile fields so I can keep our internal database up to date.

    Two questions, if you don’t mind.

    1. Will I be able to use this same functionality for extended profile fields within BuddyPress (please say yes).

    2. If so, I just need a little help with what to do with this code. I’ve never messed around with anything other than css changes. Do I put this somewhere in particular? Is it part of an existing php file or do I create a new one? Thanks in advance for your help.

    • OK. I taught myself how to create a new plugin php file and loaded this code in. I added a section for the meta data for nickname. I then went in and attempted to change info for a user’s nickname but have not received an email yet. Am I missing something?

      I changed this line from 60 * 60 to 5 * 5 thinking it’s supposed to represent 5 minutes?

      // 1 hour should be sufficient
      set_transient( ‘sr_old_user_data_’ . $user_id, $user_data->data, 5 * 5 );

    • Chris Perryman

      Also, you don’t need to change the transient time…you want it to be more than 5 minutes ;)

    • Thanks for getting back to me Chris.

      I spent way too much time on this today and left the office pretty discouraged. I feel like I’m close to a solution and this is the only thing holding me back from making my site live for my members.

      Adding the text for the nickname works great and I had actually figured that out.

      My problem is that the fields I need to access aren’t cookie-cutter WordPress fields. They are extended fields made from the BuddyPress plugin. So they are in a different database table than the standard WordPress fields.

      I have a basic understanding of how code works because I know some VBA, so I can follow the code relatively well. I just can’t figure out how to tell the first couple of lines to look in that other table instead. Is that a big problem? Am I making sense?

    • Chris Perryman

      I’m sorry you’re discouraged…I know the feeling well!

      I don’t think this should be too hard to alter to make that work. I think we may need to change some variables. Let me see if I can run some tests and I’ll get back to you.

    • Chris Perryman

      I setup the plugin and spent a lot of time trying to get this to work…for some reason, I can’t even get the BP fields to show in the email at all (not even trying to use the transients).

      I’m not sure what kind of site this is, but I’m sure you could have a developer figure out the issue. I’m not too familiar with BuddyPress and the ins and outs of what it’s doing.

      If you’d like some referrals, I’d me more than happy to provide you with some.

    • Hi Chris. I posted a topic on BuddyPress about this and got this comment.

      “The hook you want is xprofile_updated_profile

      Full hook:
      do_action( ‘xprofile_updated_profile’, bp_displayed_user_id(), $posted_field_ids, $errors, $old_values, $new_values );

      See buddypress\bp-xprofile\bp-xprofile-screens.php”

      I don’t know if perhaps you’d understand enough of this to help me from here? Again, no worries if you can’t or don’t have the time. You’ve been super helpful already. I’m going to consult a friend here about this too.

    • Chris Perryman

      Excellent! It’s your lucky day :) I had tried something similar…but it was a long day, maybe my eyes were failing. Here is your solution, in this example I added a “Color” field to the BP profile:

      // IF COLOR FIELD CHANGES
      function rc_buddypress_profile_update( $user_id ) { 
           
           $admin_email = "ADD-YOUR-EMAIL@DOMAIN.COM";
           $message = sprintf( __( 'Member: %1$s', 'buddypress' ), bp_core_get_user_displayname( $user_id ) ) . "\r\n\r\n"; 
           $message .= sprintf( __( 'Color: %s' ), bp_get_profile_field_data('field=Color') ). "\r\n\r\n";
           wp_mail( $admin_email, sprintf( __( '[YOUR SITE] Member Profile Update' ), get_option('blogname') ), $message );
       }
      
       add_action( 'xprofile_updated_profile', 'rc_buddypress_profile_update', 10, 5 ); 
      
    • Totally awesome! It works perfectly. You made my day. Thanks so much!

      You’ve got the makings of a great plugin with this code. I saw several others looking for a solution similar to this one.

      Have a great evening!

    • Chris Perryman

      I created a post for the topic, so hopefully some folks will find it in their searches. Also, if you want to thank me proper, you can take a look at some ideas here: Say Thanks.

    • Will do and glad to. You saved the day for me. I’ll be in touch tomorrow via email.

  5. Tony

    Thanks for the post! This is just what I needed for my dev project.

{ Respond }

Leave a response