user_can( int|object $user, string $capability )

Whether a particular user has capability or role.

Documentation says that this should work for capabilities, but so far, it's only working for roles. This is being run during plugin deactivation.

Using a capability as an argument returns false:
user_can( $user_id, 'read' )

Using a role as an argument returns true:
user_can( $user_id, 'my_custom_role' )

I have confirmed that the user has the capability by using
var_dump( get_userdata( $user_id ) );

Excerpt of output:

  public 'allcaps' => 
    array (size=3)
      'my_custom_cap' => boolean true
      'read' => boolean true
      'my_custom_role' => boolean true

Why does user_can() recognize the role, but not the capability?

If you look at the source for user_can(), it relies on get_userdata() as well. Why does it see one, but not the other? Can anybody duplicate this, or is it just me?

Edit: I have confirmed that user_can( $user_id, 'read' ) returns true during the main plugin, but it appears to return no value when run during deactivation. Can anyone get this to return true during plugin deactivation? Why does it return an empty value instead of true or false?

  • Is it possible that your custom capability is being added too late? If it's a demo installation of WordPress then feel free to edit the user_can function and log / print_r what it outputs. Apr 6, 2017 at 6:31
  • I am testing with the native capability read. My custom capability is added during plugin activation. Both return false when passed to user_can. Because these capabilities are stored in the database, they exist 100% of the time. I don't think it's possible that they are added late. Unlike current_user_can, there is no need to check for the user being logged in. As I understand, it is just a database query.
    – iyrin
    Apr 6, 2017 at 13:30
  • Well, I went ahead and tested and for whatever reason, it returns true when used after the plugin is loaded, but it returns empty during deactivation.
    – iyrin
    Apr 6, 2017 at 18:26

1 Answer 1


This was a very simple mistake in my deactivation script. The function to remove my custom role was being called before the function to remove the user.

This is the part that led to confusion: When a role is removed, it becomes unavailable, but user's assigned to that role will still retain the role in their user data. This is why a conditional check for the user belonging to this role still returned true. So I was expecting the capabilities to remain because the check for the role returned true. While the role is present in user data, the capabilities for this role are emptied.

I'm still not sure why it seems to return empty rather than explicitly returning false, even if it is treated as false, but at the time is was executed in my code, the user did not in fact have these capabilities because the role did not exist.

I believe the primary purpose for the role remaining in user data is that a role can be removed and then added again and all users previously assigned to that role will once again resume having access to all of the role's capabilities.

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.