Make WordPress Core

Opened 17 years ago

Closed 15 years ago

#5255 closed task (blessed) (wontfix)

Simplify role/capability for easier cap => user lookups

Reported by: markjaquith's profile markjaquith Owned by: jacobsantos's profile jacobsantos
Milestone: Priority: normal
Severity: normal Version:
Component: Role/Capability Keywords: needs-patch close
Focuses: Cc:

Description

We should drop:

  • per-user capabilities
  • more than one role per user

With one user having one role, we can do cap => user lookups by doing a query looking for users who have a role that contains that capability.

Change History (21)

#1 follow-up: @Bobcat
17 years ago

If I understand your description, this will break features that I use on my blog. I use the Role Manager plugin to assign specific capabilities to certain users. The plugin can also be used to remove capabilities from users. You cannot see if a user has a particular capability just by looking up the roles.

#2 in reply to: ↑ 1 @Viper007Bond
17 years ago

While it may remove some flexibility, I think it's worth it as it greatly simplifies the whole capabilities system and more in the spirit of the original feature's idea IMO.

Replying to Bobcat:

If I understand your description, this will break features that I use on my blog.

You'd still be able to do it, you'd just have to have a role with the permissions you want the user to have and then assign that user to that role. Possibly a role per user depending on how customized your roles are (i.e. if no two permissions are alike).

#3 @darkdragon
17 years ago

It isn't that the feature is broken because of its perceived complexity (why would you want to simplify it otherwise?), it is broken because the API doesn't allow for one quick stop for adding capabilities.

Why would want to take away an excellent feature that would make WordPress worthy of being a CMS? It doesn't make sense. Just add a couple more functions that does the simplification for you. If you want to change the scheme, okay, just allow for what is currently available.

I would seriously have to reevaluate my position of using WordPress in the business environment if such a neat feature is dismissed.

#4 @Bobcat
17 years ago

It seems to me that both of the features you want to drop were part of the plan from the beginning:

From http://codex.wordpress.org/Roles_and_Capabilities

Plugin developers will likely revise the 'standard' Roles and Capabilities because WordPress Developers left open the future possibility of assigning a user to one or more Roles, or assigning Capabilities directly to a User.

From http://boren.nu/archives/2005/12/01/whats-new-in-20-roles-and-capabilities/

Users can belong to one or more roles and can have individual capabilities assigned to them outside of the context of a role.

#5 follow-up: @ryan
17 years ago

The current implementation has several faults. Fetching all users with a given role or capability is painful. This is due mainly to how things are stored in arrays rather than rows in a table. Also, role definitions are stored per-blog in the options table rather than globally. This creates pain for those doing multi-blog WP. Finally, allowing multiple roles and caps per user is extra complexity for little gain. It's a bunch of largely unused cruft.

Limiting users to one role instead of multiple roles and capabilities cleans up much of this. A user has one role and that's it. All capabilities come through it. If you want to change what a user can do, give the user a new role with a new set of capabilities. The user's assigned role would no longer be stored in usermeta as an array but as a single value. This allows easy fetching of all users with a given role without having to parse array values out of a SELECT. To get all users with a given capability, lookup which roles have that capability and fetch users with those roles. Simpler code and queries, and also simpler conceptually. What can this user do? Look at his role definition. He can do only what his role allows. This is pretty much what we do at wordpress.com to handle the many users there. Multiple role and capability assignments get unmanageable pretty quickly.

The next phase would be to rewrite the role storage to use the proposed sitemeta table so that we can fetch role definitions out of a proper table instead of out of an array stored in the options table. We could directly join on this, if desired, or we could continue doing the role cap lookup. People would still have the option of foregoing storing the role definitions in the DB altogether, which is what many multi-blog WP and WPMU sites do.

We've had this redesign discussion several times since we created capabilities. I think the time has come to fix this mess. No one likes it as is.

#6 in reply to: ↑ 5 ; follow-up: @filosofo
17 years ago

Why not just drop roles entirely, and list capabilities on separate usermeta rows? Then if you want to find out who can edit posts or whatever, it's a simple query.

Likewise, it's a simple query to see what capabilities a user has on a given site.

Replying to ryan:

To get all users with a given capability, lookup which roles have that capability and fetch users with those roles. Simpler code and queries, and also simpler conceptually. What can this user do? Look at his role definition. He can do only what his role allows. This is pretty much what we do at wordpress.com to handle the many users there. Multiple role and capability assignments get unmanageable pretty quickly.

How would you get around the following two problems? Currently, if a plugin wants to add a capability to a role, say "cap_X", it degrades nicely when the plugin is no longer in use--i.e. having an unused capability doesn't hurt anything. However, under the proposed system one would have to create a new role for each new combination of capabilities. If I add "cap_X" to all my administrators, then they will no longer each be an "administrator"; they will be something plugin-specific.

The first problem occurs if you de-activate the plugin: poof! all the administrators lose *all* of their capabilities, as their plugin-specific role no longer means anything.

The second problem is getting two different plugins that add capabilities to work together. One wants to give a user "cap_X," and the other wants to give the same user "cap_Y", so which gets to define the role? It seems to me that in some fairly common scenarios the number of distinct roles could approach the number of users.

#7 in reply to: ↑ 6 ; follow-up: @markjaquith
17 years ago

Replying to filosofo:

Why not just drop roles entirely, and list capabilities on separate usermeta rows? Then if you want to find out who can edit posts or whatever, it's a simple query.

Because then you lose the ability to modify roles and have all people using that role get the modification.

How would you get around the following two problems? Currently, if a plugin wants to add a capability to a role, say "cap_X", it degrades nicely when the plugin is no longer in use--i.e. having an unused capability doesn't hurt anything. However, under the proposed system one would have to create a new role for each new combination of capabilities. If I add "cap_X" to all my administrators, then they will no longer each be an "administrator"; they will be something plugin-specific.

You don't add cap_X to your administrators, you add it to the administrator role, and all of your users with that role get that capability because it is contained in the role they're using.

The second problem is getting two different plugins that add capabilities to work together. One wants to give a user "cap_X," and the other wants to give the same user "cap_Y", so which gets to define the role? It seems to me that in some fairly common scenarios the number of distinct roles could approach the number of users.

If each user has a distinct role, then yeah, you'll have a user:role ratio of 1. That's not the common case in multi-user installs.

The reason arbitrary capabilities have been a flop is that there is no built-in method for modifying roles. The plugin has to make assumptions -- assuming that the default roles exist and that they haven't been severly modified such that its assumptions are incorrect. I'm not sure there's a good solution to that besides having a simple built-in method of assigning these new capabilities to roles.

#8 in reply to: ↑ 7 ; follow-ups: @filosofo
17 years ago

Replying to markjaquith:

Replying to filosofo:

How would you get around the following two problems? Currently, if a plugin wants to add a capability to a role, say "cap_X", it degrades nicely when the plugin is no longer in use--i.e. having an unused capability doesn't hurt anything. However, under the proposed system one would have to create a new role for each new combination of capabilities. If I add "cap_X" to all my administrators, then they will no longer each be an "administrator"; they will be something plugin-specific.

You don't add cap_X to your administrators, you add it to the administrator role, and all of your users with that role get that capability because it is contained in the role they're using.

First, it's not clear to me what you're proposing. Ryan says above that "If you want to change what a user can do, give the user a new role with a new set of capabilities." That sounds to me like you can't change a role's existing capabilities; instead, you have to create a new role with its own capabilities.

Second, even if the proposed system does allow one to add capabilities to roles, that seems of trivial use. Let's say my plugin checks for its "edit_video" capability. If I can add that capability only on a per-role basis, what's the point? Instead of adding "edit_video" to all "editors," I should just check whether someone is an "editor." The particular capability has become superfluous.

Instead, a more likely--and useful--situation is that I want to assign the "edit_video" capability in a way that doesn't map neatly to existing roles. So for example Bob who is an "author" can "edit_video," as well as Mary an "editor," but not other editors or authors.

Replying to markjaquith:

Replying to filosofo:

Why not just drop roles entirely, and list capabilities on separate usermeta rows? Then if you want to find out who can edit posts or whatever, it's a simple query.

Because then you lose the ability to modify roles and have all people using that role get the modification.

We could get around that by making roles into capabilities; then adding a capability to users who can "administrate" would be as simple as 1. changing the default caps for administrators (for future new users) and 2. adding the capability to all users who currently can administrate.

Besides, we don't really use roles that much, at least in core WP. Grepping through 2.3 I don't see anywhere that we check for users having the role of 'administrator' or 'editor.' Rather, we check capabilities.

Replying to markjaquith:

Replying to filosofo:

The second problem is getting two different plugins that add capabilities to work together. One wants to give a user "cap_X," and the other wants to give the same user "cap_Y", so which gets to define the role? It seems to me that in some fairly common scenarios the number of distinct roles could approach the number of users.

If each user has a distinct role, then yeah, you'll have a user:role ratio of 1. That's not the common case in multi-user installs.

Right--what I'm saying is that if users can have only one role, then that's the kind of situation you could end up with. If I want Bob to "edit_video" and have all the other capabilities of an author, but I don't want other authors to have the "edit_video" cap, then I'll have to create a new role with author capabilities + the "edit_video" capability, and assign it to Bob. Then if another plugin wants to assign, say, the "make_podcast" capability without giving it to everyone within an existing role, that plugin will have to generate a new role. It seems like the following would be some of the consequences to this arrangement:

  • Plugins clutter up the system with new roles for what would otherwise be slight changes (adding a capability).
  • Roles become meaningless. I can't assume that Bob is an author anymore, as he might have become the new role that combines the capabilities of an author with "edit_video." So it does no good to test someone's role.
  • Plugins' different roles collide.

#9 in reply to: ↑ 8 @Bobcat
17 years ago

Replying to filosofo:

Instead, a more likely--and useful--situation is that I want to assign the "edit_video" capability in a way that doesn't map neatly to existing roles. So for example Bob who is an "author" can "edit_video," as well as Mary an "editor," but not other editors or authors.

That's exactly how I change capabilities, and I find that very useful.

#10 in reply to: ↑ 8 ; follow-up: @markjaquith
17 years ago

Replying to filosofo:

First, it's not clear to me what you're proposing. Ryan says above that "If you want to change what a user can do, give the user a new role with a new set of capabilities." That sounds to me like you can't change a role's existing capabilities; instead, you have to create a new role with its own capabilities.

Two different scenarios:

  1. You want to add Cap_X to User_Y
  2. You want to add Cap_X to Role_Z

Ryan is saying that what would change in order to do #1 is that you would need to create a new role in order to isolate the changes for that user. #2 doesn't change at all... so you'll still be able to change an existing role's capabilities.

Second, even if the proposed system does allow one to add capabilities to roles, that seems of trivial use. Let's say my plugin checks for its "edit_video" capability. If I can add that capability only on a per-role basis, what's the point? Instead of adding "edit_video" to all "editors," I should just check whether someone is an "editor." The particular capability has become superfluous.

Checking the role assumes that the role exists, and that its meaning has not changed. That's not necessarily the case. So it's much better for a plugin to define new capabilities and let the user decide which roles should get those capabilities.

Instead, a more likely--and useful--situation is that I want to assign the "edit_video" capability in a way that doesn't map neatly to existing roles. So for example Bob who is an "author" can "edit_video," as well as Mary an "editor," but not other editors or authors.

If it doesn't map neatly to existing roles, yeah, you'd need a new role. Not ideal for that scenario the first time you need to do it, but it scales a lot better if you create a new role, because you can perform bulk operations on that role. "Add foo_bar to everyone with edit_video" is a lot easier if you only have to do it for each role with edit_video, and not every individual user. Obviously there are pros and cons, but I think that few people are going to want a large number of distinct capability combinations.

Besides, we don't really use roles that much, at least in core WP. Grepping through 2.3 I don't see anywhere that we check for users having the role of 'administrator' or 'editor.' Rather, we check capabilities.

Roles are containers of capabilities, for grouping purposes. They don't have inherent meaning. That's why we don't do current_user_can('editor').

If each user has a distinct role, then yeah, you'll have a user:role ratio of 1. That's not the common case in multi-user installs.

Right--what I'm saying is that if users can have only one role, then that's the kind of situation you could end up with. If I want Bob to "edit_video" and have all the other capabilities of an author, but I don't want other authors to have the "edit_video" cap, then I'll have to create a new role with author capabilities + the "edit_video" capability, and assign it to Bob. Then if another plugin wants to assign, say, the "make_podcast" capability without giving it to everyone within an existing role, that plugin will have to generate a new role. It seems like the following would be some of the consequences to this arrangement:

  • Plugins clutter up the system with new roles for what would otherwise be slight changes (adding a capability).

Plugins shouldn't add new roles for this reason. Instead, they should allow users to make the choice of adding the new capability to existing roles and/or new roles. The problem there is that role management requires a plugin. Perhaps that needs to change. And it's certainly more likely to happen if our cap/role system trims some of the fat.

  • Roles become meaningless. I can't assume that Bob is an author anymore, as he might have become the new role that combines the capabilities of an author with "edit_video." So it does no good to test someone's role.

Roles are meaningless. They're only containers of capabilities.

#11 in reply to: ↑ 10 @MichaelH
17 years ago

Replying to markjaquith:

...The problem there is that role management requires a plugin. Perhaps that needs to change. And it's certainly more likely to happen if our cap/role system trims some of the fat.

Excellent observation. +1 for adding role/cap management to the core. With the initiative to improve the admin experience underway, in addition to providing users role/cap management, might consider allowing users to manage the capabilities necessary to execute each admin function. Of course that might mean adding a manage_cap cap ;)

#12 @imwebgefunden
16 years ago

I'm the maintainer of WordPRess' Role Manager Plugin.
The first time I came to the Role Manager I don't like the function to remove/set a single capability on users profile page. But in the meantime I used this way very often and today I like it. It's gives the administrator more flexibility to try single permission tests.

In the last months of development for the Role Manager I'm missing the following things:

  1. The maximum length and allowed signs for roles and capabilities should be described. For a couple of days I released a new version 2.2.0. The new release set the max. length for roles and caps to 30 signs and only letters, digits and spaces are allowed for input. For caps all spaces are stored as a "_". But other plugins - such the very popular 'NextGen-Gallery-Plugin' don't do this translation and stores spaces as spaces. If you do so - you can have different capabilities one with a single space and one with a double space in the name, eg
    cap 1
    

and

cap  1

Caps and Roles first should be trim'ed and then double spaces should be replaced by single spaces. And single spaces are stored as "_". We can go an other way - but what we need is a description for all plugin authors.

  1. We need a list, eg in the otions-table, with all capabilities - not only the assigned to one or more roles. I wrote a plugin to hide the dashboard. It's based on a capability "hide_dashboard". If a user has this capability the dashboard is hidden. Most plugins add all their capabilities on activation to the administrator-role. But if you have a "negative" capability such as "hide_dashborad" you "can't" add this to the administrator-role on this way. Maybe, a way can be, to only register a capability. In the next step the administrator can assign this capability to one or more roles or single user as an exra cap.

#13 @darkdragon
16 years ago

  • Keywords hunt-sendnext added

Think this should be filed alongside the other role enhancement.

#14 @thee17
16 years ago

  • Milestone changed from 2.4 to 2.5

#15 @darkdragon
16 years ago

  • Keywords hunt-sendnext removed

Well, since we are in agreement.

#16 @santosj
16 years ago

  • Owner changed from anonymous to jacobsantos

#17 @jacobsantos
15 years ago

  • Component changed from General to Role/Capability

#20 @Denis-de-Bernardy
15 years ago

  • Keywords needs-patch close added
  • Milestone changed from 2.9 to Future Release

suggesting close, with a reference to the three above tickets

#21 @Denis-de-Bernardy
15 years ago

  • Milestone Future Release deleted
  • Resolution set to wontfix
  • Status changed from new to closed

see #10201

Note: See TracTickets for help on using tickets.