Make WordPress Core

Opened 13 years ago

Last modified 3 years ago

#17924 new enhancement

Make Integrating Multiple Roles Per User Easier for Plugin Authors

Reported by: mobius5150's profile mobius5150 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: major Version: 2.0
Component: Role/Capability Keywords: has-patch 2nd-opinion dev-feedback needs-refresh
Focuses: Cc:

Description

WordPress supports multiple role per user, however to use this feature is very difficult for plugin authors to integrate well, and often requires adding plugin admin pages instead of integrating with the pre-existing user-edit.php. Due to the difficulty of this, and the fact that most plugins that allow this aren't very user-friendly, I believe users are staying away from multiple roles.

This ticket aims to change how easy it is to work with the current role management system, as well as to add a couple role-based filters and actions, while still keeping the front-end of the administrative interface single-role only. (Because it seems to be the prevailing opinion the multiple roles per user is plugin territory.) In addition, I completely agree that the vast majority of sites can best function with one role per user, however in some cases (such as the site I'm working on now) you simply need to be able to choose multiple roles.

Changes

First Patch File

attachment:Replace_Admin_Role_Dropdown.patch
The first patch file moves the code for the role dropdown off of /wp-admin/user-edit.php, /wp-admin/includesclass-wp-users-list-table.php, /wp-admin/users-new.php, /wp-admin/options-general.php and into /wp-admin/includes/template.php where two new functions are created:

wp_get_dropdown_roles()

This function does what wp_dropdown_roles used to do, but it returns the value instead of echoing it. (Note that wp_dropdown_roles() now acts as a wrapper for wp_get_dropdown_roles(). (The old function is still in place for backwards compatibility.)

wp_user_role_selector()

This function creates the full dropdown and applies a new 'user_role_selector' filter to the markup before echoing it out. This way the default dropdown can be overridden by something else (perhaps checkboxes).

Second Patch File

attachment:Create_Role_Update_Actions_Filters.patch
The second patch file changes the functions that handle user creation and updating so they can be hooked into and a developer could make this work with multiple roles. This file affects /wp-admin/includes/users.php and /wp-includes/user.php.

wp_sanitize_user_role()

A new sanitize_user_role filter was created and sanitation of $_POST['role'] in /wp-admin/includes/user.php when user-edit.php is submitted was moved there. The new function is called wp_sanitize_user_role(). (This is so that if user-edit.php is submitted and $_POST['role'] were to contain a value other than a string (perhaps an array of roles) it can be sanitized and worked with accordingly.

pre_user_role

A new pre_user_role filter was added to wp_insert_user() in /wp-includes/user.php. This was mainly done because almost every other field that this function processes has a matching filter like this, and I thought maybe $roles felt left out as it did not. :(

I supposed somebody could also use it for something useful as well.

apply_user_role

A new apply_user_role action was added to wp_insert_user(). The function itself no longer uses $user->set_role(), instead saving user role changes is now handled by this new action. A matching function wp_apply_user_role() was added to set the user role like wp_insert_user() used to do. This way however, a plugin author could simply hook into apply_user_role to apply multiple roles to a user.

Conclusion

All in all, this patch was designed so that the average user would never even notice that a change has been made to user management, however a plugin author looking to add an easy way for people to select multiple roles for a user can quickly hook into this and have a nice, easy, well integrated and WordPress-like plugin.

I have done a few tests adding users and changing roles around with these patches applied on a fresh installation with no plugins and the only changes to WordPress being those that are in the attached patches, and everything seems to work seamlessly.

By the way, I am quite new to WordPress, so I added the needs-testing tag, because it does, but I also want to make sure I've done everything the 'WordPress' way and I want to make sure I havn't missed anything that is broken because of these small changes.

Attachments (8)

Replace_Admin_Role_Dropdown.patch (9.3 KB) - added by mobius5150 13 years ago.
The first patch.
Create_Role_Update_Actions_Filters.patch (5.0 KB) - added by mobius5150 13 years ago.
The second patch.
Create_Role_Update_Actions_Filters_3.2.1.patch (4.8 KB) - added by mobius5150 13 years ago.
The second patch.
Replace_Admin_Role_Dropdown_3.2.1.patch (9.3 KB) - added by mobius5150 13 years ago.
The first patch.
wp-3.3.2-multi-role-diff.patch (3.7 KB) - added by mobius5150 12 years ago.
A single patch file for WP 3.3.2
wp-3.6-alpha-multi-role-diff.patch (13.2 KB) - added by mobius5150 11 years ago.
A patch prepared against trunk of WP 3.6-alpha
17924.07.patch (1.5 KB) - added by johnjamesjacoby 9 years ago.
17924.08.patch (1.7 KB) - added by netweb 8 years ago.

Download all attachments as: .zip

Change History (58)

#1 follow-up: @scribu
13 years ago

Related: #10201

#2 @anointed
13 years ago

  • Cc anointed added

#3 in reply to: ↑ 1 @mobius5150
13 years ago

I updated the second diff so that the users list table on /wp-admin/users.php now uses a user_role_name filter to list the roles of the user. In addition, if the $role variable that $WP_Users_List_Table->single_row() is left empty, it will load an array of roles from the $user_object passed to it.

Again, this has not been updated to actually use multiple roles, it simply provides of means for plugin authors to work with this table.

Replying to scribu:

Related: #10201

Yes, the comment here by Jeremy Clarke presented good points and is what initially got me thinking about this. I just felt that the initial direction of that ticket was pretty different than what I had in mind.

#4 @mobius5150
13 years ago

Updated the filter in the first patch to pass the args of the wp_user_role_selector() function to the filter.

@mobius5150
13 years ago

The first patch.

@mobius5150
13 years ago

The second patch.

#5 @mobius5150
13 years ago

I've uploaded a new copy of each patch with 3.2.1 in the file name -- these have been modified to work with the new release of 3.2.1

Really hoping this will gain some traction, I'd really like to see this ability in WordPress, and I have several projects that would highly benefit from this.

#6 @nacin
13 years ago

I could get behind this.

#7 @lpryor
13 years ago

This would be really useful. I'd love to have multiple roles per user.

I'd use it to define a number of roles, each with a separate group of capabilities: for example, one around creating and managing blog posts, one around each type of custom post, one for moderating forums (I'm using buddypress) and so on. And then a user could be a blog manager, a forums moderator, or both. At the moment you have to define a separate role for each possible combination of responsibilities.

#8 @dragunoff
12 years ago

  • Cc dragunoff added

#9 @NateJacobs
12 years ago

  • Cc NateJacobs added

#10 @marfarma
12 years ago

  • Cc pauli.price@… added

#11 @deltafactory
12 years ago

  • Cc deltafactory added

#12 @landwire
12 years ago

  • Cc sascha@… added

#13 @mobius5150
12 years ago

  • Keywords dev-feedback needs-testing removed

Hi Everyone,

Sorry I have not had time to generate a diff patch for this as things have been changing on my end.

I have however updated the code to work with the latest version of WordPress at the time of writing. It is available on my blog at: http://michaelblouin.ca/2011/multiple-roles-per-user-in-wordpress

Just scroll to the bottom of the article and follow the instructions to install both the modified version of WP and te plugin and you'll have multiple roles per user.

In the meantime if anyone would be willing to petition anyone higher up on the commit chain to support our cause it would be highly appreciated.

If we can get more support I would release the neccesary diff to apply this to the latest WP version

Best regards,
Michael Blouin (Mobius5150)

#14 follow-up: @greenshady
12 years ago

Just wanted to chime in here to say that multiple roles per user is one of the most-requested features for my Members plugin. I'm definitely on board with testing this and trying to get it into 3.5.

#15 in reply to: ↑ 14 @mobius5150
12 years ago

Replying to greenshady:

Just wanted to chime in here to say that multiple roles per user is one of the most-requested features for my Members plugin. I'm definitely on board with testing this and trying to get it into 3.5.

This is great news. I'm just entering exam weeks here, so it will be a little while before I resurface, but expect me to be fully back at it with this by (very) early may at the latest to make a push for 3.5.

#16 @knutsp
12 years ago

  • Cc knut@… added

#17 @ruthik
12 years ago

Definitely added.

#18 @equalserving
12 years ago

I too am willing to test this as it is a feature that is most often requested by my clients.

#19 @mobius5150
12 years ago

Hello all.

I've created a new patch for 3.3.2 -- although I've gotten lazy and I no longer split it into 2 patch files (which I don't know why I did anyways).

I know, its kindof a funny time in the WP development cycle to release a patch for 3.3.2, with 3.4 coming soon, but I assure you that the 3.4 patch won't be long after 3.4 is released.

Let me know if you have any issues with this patch.

@mobius5150
12 years ago

A single patch file for WP 3.3.2

#20 follow-up: @mobius5150
12 years ago

I forgot to mention -- as always, a pre-diffed and ready-to-go copy of WordPress is available for your enjoyment here: http://michaelblouin.ca/2011/multiple-roles-per-user-in-wordpress

(For those of you that are currently using this on your sites)

#21 in reply to: ↑ 20 ; follow-up: @nacin
12 years ago

Replying to mobius5150:

(For those of you that are currently using this on your sites)

You should try to implement this as a plugin using the hooks available rather than as a core hack. In general, if you are going to submit a temporary hack, you should only distribute it as a patch file. Then, ideally, only those knowledgeable enough to realize what they are doing will go forward with it.

As a matter of creating patches, please post a single patch with all changes, and make that patch against "trunk", which is currently 3.4-RC1 but is always a moving target.

And in terms of getting it into a future release, I'd have to take a closer look at the approach, but I definitely like the general direction.

#22 in reply to: ↑ 21 @mobius5150
12 years ago

Replying to nacin:

You should try to implement this as a plugin using the hooks available rather than as a core hack. In general, if you are going to submit a temporary hack, you should only distribute it as a patch file. Then, ideally, only those knowledgeable enough to realize what they are doing will go forward with it.

The reason for this patch is that short of output buffering the WP admin pages and doing a search and replace on the page html, there is no way of implementing this with only hooks. All the patch does is add the actions and filters necessary to extend this functionality, the rest is done with a plugin.

As a matter of creating patches, please post a single patch with all changes, and make that patch against "trunk", which is currently 3.4-RC1 but is always a moving target.

In my hurry to get this patched before I fell asleep at my keyboard, I actually didn't notice trunk was 3.4-RC1, and actually made the diff for that. Once 3.4 is officially release I'll update the patch file again.

And in terms of getting it into a future release, I'd have to take a closer look at the approach, but I definitely like the general direction.

Thanks for your feedback, I know a number of people would love more support for this.

#23 @ruthik
12 years ago

I'm on-board. I'm restricting site content on a per-role basis. One role can't access the same content another role has access to, but some users need to have both of those roles. Will download the patch files and start playing with it now :) Thanks for this!

#24 @danielrolls
12 years ago

  • Cc danielrolls added

#25 @dcowgill
12 years ago

  • Cc dcowgill@… added

#26 @rahul286
12 years ago

  • Cc rahul286@… added

Multiple Role will take care of way too many things! :-)

I am really delighted to see there is work in progress here.

Its quite intuitive as a user can be "subscriber" on blog, "moderator" in forum, "foo" in some plugin & "bar" in some other plugin!

With current way - a lot of capabilities manipulation need to be done to get things working... :|

Last edited 11 years ago by rahul286 (previous) (diff)

#27 @etvoilaletravail
11 years ago

  • Cc etvoilaletravail added

#28 @anointed
11 years ago

+++1 trying my best to show continued huge interest in this.

Hoping it just might sneak its way into 3.5 since it can't work as a standalone plugin.

#29 @scribu
11 years ago

I don't think this will make it into 3.5, since it hasn't been discussed at all during the first part of the release cycle and we're already in beta: http://make.wordpress.org/core/version-3-5-project-schedule/

#30 @scribu
11 years ago

Related: #22361

#31 @johnjamesjacoby
11 years ago

  • Cc johnjamesjacoby added

#32 follow-up: @scribu
11 years ago

  • Milestone changed from Awaiting Review to 3.6

#33 @scribu
11 years ago

Related: #22959

#34 in reply to: ↑ 32 @mobius5150
11 years ago

Replying to scribu:
Thanks! I'm starting to get excited for this.

I've prepared a version patched against the current trunk (3.6-alpha). And am attaching it now. I also found a bug in the 3.3.2 patch -- so I hope that nobody ended up using or trying that.

The version I'm currently uploading has been tested against a freshly checked out WP (from trunk) and appears to work just fine, a second set of eyes may be beneficial if someone has the time, but not much has changed from previous patches.

@mobius5150
11 years ago

A patch prepared against trunk of WP 3.6-alpha

#35 @swissspidy
11 years ago

  • Cc hello@… added

#36 @goto10
11 years ago

  • Cc dromsey@… added

#37 @ryan
11 years ago

  • Milestone changed from 3.6 to Future Release

#38 @gare_c
11 years ago

  • Cc gare_c added

#39 @nopivnick
11 years ago

  • Cc nopivnick added

#40 @pbaylies
11 years ago

  • Cc pbaylies added

#41 follow-up: @nikolov.tmw
10 years ago

  • Cc ico.the.star.dust@… added

For anyone interested in using that on their sites, I wrote a little plugin that will allow you to set multiple roles per user. Of course in a standard WordPress environment, there isn't much use of that, since the user will have the privileges of the most-powerful role(since every role that has more privileges builds on top of the privileges of the previous one).

But since you need that kind of plugin, I assume you are using custom privileges and roles.

You can take a look at the code here - https://gist.github.com/nikolov-tmw/7808046 or you can download a bundled .zip file of the plugin here - http://paiyakdev.com/downloads/multiple-roles-per-user.zip

I've tested the plugin on a pretty basic install with very little plugins and on an install with multiple plugins.

What this plugin doesn't do for you is to give you an easy way to programmatically set multiple roles per user. But, since that's already built-in to the WP_User class, you can do it in the same way the plugin does it:

$user = new WP_User( $user_id );
$user->add_role( 'role1' );
$user->add_role( 'role2' );

It's rather simple in my opinion and I don't see why you'd need to be able to specify an array of roles when you use wp_insert_user().
Just make sure to either specify an empty string, or at least one of the roles for a user when you do wp_insert_user() - otherwise your new user would have the default role(which might not be the desired result in some cases).

PS: As you can see my plugin uses a JS hack-around to replace the standard role selector with checkboxes - I generally don't think that's an issue since that's not the only component in the WP admin that relies on JS - besides the checkboxes would still be displayed even without JS, except for they wouldn't be in the same place as the Role select.

Last edited 10 years ago by nikolov.tmw (previous) (diff)

#42 in reply to: ↑ 41 ; follow-up: @landwire
10 years ago

Replying to nikolov.tmw:

Nikolov, that plugin works great for me. One thing though, as I am planning to use permalinks based on a users role at some point: Would it be possible to add the functionality to set the order of the roles or basically set a "main role" and "sub roles"? Basically making sure that the main role is always the first role in array. Or are there any better solutions to accomplish having "main role" and "sub roles"? Maybe with key value pairs for the role array?

Not sure about array syntax, but basically:
$role[('main' => 'coach'), ('sub' => 'player'), ('sub' => 'fan')] for a player coach for instance that is mainly a coach, but also player and fan.
Or even:
$role[('main' => 'coach'), ('sub_1' => 'player'), ('custom_sub' => 'fan')] to distinguish between all roles?

There might be better examples :)

Last edited 10 years ago by landwire (previous) (diff)

#43 in reply to: ↑ 42 @nikolov.tmw
10 years ago

Replying to landwire:

Replying to nikolov.tmw:

... Basically making sure that the main role is always the first role in array. Or are there any better solutions to accomplish having "main role" and "sub roles"? Maybe with key value pairs for the role array? ...

Hmmm - at this moment besides manually fiddling with the meta that holds the user roles after you add/remove a role, I don't see another way. The user's roles are stored in an array like this:

array(
    'administrator' => true,
    'custom-role' => true,
    ...
)

That means that you can do something like

// We need this for WP_User::$cap_key
$user = new WP_User( $user_id );
$user_roles = get_user_meta( $user->ID, $user->cap_key, true );
$main_role = 'custom-role';
$_user_roles = array();
$update_roles = false;
foreach ( $user_roles as $role => $enabled ) {
    if ( $enabled && $role == $main_role ) {
        $_user_roles[ $role ] = $enabled;
        unset( $user_roles[ $role ] );
        $user_roles = array_merge( $_user_roles, $user_roles );
        $update_roles = true;
        break;
    }
}

if ( $update_roles ) {
    update_user_meta( $user->ID, $user->cap_key, $user_roles );
}

You would then have to grab the first role when you access the user's roles.

$user = new WP_User( $user_id );
$main_role = $user->roles[0];

I've tried the above code and it works fine for me.

Not the best solution, but you can modify the sample plugin I wrote to use that code in it - you would have to add a drop-down with all available roles to the edit user screen and after the roles are updated use that code to shift them around in the desired order.

#44 @johnjamesjacoby
9 years ago

  • Keywords 2nd-opinion added
  • Milestone changed from Future Release to Awaiting Review
  • Severity changed from normal to major
  • Type changed from enhancement to defect (bug)
  • Version changed from 3.2 to 2.0

At the risk of abusing some power, I'm updating a few ticket properties to draw some attention:

I'm afraid years worth of patches have over complicated the iterative solution to a problem that runs deep within the WP_Roles API. 17924.07.patch is the minimum requirement to avoiding plugin breakage (see: #BB2597 for more.)

The problem is set_role() – it's a nuclear approach reserved for setting or preserving the default role of a given site. Any other user role adjustment should be sensitive to the fact that any user can have any combination of roles or capabilities outside of the "blog" portion of a site.

See also #23016.

#45 follow-up: @jorbin
9 years ago

  • Keywords commit added
  • Type changed from defect (bug) to enhancement

At first glance, @jjj's approach seems sane. Would love another set of eyes on it to ensure it's sane. I think this is a minimally invasive approach and allows plugins to add the role management as needed.

#46 in reply to: ↑ 45 @greenshady
9 years ago

Replying to jorbin:

At first glance, @jjj's approach seems sane. Would love another set of eyes on it to ensure it's sane. I think this is a minimally invasive approach and allows plugins to add the role management as needed.

It looks like a good first step and an easy win for those of us utilizing more complex role setups.

This ticket was mentioned in Slack in #bbpress by netweb. View the logs.


8 years ago

@netweb
8 years ago

#49 @netweb
7 years ago

  • Keywords dev-feedback added

It would be great to see this milestoned in the near future, adding dev-feedback to existing commit hoping to attract some attention

FYI: Patch still applies to /trunk cleanly :)

Last edited 7 years ago by netweb (previous) (diff)

#50 @johnbillion
3 years ago

  • Keywords needs-refresh added; commit removed
Note: See TracTickets for help on using tickets.