Jason Conroy of _FindingSimple emailed me today to ask if I knew how to allow site admins to edit the profiles of other users.

I hadn’t even realised administrators couldn’t edit users!

That’s because it relates only to WordPress networks. In a WordPress 3.x Network, the Super Admin role is the only role allowed to edit users.

Diagnosing the Problem

As a solution for Jason, my first thought was to simply assign the edit_users capability to the admin role.

I used Justin Tadlock’s Members plugin to check that the admin roles no longer had the edit_users & related user capabilities. However, despite not being able to edit users, admins do have the edit_users capability. In my opinion, that’s a bug in 3.1 or at very least a quirk. If a user has the edit_users capability, they should be able to edit users.

The only hope then was to enter the dark depths of the map_meta_cap function found in capabilities.php.

Around line 816 of that file, within map_meta_cap I found this bit of code:

59 Responses to How to Allow Administrators to Edit Users in a WordPress Network

I’ve been using this method rather successfully for a few weeks now in a new multisite setup, though it seems with the latest WP update (3.1.3), it is no longer working. It is a bit odd though, I looked through the changelog for WP 3.1.3 and I dont see anything off the bat that would have touched the map_meta_cap function.

I’m doing some digging this afternoon to see if I can uncover what is happening, but is anyone else seeing issues after the latest upgrade? Of course it could always be a bonehead bug I introduced myself!

Oooops! Turns out I was simply misunderstanding the bug I was seeing. With Brent’s code above, my editors (who I’d granted the edit_users capability) could see the Edit link for users, but were receiving an error: “You do not have permission to edit this user”.

Adding this line to the wp-config file solved the problem:

define( "EDIT_ANY_USER", true );

This is the snippet used in old WPMU for allowing user editing and it seems it still carries some importance in 3.0+ Multisite instances. Hopefully as the merged branches mature a little bit, the user management will be a bit more streamlined!

If I understand correctly, you are saying your network has multiple themes and you want a solution that is external to your theme so you dont need to edit each theme individually.

You could edit the WP core code, but that is rarely a good idea, because you will have to edit it each time you update.

I would suggest you create a simple plugin to achieve this – that way, as long as your plugin is activated on a site, it wont matter what theme is active. I’m not a great resource for how to write plugins, but there are a number of tutorials out there with some simple Googling.

I recently moved this and a few other things out of my theme’s functions.php folder and into a custom plugin for a client and it works great. The only ting I had to change in this code was the priority of the filter.

add_filter( 'map_meta_cap', 'mc_admin_users_caps', 1, 4 );

Leaving it at priority of 10 didn’t work, but changing that to 1 makes it work just fine. So if you are putting this in functions.php, leave it as you see above, just copy+paste. But if you are putting this in a plugin, you will need to edit line #25 as I have shown here.

@ShinichiN
This didn’t work for me on 3.2 either, so I looked into it and found a filter in user_edit.php – enable_edit_any_user_configuration – which prevents user editing – this filter is set to return false in ms-default-filters.php. You need to add the following:

But I also noticed a serious security bug.
By changing the user id in the header when editing a user, a admin can also edit users (example the superadmin) that are no member of his blog. Note the user_id=1 for getting to the superadmin:

user-edit.php?user_id=1&wp_http_referer=%2Fwp-admin%2Fusers.php

Dont know WP that good, but is it a solution that someone adds a ‘member of subblog check’ in this?

Good find Morty- that’s definitely a problem. I spent a little time this afternoon on a function to patch.

function edit_perm_check() { //The mac_admin_users_cap function bleow has a flaw that allows edit access to all users if they change the user ID int he URL - this patches that bug
$screen = get_current_screen(); //get the relevant info for this page
global $current_user; //user doing the editing
get_currentuserinfo();
global $profileuser; //The person whose profile we are accessing
if($screen->base === 'user-edit' || $screen->base === 'user-edit-network') { //make sure we care about this page
if (!is_super_admin($current_user->ID)) { //Skip all of this is the user is super admin.
//Next, check to see if the user being edited is a member of this blog AND check if the current user is a member of this blog
if (!(is_user_member_of_blog($profileuser->ID, get_current_blog_id()) && is_user_member_of_blog($current_user->ID, get_current_blog_id()))) {
wp_die( __( 'You do not have permission to edit this user.' ) );
} //end permission check
} //end Super admin check
}
}
add_filter( 'admin_head', 'edit_perm_check', 1, 4 );

Basically, when accessing a user edit page, we check to see if both the user doing the editing and the user being edited are both members of the current blog (with an exception for Super Admins). I left the page check in for both ‘user-edit’ and user-edit-network’ because I have a plugin I share between single site and network WP setups, though on a single site, this function won’t do anything.

This still doesn’t prevent administrators of a blog deleting a super-administrator from their blog. I can’t see an obvious way of filtering this as the $screen->base for user deletion is set to ‘users’ rather than ‘user-edit’ or user-edit-network’ so it sidesteps the permission check. You may be able to check the $query_vars for user deletions to prevent this I guess. In a way, I don’t see that this is such a problem – super-admins can edit sites without being members of them

In your provided latest code there is a missing closing parenthesis on this line 40. the function closing parenthesis is missing.
I think you should update it so users who have no idea about code errors will easily copy paste the code to their function.php file.

The code works great, but there’s a potential security flaw that I haven’t seen discussed.
With this code installed, Admin #1 can invite another user on a network to join a site. Let’s say that other user, Admin #2, is already an admin of another site on the network. If Admin #2 accepts Admin #1’s invitation, Admin #1 can take control of Admin #2’s site by changing his password or other user information. If Admin #1 wants to be a subscriber on any other site on the same network, he can’t use the email address associated with his admin account.

This isn’t a shortcoming of the code here, but I suspect that disabling edit_user in multisite is for the security issue I’m raising here. In other words, not giving site admins the edit_user capability in multisite is by design, not oversight.

When a user attempts to add an existing network user to his blog, he can only choose from users that share his email domain. This works for us because our client base is very corporate. Keeps it “all in the family”, if you will.

Scott – Out of curiosity, how are you limiting an admin to only adding users that share his email domain? It’s an interesting idea, but it wouldn’t really work for us (we’re a soon-to-be public network). We have a number of admins who registered with email domains of gmail, so that would be a pretty big family. Personally, I think a safer solution would be to remove the ability for an admin to add an existing user on the network, but even that is not perfectly safe, because an admin of a site on our network may register on a domain-mapped site, not even realizing that site is also on our network.

First, I made a function to check the current_user against 20-25 common, free email service domains (gmail, hotmail, etc…). No one with an email domain on that blacklist may add existing network users.

The nature of our business model is such that almost all of our clients are going to have corporate email domains.

Second, I made a function to populate a jQuery autosuggest with all the existing network users that share the email domain with the current_user. That is the only pool from which current_user can add existing network users. And yes, there is server-side validation behind that jQuery autosuggest as well.