WordPress.org

Make WordPress Core

Ticket #22212: 22212.diff

File 22212.diff, 14.3 KB (added by boonebgorges, 6 years ago)
  • src/wp-includes/class-wp-user-query.php

    diff --git src/wp-includes/class-wp-user-query.php src/wp-includes/class-wp-user-query.php
    index 1bc08aa..11f7ddf 100644
    class WP_User_Query { 
    8888                $defaults = array(
    8989                        'blog_id' => $GLOBALS['blog_id'],
    9090                        'role' => '',
     91                        'role__in' => array(),
     92                        'role__not_in' => array(),
    9193                        'meta_key' => '',
    9294                        'meta_value' => '',
    9395                        'meta_compare' => '',
    class WP_User_Query { 
    117119         * @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax
    118120         *              for `$orderby` parameter.
    119121         * @since 4.3.0 Added 'has_published_posts' parameter.
    120          * @since 4.4.0 Added 'paged' parameter.
     122         * @since 4.4.0 Added 'paged', 'role__in', and 'role__not_in' parameters. 'role' parameter was updated to
     123         *              permit an array or comma-separated list of values.
    121124         * @access public
    122125         *
    123126         * @global wpdb $wpdb
    class WP_User_Query { 
    127130         *     Optional. Array or string of Query parameters.
    128131         *
    129132         *     @type int          $blog_id             The site ID. Default is the global blog id.
    130          *     @type string       $role                Role name. Default empty.
     133         *     @type string|array $role                An array or a comma-separated list of role names that users must match
     134         *                                             to be included in results. Note that this is an inclusive list: users
     135         *                                             must match *each* role. Default empty.
     136         *     @type array        $role__in            An array of role names. Matched users must have at least one of these
     137         *                                             roles. Default empty array.
     138         *     @type array        $role__not_in        An array of role names to exclude. Users matching one or more of these
     139         *                                             roles will not be included in results. Default empty array.
    131140         *     @type string       $meta_key            User meta key. Default empty.
    132141         *     @type string       $meta_value          User meta value. Default empty.
    133142         *     @type string       $meta_compare        Comparison operator to test the `$meta_value`. Accepts '=', '!=',
    class WP_User_Query { 
    259268                $this->meta_query = new WP_Meta_Query();
    260269                $this->meta_query->parse_query_vars( $qv );
    261270
    262                 $role = '';
     271                $roles = array();
    263272                if ( isset( $qv['role'] ) ) {
    264                         $role = trim( $qv['role'] );
     273                        if ( is_array( $qv['role'] ) ) {
     274                                $roles = $qv['role'];
     275                        } elseif ( is_string( $qv['role'] ) && ! empty( $qv['role'] ) ) {
     276                                $roles = array_map( 'trim', explode( ',', $qv['role'] ) );
     277                        }
     278                }
     279
     280                $role__in = array();
     281                if ( isset( $qv['role__in'] ) ) {
     282                        $role__in = (array) $qv['role__in'];
    265283                }
    266284
    267                 if ( $blog_id && ( $role || is_multisite() ) ) {
    268                         $cap_meta_query = array();
    269                         $cap_meta_query['key'] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
     285                $role__not_in = array();
     286                if ( isset( $qv['role__not_in'] ) ) {
     287                        $role__not_in = (array) $qv['role__not_in'];
     288                }
    270289
    271                         if ( $role ) {
    272                                 $cap_meta_query['value'] = '"' . $role . '"';
    273                                 $cap_meta_query['compare'] = 'like';
     290                if ( $blog_id && ( ! empty( $roles ) || ! empty( $role__in ) || ! empty( $role__not_in ) || is_multisite() ) ) {
     291                        $role_queries  = array();
     292
     293                        $roles_clauses = array( 'relation' => 'AND' );
     294                        if ( ! empty( $roles ) ) {
     295                                foreach ( $roles as $role ) {
     296                                        $roles_clauses[] = array(
     297                                                'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
     298                                                'value'   => $role,
     299                                                'compare' => 'LIKE',
     300                                        );
     301                                }
     302
     303                                // Sanity check: this clause may already have been added to the meta_query.
     304                                if ( empty( $this->meta_query->clauses ) || ! in_array( $roles_clauses, $this->meta_query_clauses, true ) ) {
     305                                        $role_queries[] = $roles_clauses;
     306                                }
    274307                        }
    275308
     309                        $role__in_clauses = array( 'relation' => 'OR' );
     310                        if ( ! empty( $role__in ) ) {
     311                                foreach ( $role__in as $role ) {
     312                                        $role__in_clauses[] = array(
     313                                                'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
     314                                                'value'   => $role,
     315                                                'compare' => 'LIKE',
     316                                        );
     317                                }
     318
     319                                $role_queries[] = $role__in_clauses;
     320                        }
     321
     322                        $role__not_in_clauses = array( 'relation' => 'AND' );
     323                        if ( ! empty( $role__not_in ) ) {
     324                                foreach ( $role__not_in as $role ) {
     325                                        $role__not_in_clauses[] = array(
     326                                                'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
     327                                                'value'   => $role,
     328                                                'compare' => 'NOT LIKE',
     329                                        );
     330                                }
     331
     332                                $role_queries[] = $role__not_in_clauses;
     333                        }
     334
     335                        // If there are no specific roles named, make sure the user has at least one role.
     336                        if ( empty( $role_queries ) ) {
     337                                $role_queries[] = array(
     338                                        'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
     339                                        'compare' => 'EXISTS',
     340                                );
     341                        }
     342
     343                        // Specify that role queries should be joined with AND.
     344                        $role_queries['relation'] = 'AND';
     345
    276346                        if ( empty( $this->meta_query->queries ) ) {
    277                                 $this->meta_query->queries = array( $cap_meta_query );
    278                         } elseif ( ! in_array( $cap_meta_query, $this->meta_query->queries, true ) ) {
     347                                $this->meta_query->queries = $role_queries;
     348                        } else {
    279349                                // Append the cap query to the original queries and reparse the query.
    280350                                $this->meta_query->queries = array(
    281351                                        'relation' => 'AND',
    282                                         array( $this->meta_query->queries, $cap_meta_query ),
     352                                        array( $this->meta_query->queries, $role_queries ),
    283353                                );
    284354                        }
    285355
  • tests/phpunit/tests/user/query.php

    diff --git tests/phpunit/tests/user/query.php tests/phpunit/tests/user/query.php
    index 064c73f..37921a0 100644
    class Tests_User_Query extends WP_UnitTestCase { 
    896896                        unset( $q->query_vars[ $k ] );
    897897                }
    898898        }
     899
     900        /**
     901         * @ticket 22212
     902         */
     903        public function test_get_single_role_by_user_query() {
     904                $this->factory->user->create_many( 2, array(
     905                        'role' => 'subscriber',
     906                ) );
     907
     908                $this->factory->user->create( array(
     909                        'role' => 'contributor',
     910                ) );
     911
     912                $wp_user_search = new WP_User_Query( array( 'role' => 'subscriber' ) );
     913                $users          = $wp_user_search->get_results();
     914
     915                $this->assertEquals( 2, count( $users ) );
     916        }
     917
     918        /**
     919         * @ticket 22212
     920         */
     921        public function test_get_multiple_roles_by_user_query() {
     922                $this->factory->user->create_many( 2, array(
     923                        'role' => 'subscriber',
     924                ) );
     925
     926                $this->factory->user->create_many( 3, array(
     927                        'role' => 'editor',
     928                ) );
     929
     930                $this->factory->user->create( array(
     931                        'role' => 'contributor',
     932                ) );
     933
     934                $wp_user_search = new WP_User_Query( array( 'role__in' => array( 'subscriber', 'editor' ) ) );
     935                $users          = $wp_user_search->get_results();
     936                $this->assertEquals( 5, count( $users ) );
     937        }
     938
     939        /**
     940         * @ticket 22212
     941         */
     942        public function test_get_single_role_by_string() {
     943                $this->factory->user->create_many( 2, array(
     944                        'role' => 'subscriber',
     945                ) );
     946
     947                $this->factory->user->create( array(
     948                        'role' => 'contributor',
     949                ) );
     950
     951                $users = get_users( array(
     952                        'role' => 'subscriber',
     953                ) );
     954
     955                $this->assertEquals( 2, count( $users ) );
     956        }
     957
     958        /**
     959         * @ticket 22212
     960         */
     961        public function test_get_single_role_by_array() {
     962                $this->factory->user->create_many( 2, array(
     963                        'role' => 'subscriber',
     964                ) );
     965
     966                $this->factory->user->create( array(
     967                        'role' => 'contributor',
     968                ) );
     969
     970                $users = get_users( array(
     971                        'role' => array( 'subscriber' ),
     972                ) );
     973
     974                $this->assertEquals( 2, count( $users ) );
     975        }
     976
     977        /**
     978         * @ticket 22212
     979         */
     980        public function test_get_multiple_roles_should_only_match_users_who_have_each_role() {
     981                $subscribers = $this->factory->user->create_many( 2, array(
     982                        'role' => 'subscriber',
     983                ) );
     984
     985                $this->factory->user->create_many( 3, array(
     986                        'role' => 'editor',
     987                ) );
     988
     989                $this->factory->user->create_many( 2, array(
     990                        'role' => 'administrator',
     991                ) );
     992
     993                $users = new WP_User_Query( array( 'role' => array( 'subscriber', 'editor' ) ) );
     994                $users = $users->get_results();
     995
     996                $this->assertEmpty( $users );
     997
     998                foreach ( $subscribers as $subscriber ) {
     999                        $subscriber = get_user_by( 'ID', $subscriber );
     1000                        $subscriber->add_role( 'editor' );
     1001                }
     1002
     1003                $users = new WP_User_Query( array( 'role' => array( 'subscriber', 'editor' ) ) );
     1004                $users = $users->get_results();
     1005
     1006                $this->assertEquals( 2, count( $users ) );
     1007
     1008                foreach ( $users as $user ) {
     1009                        $this->assertInstanceOf( 'WP_User', $user );
     1010                }
     1011        }
     1012
     1013        /**
     1014         * @ticket 22212
     1015         */
     1016        public function test_get_multiple_roles_or() {
     1017                $this->factory->user->create_many( 2, array(
     1018                        'role' => 'subscriber',
     1019                ) );
     1020
     1021                $this->factory->user->create_many( 3, array(
     1022                        'role' => 'editor',
     1023                ) );
     1024
     1025                $this->factory->user->create_many( 2, array(
     1026                        'role' => 'administrator',
     1027                ) );
     1028
     1029                $this->factory->user->create_many( 1, array(
     1030                        'role' => 'contributor',
     1031                ) );
     1032
     1033                $users = new WP_User_Query( array( 'role__in' => array( 'subscriber', 'editor', 'administrator' ) ) );
     1034                $users = $users->get_results();
     1035
     1036                // +1 for the default user created during installation.
     1037                $this->assertEquals( 8, count( $users ) );
     1038                foreach ( $users as $user ) {
     1039                        $this->assertInstanceOf( 'WP_User', $user );
     1040                }
     1041        }
     1042
     1043        /**
     1044         * @ticket 22212
     1045         */
     1046        public function test_get_multiple_roles_by_comma_separated_list() {
     1047                $subscribers = $this->factory->user->create_many( 2, array(
     1048                        'role' => 'subscriber',
     1049                ) );
     1050
     1051                $this->factory->user->create_many( 3, array(
     1052                        'role' => 'editor',
     1053                ) );
     1054
     1055                $users = get_users( array(
     1056                        'role' => 'subscriber, editor',
     1057                ) );
     1058
     1059                $this->assertEmpty( $users );
     1060
     1061                foreach ( $subscribers as $subscriber ) {
     1062                        $subscriber = get_user_by( 'ID', $subscriber );
     1063                        $subscriber->add_role( 'editor' );
     1064                }
     1065
     1066                $users = get_users( array(
     1067                        'role' => 'subscriber, editor',
     1068                ) );
     1069
     1070                $this->assertEquals( 2, count( $users ) );
     1071        }
     1072
     1073        /**
     1074         * @ticket 22212
     1075         */
     1076        public function test_get_multiple_roles_with_meta() {
     1077                // Create administrator user + meta
     1078                $administrator_id = $this->factory->user->create( array( 'role' => 'administrator' ) );
     1079                update_user_meta( $administrator_id, 'mk1', 1 );
     1080                update_user_meta( $administrator_id, 'mk2', 1 );
     1081
     1082                // Create editor user + meta
     1083                $editor_id = $this->factory->user->create( array( 'role' => 'editor' ) );
     1084                update_user_meta( $editor_id, 'mk1', 1 );
     1085                update_user_meta( $editor_id, 'mk2', 2 );
     1086
     1087                // Create subscriber user + meta
     1088                $subscriber_id = $this->factory->user->create( array( 'role' => 'subscriber' ) );
     1089                update_user_meta( $subscriber_id, 'mk1', 1 );
     1090                update_user_meta( $subscriber_id, 'mk2', 1 );
     1091
     1092                // Create contributor user + meta
     1093                $contributor_id = $this->factory->user->create( array( 'role' => 'contributor' ) );
     1094                update_user_meta( $contributor_id, 'mk1', 1 );
     1095                update_user_meta( $contributor_id, 'mk2', 2 );
     1096
     1097                // Fetch users
     1098                $users = get_users( array(
     1099                        'role__in'   => array( 'administrator', 'editor', 'subscriber' ),
     1100                        'meta_query' => array(
     1101                                'relation' => 'AND',
     1102                                array(
     1103                                        'key'     => 'mk1',
     1104                                        'value'   => '1',
     1105                                        'compare' => "=",
     1106                                        'type'    => 'numeric',
     1107                                ),
     1108                                array(
     1109                                        'key'     => 'mk2',
     1110                                        'value'   => '2',
     1111                                        'compare' => "=",
     1112                                        'type'    => 'numeric',
     1113                                ),
     1114                        ),
     1115                ) );
     1116
     1117                // Check results
     1118                $this->assertEquals( 1, count( $users ) );
     1119                $this->assertSame( $editor_id, (int) $users[0]->ID );
     1120        }
     1121
     1122        /**
     1123         * @ticket 22212
     1124         */
     1125        public function test_role_exclusion() {
     1126                $this->factory->user->create_many( 2, array(
     1127                        'role' => 'subscriber',
     1128                ) );
     1129
     1130                $this->factory->user->create_many( 3, array(
     1131                        'role' => 'editor',
     1132                ) );
     1133
     1134                $users = get_users( array(
     1135                        'role__not_in' => 'subscriber',
     1136                ) );
     1137
     1138                // +1 for the default user created during installation.
     1139                $this->assertEquals( 4, count( $users ) );
     1140
     1141                $users = get_users( array(
     1142                        'role__not_in' => 'editor',
     1143                ) );
     1144
     1145                // +1 for the default user created during installation.
     1146                $this->assertEquals( 3, count( $users ) );
     1147        }
     1148
     1149        /**
     1150         * @ticket 22212
     1151         */
     1152        public function test_role__in_role__not_in_combined() {
     1153                $subscribers = $this->factory->user->create_many( 2, array(
     1154                        'role' => 'subscriber',
     1155                ) );
     1156
     1157                $this->factory->user->create_many( 3, array(
     1158                        'role' => 'editor',
     1159                ) );
     1160
     1161                foreach ( $subscribers as $subscriber ) {
     1162                        $subscriber = get_user_by( 'ID', $subscriber );
     1163                        $subscriber->add_role( 'editor' );
     1164                }
     1165
     1166                $users = get_users( array(
     1167                        'role__in'     => 'editor',
     1168                ) );
     1169
     1170                $this->assertEquals( 5, count( $users ) );
     1171
     1172                $users = get_users( array(
     1173                        'role__in'     => 'editor',
     1174                        'role__not_in' => 'subscriber',
     1175                ) );
     1176
     1177                $this->assertEquals( 3, count( $users ) );
     1178        }
     1179
     1180        /**
     1181         * @ticket 22212
     1182         */
     1183        public function test_role__not_in_role_combined() {
     1184                $subscribers = $this->factory->user->create_many( 2, array(
     1185                        'role' => 'subscriber',
     1186                ) );
     1187
     1188                $this->factory->user->create_many( 3, array(
     1189                        'role' => 'editor',
     1190                ) );
     1191
     1192                $subscriber = get_user_by( 'ID', $subscribers[0] );
     1193                $subscriber->add_role( 'editor' );
     1194
     1195                $users = get_users( array(
     1196                        'role'         => 'subscriber',
     1197                        'role__not_in' => array( 'editor' ),
     1198                ) );
     1199
     1200                $this->assertEquals( 1, count( $users ) );
     1201        }
     1202
     1203        /**
     1204         * @ticket 22212
     1205         */
     1206        public function test_role__not_in_user_without_role() {
     1207                $user_without_rule = $this->factory->user->get_object_by_id( $this->factory->user->create( array(
     1208                        'role' => 'subscriber',
     1209                ) ) );
     1210
     1211                $user_without_rule->remove_role( 'subscriber' );
     1212
     1213                $this->factory->user->create_many( 3, array(
     1214                        'role' => 'editor',
     1215                ) );
     1216
     1217                $users = get_users( array(
     1218                        'role__not_in' => 'subscriber',
     1219                ) );
     1220
     1221                // +1 for the default user created during installation.
     1222                $this->assertEquals( 5, count( $users ) );
     1223
     1224                $users = get_users( array(
     1225                        'role__not_in' => 'editor',
     1226                ) );
     1227
     1228                // +1 for the default user created during installation.
     1229                $this->assertEquals( 2, count( $users ) );
     1230        }
     1231
     1232        /**
     1233         * @ticket 22212
     1234         */
     1235        public function test_blog_id_should_restrict_by_blog_without_requiring_a_named_role() {
     1236                if ( ! is_multisite() ) {
     1237                        $this->markTestSkipped( __METHOD__ . ' requires multisite.' );
     1238                }
     1239
     1240                $sites = $this->factory->blog->create_many( 2 );
     1241                $users = $this->factory->user->create_many( 2 );
     1242
     1243                add_user_to_blog( $sites[0], $users[0], 'author' );
     1244                add_user_to_blog( $sites[1], $users[1], 'author' );
     1245
     1246                $found = get_users( array(
     1247                        'blog_id' => $sites[1],
     1248                        'fields' => 'ID',
     1249                ) );
     1250
     1251                $this->assertEqualSets( array( $users[1] ), $found );
     1252        }
    8991253}