Opened 2 years ago
Last modified 2 years ago
#56256 new defect (bug)
The 'capability' parameter in the get_users function may not give the expected results.
Reported by: | tmatsuur | Owned by: | |
---|---|---|---|
Milestone: | Future Release | Priority: | normal |
Severity: | normal | Version: | 5.9 |
Component: | Role/Capability | Keywords: | has-patch has-unit-tests |
Focuses: | Cc: |
Description
Specifying multiple different capabilities for the 'capability', 'capabilityin', and 'capabilitynot_in' parameters of the get_users function may not produce the expected results.
The user's metadata is as follows
mysql> select * from wp_usermeta where meta_key='wp_capabilities'; +----------+---------+-----------------+---------------------------------+ | umeta_id | user_id | meta_key | meta_value | +----------+---------+-----------------+---------------------------------+ | 12 | 1 | wp_capabilities | a:1:{s:13:"administrator";b:1;} | | 54 | 2 | wp_capabilities | a:1:{s:6:"author";b:1;} | +----------+---------+-----------------+---------------------------------+
In this situation, run the following PHP script
var_dump( get_users( [ 'capability' => ['edit_posts', 'edit_pages'], 'fields' => 'ID' ] ) );
The output is as follows, and no matching user ID can be obtained.
array(0) { }
The cause is in the code after line 481 of class-wp-user-query.php
.
foreach ( $available_roles as $role => $role_data ) { $role_caps = array_keys( array_filter( $role_data['capabilities'] ) ); foreach ( $capabilities as $cap ) { if ( in_array( $cap, $role_caps, true ) ) { $caps_with_roles[ $cap ][] = $role; break; } } foreach ( $capability__in as $cap ) { if ( in_array( $cap, $role_caps, true ) ) { $role__in[] = $role; break; } } foreach ( $capability__not_in as $cap ) { if ( in_array( $cap, $role_caps, true ) ) { $role__not_in[] = $role; break; } } }
Because the loop process is terminated immediately after storing the "role" of the first "capability" in the array, the "roles" of the second and subsequent "capabilities" are not stored.
Therefore, the 'role' of the second and subsequent 'capability' is no longer included in the search criteria, and the expected results are not obtained.
Specifically, the search query looks like this
WHERE 1=1 AND ( ( ( ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"edit\\_posts\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"administrator\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"editor\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"author\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"contributor\"%' ) ) AND ( ( mt1.meta_key = 'wp_capabilities' AND mt1.meta_value LIKE '%\"edit\\_pages\"%' ) ) ) )
Remove the break statement for confirmation.
The search query then changes as follows
WHERE 1=1 AND ( ( ( ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"edit\\_posts\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"administrator\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"editor\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"author\"%' ) OR ( wp_usermeta.meta_key = 'wp_capabilities' AND wp_usermeta.meta_value LIKE '%\"contributor\"%' ) ) AND ( ( mt1.meta_key = 'wp_capabilities' AND mt1.meta_value LIKE '%\"edit\\_pages\"%' ) OR ( mt1.meta_key = 'wp_capabilities' AND mt1.meta_value LIKE '%\"administrator\"%' ) OR ( mt1.meta_key = 'wp_capabilities' AND mt1.meta_value LIKE '%\"editor\"%' ) ) ) )
The return value of the get_users function is as follows
array(1) { [0]=> string(1) "1" }
Something similar occurs with the 'capabilityin' and 'capabilitynot_in' parameters.
Thanks for your report!
Introduced in #16841 / [51943] and [52290]