3

In the administration of my blog, I would like to prevent anyone (admin included) from deleting any user unless it is a simple subscriber.

Basicaly, in the "users" section of the administration, I would like the option "delete" to only be visible under the subscribers, not under the administrators, editors, authors or contributors.

How can I do that in my functions.php file (I'm not interested in a plugin)?

I tried the "remove_cap ('delete_users')" function but it has a too large scope as it prevents from deleting any user while I would like to prevent deleting any user BUT the subscribers.

Thank you for your help.

3 Answers 3

5

If you mean the delete button on the user list at /wp-admin/users.php, then that button is created by the WP_Users_List_Table class around (currently) line 256. If you look a little further down-- a few lines-- you will see a filter called user_row_actions. You can use that to hide the 'delete' link.

add_filter(
  'user_row_actions',
  function($actions, $user_object) {
    if (1 >= count($user_object->roles) && 'subscriber' !== $user_object->roles[0]) {
      unset($actions['delete']);
    }
    return $actions;
  },
  1,2
);

Minimally tested, but I think that logic is correct. You should see the 'delete' link for subscribers but not for users with any other role, including users with "subscriber" and some other role just in case you have that odd setup.

If you look carefully, and have a mischievous mind, you will notice that you can still delete any user you want by manipulating the user ID in the URL. Look carefully:

/wp-admin/users.php?action=delete&user=9&_wpnonce=8059e669c1

The filter above just hides the link. It does not prevent access to the delete screen. To do that, we'll need more code:

add_action(
  'load-users.php',
  function() {
    if (isset($_GET['action']) && 'delete' === $_GET['action']) {
      if (isset($_GET['user'])) {
        $user_object = get_userdata($_GET['user']);
        if (1 >= count($user_object->roles) && 'subscriber' !== $user_object->roles[0]) {
          wp_die('This user cannot be deleted');
        }
      }
    }
  }
);

Even with that in place, a clever user might still be able to push the right POST values through and delete a user anyway, so you might also want a final fail-safe right before user deletion.

add_action(
  'delete_user', 
  function($id) {
    $user_object = get_userdata($id);
    if (1 >= count($user_object->roles) && 'subscriber' !== $user_object->roles[0]) {
      wp_die('This user cannot be deleted');
    }
  }
);

Note: this code was tested in a MU-Plugin file. I think is should probably work from functions.php but be sure to verify that. Also, in practice, I'd probably try to extract some of that logic so that it is reusable. Those callbacks are dangerously close to repetitive.

1
  • 1
    Wow, thank you, that is a very thorough answer. The first idea is more than enough for me as I'm trying not my client to mess with the users by mistake, that's not an issue for me if there is some workaround to delete a user as the client is not savvy enough to do so. However, the first solution seems to be the way to go but it doesn't work yet... I put this first "add_filter" function inside "functions.php" but the "delete" link is still visible below each user. And if this code is supposed to go inside the core of WP, that might be an issue for further updates...
    – Baylock
    Feb 1, 2014 at 21:16
1

Ok s_ha_dum, I got it to work with some changes:

the "count" seems to ruin the function but like this, it worked like a charm:

function test($actions, $user_object) 
{
    if ( 'subscriber' !== $user_object->roles[0]) {unset($actions['delete']);}
    return $actions;
}
add_filter('user_row_actions','test',1,2);

Thank you for you great help!

0

Yes we can achieve it by following .

add_filter( 'user_row_actions', 'custom_action_function', 1, 2 );
function custom_action_function($actions, $user_object) {
    if ( 1 >= count( $user_object->roles ) && 'subscriber' !== $user_object->roles[0] ) {
      unset( $actions['delete'] );
    }
    return $actions;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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