wp/wp-includes/class-wp-user-query.php
changeset 19 3d72ae0968f4
parent 18 be944660c56a
child 21 48c4eec2b7e6
equal deleted inserted replaced
18:be944660c56a 19:3d72ae0968f4
    91 		$defaults = array(
    91 		$defaults = array(
    92 			'blog_id'             => get_current_blog_id(),
    92 			'blog_id'             => get_current_blog_id(),
    93 			'role'                => '',
    93 			'role'                => '',
    94 			'role__in'            => array(),
    94 			'role__in'            => array(),
    95 			'role__not_in'        => array(),
    95 			'role__not_in'        => array(),
       
    96 			'capability'          => '',
       
    97 			'capability__in'      => array(),
       
    98 			'capability__not_in'  => array(),
    96 			'meta_key'            => '',
    99 			'meta_key'            => '',
    97 			'meta_value'          => '',
   100 			'meta_value'          => '',
    98 			'meta_compare'        => '',
   101 			'meta_compare'        => '',
    99 			'include'             => array(),
   102 			'include'             => array(),
   100 			'exclude'             => array(),
   103 			'exclude'             => array(),
   119 
   122 
   120 		return wp_parse_args( $args, $defaults );
   123 		return wp_parse_args( $args, $defaults );
   121 	}
   124 	}
   122 
   125 
   123 	/**
   126 	/**
   124 	 * Prepare the query variables.
   127 	 * Prepares the query variables.
   125 	 *
   128 	 *
   126 	 * @since 3.1.0
   129 	 * @since 3.1.0
   127 	 * @since 4.1.0 Added the ability to order by the `include` value.
   130 	 * @since 4.1.0 Added the ability to order by the `include` value.
   128 	 * @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax
   131 	 * @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax
   129 	 *              for `$orderby` parameter.
   132 	 *              for `$orderby` parameter.
   131 	 * @since 4.4.0 Added 'paged', 'role__in', and 'role__not_in' parameters. The 'role' parameter was updated to
   134 	 * @since 4.4.0 Added 'paged', 'role__in', and 'role__not_in' parameters. The 'role' parameter was updated to
   132 	 *              permit an array or comma-separated list of values. The 'number' parameter was updated to support
   135 	 *              permit an array or comma-separated list of values. The 'number' parameter was updated to support
   133 	 *              querying for all users with using -1.
   136 	 *              querying for all users with using -1.
   134 	 * @since 4.7.0 Added 'nicename', 'nicename__in', 'nicename__not_in', 'login', 'login__in',
   137 	 * @since 4.7.0 Added 'nicename', 'nicename__in', 'nicename__not_in', 'login', 'login__in',
   135 	 *              and 'login__not_in' parameters.
   138 	 *              and 'login__not_in' parameters.
       
   139 	 * @since 5.1.0 Introduced the 'meta_compare_key' parameter.
       
   140 	 * @since 5.3.0 Introduced the 'meta_type_key' parameter.
       
   141 	 * @since 5.9.0 Added 'capability', 'capability__in', and 'capability__not_in' parameters.
   136 	 *
   142 	 *
   137 	 * @global wpdb $wpdb WordPress database abstraction object.
   143 	 * @global wpdb $wpdb WordPress database abstraction object.
   138 	 * @global int  $blog_id
   144 	 * @global int  $blog_id
   139 	 *
   145 	 *
   140 	 * @param string|array $query {
   146 	 * @param string|array $query {
   141 	 *     Optional. Array or string of Query parameters.
   147 	 *     Optional. Array or string of Query parameters.
   142 	 *
   148 	 *
   143 	 *     @type int          $blog_id             The site ID. Default is the current site.
   149 	 *     @type int             $blog_id             The site ID. Default is the current site.
   144 	 *     @type string|array $role                An array or a comma-separated list of role names that users must match
   150 	 *     @type string|string[] $role                An array or a comma-separated list of role names that users must match
   145 	 *                                             to be included in results. Note that this is an inclusive list: users
   151 	 *                                                to be included in results. Note that this is an inclusive list: users
   146 	 *                                             must match *each* role. Default empty.
   152 	 *                                                must match *each* role. Default empty.
   147 	 *     @type string[]     $role__in            An array of role names. Matched users must have at least one of these
   153 	 *     @type string[]        $role__in            An array of role names. Matched users must have at least one of these
   148 	 *                                             roles. Default empty array.
   154 	 *                                                roles. Default empty array.
   149 	 *     @type string[]     $role__not_in        An array of role names to exclude. Users matching one or more of these
   155 	 *     @type string[]        $role__not_in        An array of role names to exclude. Users matching one or more of these
   150 	 *                                             roles will not be included in results. Default empty array.
   156 	 *                                                roles will not be included in results. Default empty array.
   151 	 *     @type string       $meta_key            User meta key. Default empty.
   157 	 *     @type string|string[] $meta_key            Meta key or keys to filter by.
   152 	 *     @type string       $meta_value          User meta value. Default empty.
   158 	 *     @type string|string[] $meta_value          Meta value or values to filter by.
   153 	 *     @type string       $meta_compare        Comparison operator to test the `$meta_value`. Accepts '=', '!=',
   159 	 *     @type string          $meta_compare        MySQL operator used for comparing the meta value.
   154 	 *                                             '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN',
   160 	 *                                                See WP_Meta_Query::__construct for accepted values and default value.
   155 	 *                                             'BETWEEN', 'NOT BETWEEN', 'EXISTS', 'NOT EXISTS', 'REGEXP',
   161 	 *     @type string          $meta_compare_key    MySQL operator used for comparing the meta key.
   156 	 *                                             'NOT REGEXP', or 'RLIKE'. Default '='.
   162 	 *                                                See WP_Meta_Query::__construct for accepted values and default value.
   157 	 *     @type int[]        $include             An array of user IDs to include. Default empty array.
   163 	 *     @type string          $meta_type           MySQL data type that the meta_value column will be CAST to for comparisons.
   158 	 *     @type int[]        $exclude             An array of user IDs to exclude. Default empty array.
   164 	 *                                                See WP_Meta_Query::__construct for accepted values and default value.
   159 	 *     @type string       $search              Search keyword. Searches for possible string matches on columns.
   165 	 *     @type string          $meta_type_key       MySQL data type that the meta_key column will be CAST to for comparisons.
   160 	 *                                             When `$search_columns` is left empty, it tries to determine which
   166 	 *                                                See WP_Meta_Query::__construct for accepted values and default value.
   161 	 *                                             column to search in based on search string. Default empty.
   167 	 *     @type array           $meta_query          An associative array of WP_Meta_Query arguments.
   162 	 *     @type string[]     $search_columns      Array of column names to be searched. Accepts 'ID', 'user_login',
   168 	 *                                                See WP_Meta_Query::__construct for accepted values.
   163 	 *                                             'user_email', 'user_url', 'user_nicename', 'display_name'.
   169 	 *     @type string|string[] $capability          An array or a comma-separated list of capability names that users must match
   164 	 *                                             Default empty array.
   170 	 *                                                to be included in results. Note that this is an inclusive list: users
   165 	 *     @type string|array $orderby             Field(s) to sort the retrieved users by. May be a single value,
   171 	 *                                                must match *each* capability.
   166 	 *                                             an array of values, or a multi-dimensional array with fields as
   172 	 *                                                Does NOT work for capabilities not in the database or filtered via {@see 'map_meta_cap'}.
   167 	 *                                             keys and orders ('ASC' or 'DESC') as values. Accepted values are
   173 	 *                                                Default empty.
   168 	 *                                             'ID', 'display_name' (or 'name'), 'include', 'user_login'
   174 	 *     @type string[]        $capability__in      An array of capability names. Matched users must have at least one of these
   169 	 *                                             (or 'login'), 'login__in', 'user_nicename' (or 'nicename'),
   175 	 *                                                capabilities.
   170 	 *                                             'nicename__in', 'user_email (or 'email'), 'user_url' (or 'url'),
   176 	 *                                                Does NOT work for capabilities not in the database or filtered via {@see 'map_meta_cap'}.
   171 	 *                                             'user_registered' (or 'registered'), 'post_count', 'meta_value',
   177 	 *                                                Default empty array.
   172 	 *                                             'meta_value_num', the value of `$meta_key`, or an array key of
   178 	 *     @type string[]        $capability__not_in  An array of capability names to exclude. Users matching one or more of these
   173 	 *                                             `$meta_query`. To use 'meta_value' or 'meta_value_num', `$meta_key`
   179 	 *                                                capabilities will not be included in results.
   174 	 *                                             must be also be defined. Default 'user_login'.
   180 	 *                                                Does NOT work for capabilities not in the database or filtered via {@see 'map_meta_cap'}.
   175 	 *     @type string       $order               Designates ascending or descending order of users. Order values
   181 	 *                                                Default empty array.
   176 	 *                                             passed as part of an `$orderby` array take precedence over this
   182 	 *     @type int[]           $include             An array of user IDs to include. Default empty array.
   177 	 *                                             parameter. Accepts 'ASC', 'DESC'. Default 'ASC'.
   183 	 *     @type int[]           $exclude             An array of user IDs to exclude. Default empty array.
   178 	 *     @type int          $offset              Number of users to offset in retrieved results. Can be used in
   184 	 *     @type string          $search              Search keyword. Searches for possible string matches on columns.
   179 	 *                                             conjunction with pagination. Default 0.
   185 	 *                                                When `$search_columns` is left empty, it tries to determine which
   180 	 *     @type int          $number              Number of users to limit the query for. Can be used in
   186 	 *                                                column to search in based on search string. Default empty.
   181 	 *                                             conjunction with pagination. Value -1 (all) is supported, but
   187 	 *     @type string[]        $search_columns      Array of column names to be searched. Accepts 'ID', 'user_login',
   182 	 *                                             should be used with caution on larger sites.
   188 	 *                                                'user_email', 'user_url', 'user_nicename', 'display_name'.
   183 	 *                                             Default -1 (all users).
   189 	 *                                                Default empty array.
   184 	 *     @type int          $paged               When used with number, defines the page of results to return.
   190 	 *     @type string|array    $orderby             Field(s) to sort the retrieved users by. May be a single value,
   185 	 *                                             Default 1.
   191 	 *                                                an array of values, or a multi-dimensional array with fields as
   186 	 *     @type bool         $count_total         Whether to count the total number of users found. If pagination
   192 	 *                                                keys and orders ('ASC' or 'DESC') as values. Accepted values are:
   187 	 *                                             is not needed, setting this to false can improve performance.
   193 	 *                                                - 'ID'
   188 	 *                                             Default true.
   194 	 *                                                - 'display_name' (or 'name')
   189 	 *     @type string|array $fields              Which fields to return. Single or all fields (string), or array
   195 	 *                                                - 'include'
   190 	 *                                             of fields. Accepts 'ID', 'display_name', 'user_login',
   196 	 *                                                - 'user_login' (or 'login')
   191 	 *                                             'user_nicename', 'user_email', 'user_url', 'user_registered'.
   197 	 *                                                - 'login__in'
   192 	 *                                             Use 'all' for all fields and 'all_with_meta' to include
   198 	 *                                                - 'user_nicename' (or 'nicename'),
   193 	 *                                             meta fields. Default 'all'.
   199 	 *                                                - 'nicename__in'
   194 	 *     @type string       $who                 Type of users to query. Accepts 'authors'.
   200 	 *                                                - 'user_email (or 'email')
   195 	 *                                             Default empty (all users).
   201 	 *                                                - 'user_url' (or 'url'),
   196 	 *     @type bool|array   $has_published_posts Pass an array of post types to filter results to users who have
   202 	 *                                                - 'user_registered' (or 'registered')
   197 	 *                                             published posts in those post types. `true` is an alias for all
   203 	 *                                                - 'post_count'
   198 	 *                                             public post types.
   204 	 *                                                - 'meta_value',
   199 	 *     @type string       $nicename            The user nicename. Default empty.
   205 	 *                                                - 'meta_value_num'
   200 	 *     @type string[]     $nicename__in        An array of nicenames to include. Users matching one of these
   206 	 *                                                - The value of `$meta_key`
   201 	 *                                             nicenames will be included in results. Default empty array.
   207 	 *                                                - An array key of `$meta_query`
   202 	 *     @type string[]     $nicename__not_in    An array of nicenames to exclude. Users matching one of these
   208 	 *                                                To use 'meta_value' or 'meta_value_num', `$meta_key`
   203 	 *                                             nicenames will not be included in results. Default empty array.
   209 	 *                                                must be also be defined. Default 'user_login'.
   204 	 *     @type string       $login               The user login. Default empty.
   210 	 *     @type string          $order               Designates ascending or descending order of users. Order values
   205 	 *     @type string[]     $login__in           An array of logins to include. Users matching one of these
   211 	 *                                                passed as part of an `$orderby` array take precedence over this
   206 	 *                                             logins will be included in results. Default empty array.
   212 	 *                                                parameter. Accepts 'ASC', 'DESC'. Default 'ASC'.
   207 	 *     @type string[]     $login__not_in       An array of logins to exclude. Users matching one of these
   213 	 *     @type int             $offset              Number of users to offset in retrieved results. Can be used in
   208 	 *                                             logins will not be included in results. Default empty array.
   214 	 *                                                conjunction with pagination. Default 0.
       
   215 	 *     @type int             $number              Number of users to limit the query for. Can be used in
       
   216 	 *                                                conjunction with pagination. Value -1 (all) is supported, but
       
   217 	 *                                                should be used with caution on larger sites.
       
   218 	 *                                                Default -1 (all users).
       
   219 	 *     @type int             $paged               When used with number, defines the page of results to return.
       
   220 	 *                                                Default 1.
       
   221 	 *     @type bool            $count_total         Whether to count the total number of users found. If pagination
       
   222 	 *                                                is not needed, setting this to false can improve performance.
       
   223 	 *                                                Default true.
       
   224 	 *     @type string|string[] $fields              Which fields to return. Single or all fields (string), or array
       
   225 	 *                                                of fields. Accepts:
       
   226 	 *                                                - 'ID'
       
   227 	 *                                                - 'display_name'
       
   228 	 *                                                - 'user_login'
       
   229 	 *                                                - 'user_nicename'
       
   230 	 *                                                - 'user_email'
       
   231 	 *                                                - 'user_url'
       
   232 	 *                                                - 'user_registered'
       
   233 	 *                                                - 'user_pass'
       
   234 	 *                                                - 'user_activation_key'
       
   235 	 *                                                - 'user_status'
       
   236 	 *                                                - 'spam' (only available on multisite installs)
       
   237 	 *                                                - 'deleted' (only available on multisite installs)
       
   238 	 *                                                - 'all' for all fields
       
   239 	 *                                                - 'all_with_meta' to include meta fields.
       
   240 	 *                                                Default 'all'.
       
   241 	 *     @type string          $who                 Type of users to query. Accepts 'authors'.
       
   242 	 *                                                Default empty (all users).
       
   243 	 *     @type bool|string[]   $has_published_posts Pass an array of post types to filter results to users who have
       
   244 	 *                                                published posts in those post types. `true` is an alias for all
       
   245 	 *                                                public post types.
       
   246 	 *     @type string          $nicename            The user nicename. Default empty.
       
   247 	 *     @type string[]        $nicename__in        An array of nicenames to include. Users matching one of these
       
   248 	 *                                                nicenames will be included in results. Default empty array.
       
   249 	 *     @type string[]        $nicename__not_in    An array of nicenames to exclude. Users matching one of these
       
   250 	 *                                                nicenames will not be included in results. Default empty array.
       
   251 	 *     @type string          $login               The user login. Default empty.
       
   252 	 *     @type string[]        $login__in           An array of logins to include. Users matching one of these
       
   253 	 *                                                logins will be included in results. Default empty array.
       
   254 	 *     @type string[]        $login__not_in       An array of logins to exclude. Users matching one of these
       
   255 	 *                                                logins will not be included in results. Default empty array.
   209 	 * }
   256 	 * }
   210 	 */
   257 	 */
   211 	public function prepare_query( $query = array() ) {
   258 	public function prepare_query( $query = array() ) {
   212 		global $wpdb;
   259 		global $wpdb;
   213 
   260 
   230 
   277 
   231 		// Ensure that query vars are filled after 'pre_get_users'.
   278 		// Ensure that query vars are filled after 'pre_get_users'.
   232 		$qv =& $this->query_vars;
   279 		$qv =& $this->query_vars;
   233 		$qv = $this->fill_query_vars( $qv );
   280 		$qv = $this->fill_query_vars( $qv );
   234 
   281 
       
   282 		$allowed_fields = array(
       
   283 			'id',
       
   284 			'user_login',
       
   285 			'user_pass',
       
   286 			'user_nicename',
       
   287 			'user_email',
       
   288 			'user_url',
       
   289 			'user_registered',
       
   290 			'user_activation_key',
       
   291 			'user_status',
       
   292 			'display_name',
       
   293 		);
       
   294 		if ( is_multisite() ) {
       
   295 			$allowed_fields[] = 'spam';
       
   296 			$allowed_fields[] = 'deleted';
       
   297 		}
       
   298 
   235 		if ( is_array( $qv['fields'] ) ) {
   299 		if ( is_array( $qv['fields'] ) ) {
   236 			$qv['fields'] = array_unique( $qv['fields'] );
   300 			$qv['fields'] = array_map( 'strtolower', $qv['fields'] );
       
   301 			$qv['fields'] = array_intersect( array_unique( $qv['fields'] ), $allowed_fields );
       
   302 
       
   303 			if ( empty( $qv['fields'] ) ) {
       
   304 				$qv['fields'] = array( 'id' );
       
   305 			}
   237 
   306 
   238 			$this->query_fields = array();
   307 			$this->query_fields = array();
   239 			foreach ( $qv['fields'] as $field ) {
   308 			foreach ( $qv['fields'] as $field ) {
   240 				$field                = 'ID' === $field ? 'ID' : sanitize_key( $field );
   309 				$field                = 'id' === $field ? 'ID' : sanitize_key( $field );
   241 				$this->query_fields[] = "$wpdb->users.$field";
   310 				$this->query_fields[] = "$wpdb->users.$field";
   242 			}
   311 			}
   243 			$this->query_fields = implode( ',', $this->query_fields );
   312 			$this->query_fields = implode( ',', $this->query_fields );
   244 		} elseif ( 'all' === $qv['fields'] ) {
   313 		} elseif ( 'all' === $qv['fields'] ) {
   245 			$this->query_fields = "$wpdb->users.*";
   314 			$this->query_fields = "$wpdb->users.*";
       
   315 		} elseif ( ! in_array( $qv['fields'], $allowed_fields, true ) ) {
       
   316 			$this->query_fields = "$wpdb->users.ID";
   246 		} else {
   317 		} else {
   247 			$this->query_fields = "$wpdb->users.ID";
   318 			$field              = 'id' === strtolower( $qv['fields'] ) ? 'ID' : sanitize_key( $qv['fields'] );
       
   319 			$this->query_fields = "$wpdb->users.$field";
   248 		}
   320 		}
   249 
   321 
   250 		if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
   322 		if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
   251 			$this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields;
   323 			$this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields;
   252 		}
   324 		}
   318 		// Meta query.
   390 		// Meta query.
   319 		$this->meta_query = new WP_Meta_Query();
   391 		$this->meta_query = new WP_Meta_Query();
   320 		$this->meta_query->parse_query_vars( $qv );
   392 		$this->meta_query->parse_query_vars( $qv );
   321 
   393 
   322 		if ( isset( $qv['who'] ) && 'authors' === $qv['who'] && $blog_id ) {
   394 		if ( isset( $qv['who'] ) && 'authors' === $qv['who'] && $blog_id ) {
       
   395 			_deprecated_argument(
       
   396 				'WP_User_Query',
       
   397 				'5.9.0',
       
   398 				sprintf(
       
   399 					/* translators: 1: who, 2: capability */
       
   400 					__( '%1$s is deprecated. Use %2$s instead.' ),
       
   401 					'<code>who</code>',
       
   402 					'<code>capability</code>'
       
   403 				)
       
   404 			);
       
   405 
   323 			$who_query = array(
   406 			$who_query = array(
   324 				'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'user_level',
   407 				'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'user_level',
   325 				'value'   => 0,
   408 				'value'   => 0,
   326 				'compare' => '!=',
   409 				'compare' => '!=',
   327 			);
   410 			);
   341 			}
   424 			}
   342 
   425 
   343 			$this->meta_query->parse_query_vars( $this->meta_query->queries );
   426 			$this->meta_query->parse_query_vars( $this->meta_query->queries );
   344 		}
   427 		}
   345 
   428 
       
   429 		// Roles.
   346 		$roles = array();
   430 		$roles = array();
   347 		if ( isset( $qv['role'] ) ) {
   431 		if ( isset( $qv['role'] ) ) {
   348 			if ( is_array( $qv['role'] ) ) {
   432 			if ( is_array( $qv['role'] ) ) {
   349 				$roles = $qv['role'];
   433 				$roles = $qv['role'];
   350 			} elseif ( is_string( $qv['role'] ) && ! empty( $qv['role'] ) ) {
   434 			} elseif ( is_string( $qv['role'] ) && ! empty( $qv['role'] ) ) {
   358 		}
   442 		}
   359 
   443 
   360 		$role__not_in = array();
   444 		$role__not_in = array();
   361 		if ( isset( $qv['role__not_in'] ) ) {
   445 		if ( isset( $qv['role__not_in'] ) ) {
   362 			$role__not_in = (array) $qv['role__not_in'];
   446 			$role__not_in = (array) $qv['role__not_in'];
       
   447 		}
       
   448 
       
   449 		// Capabilities.
       
   450 		$available_roles = array();
       
   451 
       
   452 		if ( ! empty( $qv['capability'] ) || ! empty( $qv['capability__in'] ) || ! empty( $qv['capability__not_in'] ) ) {
       
   453 			global $wp_roles;
       
   454 
       
   455 			$wp_roles->for_site( $blog_id );
       
   456 			$available_roles = $wp_roles->roles;
       
   457 		}
       
   458 
       
   459 		$capabilities = array();
       
   460 		if ( ! empty( $qv['capability'] ) ) {
       
   461 			if ( is_array( $qv['capability'] ) ) {
       
   462 				$capabilities = $qv['capability'];
       
   463 			} elseif ( is_string( $qv['capability'] ) ) {
       
   464 				$capabilities = array_map( 'trim', explode( ',', $qv['capability'] ) );
       
   465 			}
       
   466 		}
       
   467 
       
   468 		$capability__in = array();
       
   469 		if ( ! empty( $qv['capability__in'] ) ) {
       
   470 			$capability__in = (array) $qv['capability__in'];
       
   471 		}
       
   472 
       
   473 		$capability__not_in = array();
       
   474 		if ( ! empty( $qv['capability__not_in'] ) ) {
       
   475 			$capability__not_in = (array) $qv['capability__not_in'];
       
   476 		}
       
   477 
       
   478 		// Keep track of all capabilities and the roles they're added on.
       
   479 		$caps_with_roles = array();
       
   480 
       
   481 		foreach ( $available_roles as $role => $role_data ) {
       
   482 			$role_caps = array_keys( array_filter( $role_data['capabilities'] ) );
       
   483 
       
   484 			foreach ( $capabilities as $cap ) {
       
   485 				if ( in_array( $cap, $role_caps, true ) ) {
       
   486 					$caps_with_roles[ $cap ][] = $role;
       
   487 					break;
       
   488 				}
       
   489 			}
       
   490 
       
   491 			foreach ( $capability__in as $cap ) {
       
   492 				if ( in_array( $cap, $role_caps, true ) ) {
       
   493 					$role__in[] = $role;
       
   494 					break;
       
   495 				}
       
   496 			}
       
   497 
       
   498 			foreach ( $capability__not_in as $cap ) {
       
   499 				if ( in_array( $cap, $role_caps, true ) ) {
       
   500 					$role__not_in[] = $role;
       
   501 					break;
       
   502 				}
       
   503 			}
       
   504 		}
       
   505 
       
   506 		$role__in     = array_merge( $role__in, $capability__in );
       
   507 		$role__not_in = array_merge( $role__not_in, $capability__not_in );
       
   508 
       
   509 		$roles        = array_unique( $roles );
       
   510 		$role__in     = array_unique( $role__in );
       
   511 		$role__not_in = array_unique( $role__not_in );
       
   512 
       
   513 		// Support querying by capabilities added directly to users.
       
   514 		if ( $blog_id && ! empty( $capabilities ) ) {
       
   515 			$capabilities_clauses = array( 'relation' => 'AND' );
       
   516 
       
   517 			foreach ( $capabilities as $cap ) {
       
   518 				$clause = array( 'relation' => 'OR' );
       
   519 
       
   520 				$clause[] = array(
       
   521 					'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
       
   522 					'value'   => '"' . $cap . '"',
       
   523 					'compare' => 'LIKE',
       
   524 				);
       
   525 
       
   526 				if ( ! empty( $caps_with_roles[ $cap ] ) ) {
       
   527 					foreach ( $caps_with_roles[ $cap ] as $role ) {
       
   528 						$clause[] = array(
       
   529 							'key'     => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
       
   530 							'value'   => '"' . $role . '"',
       
   531 							'compare' => 'LIKE',
       
   532 						);
       
   533 					}
       
   534 				}
       
   535 
       
   536 				$capabilities_clauses[] = $clause;
       
   537 			}
       
   538 
       
   539 			$role_queries[] = $capabilities_clauses;
       
   540 
       
   541 			if ( empty( $this->meta_query->queries ) ) {
       
   542 				$this->meta_query->queries[] = $capabilities_clauses;
       
   543 			} else {
       
   544 				// Append the cap query to the original queries and reparse the query.
       
   545 				$this->meta_query->queries = array(
       
   546 					'relation' => 'AND',
       
   547 					array( $this->meta_query->queries, array( $capabilities_clauses ) ),
       
   548 				);
       
   549 			}
       
   550 
       
   551 			$this->meta_query->parse_query_vars( $this->meta_query->queries );
   363 		}
   552 		}
   364 
   553 
   365 		if ( $blog_id && ( ! empty( $roles ) || ! empty( $role__in ) || ! empty( $role__not_in ) || is_multisite() ) ) {
   554 		if ( $blog_id && ( ! empty( $roles ) || ! empty( $role__in ) || ! empty( $role__not_in ) || is_multisite() ) ) {
   366 			$role_queries = array();
   555 			$role_queries = array();
   367 
   556 
   579 		 */
   768 		 */
   580 		do_action_ref_array( 'pre_user_query', array( &$this ) );
   769 		do_action_ref_array( 'pre_user_query', array( &$this ) );
   581 	}
   770 	}
   582 
   771 
   583 	/**
   772 	/**
   584 	 * Execute the query, with the current variables.
   773 	 * Executes the query, with the current variables.
   585 	 *
   774 	 *
   586 	 * @since 3.1.0
   775 	 * @since 3.1.0
   587 	 *
   776 	 *
   588 	 * @global wpdb $wpdb WordPress database abstraction object.
   777 	 * @global wpdb $wpdb WordPress database abstraction object.
   589 	 */
   778 	 */
   609 		 * @param WP_User_Query $query   The WP_User_Query instance (passed by reference).
   798 		 * @param WP_User_Query $query   The WP_User_Query instance (passed by reference).
   610 		 */
   799 		 */
   611 		$this->results = apply_filters_ref_array( 'users_pre_query', array( null, &$this ) );
   800 		$this->results = apply_filters_ref_array( 'users_pre_query', array( null, &$this ) );
   612 
   801 
   613 		if ( null === $this->results ) {
   802 		if ( null === $this->results ) {
   614 			$this->request = "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit";
   803 			$this->request = "
       
   804 				SELECT {$this->query_fields}
       
   805 				{$this->query_from}
       
   806 				{$this->query_where}
       
   807 				{$this->query_orderby}
       
   808 				{$this->query_limit}
       
   809 			";
   615 
   810 
   616 			if ( is_array( $qv['fields'] ) || 'all' === $qv['fields'] ) {
   811 			if ( is_array( $qv['fields'] ) || 'all' === $qv['fields'] ) {
   617 				$this->results = $wpdb->get_results( $this->request );
   812 				$this->results = $wpdb->get_results( $this->request );
   618 			} else {
   813 			} else {
   619 				$this->results = $wpdb->get_col( $this->request );
   814 				$this->results = $wpdb->get_col( $this->request );
   638 		}
   833 		}
   639 
   834 
   640 		if ( ! $this->results ) {
   835 		if ( ! $this->results ) {
   641 			return;
   836 			return;
   642 		}
   837 		}
   643 
   838 		if (
   644 		if ( 'all_with_meta' === $qv['fields'] ) {
   839 			is_array( $qv['fields'] ) &&
       
   840 			isset( $this->results[0]->ID )
       
   841 		) {
       
   842 			foreach ( $this->results as $result ) {
       
   843 				$result->id = $result->ID;
       
   844 			}
       
   845 		} elseif ( 'all_with_meta' === $qv['fields'] ) {
   645 			cache_users( $this->results );
   846 			cache_users( $this->results );
   646 
   847 
   647 			$r = array();
   848 			$r = array();
   648 			foreach ( $this->results as $userid ) {
   849 			foreach ( $this->results as $userid ) {
   649 				$r[ $userid ] = new WP_User( $userid, '', $qv['blog_id'] );
   850 				$r[ $userid ] = new WP_User( $userid, '', $qv['blog_id'] );
   656 			}
   857 			}
   657 		}
   858 		}
   658 	}
   859 	}
   659 
   860 
   660 	/**
   861 	/**
   661 	 * Retrieve query variable.
   862 	 * Retrieves query variable.
   662 	 *
   863 	 *
   663 	 * @since 3.5.0
   864 	 * @since 3.5.0
   664 	 *
   865 	 *
   665 	 * @param string $query_var Query variable key.
   866 	 * @param string $query_var Query variable key.
   666 	 * @return mixed
   867 	 * @return mixed
   672 
   873 
   673 		return null;
   874 		return null;
   674 	}
   875 	}
   675 
   876 
   676 	/**
   877 	/**
   677 	 * Set query variable.
   878 	 * Sets query variable.
   678 	 *
   879 	 *
   679 	 * @since 3.5.0
   880 	 * @since 3.5.0
   680 	 *
   881 	 *
   681 	 * @param string $query_var Query variable key.
   882 	 * @param string $query_var Query variable key.
   682 	 * @param mixed  $value     Query variable value.
   883 	 * @param mixed  $value     Query variable value.
   684 	public function set( $query_var, $value ) {
   885 	public function set( $query_var, $value ) {
   685 		$this->query_vars[ $query_var ] = $value;
   886 		$this->query_vars[ $query_var ] = $value;
   686 	}
   887 	}
   687 
   888 
   688 	/**
   889 	/**
   689 	 * Used internally to generate an SQL string for searching across multiple columns
   890 	 * Used internally to generate an SQL string for searching across multiple columns.
   690 	 *
   891 	 *
   691 	 * @since 3.1.0
   892 	 * @since 3.1.0
   692 	 *
   893 	 *
   693 	 * @global wpdb $wpdb WordPress database abstraction object.
   894 	 * @global wpdb $wpdb WordPress database abstraction object.
   694 	 *
   895 	 *
   695 	 * @param string $string
   896 	 * @param string   $search  Search string.
   696 	 * @param array  $cols
   897 	 * @param string[] $columns Array of columns to search.
   697 	 * @param bool   $wild   Whether to allow wildcard searches. Default is false for Network Admin, true for single site.
   898 	 * @param bool     $wild    Whether to allow wildcard searches. Default is false for Network Admin, true for single site.
   698 	 *                       Single site allows leading and trailing wildcards, Network Admin only trailing.
   899 	 *                          Single site allows leading and trailing wildcards, Network Admin only trailing.
   699 	 * @return string
   900 	 * @return string
   700 	 */
   901 	 */
   701 	protected function get_search_sql( $string, $cols, $wild = false ) {
   902 	protected function get_search_sql( $search, $columns, $wild = false ) {
   702 		global $wpdb;
   903 		global $wpdb;
   703 
   904 
   704 		$searches      = array();
   905 		$searches      = array();
   705 		$leading_wild  = ( 'leading' === $wild || 'both' === $wild ) ? '%' : '';
   906 		$leading_wild  = ( 'leading' === $wild || 'both' === $wild ) ? '%' : '';
   706 		$trailing_wild = ( 'trailing' === $wild || 'both' === $wild ) ? '%' : '';
   907 		$trailing_wild = ( 'trailing' === $wild || 'both' === $wild ) ? '%' : '';
   707 		$like          = $leading_wild . $wpdb->esc_like( $string ) . $trailing_wild;
   908 		$like          = $leading_wild . $wpdb->esc_like( $search ) . $trailing_wild;
   708 
   909 
   709 		foreach ( $cols as $col ) {
   910 		foreach ( $columns as $column ) {
   710 			if ( 'ID' === $col ) {
   911 			if ( 'ID' === $column ) {
   711 				$searches[] = $wpdb->prepare( "$col = %s", $string );
   912 				$searches[] = $wpdb->prepare( "$column = %s", $search );
   712 			} else {
   913 			} else {
   713 				$searches[] = $wpdb->prepare( "$col LIKE %s", $like );
   914 				$searches[] = $wpdb->prepare( "$column LIKE %s", $like );
   714 			}
   915 			}
   715 		}
   916 		}
   716 
   917 
   717 		return ' AND (' . implode( ' OR ', $searches ) . ')';
   918 		return ' AND (' . implode( ' OR ', $searches ) . ')';
   718 	}
   919 	}
   719 
   920 
   720 	/**
   921 	/**
   721 	 * Return the list of users.
   922 	 * Returns the list of users.
   722 	 *
   923 	 *
   723 	 * @since 3.1.0
   924 	 * @since 3.1.0
   724 	 *
   925 	 *
   725 	 * @return array Array of results.
   926 	 * @return array Array of results.
   726 	 */
   927 	 */
   727 	public function get_results() {
   928 	public function get_results() {
   728 		return $this->results;
   929 		return $this->results;
   729 	}
   930 	}
   730 
   931 
   731 	/**
   932 	/**
   732 	 * Return the total number of users for the current query.
   933 	 * Returns the total number of users for the current query.
   733 	 *
   934 	 *
   734 	 * @since 3.1.0
   935 	 * @since 3.1.0
   735 	 *
   936 	 *
   736 	 * @return int Number of total users.
   937 	 * @return int Number of total users.
   737 	 */
   938 	 */
   738 	public function get_total() {
   939 	public function get_total() {
   739 		return $this->total_users;
   940 		return $this->total_users;
   740 	}
   941 	}
   741 
   942 
   742 	/**
   943 	/**
   743 	 * Parse and sanitize 'orderby' keys passed to the user query.
   944 	 * Parses and sanitizes 'orderby' keys passed to the user query.
   744 	 *
   945 	 *
   745 	 * @since 4.2.0
   946 	 * @since 4.2.0
   746 	 *
   947 	 *
   747 	 * @global wpdb $wpdb WordPress database abstraction object.
   948 	 * @global wpdb $wpdb WordPress database abstraction object.
   748 	 *
   949 	 *
   797 
   998 
   798 		return $_orderby;
   999 		return $_orderby;
   799 	}
  1000 	}
   800 
  1001 
   801 	/**
  1002 	/**
   802 	 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
  1003 	 * Parses an 'order' query variable and casts it to ASC or DESC as necessary.
   803 	 *
  1004 	 *
   804 	 * @since 4.2.0
  1005 	 * @since 4.2.0
   805 	 *
  1006 	 *
   806 	 * @param string $order The 'order' query variable.
  1007 	 * @param string $order The 'order' query variable.
   807 	 * @return string The sanitized 'order' query variable.
  1008 	 * @return string The sanitized 'order' query variable.
   817 			return 'DESC';
  1018 			return 'DESC';
   818 		}
  1019 		}
   819 	}
  1020 	}
   820 
  1021 
   821 	/**
  1022 	/**
   822 	 * Make private properties readable for backward compatibility.
  1023 	 * Makes private properties readable for backward compatibility.
   823 	 *
  1024 	 *
   824 	 * @since 4.0.0
  1025 	 * @since 4.0.0
   825 	 *
  1026 	 *
   826 	 * @param string $name Property to get.
  1027 	 * @param string $name Property to get.
   827 	 * @return mixed Property.
  1028 	 * @return mixed Property.
   831 			return $this->$name;
  1032 			return $this->$name;
   832 		}
  1033 		}
   833 	}
  1034 	}
   834 
  1035 
   835 	/**
  1036 	/**
   836 	 * Make private properties settable for backward compatibility.
  1037 	 * Makes private properties settable for backward compatibility.
   837 	 *
  1038 	 *
   838 	 * @since 4.0.0
  1039 	 * @since 4.0.0
   839 	 *
  1040 	 *
   840 	 * @param string $name  Property to check if set.
  1041 	 * @param string $name  Property to check if set.
   841 	 * @param mixed  $value Property value.
  1042 	 * @param mixed  $value Property value.
   846 			return $this->$name = $value;
  1047 			return $this->$name = $value;
   847 		}
  1048 		}
   848 	}
  1049 	}
   849 
  1050 
   850 	/**
  1051 	/**
   851 	 * Make private properties checkable for backward compatibility.
  1052 	 * Makes private properties checkable for backward compatibility.
   852 	 *
  1053 	 *
   853 	 * @since 4.0.0
  1054 	 * @since 4.0.0
   854 	 *
  1055 	 *
   855 	 * @param string $name Property to check if set.
  1056 	 * @param string $name Property to check if set.
   856 	 * @return bool Whether the property is set.
  1057 	 * @return bool Whether the property is set.
   860 			return isset( $this->$name );
  1061 			return isset( $this->$name );
   861 		}
  1062 		}
   862 	}
  1063 	}
   863 
  1064 
   864 	/**
  1065 	/**
   865 	 * Make private properties un-settable for backward compatibility.
  1066 	 * Makes private properties un-settable for backward compatibility.
   866 	 *
  1067 	 *
   867 	 * @since 4.0.0
  1068 	 * @since 4.0.0
   868 	 *
  1069 	 *
   869 	 * @param string $name Property to unset.
  1070 	 * @param string $name Property to unset.
   870 	 */
  1071 	 */
   873 			unset( $this->$name );
  1074 			unset( $this->$name );
   874 		}
  1075 		}
   875 	}
  1076 	}
   876 
  1077 
   877 	/**
  1078 	/**
   878 	 * Make private/protected methods readable for backward compatibility.
  1079 	 * Makes private/protected methods readable for backward compatibility.
   879 	 *
  1080 	 *
   880 	 * @since 4.0.0
  1081 	 * @since 4.0.0
   881 	 *
  1082 	 *
   882 	 * @param string $name      Method to call.
  1083 	 * @param string $name      Method to call.
   883 	 * @param array  $arguments Arguments to pass when calling.
  1084 	 * @param array  $arguments Arguments to pass when calling.