WordPress Trac: Ticket #5540: User roles overhaulhttps://core.trac.wordpress.org/ticket/5540
<p>
This patch changes the way user roles are stored, moving them out of the usermeta table into a new user_role table. The API is unchanged and should work exactly the same as before, but operations such as fetching a list of users by role are much faster and easier to implement with joins.
</p>
<p>
It's mostly important to mu and bbpress, but is also relevant to blogs with large user tables. I'm posting it here first for review, an mu patch is forthcoming.
</p>
<p>
The main changes are:
</p>
<ul><li>User roles are no longer stored in usermeta wp_capabilities entries. They're moved to the new user_role table (blog_id, user_id, role).
</li></ul><ul><li>Per-user capabilities are still supported, and still stored in usermeta as before.
</li></ul><ul><li>The upgrade process removes any usermeta wp_capabilities that match role names, and insert user_role entries in their place.
</li></ul><ul><li>Old style wp_capabilities roles are still honored if they exist, to permit logging in before the upgrade has completed, but will be removed during the upgrade.
</li></ul><p>
The API and upgrade process are unit tested. The capabilities API works exactly the same as before for all cases I've tested. The main thing that needs review here is the upgrade process: it has the potential to lock administrators out of the blog if it doesn't work, and it's possible it could take a long time on blogs with many users.
</p>
en-usWordPress Trachttps://core.trac.wordpress.org/chrome/site/your_project_logo.pnghttps://core.trac.wordpress.org/ticket/5540
Trac 1.0.1tellyworthThu, 27 Dec 2007 23:36:39 GMTattachment sethttps://core.trac.wordpress.org/ticket/5540
https://core.trac.wordpress.org/ticket/5540
<ul>
<li><strong>attachment</strong>
set to <em>user_role-r6506.patch</em>
</li>
</ul>
TickettellyworthThu, 27 Dec 2007 23:43:15 GMThttps://core.trac.wordpress.org/ticket/5540#comment:1
https://core.trac.wordpress.org/ticket/5540#comment:1
<p>
Unit tests are here: <a class="ext-link" href="http://svn.automattic.com/wordpress-tests/wp-testcase/test_user_capabilities.php"><span class="icon">​</span>http://svn.automattic.com/wordpress-tests/wp-testcase/test_user_capabilities.php</a>
</p>
<p>
Most of it covers the API level and should pass with or without the patch applied. It covers uncommon cases such as users with multiple roles and per-user caps. The additional tests specific to the user_role patch are at the bottom, test_upgrade() in particular.
</p>
TicketmattFri, 28 Dec 2007 00:02:16 GMThttps://core.trac.wordpress.org/ticket/5540#comment:2
https://core.trac.wordpress.org/ticket/5540#comment:2
<p>
I think this would be useful as a plugin that mirrored the data rather than replacing the internal storage, which is okay for single-blog use.
</p>
TicketryanFri, 28 Dec 2007 00:29:14 GMThttps://core.trac.wordpress.org/ticket/5540#comment:3
https://core.trac.wordpress.org/ticket/5540#comment:3
<p>
See also <a class="closed ticket" href="https://core.trac.wordpress.org/ticket/5255" title="task (blessed): Simplify role/capability for easier cap =&gt; user lookups (closed: wontfix)">#5255</a>. This fits in with that. Having this as a plugin means we can't clean up our crappy queries. :-)
</p>
TickettellyworthFri, 28 Dec 2007 00:47:35 GMThttps://core.trac.wordpress.org/ticket/5540#comment:4
https://core.trac.wordpress.org/ticket/5540#comment:4
<p>
This could be implemented as a plugin, though some core changes are probably necessary to support that. An alternative to mirroring data with actions and filters would be to make the entire WP_Role and WP_User classes pluggable or overrideable.
</p>
TicketryanFri, 28 Dec 2007 01:09:18 GMThttps://core.trac.wordpress.org/ticket/5540#comment:5
https://core.trac.wordpress.org/ticket/5540#comment:5
<p>
Role and capability storage and queries are a known headache that should just be fixed.
</p>
<p>
This fixes role queries, but querying all users with a given capability is still a pain. The gist of <a class="closed ticket" href="https://core.trac.wordpress.org/ticket/5255" title="task (blessed): Simplify role/capability for easier cap =&gt; user lookups (closed: wontfix)">#5255</a> was not allow individual caps so that we could always associate a given cap with a role or set of roles.
</p>
TickettellyworthFri, 28 Dec 2007 02:35:53 GMThttps://core.trac.wordpress.org/ticket/5540#comment:6
https://core.trac.wordpress.org/ticket/5540#comment:6
<p>
I can see one relatively simple way to handle the query-users-by-cap thing with this patch: Implement a find_roles_with_capability($cap_name) function that would return a list of roles with a given capability. Then query the user_role table where role in(a, b, c).
</p>
<p>
That method could work independent of this patch if we assume there is a get_users_with_roles($role_names) function. Obviously that function would be trivial to implement with this patch (just a simple query of the user_role table), and slow and ugly without it (iterating over usermeta wp_capabilities entries).
</p>
<p>
A more complete solution would be to have a user_capabilities and/or role_capabilities table and query a join on that. But I think that's well and truly overkill, with little extra benefit, so I'll mention it only to rule it out.
</p>
TicketryanFri, 28 Dec 2007 05:28:46 GMThttps://core.trac.wordpress.org/ticket/5540#comment:7
https://core.trac.wordpress.org/ticket/5540#comment:7
<p>
Replying to <a class="closed" href="https://core.trac.wordpress.org/ticket/5540#comment:6" title="Comment 6 for Ticket #5540">tellyworth</a>:
</p>
<blockquote class="citation">
<p>
I can see one relatively simple way to handle the query-users-by-cap thing with this patch: Implement a find_roles_with_capability($cap_name) function that would return a list of roles with a given capability. Then query the user_role table where role in(a, b, c).
</p>
</blockquote>
<p>
Yes, but retaining the ability to put caps in user_meta means not all of a user's caps will be in a role, correct? But maybe that's not worth worrying about. Such caps are not supported out of the box.
</p>
<p>
Moving the roles to a separate table, implementing the functions you mention, and not going out of our way for caps directly associated with a user (without an intervening role), seems like a good-enough solution that removes the biggest problems with the current arrangement.
</p>
TicketdarkdragonFri, 28 Dec 2007 05:32:20 GMThttps://core.trac.wordpress.org/ticket/5540#comment:8
https://core.trac.wordpress.org/ticket/5540#comment:8
<p>
Replying to <a class="closed" href="https://core.trac.wordpress.org/ticket/5540#comment:7" title="Comment 7 for Ticket #5540">ryan</a>:
</p>
<blockquote class="citation">
<p>
Moving the roles to a separate table, implementing the functions you mention, and not going out of our way for caps directly associated with a user (without an intervening role), seems like a good-enough solution that removes the biggest problems with the current arrangement.
</p>
</blockquote>
<p>
Why move the roles to a separate table when you can use the taxonomy API? I have an idea on how this could be implemented and the problem is as such that I'm willing to put forth an effort to prove my assertion.
</p>
TicketdarkdragonFri, 28 Dec 2007 05:35:53 GMThttps://core.trac.wordpress.org/ticket/5540#comment:9
https://core.trac.wordpress.org/ticket/5540#comment:9
<p>
The only problem with using the taxonomy API instead of a separate table, but you lose it anyway with tellyworth's proposal, is that capabilities aren't associated with capabilities by default and each user would have to have the capabilities added differently.
</p>
<p>
However, I believe that this could be solved by only creating a capabilities table, or having the term relationships for roles and assigning those capability relationship in with the roles.
</p>
TicketdarkdragonFri, 28 Dec 2007 05:42:52 GMThttps://core.trac.wordpress.org/ticket/5540#comment:10
https://core.trac.wordpress.org/ticket/5540#comment:10
<p>
So the problem would be that you would have a set of roles for each blog and those will be assigned to each user, which in turn would have a relationship to a single capability.
</p>
<p>
So the roles will increase by the amount of blogs, while the capabilities should stay the same.
</p>
<p>
I'm unsure and I forget if it is possible to have terms with the same name and slug, however, you could simply append the blog_id to the slug of the role. The group_id would be used for the roles belong to what blog. Group ID = Blog ID.
</p>
<p>
Since the capabilities don't really matter based on the blog, or so it can also. You can assign the group ID also by Blog ID. The Worse case shouldn't happen by in the rate of cases.
</p>
<p>
Oh yeah, by all means, looking at the post, taxonomy, and category APIs, it appears that it would make the role code very complex, but I think it would be well worth the effort.
</p>
TickettellyworthFri, 28 Dec 2007 05:47:17 GMTattachment sethttps://core.trac.wordpress.org/ticket/5540
https://core.trac.wordpress.org/ticket/5540
<ul>
<li><strong>attachment</strong>
set to <em>user_role-r6506-a.patch</em>
</li>
</ul>
<p>
Updated patch fixes an issue with get_users_of_blog()
</p>
TickettellyworthFri, 28 Dec 2007 05:47:59 GMThttps://core.trac.wordpress.org/ticket/5540#comment:11
https://core.trac.wordpress.org/ticket/5540#comment:11
<p>
get_users_of_blog() didn't work correctly in the original patch. The -a patch fixes it.
</p>
TickettellyworthFri, 28 Dec 2007 05:55:18 GMTattachment sethttps://core.trac.wordpress.org/ticket/5540
https://core.trac.wordpress.org/ticket/5540
<ul>
<li><strong>attachment</strong>
set to <em>get_users_with_cap.patch</em>
</li>
</ul>
<p>
sample implementation of get_users_with_cap()
</p>
TicketryanFri, 28 Dec 2007 06:01:19 GMThttps://core.trac.wordpress.org/ticket/5540#comment:12
https://core.trac.wordpress.org/ticket/5540#comment:12
<p>
We'll also need a CUSTOM_USER_ROLE_TABLE define for use by MU and by those doing the WP multi-blog hack so that the table can be made global.
</p>
<p>
darkdragon, this need to be able to make the table global across multiple blogs makes using taxonomy impractical, I think.
</p>
TickettellyworthFri, 28 Dec 2007 06:06:44 GMThttps://core.trac.wordpress.org/ticket/5540#comment:13
https://core.trac.wordpress.org/ticket/5540#comment:13
<p>
A simple implementation of get_users_with_cap() is attached. It doesn't cope with per-user capabilities, but there's a trivial way to implement that: drop per-user caps in favour of multiple roles.
</p>
<p>
i.e. if I want a particular Contributor user to have an addition upload_files capability, I create a new Uploader role with the required cap, then assign both roles (Contributor, Uploader) to that user. The code here can already handle this.
</p>
TicketryanFri, 28 Dec 2007 06:08:50 GMThttps://core.trac.wordpress.org/ticket/5540#comment:14
https://core.trac.wordpress.org/ticket/5540#comment:14
<p>
Sounds good to me.
</p>
TicketfilosofoFri, 28 Dec 2007 14:52:40 GMThttps://core.trac.wordpress.org/ticket/5540#comment:15
https://core.trac.wordpress.org/ticket/5540#comment:15
<p>
Replying to <a class="closed" href="https://core.trac.wordpress.org/ticket/5540#comment:12" title="Comment 12 for Ticket #5540">ryan</a>:
</p>
<blockquote class="citation">
<p>
We'll also need a CUSTOM_USER_ROLE_TABLE define for use by MU and by those doing the WP multi-blog hack so that the table can be made global.
</p>
<p>
darkdragon, this need to be able to make the table global across multiple blogs makes using taxonomy impractical, I think.
</p>
</blockquote>
<p>
Couldn't this be done with the general meta-data table? <a class="closed ticket" href="https://core.trac.wordpress.org/ticket/5183" title="enhancement: General Meta-Data Table (closed: wontfix)">#5183</a>
</p>
TicketdarkdragonFri, 28 Dec 2007 19:40:28 GMThttps://core.trac.wordpress.org/ticket/5540#comment:16
https://core.trac.wordpress.org/ticket/5540#comment:16
<p>
Replying to <a class="closed" href="https://core.trac.wordpress.org/ticket/5540#comment:15" title="Comment 15 for Ticket #5540">filosofo</a>:
</p>
<blockquote class="citation">
<p>
Replying to <a class="closed" href="https://core.trac.wordpress.org/ticket/5540#comment:12" title="Comment 12 for Ticket #5540">ryan</a>:
</p>
<blockquote class="citation">
<p>
We'll also need a CUSTOM_USER_ROLE_TABLE define for use by MU and by those doing the WP multi-blog hack so that the table can be made global.
</p>
<p>
darkdragon, this need to be able to make the table global across multiple blogs makes using taxonomy impractical, I think.
</p>
</blockquote>
<p>
Couldn't this be done with the general meta-data table? <a class="closed ticket" href="https://core.trac.wordpress.org/ticket/5183" title="enhancement: General Meta-Data Table (closed: wontfix)">#5183</a>
</p>
</blockquote>
<p>
It appears that whatever solution is approached would have to be one that is quite simple and would need to have the ability to link capabilities to both roles and users, as well as roles to users.
</p>
<p>
I think the general meta-data table should be in WordPress, but these people seem to have the goal in sight and after some contemplate, I agree.
</p>
TickettellyworthSat, 29 Dec 2007 02:19:16 GMThttps://core.trac.wordpress.org/ticket/5540#comment:17
https://core.trac.wordpress.org/ticket/5540#comment:17
<p>
I took a quick stab at a different approach to handling role-capabilitites in <a class="closed ticket" href="https://core.trac.wordpress.org/ticket/5541" title="enhancement: Refactor and simplify WP_Roles (closed: wontfix)">#5541</a>. Roles aren't stored in the database at all, just in memory, with an action that can be used to define new roles and a filter for changing the capabilities of existing ones.
</p>
<p>
It works with or without the user_role patch, and passes all the relevant unit tests.
</p>
<p>
It would work well with the multiple-roles approach to deprecating user-caps that I outlined above.
</p>
TicketryanSat, 29 Dec 2007 03:43:46 GMThttps://core.trac.wordpress.org/ticket/5540#comment:18
https://core.trac.wordpress.org/ticket/5540#comment:18
<p>
Since there can be millions of users in a WPMU setup, I prefer to have dedicated user tables that have indices that are as fast a possible. Lumping user info in with general site meta would be less optimal.
</p>
TicketsantosjWed, 06 Aug 2008 21:58:20 GMTowner changedhttps://core.trac.wordpress.org/ticket/5540#comment:19
https://core.trac.wordpress.org/ticket/5540#comment:19
<ul>
<li><strong>owner</strong>
changed from <em>anonymous</em> to <em>jacobsantos</em>
</li>
</ul>
TicketryanTue, 10 Mar 2009 17:33:16 GMTcomponent changedhttps://core.trac.wordpress.org/ticket/5540#comment:20
https://core.trac.wordpress.org/ticket/5540#comment:20
<ul>
<li><strong>component</strong>
changed from <em>General</em> to <em>Role/Capability</em>
</li>
</ul>
TicketDenis-de-BernardyMon, 20 Apr 2009 08:51:27 GMThttps://core.trac.wordpress.org/ticket/5540#comment:21
https://core.trac.wordpress.org/ticket/5540#comment:21
<p>
see also: <a class="closed ticket" href="https://core.trac.wordpress.org/ticket/5541" title="enhancement: Refactor and simplify WP_Roles (closed: wontfix)">#5541</a>, <a class="closed ticket" href="https://core.trac.wordpress.org/ticket/5255" title="task (blessed): Simplify role/capability for easier cap =&gt; user lookups (closed: wontfix)">#5255</a>, <a class="assigned ticket" href="https://core.trac.wordpress.org/ticket/2531" title="enhancement: Functions for registering additional capabilities and getting a list of ... (assigned)">#2531</a>, <a class="closed ticket" href="https://core.trac.wordpress.org/ticket/2787" title="enhancement: New Method of storing and calculating cap2user and user2cap (closed: wontfix)">#2787</a>
</p>
TicketDenis-de-BernardySat, 13 Jun 2009 15:15:29 GMTkeywords, milestone changedhttps://core.trac.wordpress.org/ticket/5540#comment:22
https://core.trac.wordpress.org/ticket/5540#comment:22
<ul>
<li><strong>keywords</strong>
<em>needs-patch</em> added; <em>has-patch</em> removed
</li>
<li><strong>milestone</strong>
changed from <em>2.9</em> to <em>Future Release</em>
</li>
</ul>
TicketDenis-de-BernardyWed, 17 Jun 2009 23:44:31 GMTstatus changed; resolution set; milestone deletedhttps://core.trac.wordpress.org/ticket/5540#comment:23
https://core.trac.wordpress.org/ticket/5540#comment:23
<ul>
<li><strong>status</strong>
changed from <em>new</em> to <em>closed</em>
</li>
<li><strong>resolution</strong>
set to <em>wontfix</em>
</li>
<li><strong>milestone</strong>
<em>Future Release</em> deleted
</li>
</ul>
<p>
see <a class="assigned ticket" href="https://core.trac.wordpress.org/ticket/10201" title="enhancement: Remove user-specific caps (assigned)">#10201</a>
</p>
TicketnacinSat, 30 Jun 2012 19:39:41 GMThttps://core.trac.wordpress.org/ticket/5540#comment:24
https://core.trac.wordpress.org/ticket/5540#comment:24
<p>
In case anyone ever digs up this ticket and says "hey, look at that," here's the original tests from tellyworth: <a class="ext-link" href="http://unit-tests.trac.wordpress.org/changeset/795"><span class="icon">​</span>http://unit-tests.trac.wordpress.org/changeset/795</a>
</p>
Ticket