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:
case 'edit_users': // If multisite these caps are allowed only for super admins. if ( is_multisite() && !is_super_admin( $user_id ) ) $caps[] = 'do_not_allow'; else $caps[] = 'edit_users'; // Explicit due to primitive fall through break;
And there it is. The master override that is preventing any role other than Super Admin from editing other users.
Solution
Fortunately, as is the wonder of WP, the $caps array is passed through a filter before being returned:
return apply_filters('map_meta_cap', $caps, $cap, $user_id, $args);
So the trick then is to use the map_meta_cap filter to turn that do_not_allow capability in the $caps array into either edit_users, delete_users or create_users.
function mc_admin_users_caps( $caps, $cap, $user_id, $args ){ foreach( $caps as $key => $capability ){ if( $capability != 'do_not_allow' ) continue; switch( $cap ) { case 'edit_user': case 'edit_users': $caps[$key] = 'edit_users'; break; case 'delete_user': case 'delete_users': $caps[$key] = 'delete_users'; break; case 'create_users': $caps[$key] = $cap; break; } } return $caps; } add_filter( 'map_meta_cap', 'mc_admin_users_caps', 10, 4 );
This restores the edit_users, delete_users and create_users capabilities to their former glory.
If a user has the admin role, or has been manually assigned any of these capabilities, they will then be able to edit users.
— Update 21 May 2012 —
A few important updates to get the code to work with WordPress 3.3 and to prevent admin users being able to edit super admin accounts and accounts of users not on their site.
Thanks to everyone in the comments, especially for those comments made by Andrew Cafourek, Peter Edwards & Morty Dot.
function mc_admin_users_caps( $caps, $cap, $user_id, $args ){ foreach( $caps as $key => $capability ){ if( $capability != 'do_not_allow' ) continue; switch( $cap ) { case 'edit_user': case 'edit_users': $caps[$key] = 'edit_users'; break; case 'delete_user': case 'delete_users': $caps[$key] = 'delete_users'; break; case 'create_users': $caps[$key] = $cap; break; } } return $caps; } add_filter( 'map_meta_cap', 'mc_admin_users_caps', 1, 4 ); remove_all_filters( 'enable_edit_any_user_configuration' ); add_filter( 'enable_edit_any_user_configuration', '__return_true'); /** * Checks that both the editing user and the user being edited are * members of the blog and prevents the super admin being edited. */ function mc_edit_permission_check() { global $current_user, $profileuser; $screen = get_current_screen(); get_currentuserinfo(); if( ! is_super_admin( $current_user->ID ) && in_array( $screen->base, array( 'user-edit', 'user-edit-network' ) ) ) { // editing a user profile if ( is_super_admin( $profileuser->ID ) ) { // trying to edit a superadmin while less than a superadmin wp_die( __( 'You do not have permission to edit this user.' ) ); } elseif ( ! ( is_user_member_of_blog( $profileuser->ID, get_current_blog_id() ) && is_user_member_of_blog( $current_user->ID, get_current_blog_id() ) )) { // editing user and edited user aren't members of the same blog wp_die( __( 'You do not have permission to edit this user.' ) ); } } } add_filter( 'admin_head', 'mc_edit_permission_check', 1, 4 );
— Update 28 June 2012 —
Updated the mc_edit_permission_check()
to prevent a super admin form being deleted. Thanks again to Peter Edwards in the comments.
— Update 29 September 2012 —
Updated the mc_edit_permission_check()
to allow super admins to edit users again. Thanks to Scott Fennell in the comments.
Such a legend. THANKS!
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!
(forgot to subscribe to follow-up comments) 🙂
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!
Thanks for sharing Andrew.
Thank you SO MUCH for this! I’d been looking for this kind of solution early this year and never found an answer. This works perfectly!
Great to know it helped Alison. 🙂
Thanks it works
Thank you! Thank you! Perfect solution for what i agree is a bit of a quirk.
ps.. thanks to Andrew for the “EDIT_ANY_USER” tip… works great for Editor roles.
sos un groso!!!!!!!
Thanks, it works perfectly for 3.2.1.
Pingback: How to Allow Administrators to Create Users in a WordPress Network | Blog do Gabriel
Yes, this is awesome! Thanks for sharing!
I don’t understand where do you paste your code ? in the wp-config.php file ?
The code that Brent goes over in the post will need to go in the functions.php file within your theme and the code I reference in my comment above will go in your wp-config.php file.
Thanks you
An other question :
When we use a lot a theme it’s not possible to paste this code in other file than function.php oh each theme to don’t do it x times… ?
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.
Thank you
I’m going to try to make my first plugin with your code…
Hi, thank you for this article..
Does this code still work on wordpress 3.2?
I made a simple plugin but it didn’t work.
I could see a link below the name of users to edit, but when I click it, WP says I have no right to edit that user..
Thanks.
Hi,
I have the same issue.
Fortunately there is http://wordpress.org/extend/plugins/user-switching/ as an alternative.
Beware it needs a fix to avoid an administrator becoming a super-administrator.
http://wordpress.org/support/topic/plugin-user-switching-security?replies=2
Regards,
Gabriel
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.
Thanks for sharing Andrew. 🙂
@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:As far as I can tell from past revisions, this filter works in conjunction with an EDIT_ANY_USER constant (possibly a hang-up from WPMU).
I create a plugin but it doesn’t work more with the last version (3.3.1)… Does anyone have a new solution ?
My code :
function mc_admin_users_caps( $caps, $cap, $user_id, $args ){
foreach( $caps as $key => $capability ){
if( $capability != 'do_not_allow' )
continue;
switch( $cap ) {
case 'edit_user':
case 'edit_users':
$caps[$key] = 'edit_users';
break;
case 'delete_user':
case 'delete_users':
$caps[$key] = 'delete_users';
break;
case 'create_users':
$caps[$key] = $cap;
break;
}
}
return $caps;
}
add_filter( 'map_meta_cap', 'mc_admin_users_caps', 1, 4 );
https://bitbucket.org/peteredwards/allowsiteadmins2editusers
This has now moved here:
https://github.com/essl-pvac/allow-network-user-edits
Thanks a lot!!!
Thank you.
I’m from Brazil, lost several hours trying to resolve this, your solution worked … thank you.
Hi, It works works for me on WP 3.3.2 with following code in a plugin:
wp_content/plugins/plugin_name.php
———————————————————————————————————–
$capability ){
if( $capability != ‘do_not_allow’ )
continue;
switch( $cap ) {
case ‘edit_user’:
case ‘edit_users’:
$caps[$key] = ‘edit_users’;
break;
case ‘delete_user’:
case ‘delete_users’:
$caps[$key] = ‘delete_users’;
break;
case ‘create_users’:
$caps[$key] = $cap;
break;
}
}
return $caps;
}
add_filter( ‘map_meta_cap’, ‘mc_admin_users_caps’, 10, 4 );
remove_all_filters( ‘enable_edit_any_user_configuration’ );
add_filter( ‘enable_edit_any_user_configuration’, ‘__return_true’);
?>
—————————————————————————————————————–
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?
How, forgot the <?php in begin of plugin ^^
Good find Morty- that’s definitely a problem. I spent a little time this afternoon on a function to patch.
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 was a quick pass so feel free to suggest edits.
Thanks Andrew & Morty. I’ve added an update to the post. 🙂
Hi,
I wrote the code on first post (updated version) in “functions.php” of theme but the admin can change the super admin. Can you help me?
There is on small addition to be made to the mc_edit_permission_check function to make sure the user being edited is not a super_admin on line 42:
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
Thanks Peter, I’ve updated the original post to include this patch. 🙂
I use the Peter Edward’s plugin in a Multisite WordPress : allow-network-user-edits.php (https://github.com/essl-pvac/allow-network-user-edits/blob/master/allow-network-user-edits.php).
Problem : all admins (and not only Super Admins) can change on the network who can edit users (Admins or Editors) via a menu…
Would be possible to show this menu only to Super Admins ?
Anything is possible. You can see if Peter is available for hire or contract a developer at Tweaky to make the change and then submit the changed back to Peter to be added into the original plugin.
I think line 42 is missing a ‘)’ at the end.
I was still finding that the mc_edit_permission_check() function above was allowing an admin level user to edit details of a super admin who was a member of the same site.
Here’s my amended function which seems to work so far:
Cool thanks Lesteph, I’ve update the function with your code – your logic is also more sane.
This is an awesome fix! Thank you so much, this solved many headaches dealing with my multisite and all the blog admins whining about not being able to edit user profiles.
I owe you! =)
Thanks for the fix.Works perfect….
Hi,
Great work here. However I found that super admins were left unable to edit user details. Therefore I amended the code as follows:
Thanks for Sharing Scott, I’ll update the post. 🙂
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.
Thanks
Hozefa
Updated, thanks Hozefa.
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.
Our stop-gap for this:
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.
Thank you for this, I really wish they’d implement this into core as a Settings option.
I just threw this into mu-plugins directory as a plugin, shabam, awesome win.
Can you share your plugin? Does it still work for you?
Pingback: 在 wordpress multisite 多網誌模式下讓子網站 administrator 也可以有部分 super admin 的權限 | 凱達米老師的教學檔案
Wow Brent. Thank you so much. Great stuff.
Just to get follow up comments. Thanks.
Hi to every one, the contents existing at this site are really remarkable for people experience, well, keep up the nice work fellows.
This was exactly what I had been looking for. Thanks so much for this!
This is awesome! Worked like a charm! Great job!