WordPress.org

Make WordPress Core

Opened 3 years ago

Last modified 4 months ago

#17924 new enhancement

Make Integrating Multiple Roles Per User Easier for Plugin Authors

Reported by: mobius5150 Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 3.2
Component: Role/Capability Keywords: has-patch
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 (6)

Replace_Admin_Role_Dropdown.patch (9.3 KB) - added by mobius5150 3 years ago.
The first patch.
Create_Role_Update_Actions_Filters.patch (5.0 KB) - added by mobius5150 3 years ago.
The second patch.
Create_Role_Update_Actions_Filters_3.2.1.patch (4.8 KB) - added by mobius5150 3 years ago.
The second patch.
Replace_Admin_Role_Dropdown_3.2.1.patch (9.3 KB) - added by mobius5150 3 years ago.
The first patch.
wp-3.3.2-multi-role-diff.patch (3.7 KB) - added by mobius5150 2 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 19 months ago.
A patch prepared against trunk of WP 3.6-alpha

Download all attachments as: .zip

Change History (49)

comment:1 follow-up: scribu3 years ago

Related: #10201

comment:2 anointed3 years ago

  • Cc anointed added

comment:3 in reply to: ↑ 1 mobius51503 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.

comment:4 mobius51503 years ago

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

mobius51503 years ago

The first patch.

mobius51503 years ago

The second patch.

comment:5 mobius51503 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.

mobius51503 years ago

The second patch.

mobius51503 years ago

The first patch.

comment:6 nacin3 years ago

I could get behind this.

comment:7 lpryor3 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.

comment:8 dragunoff3 years ago

  • Cc dragunoff added

comment:9 NateJacobs3 years ago

  • Cc NateJacobs added

comment:10 marfarma3 years ago

  • Cc pauli.price@… added

comment:11 deltafactory3 years ago

  • Cc deltafactory added

comment:12 landwire3 years ago

  • Cc sascha@… added

comment:13 mobius51502 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)

comment:14 follow-up: greenshady2 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.

comment:15 in reply to: ↑ 14 mobius51502 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.

comment:16 knutsp2 years ago

  • Cc knut@… added

comment:17 ruthik2 years ago

Definitely added.

comment:18 equalserving2 years ago

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

comment:19 mobius51502 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.

mobius51502 years ago

A single patch file for WP 3.3.2

comment:20 follow-up: mobius51502 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)

comment:21 in reply to: ↑ 20 ; follow-up: nacin2 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.

comment:22 in reply to: ↑ 21 mobius51502 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.

comment:23 ruthik2 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!

comment:24 danielrolls2 years ago

  • Cc danielrolls added

comment:25 dcowgill2 years ago

  • Cc dcowgill@… added

comment:26 rahul2862 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 21 months ago by rahul286 (previous) (diff)

comment:27 etvoilaletravail21 months ago

  • Cc etvoilaletravail added

comment:28 anointed21 months 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.

comment:29 scribu21 months 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/

comment:31 johnjamesjacoby21 months ago

  • Cc johnjamesjacoby added

comment:32 follow-up: scribu19 months ago

  • Milestone changed from Awaiting Review to 3.6

comment:34 in reply to: ↑ 32 mobius515019 months 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.

mobius515019 months ago

A patch prepared against trunk of WP 3.6-alpha

comment:35 swissspidy19 months ago

  • Cc hello@… added

comment:36 goto1019 months ago

  • Cc dromsey@… added

comment:37 ryan14 months ago

  • Milestone changed from 3.6 to Future Release

comment:38 gare_c14 months ago

  • Cc gare_c added

comment:39 nopivnick11 months ago

  • Cc nopivnick added

comment:40 pbaylies10 months ago

  • Cc pbaylies added

comment:41 follow-up: nikolov.tmw7 months 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 7 months ago by nikolov.tmw (previous) (diff)

comment:42 in reply to: ↑ 41 ; follow-up: landwire4 months 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 4 months ago by landwire (previous) (diff)

comment:43 in reply to: ↑ 42 nikolov.tmw4 months 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.

Note: See TracTickets for help on using tickets.