• Hello,

    I’m working on some code to prevent users from changing their email address and name. We authenticate with an external source and profile data is managed by and synced from the external source.

    I have written code to disable the HTML form fields on profile.php and user-edit.php. This is working fine. However, I also want to handle the POST data properly, as we all know the HTML form fields can be re-enabled with a DOM editor.

    I was successful with preventing changes to first name, last name, and nickname, but email is not working. If I POST a new email address, I get the notice “There is a pending change of your email to [email protected]” and the email change confirmation email is sent out to the new address.

    My code is below. I’d be very grateful for any assistance on preventing users from changing their email address. Thanks!

    <?php
    
    new CustomStopEmailChange();
    
    class CustomStopEmailChange {
    	public function __construct() {
    		add_action('admin_init', array($this, 'add_admin_hooks'));
    	}
    
    	public function add_admin_hooks() {
    		// These two functions disable the actual HTML form fields using jquery.
    		add_action('admin_footer-profile.php', array($this, 'disable_profile_fields'));
    		add_action('admin_footer-user-edit.php', array($this, 'disable_profile_fields'));
    		
    		// Handle the POST data as well.
    		add_action('personal_options_update', array($this, 'disable_profile_fields_post'));
    	}
    	
    	public function disable_profile_fields() {
    		$Selectors = '#first_name,#last_name,#nickname,#email';
    		
    		// Use readonly instead of disabled because disabled fields are not included in the POST data.
    		echo '<script type="text/javascript">jQuery(function() {' . "\n";
    		echo 'jQuery("' . $Selectors . '").prop("readonly", true);' . "\n";
    		echo '});</script>';
    	}
    
    	public function disable_profile_fields_post() {
    		// All of these work EXCEPT for the last one: email changes.
    		
    		add_filter('pre_user_first_name', function () { $UserObj = wp_get_current_user(); return $UserObj->first_name; });
    		add_filter('pre_user_last_name', function () { $UserObj = wp_get_current_user(); return $UserObj->last_name; });
    		add_filter('pre_user_nickname', function () { $UserObj = wp_get_current_user(); return $UserObj->user_nicename; });
    		add_filter('pre_user_email', function () { $UserObj = wp_get_current_user(); return $UserObj->user_email; });
    	}
    }
    
    ?>
Viewing 3 replies - 1 through 3 (of 3 total)
  • Moderator bcworkz

    (@bcworkz)

    Use the “personal_options_update” action to set $_POST[’email’] to whatever is already in the DB. Then no matter what anyone manages to send in POST, the email field remains what it was, WP sees no change, so no notices are sent. If the email actually does need to be changed to match the external data, set it directly in the DB without using high level WP functions, use $wpdb methods.

    If you need to prevent editors and admins from changing other’s emails, also hook “edit_user_profile_update” to the same callback. Add a conditional where if the current user is a particular ID, let the new email be applied so that at least one person can change emails.

    Thread Starter Steve

    (@srg-1)

    Hi @bcworkz,

    Thanks for the response. I tried to override $_POST[’email’] as you mentioned, but it doesn’t seem to be working still.

    I have an if statement that checks if $_POST[’email’] is different from what’s currently in the DB. It seems that when I try to change the email on the Profile Edit page, $_POST[’email’] still has the OLD email address, not the new one. I used error_log() to debug this. My code is below (the code is stripped of other functions for simplicity).

    In my code above, is it a bug that pre_user_first_name, pre_user_last_name, and pre_user_nickname work fine, but pre_user_email does not? If so, should I file a bug report?

    <?php
    new StopEmailChange();
    
    class StopEmailChange {
    	public function __construct() {
    		add_action('admin_init', array($this, 'add_admin_hooks'));
    	}
    	
    	public function add_admin_hooks() {
    		add_action('personal_options_update', array($this, 'disable_profile_fields_post'));
    	}
    
    	public function disable_profile_fields_post() {
    		add_filter('pre_user_first_name', function () { $UserObj = wp_get_current_user(); return $UserObj->first_name; });
    		add_filter('pre_user_last_name', function () { $UserObj = wp_get_current_user(); return $UserObj->last_name; });
    		add_filter('pre_user_nickname', function () { $UserObj = wp_get_current_user(); return $UserObj->user_nicename; });
    	
    		// The above add_filter() won't work for email addresses for some reason. Instead, just modify $_POST directly.
    		$UserObj = wp_get_current_user();
    		error_log('User Email in DB: ' . $UserObj->user_email);
    	
    		if (isset($_POST['email'])) {
    			error_log('POSTemail is set: ' . $_POST['email']);
    		
    			if ($_POST['email'] != $UserObj->user_email) {
    				error_log('Email has changed in POST; changing back.');
    				$_POST['email'] = $UserObj->user_email;
    			}
    		}
    	}
    }
    ?>

    In my PHP error log, this is printing:

    [03-Jan-2017 16:06:29 UTC] User Email in DB: [email protected]
    [03-Jan-2017 16:06:29 UTC] POSTemail is set: [email protected]

    Even though I am trying to change my email to [email protected]. It never gets inside that last if statement.

    Thank you!

    • This reply was modified 7 years, 11 months ago by Steve.
    Moderator bcworkz

    (@bcworkz)

    I tried your code on my local, basic dev installation and it works fine. I did alter the structure to focus only on email and went to procedural style, but that would make no difference. This was my log:

    User Email in DB: [email protected]
    POSTemail is set: [email protected]
    Email has changed in POST; changing back.

    And the email of course failed to change in the DB, it remained root@lenny.lan

    Something is bizarre about your output. It’s showing the old email in $_POST, but the only way to get that output is if $_POST[’email’] was not set at all. It makes no sense. Your output must be from a different version than what you posted here. Unless PHP’s isset() is not working as expected.

    You are testing through the logged in user’s own profile page, right? The admin process of editing someone else’s email is a different process.

    As for the possible bug, your original code works on my installation as well. I was hoping by using “personal_options_update”, it would work around what ever was going on with the “pre_user_email”. Apparently it doesn’t. So I’d advise against filing a bug report ??

    Something else is going on somewhere. Be sure you don’t have some earlier coding effort still in effect. Then do the entire deactivate plugins and switch to a twenty* theme thing. Either version of your email code should work then. Reactivate everything one at a time, testing after each change. When your code fails to work again, the last activated code is creating some kind of conflict.

Viewing 3 replies - 1 through 3 (of 3 total)
  • The topic ‘Disabling Email Changes – Not Working’ is closed to new replies.