Skip to content

Commit be5e8f6

Browse files
authored
Merge pull request #234 from WPUserManager/#230-Allow-multiple-user-roles
Allow multiple user roles #230
2 parents 80353b6 + c7f814a commit be5e8f6

File tree

3 files changed

+305
-12
lines changed

3 files changed

+305
-12
lines changed

includes/actions.php

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,14 +381,40 @@ function wpum_finish_db_setup_after_plugin_init() {
381381
add_action( 'after_wpum_init', 'wpum_finish_db_setup_after_plugin_init' );
382382

383383
function wpum_register_profile_privacy_fields() {
384+
global $pagenow;
385+
386+
$roles = [];
387+
388+
foreach ( wpum_get_roles( true, true ) as $role ) {
389+
$roles[ $role['value'] ] = $role['label'];
390+
}
391+
392+
$allow_multiple_roles = wpum_get_option( 'allow_multiple_user_roles' );
393+
394+
$user_id = isset( $_GET['user_id'] ) ? absint( $_GET['user_id'] ) : false;
395+
396+
$profileuser = isset( $user_id ) ? get_user_by( 'id', $user_id ) : false;
397+
$existing_roles = ( $profileuser ) ? $profileuser->roles : [];
398+
399+
$fields = array(
400+
Field::make( 'checkbox', 'hide_profile_guests', esc_html__( 'Hide profile from guests', 'wp-user-manager' ) )
401+
->set_help_text( esc_html__( 'Hide this profile from guests. Overrides the global profile options.', 'wp-user-manager' ) ),
402+
Field::make( 'checkbox', 'hide_profile_members', esc_html__( 'Hide profile from members', 'wp-user-manager' ) )
403+
->set_help_text( esc_html__( 'Hide this profile from members. Overrides the global profile options.', 'wp-user-manager' ) ),
404+
);
405+
406+
if ( $allow_multiple_roles && ( $profileuser || $pagenow == 'user-new.php' ) && ! is_network_admin() ) {
407+
$fields[] = Field::make( 'multiselect', 'wpum_user_roles', '' )
408+
->add_options( $roles )
409+
->set_default_value( $existing_roles )
410+
->set_classes( 'wpum-multiple-user-roles' )
411+
->set_help_text( esc_html__( 'Select one or more roles for this user.', 'wp-user-manager' ) );
412+
}
413+
384414
Container::make( 'user_meta', esc_html__( 'Profile Privacy', 'wp-user-manager' ) )
385-
->add_fields( array(
386-
Field::make( 'checkbox', 'hide_profile_guests', esc_html__( 'Hide profile from guests', 'wp-user-manager' ) )
387-
->set_help_text( esc_html__( 'Hide this profile from guests. Overrides the global profile options.', 'wp-user-manager' ) ),
388-
Field::make( 'checkbox', 'hide_profile_members', esc_html__( 'Hide profile from members', 'wp-user-manager' ) )
389-
->set_help_text( esc_html__( 'Hide this profile from members. Overrides the global profile options.', 'wp-user-manager' ) )
390-
) );
415+
->add_fields( $fields );
391416
}
417+
392418
add_action( 'carbon_fields_register_fields', 'wpum_register_profile_privacy_fields' );
393419

394420
add_action( 'template_redirect', 'wpum_reset_password_redirect' );
@@ -418,6 +444,71 @@ function wpum_reset_password_redirect() {
418444
exit;
419445
}
420446

447+
function wpum_action_profile_update( $userId, $oldUserData = [] ) {
448+
449+
$allow_multiple_roles = wpum_get_option( 'allow_multiple_user_roles' );
450+
if ( ! $allow_multiple_roles ) {
451+
return;
452+
}
453+
454+
if ( isset( $_POST['_wpum_user_roles'] ) && current_user_can( 'promote_user' ) ) {
455+
456+
$user = get_user_by('ID', $userId);
457+
458+
$wpum_roles = explode( '|', $_POST['_wpum_user_roles'] );
459+
$currentRoles = $user->roles;
460+
461+
if ( empty( $wpum_roles ) || ! is_array( $wpum_roles )) {
462+
return;
463+
}
464+
465+
// Remove unselected roles
466+
foreach ( $currentRoles as $role ) {
467+
if ( ! in_array( $role, $wpum_roles ) ) {
468+
$user->remove_role( $role );
469+
}
470+
}
471+
472+
// Add new roles
473+
foreach ( $wpum_roles as $role ) {
474+
if ( ! in_array( $role, $currentRoles ) ) {
475+
$user->add_role( $role );
476+
}
477+
}
478+
}
479+
}
480+
481+
add_action( 'profile_update', 'wpum_action_profile_update', 99, 2 );
482+
if ( is_multisite() ) {
483+
add_action( 'add_user_to_blog', 'wpum_action_profile_update', 99 );
484+
} else {
485+
add_action( 'user_register', 'wpum_action_profile_update', 99 );
486+
}
487+
488+
function wpum_modify_multiple_roles_ui( $user ) {
489+
$allow_multiple_roles = wpum_get_option( 'allow_multiple_user_roles' );
490+
if ( ! $allow_multiple_roles ) {
491+
return;
492+
}
493+
494+
echo <<<HTML
495+
<script>
496+
jQuery(function ( $ ) {
497+
if ( ! $( '.user-role-wrap select#role, #createuser select#role' ).length ) {
498+
return;
499+
}
500+
var el_userrole = $('.user-role-wrap select#role, #createuser select#role');
501+
$( $( '.wpum-multiple-user-roles' ) ).insertAfter( el_userrole ).css('padding', 0);
502+
$( el_userrole ).hide();
503+
});
504+
</script>
505+
HTML;
506+
}
507+
508+
add_action( 'user_new_form', 'wpum_modify_multiple_roles_ui', 0 );
509+
add_action( 'show_user_profile', 'wpum_modify_multiple_roles_ui', 0 );
510+
add_action( 'edit_user_profile', 'wpum_modify_multiple_roles_ui', 0 );
511+
421512
/**
422513
* Restrict profile page when disabled.
423514
*
@@ -433,3 +524,4 @@ function wpum_restrict_profile_page() {
433524
}
434525

435526
add_action( 'template_redirect', 'wpum_restrict_profile_page' );
527+

includes/wpum-admin/class-wpum-options-panel.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,12 @@ public function register_settings( $settings ) {
253253
'desc' => __( 'Enable the roles editor in the Users menu.', 'wp-user-manager' ),
254254
'type' => 'checkbox'
255255
),
256+
array(
257+
'id' => 'allow_multiple_user_roles',
258+
'name' => __( 'Allow Multiple Roles', 'wp-user-manager' ),
259+
'desc' => __( 'Users can be assigned multiple roles.', 'wp-user-manager' ),
260+
'type' => 'checkbox'
261+
),
256262
],
257263
'registration' => [
258264
array(

includes/wpum-admin/class-wpum-user-table.php

Lines changed: 201 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,217 @@ class WPUM_User_Table {
1919
* Get things started.
2020
*/
2121
public function __construct() {
22-
2322
add_filter( 'manage_users_columns', [ $this, 'add_user_id_column' ] );
24-
add_action( 'manage_users_custom_column', [ $this, 'show_user_id' ], 10, 3 );
23+
add_action( 'manage_users_custom_column', [ $this, 'show_user_id' ], 10, 3 );
24+
add_action( 'admin_head', [ $this, 'hide_change_role_field' ] );
25+
add_action( 'load-users.php', [ $this, 'load_users' ] );
26+
add_action( 'load-users.php', [ $this, 'load_users_role_bulk_add' ] );
27+
add_action( 'load-users.php', [ $this, 'load_users_role_bulk_remove' ] );
28+
}
29+
30+
public function hide_change_role_field() {
31+
?>
32+
<style type="text/css">
33+
label[for="new_role"], #new_role, #changeit,
34+
label[for="new_role2"], #new_role2, #changeit2 { display: none !important; }
35+
</style>
36+
<?php
37+
}
38+
39+
public function bulk_fields_dropdown( $which ) {
40+
if ( ! current_user_can( 'promote_users' ) ) {
41+
return;
42+
}
43+
44+
wp_nonce_field( 'wpum-bulk-users', 'wpum-bulk-users-nonce' ); ?>
45+
46+
<label class="screen-reader-text" for="<?php echo esc_attr( "wpum-add-role-{$which}" ); ?>">
47+
<?php esc_html_e( 'Add role&hellip;', 'wp-user-manager' ); ?>
48+
</label>
49+
<select name="<?php echo esc_attr( "wpum-add-role-{$which}" ); ?>"
50+
id="<?php echo esc_attr( "wpum-add-role-{$which}" ); ?>" style="display: inline-block; float: none;">
51+
<option value=""><?php esc_html_e( 'Add role&hellip;', 'wp-user-manager' ); ?></option>
52+
<?php wp_dropdown_roles(); ?>
53+
</select>
54+
55+
<?php submit_button( esc_html__( 'Add', 'wp-user-manager' ), 'secondary', esc_attr( "wpum-add-role-submit-{$which}" ), false ); ?>
2556

57+
<label class="screen-reader-text" for="<?php echo esc_attr( "wpum-remove-role-{$which}" ); ?>">
58+
<?php esc_html_e( 'Remove role&hellip;', 'wp-user-manager' ); ?>
59+
</label>
60+
61+
<select name="<?php echo esc_attr( "wpum-remove-role-{$which}" ); ?>"
62+
id="<?php echo esc_attr( "wpum-remove-role-{$which}" ); ?>" style="display: inline-block; float: none;">
63+
<option value=""><?php esc_html_e( 'Remove role&hellip;', 'wp-user-manager' ); ?></option>
64+
<?php wp_dropdown_roles(); ?>
65+
</select>
66+
67+
<?php submit_button( esc_html__( 'Remove', 'wp-user-manager' ), 'secondary', esc_attr( "wpum-remove-role-submit-{$which}" ), false );
68+
}
69+
70+
public function load_users() {
71+
add_action( 'restrict_manage_users',[ $this, 'bulk_fields_dropdown' ], 5 );
72+
73+
if ( ! isset( $_GET['update'] ) ) {
74+
return;
75+
}
76+
77+
$action = sanitize_key( $_GET['update'] );
78+
$role = sanitize_key( $_GET['name'] );
79+
$count = intval( $_GET['count'] );
80+
if ( 'wpum-role-added' === $action ) {
81+
WPUM()->notices->register_notice( 'wpum_role_added', 'success', sprintf( '<b>%s</b> role added to <b>%d</b> %s.', ucwords( $role ), $count, $count > 1 ? 'users': 'user' ), 'wp-user-manager' );
82+
} elseif ( 'wpum-role-removed' === $action ) {
83+
WPUM()->notices->register_notice( 'wpum_role_removed', 'success', sprintf( '<b>%s</b> role removed from <b>%d</b> %s.', ucwords( $role ), $count, $count > 1 ? 'users': 'user' ), 'wp-user-manager' );
84+
} elseif ( 'wpum-error-remove-admin' === $action ) {
85+
WPUM()->notices->register_notice( 'wpum_admin_error', 'error', sprintf( 'You cannot remove the <b>%s</b> role from your account.', ucwords( $role ) ), 'wp-user-manager' );
86+
}
87+
}
88+
89+
public function load_users_role_bulk_add() {
90+
if ( empty( $_REQUEST['users'] ) ) {
91+
return;
92+
}
93+
94+
check_admin_referer( 'wpum-bulk-users', 'wpum-bulk-users-nonce' );
95+
96+
if ( ! current_user_can( 'promote_users' ) ) {
97+
return;
98+
}
99+
100+
if ( ! empty( $_REQUEST['wpum-add-role-top'] ) && ! empty( $_REQUEST['wpum-add-role-submit-top'] ) ) {
101+
$role = sanitize_text_field( $_REQUEST['wpum-add-role-top'] );
102+
} else if ( ! empty( $_REQUEST['wpum-add-role-bottom'] ) && ! empty( $_REQUEST['wpum-add-role-submit-bottom'] ) ) {
103+
$role = sanitize_text_field( $_REQUEST['wpum-add-role-bottom'] );
104+
}
105+
106+
$m_role = wpum_get_role( $role );
107+
$roles = array_column( wpum_get_roles( false, true ), 'value' );
108+
109+
if ( empty( $role ) || ! in_array( $role, $roles ) ) {
110+
return;
111+
}
112+
113+
$count = 0;
114+
115+
foreach ( (array) $_REQUEST['users'] as $user_id ) {
116+
117+
$user_id = absint( $user_id );
118+
if ( is_multisite() && ! is_user_member_of_blog( $user_id ) ) {
119+
120+
wp_die( sprintf( '<h1>%s</h1> <p>%s</p>', esc_html__( 'One of the selected users is not a member of this site.', 'wp-user-manager' ) ), 403 );
121+
}
122+
123+
if ( ! current_user_can( 'promote_user', $user_id ) ) {
124+
continue;
125+
}
126+
127+
$user = new \WP_User( $user_id );
128+
129+
if ( ! in_array( $role, $user->roles ) ) {
130+
$user->add_role( $role );
131+
$count ++;
132+
}
133+
}
134+
wp_redirect( add_query_arg( [
135+
'update' => 'wpum-role-added',
136+
'name' => $m_role->label,
137+
'count' => $count,
138+
], 'users.php' ) );
139+
140+
exit;
141+
}
142+
143+
public function load_users_role_bulk_remove() {
144+
if ( empty( $_REQUEST['users'] ) ) {
145+
return;
146+
}
147+
148+
check_admin_referer( 'wpum-bulk-users', 'wpum-bulk-users-nonce' );
149+
150+
if ( ! current_user_can( 'promote_users' ) ) {
151+
return;
152+
}
153+
154+
if ( ! empty( $_REQUEST['wpum-remove-role-top'] ) && ! empty( $_REQUEST['wpum-remove-role-submit-top'] ) ) {
155+
$role = sanitize_text_field( $_REQUEST['wpum-remove-role-top'] );
156+
} elseif ( ! empty( $_REQUEST['wpum-remove-role-bottom'] ) && ! empty( $_REQUEST['wpum-remove-role-submit-bottom'] ) ) {
157+
$role = sanitize_text_field( $_REQUEST['wpum-remove-role-bottom'] );
158+
}
159+
160+
$roles = array_column( wpum_get_roles(), 'value' );
161+
162+
if ( empty( $role ) || ! in_array( $role, $roles ) ) {
163+
return;
164+
}
165+
166+
$current_user = wp_get_current_user();
167+
$m_role = wpum_get_role( $role );
168+
$update = 'wpum-role-removed';
169+
170+
$count = 0;
171+
172+
foreach ( (array) $_REQUEST['users'] as $user_id ) {
173+
174+
$user_id = absint( $user_id );
175+
176+
if ( is_multisite() && ! is_user_member_of_blog( $user_id ) ) {
177+
178+
wp_die( sprintf( '<h1>%s</h1> <p>%s</p>', esc_html__( 'One of the selected users is not a member of this site.', 'wp-user-manager' ) ), 403 );
179+
}
180+
181+
if ( ! current_user_can( 'promote_user', $user_id ) ) {
182+
continue;
183+
}
184+
185+
$is_current_user = $user_id == $current_user->ID;
186+
$role_can_promote = in_array( 'promote_users', $m_role->granted_caps );
187+
$can_manage_network = is_multisite() && current_user_can( 'manage_network_users' );
188+
189+
if ( $is_current_user && $role_can_promote && ! $can_manage_network ) {
190+
$can_remove = false;
191+
192+
foreach ( $current_user->roles as $_r ) {
193+
194+
if ( $role !== $_r && in_array( 'promote_users', wpum_get_role( $_r )->granted_caps ) ) {
195+
196+
$can_remove = true;
197+
break;
198+
}
199+
}
200+
201+
if ( ! $can_remove ) {
202+
$update = 'wpum-error-remove-admin';
203+
continue;
204+
}
205+
}
206+
207+
$user = new \WP_User( $user_id );
208+
209+
if ( in_array( $role, $user->roles ) ) {
210+
$user->remove_role( $role );
211+
$count ++;
212+
}
213+
}
214+
wp_redirect( add_query_arg( [
215+
'update' => $update,
216+
'name' => $m_role->label,
217+
'count' => $count,
218+
], 'users.php' ) );
219+
220+
exit;
26221
}
27222

28223
/**
29224
* Add the user id column.
30225
*
31226
* @param array $columns
32-
* @return void
227+
* @return array
33228
*/
34229
public function add_user_id_column( $columns ) {
35-
36230
$columns['user_id'] = __( 'ID', 'wp-user-manager' );
37-
return $columns;
38231

232+
return $columns;
39233
}
40234

41235
/**
@@ -44,12 +238,13 @@ public function add_user_id_column( $columns ) {
44238
* @param string $value
45239
* @param string $column_name
46240
* @param int $user_id
47-
* @return void
241+
* @return mixed
48242
*/
49243
public function show_user_id( $value, $column_name, $user_id ) {
50244
if ( 'user_id' == $column_name ) {
51245
return $user_id;
52246
}
247+
53248
return $value;
54249
}
55250

0 commit comments

Comments
 (0)