[wp-trac] [WordPress Trac] #56256: The 'capability' parameter in the get_users function may not give the expected results.

WordPress Trac noreply at wordpress.org
Wed Jul 20 12:51:07 UTC 2022


#56256: The 'capability' parameter in the get_users function may not give the
expected results.
--------------------------+-----------------------------
 Reporter:  tmatsuur      |      Owner:  (none)
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  Users         |    Version:  6.0
 Severity:  normal        |   Keywords:  has-patch
  Focuses:                |
--------------------------+-----------------------------
 Specifying multiple different capabilities for the 'capability',
 'capability__in', and 'capability__not_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 'capability__in' and
 'capability__not_in' parameters.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/56256>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list