Disable user profile editing for one user

I have being looking in internet how can I disable the option of edit profile in Wordpress for a user and I didn't find a good way. The problem is that I want that the 95% of users can edit their profiles (address, telephone,...) but there is another 5% that I don't want them to have access to the profile section. The best solution for me is to select manually the users that I want to disable but I also thought about create a role or a group of users to manage it.

There is no plugin for this and the only thing I have found is the following code but it is not working.

add_action('admin_init', 'user_profile_fields_disable');

function user_profile_fields_disable() {

    global $pagenow;

    // apply only to user profile or user edit pages
    if ($pagenow!=='profile.php'  $pagenow!=='user-edit.php') {
        return;
    }

    // do not change anything for the administrator
    if (current_user_can('administrator')) {
    return;
    }
    if (current_user_can('custom_role') {
      add_action( 'admin_footer', 'user_profile_fields_disable_js' );
    }      
}
/**
 * Disables selected fields in WP Admin user profile (profile.php, user-edit.php)
 */
function user_profile_fields_disable_js() {
?
    script
        jQuery(document).ready( function($) {
            var fields_to_disable = ['email', 'role'];
            for(i=0; ifields_to_disable.length; i++) {
                if ( $('#'+ fields_to_disable[i]).length ) {
                    $('#'+ fields_to_disable[i]).attr("disabled", "disabled");
                }
            }
        });
    /script
?php
}

You have to substitute the "custom_role" with the name of the role I have assign to the user. Is that code obsolete or bad? Any idea of how to solve it?


Thank you very much G.M.! It was a great and perfect solution. I forgot to tell that I am using the Woocommerce plugin and I still have the problem of profile editing in the "my account" page.

Could you add something to the plugin above to remove the "edit" link? I don't mind that the user can read his profile but don't allow to edit it.

Here is what I am talking about (some fields are in spanish):

Thanks again for your work!

Topic profiles users Wordpress

Category Web


If you want to completerly remove the possibility for an user to access on profile, you can

  1. Give admin possibility to choose which user can access on profile and which not
  2. Remove the profile link from menu and from admin bar
  3. Ensure the profile is not accessible even if accessed directly by manually typing address

Step 1

First point is pretty easy using 'personal_options', 'edit_user_profile_update' hooks:

add_action( 'personal_options', 'rpa_profile_ban_field' );
add_action( 'edit_user_profile_update', 'rpa_profile_ban_field_save' );

function rpa_profile_ban_field( \WP_User $user ) {
  $current = wp_get_current_user();
  if ( ! is_admin() || $user->ID === $current->ID ) return;
  if ( ! user_can( $current, 'edit_users' ) ) return;
  $target = new WP_User( $user->ID ); 
  if ( $target->exists() &&  ! user_can( $target, 'edit_users' ) ) {
    $banned = (int) get_user_meta( $user->ID, '_profile_banned', TRUE );
  ?>
  <table class="form-table"><tbody><tr>
  <th scope="row">Profile Ban</th><td>
  <input<?php checked(1, $banned); ?> name="_profile_banned" value="1" type="checkbox">
  Ban user to enter profile?
  </td></tr></tbody></table>
  <?php
  }
}

function rpa_profile_ban_field_save( $userid ) {
  $current = wp_get_current_user();
  if ( ! is_admin() || $user->ID === $current->ID ) return;
  if ( ! user_can( $current, 'edit_users' ) ) return;
  $target = new WP_User( $userid );
  if ( ! $target->exists() || user_can( $target, 'edit_users' ) ) return; 
  $ban = filter_input( INPUT_POST, '_profile_banned', FILTER_SANITIZE_NUMBER_INT );
  if ( (int) $ban > 0 ) {
    update_user_meta( $userid, '_profile_banned', 1 );
  } elseif ( get_user_meta( $userid, '_profile_banned', TRUE ) ) {
    delete_user_meta( $userid, '_profile_banned' );
  }
}

Using this code administrators can go to each user and disable the access to profile page. This is the output of the code:

Ban user fields

Step 2

Remove profile link from menu is easy using remove_menu_page:

add_action( 'admin_menu', 'rpa_profile_menu_remove' );

function rpa_profile_menu_remove(){
  $remove = get_user_meta( get_current_user_id(), '_profile_banned', TRUE );
  if ( ! current_user_can( 'edit_users' ) && (int) $remove > 0 ) {
    remove_menu_page( 'profile.php' );
  } 
}

Remove profile link from admin bar is a little more complex, or better, completely remove the user menu on top right is easy using $wp_admin_bar->remove_menu('my-account') (see WP_Admin_Bar docs), but it is "unaesthetic" and also you remove the possibility to logout. So a better solution is remove just the link to profile:

add_action( 'wp_before_admin_bar_render', 'rpa_profile_adminbar_remove' );

function rpa_profile_adminbar_remove() {
  $remove = get_user_meta( get_current_user_id(), '_profile_banned', TRUE );
  if ( (int) $remove !== 1 || current_user_can( 'edit_users' ) ) return;
  global $wp_admin_bar;
  $account = (array) $wp_admin_bar->get_node('my-account');
  $info = (array) $wp_admin_bar->get_node('user-info');
  $logout = (array) $wp_admin_bar->get_node('logout');
  $account['href'] = $info['href'] = '#';
  $wp_admin_bar->remove_node('my-account');
  $wp_admin_bar->remove_node('user-info');
  $wp_admin_bar->remove_node('edit-profile');
  $wp_admin_bar->remove_node('logout');
  $wp_admin_bar->add_node($account);
  $wp_admin_bar->add_node($info);
  $wp_admin_bar->add_node($logout);
}

Step 3

Using all the code above, an user do not see a link to profile anymore, however, just typing http://www.example.com/wp-admin/profile.php and profile page is shown. This can be easily solved:

add_action( 'load-profile.php', 'rpa_profile_banned_check' );
add_action( 'load-index.php', 'rpa_profile_banned_msg' );
add_action( 'all_admin_notices', 'rpa_profile_banned_msg' );

function rpa_profile_banned_check() {
  $remove = get_user_meta( get_current_user_id(), '_profile_banned', TRUE );
  if ( (int) $remove === 1 && ! current_user_can( 'edit_users' ) ) {
    wp_redirect( add_query_arg( array( 'pbanned' => 1), admin_url('index.php') ) );
    exit();
  }
}

function rpa_profile_banned_msg() {
  if ( current_user_can( 'edit_users' ) ) return;
  static $show = false;
  if ( current_filter() === 'load-index.php' ) {
    $msg = (int) filter_input( INPUT_GET, 'pbanned', FILTER_SANITIZE_NUMBER_INT);
    $banned = (int) get_user_meta( get_current_user_id(), '_profile_banned', TRUE );
    $show = ( $msg === $banned && $banned === 1 );    
  } elseif ( current_filter() === 'all_admin_notices' && $show ) {
    echo '<div class="error"><p>Sorry, you are not allowed to edit your profile.</p></div>';
  }
}

The previous code check if the user is banned when the profile page is loaded, and if so redirect the user to dashboard adding a variable in the url that allow to show a message that inform user that he/she is not allowed to see profile.

This is how the message appear:

Admin notices for user not allowed to see profile


All code, as a plugin, available in a Gist here.


Somebody helped me to get the same for Woocommerce 2.0.XX. The first thing is to install the G.M. plugin above. Then, I have edited the file /plugins/woocommerce/templates/myaccount/my-address.php and you have to add in line 28:

$checkProfile =  get_user_meta( $customer_id, '_profile_banned', TRUE );

And also you have to substitude in line 45:

<a href="<?php echo esc_url( add_query_arg('address', $name, get_permalink(woocommerce_get_page_id( 'edit_address' ) ) ) ); ?>" class="edit"><?php _e( 'Edit', 'woocommerce' ); ?></a>

with:

<?php 
if (!empty($checkProfile) && $checkProfile==1) {
echo '';
} else {
echo '<a href="', esc_url( add_query_arg('address', $name, get_permalink(woocommerce_get_page_id( 'edit_address' ) ) ) ), '" class="edit">', _e( 'Edit', 'woocommerce' ), '</a>';
}
?>

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.