Make WordPress Core

Opened 4 years ago

Last modified 7 months ago

#50260 new defect (bug)

Multisite - Getting actual user capabilities with get_role_caps() different with current_user_can()

Reported by: mahesh901122's profile Mahesh901122 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 5.4.1
Component: Role/Capability Keywords: dev-feedback needs-docs
Focuses: multisite Cc:

Description

If I check below user capabilities for Administrator then I get both capabilities as false.

current_user_can( 'install_plugins' )
current_user_can( 'activate_plugins' )

But, If I check the same capabilities by login to the Super Administrator then both return true.

The administrator user role has no such capabilities but, If we check the current user capabilities with:

$current_user = wp_get_current_user();
print_r( $current_user->allcaps );
print_r( $current_user->get_role_caps() );

Then for the administrator user role, I get below a list of capabilities:

// Array
// (
//     [switch_themes] => 1
//     [edit_themes] => 1
//     [activate_plugins] => 1
//     [edit_plugins] => 1
//     [edit_users] => 1
//     [edit_files] => 1
//     [manage_options] => 1
//     [moderate_comments] => 1
//     [manage_categories] => 1
//     [manage_links] => 1
//     [upload_files] => 1
//     [import] => 1
//     [unfiltered_html] => 1
//     [edit_posts] => 1
//     [edit_others_posts] => 1
//     [edit_published_posts] => 1
//     [publish_posts] => 1
//     [edit_pages] => 1
//     [read] => 1
//     [level_10] => 1
//     [level_9] => 1
//     [level_8] => 1
//     [level_7] => 1
//     [level_6] => 1
//     [level_5] => 1
//     [level_4] => 1
//     [level_3] => 1
//     [level_2] => 1
//     [level_1] => 1
//     [level_0] => 1
//     [edit_others_pages] => 1
//     [edit_published_pages] => 1
//     [publish_pages] => 1
//     [delete_pages] => 1
//     [delete_others_pages] => 1
//     [delete_published_pages] => 1
//     [delete_posts] => 1
//     [delete_others_posts] => 1
//     [delete_published_posts] => 1
//     [delete_private_posts] => 1
//     [edit_private_posts] => 1
//     [read_private_posts] => 1
//     [delete_private_pages] => 1
//     [edit_private_pages] => 1
//     [read_private_pages] => 1
//     [delete_users] => 1
//     [create_users] => 1
//     [unfiltered_upload] => 1
//     [edit_dashboard] => 1
//     [update_plugins] => 1
//     [delete_plugins] => 1
//     [install_plugins] => 1
//     [update_themes] => 1
//     [install_themes] => 1
//     [update_core] => 1
//     [list_users] => 1
//     [remove_users] => 1
//     [promote_users] => 1
//     [edit_theme_options] => 1
//     [delete_themes] => 1
//     [export] => 1
//     [restrict_content] => 1
//     [list_roles] => 1
//     [administrator] => 1
// )

Here we can see the Administrator user has the capability:

//     [install_plugins] => 1
//     [activate_plugins] => 1

But, When we check them with current_user_can() then both return false.

After debugging in dept I found that the do_not_allow is set for the Non-super admin users for install_plugins capability.

case 'update_plugins':
case 'delete_plugins':
case 'install_plugins':
case 'upload_plugins':
case 'update_themes':
case 'delete_themes':
case 'install_themes':
case 'upload_themes':
case 'update_core':
	...
	} elseif ( is_multisite() && ! is_super_admin( $user_id ) ) {
		$caps[] = 'do_not_allow';
	....
	break;

Same for the activate_plugins the capabilities are set as ["activate_plugins","manage_network_plugins"]

case 'activate_plugins':
case 'deactivate_plugins':
case 'activate_plugin':
case 'deactivate_plugin':
	$caps[] = 'activate_plugins';
	if ( is_multisite() ) {
		// update_, install_, and delete_ are handled above with is_super_admin().
		$menu_perms = get_site_option( 'menu_items', array() );
		if ( empty( $menu_perms['plugins'] ) ) {
			$caps[] = 'manage_network_plugins';
		}
	}
	break;

So, Ideally only those capabilities need to return by $current_user->get_role_caps().

Those capabilities need to exclude from the list which current user cant perform. E.g. do_not_allow.

Change History (5)

#1 @Mahesh901122
4 years ago

I'm getting below capabilities as false with current_user_can():

edit_themes
activate_plugins
edit_plugins
edit_users
edit_files
manage_links
unfiltered_html
delete_users
create_users
unfiltered_upload
update_plugins
delete_plugins
install_plugins
update_themes
install_themes
update_core
delete_themes

and true for below:

switch_themes
manage_options
moderate_comments
manage_categories
upload_files
import
edit_posts
edit_others_posts
edit_published_posts
publish_posts
edit_pages
read
level_10
level_9
level_8
level_7
level_6
level_5
level_4
level_3
level_2
level_1
level_0
edit_others_pages
edit_published_pages
publish_pages
delete_pages
delete_others_pages
delete_published_pages
delete_posts
delete_others_posts
delete_published_posts
delete_private_posts
edit_private_posts
read_private_posts
delete_private_pages
edit_private_pages
read_private_pages
edit_dashboard
list_users
remove_users
promote_users
edit_theme_options
export
restrict_content
list_roles
administrator

#2 @SergeyBiryukov
4 years ago

  • Focuses multisite added

#3 @vgstudios
7 months ago

Hi. Sorry for bothering. Is it advised to workaround this problem with plugins or by other means for now (e.g. because existing code relays on the wrong behavior), or is it reasonable to hope for a fix in the future?

I am asking because this unexpected / undocumented behavior causes problems in other plugins, e.g.: https://github.com/elementor/elementor/issues/23302

With kind regards
Dominik

#4 @manfcarlo
7 months ago

  • Keywords needs-docs added

The current behaviour is correct in my view, because it gives the ability to discern capabilities between declared and forced where there is a need to do so. If the two functions behave the same, what is the point of having both of them?

I do think a warning should be added to the docblock for get_role_caps about the super admin discrepancies and others, but no need for code changes.

Regarding the Elementor issue, it looks like current_user_can is the function being used, not get_role_caps, so amending get_role_caps would not have any impact on it anyway. Frankly, the Elementor issue is not even related to multisite at all and looks more related to kses.

In response to the question about working around core bugs, I have a personal view that I could share. On the other hand, I don't think it would be relevant to share, since the issue seems the responsibility of Elementor and not core, and I don't know how promptly bugs tend to get fixed with Elementor.

#5 @vgstudios
7 months ago

Thank you for your reply. I misread the first post partially and assumed current_user_can would be the one being wrong, while it's get_role_caps as you and the first person said. Sorry. So I guess there's a valid reason to have non-super admins not have unfiltered_html on MultiSites by default (which makes sense if they can't be trusted at all, so they can't destroy the domain reputation e.g. with malicious script content).

Note: See TracTickets for help on using tickets.