Make WordPress Core

Changeset 34875


Ignore:
Timestamp:
10/06/2015 05:39:23 PM (11 years ago)
Author:
boonebgorges
Message:

Improve role-related arguments in WP_User_Query.

  • 'role' now accepts an array or comma-separated list of role names. When passing multiple values for 'role', WP_User_Query will only match users that have all of the specified roles.
  • 'rolein' accepts an array of role names, and allow the filtering of matched users to those with at least one of the specified roles.
  • 'rolenot_in' accepts an array of role names, and allows the filtering of matched users to those who have none of the specified roles.

Props swissspidy, mordauk, barrykooij, sirbrillig.
Fixes #22212.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-user-query.php

    r34804 r34875  
    8989                        'blog_id' => $GLOBALS['blog_id'],
    9090                        'role' => '',
     91                        'role__in' => array(),
     92                        'role__not_in' => array(),
    9193                        'meta_key' => '',
    9294                        'meta_value' => '',
     
    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         *
     
    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.
     
    260269                $this->meta_query->parse_query_vars( $qv );
    261270
    262                 $role = '';
     271                $roles = array();
    263272                if ( isset( $qv['role'] ) ) {
    264                         $role = trim( $qv['role'] );
    265                 }
    266 
    267                 if ( $blog_id && ( $role || is_multisite() ) ) {
    268                         $cap_meta_query = array();
    269                         $cap_meta_query['key'] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
    270 
    271                         if ( $role ) {
    272                                 $cap_meta_query['value'] = '"' . $role . '"';
    273                                 $cap_meta_query['compare'] = 'like';
     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'];
     283                }
     284
     285                $role__not_in = array();
     286                if ( isset( $qv['role__not_in'] ) ) {
     287                        $role__not_in = (array) $qv['role__not_in'];
     288                }
     289
     290                if ( $blog_id && ( ! empty( $roles ) || ! empty( $role__in ) || ! empty( $role__not_in ) || is_multisite() ) ) {
     291                        $role_queries  = array( 'relation' => 'AND' );
     292                        $roles_clauses = array( 'relation' => 'AND' );
     293                        if ( ! empty( $roles ) ) {
     294                                foreach ( $roles as $role ) {
     295                                        $roles_clauses[] = array(
     296                                                'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
     297                                                'value'   => $role,
     298                                                'compare' => 'LIKE',
     299                                        );
     300                                }
     301
     302                                // Sanity check: this clause may already have been added to the meta_query.
     303                                if ( empty( $this->meta_query->clauses ) || ! in_array( $roles_clauses, $this->meta_query_clauses, true ) ) {
     304                                        $role_queries[] = $roles_clauses;
     305                                }
     306                        }
     307
     308                        $role__in_clauses = array( 'relation' => 'OR' );
     309                        if ( ! empty( $role__in ) ) {
     310                                foreach ( $role__in as $role ) {
     311                                        $role__in_clauses[] = array(
     312                                                'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
     313                                                'value'   => $role,
     314                                                'compare' => 'LIKE',
     315                                        );
     316                                }
     317
     318                                $role_queries[] = $role__in_clauses;
     319                        }
     320
     321                        $role__not_in_clauses = array( 'relation' => 'AND' );
     322                        if ( ! empty( $role__not_in ) ) {
     323                                foreach ( $role__not_in as $role ) {
     324                                        $role__not_in_clauses[] = array(
     325                                                'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
     326                                                'value'   => $role,
     327                                                'compare' => 'NOT LIKE',
     328                                        );
     329                                }
     330
     331                                $role_queries[] = $role__not_in_clauses;
    274332                        }
    275333
    276334                        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 ) ) {
     335                                $this->meta_query->queries = $role_queries;
     336                        } else {
    279337                                // Append the cap query to the original queries and reparse the query.
    280338                                $this->meta_query->queries = array(
    281339                                        'relation' => 'AND',
    282                                         array( $this->meta_query->queries, $cap_meta_query ),
     340                                        array( $this->meta_query->queries, $role_queries ),
    283341                                );
    284342                        }
  • trunk/tests/phpunit/tests/user/query.php

    r34804 r34875  
    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        }
    8991231}
Note: See TracChangeset for help on using the changeset viewer.