WP_User_Query

Core class used for querying users.

Defined (1)

The class is defined in the following location(s).

/wp-includes/class-wp-user-query.php  
  1. class WP_User_Query { 
  2.  
  3. /** 
  4. * Query vars, after parsing 
  5. * @since 3.5.0 
  6. * @access public 
  7. * @var array 
  8. */ 
  9. public $query_vars = array(); 
  10.  
  11. /** 
  12. * List of found user ids 
  13. * @since 3.1.0 
  14. * @access private 
  15. * @var array 
  16. */ 
  17. private $results; 
  18.  
  19. /** 
  20. * Total number of found users for the current query 
  21. * @since 3.1.0 
  22. * @access private 
  23. * @var int 
  24. */ 
  25. private $total_users = 0; 
  26.  
  27. /** 
  28. * Metadata query container. 
  29. * @since 4.2.0 
  30. * @access public 
  31. * @var WP_Meta_Query 
  32. */ 
  33. public $meta_query = false; 
  34.  
  35. /** 
  36. * The SQL query used to fetch matching users. 
  37. * @since 4.4.0 
  38. * @access public 
  39. * @var string 
  40. */ 
  41. public $request; 
  42.  
  43. private $compat_fields = array( 'results', 'total_users' ); 
  44.  
  45. // SQL clauses 
  46. public $query_fields; 
  47. public $query_from; 
  48. public $query_where; 
  49. public $query_orderby; 
  50. public $query_limit; 
  51.  
  52. /** 
  53. * PHP5 constructor. 
  54. * @since 3.1.0 
  55. * @param null|string|array $query Optional. The query variables. 
  56. */ 
  57. public function __construct( $query = null ) { 
  58. if ( ! empty( $query ) ) { 
  59. $this->prepare_query( $query ); 
  60. $this->query(); 
  61.  
  62. /** 
  63. * Fills in missing query variables with default values. 
  64. * @since 4.4.0 
  65. * @access public 
  66. * @param array $args Query vars, as passed to `WP_User_Query`. 
  67. * @return array Complete query variables with undefined ones filled in with defaults. 
  68. */ 
  69. public static function fill_query_vars( $args ) { 
  70. $defaults = array( 
  71. 'blog_id' => get_current_blog_id(),  
  72. 'role' => '',  
  73. 'role__in' => array(),  
  74. 'role__not_in' => array(),  
  75. 'meta_key' => '',  
  76. 'meta_value' => '',  
  77. 'meta_compare' => '',  
  78. 'include' => array(),  
  79. 'exclude' => array(),  
  80. 'search' => '',  
  81. 'search_columns' => array(),  
  82. 'orderby' => 'login',  
  83. 'order' => 'ASC',  
  84. 'offset' => '',  
  85. 'number' => '',  
  86. 'paged' => 1,  
  87. 'count_total' => true,  
  88. 'fields' => 'all',  
  89. 'who' => '',  
  90. 'has_published_posts' => null,  
  91. 'nicename' => '',  
  92. 'nicename__in' => array(),  
  93. 'nicename__not_in' => array(),  
  94. 'login' => '',  
  95. 'login__in' => array(),  
  96. 'login__not_in' => array() 
  97. ); 
  98.  
  99. return wp_parse_args( $args, $defaults ); 
  100.  
  101. /** 
  102. * Prepare the query variables. 
  103. * @since 3.1.0 
  104. * @since 4.1.0 Added the ability to order by the `include` value. 
  105. * @since 4.2.0 Added 'meta_value_num' support for `$orderby` parameter. Added multi-dimensional array syntax 
  106. * for `$orderby` parameter. 
  107. * @since 4.3.0 Added 'has_published_posts' parameter. 
  108. * @since 4.4.0 Added 'paged', 'role__in', and 'role__not_in' parameters. The 'role' parameter was updated to 
  109. * permit an array or comma-separated list of values. The 'number' parameter was updated to support 
  110. * querying for all users with using -1. 
  111. * @since 4.7.0 Added 'nicename', 'nicename__in', 'nicename__not_in', 'login', 'login__in',  
  112. * and 'login__not_in' parameters. 
  113. * @access public 
  114. * @global wpdb $wpdb WordPress database abstraction object. 
  115. * @global int $blog_id 
  116. * @param string|array $query { 
  117. * Optional. Array or string of Query parameters. 
  118. * @type int $blog_id The site ID. Default is the current site. 
  119. * @type string|array $role An array or a comma-separated list of role names that users must match 
  120. * to be included in results. Note that this is an inclusive list: users 
  121. * must match *each* role. Default empty. 
  122. * @type array $role__in An array of role names. Matched users must have at least one of these 
  123. * roles. Default empty array. 
  124. * @type array $role__not_in An array of role names to exclude. Users matching one or more of these 
  125. * roles will not be included in results. Default empty array. 
  126. * @type string $meta_key User meta key. Default empty. 
  127. * @type string $meta_value User meta value. Default empty. 
  128. * @type string $meta_compare Comparison operator to test the `$meta_value`. Accepts '=', '!=',  
  129. * '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN',  
  130. * 'BETWEEN', 'NOT BETWEEN', 'EXISTS', 'NOT EXISTS', 'REGEXP',  
  131. * 'NOT REGEXP', or 'RLIKE'. Default '='. 
  132. * @type array $include An array of user IDs to include. Default empty array. 
  133. * @type array $exclude An array of user IDs to exclude. Default empty array. 
  134. * @type string $search Search keyword. Searches for possible string matches on columns. 
  135. * When `$search_columns` is left empty, it tries to determine which 
  136. * column to search in based on search string. Default empty. 
  137. * @type array $search_columns Array of column names to be searched. Accepts 'ID', 'login',  
  138. * 'nicename', 'email', 'url'. Default empty array. 
  139. * @type string|array $orderby Field(s) to sort the retrieved users by. May be a single value,  
  140. * an array of values, or a multi-dimensional array with fields as 
  141. * keys and orders ('ASC' or 'DESC') as values. Accepted values are 
  142. * 'ID', 'display_name' (or 'name'), 'include', 'user_login' 
  143. * (or 'login'), 'login__in', 'user_nicename' (or 'nicename'),  
  144. * 'nicename__in', 'user_email (or 'email'), 'user_url' (or 'url'),  
  145. * 'user_registered' (or 'registered'), 'post_count', 'meta_value',  
  146. * 'meta_value_num', the value of `$meta_key`, or an array key of 
  147. * `$meta_query`. To use 'meta_value' or 'meta_value_num', `$meta_key` 
  148. * must be also be defined. Default 'user_login'. 
  149. * @type string $order Designates ascending or descending order of users. Order values 
  150. * passed as part of an `$orderby` array take precedence over this 
  151. * parameter. Accepts 'ASC', 'DESC'. Default 'ASC'. 
  152. * @type int $offset Number of users to offset in retrieved results. Can be used in 
  153. * conjunction with pagination. Default 0. 
  154. * @type int $number Number of users to limit the query for. Can be used in 
  155. * conjunction with pagination. Value -1 (all) is supported, but 
  156. * should be used with caution on larger sites. 
  157. * Default empty (all users). 
  158. * @type int $paged When used with number, defines the page of results to return. 
  159. * Default 1. 
  160. * @type bool $count_total Whether to count the total number of users found. If pagination 
  161. * is not needed, setting this to false can improve performance. 
  162. * Default true. 
  163. * @type string|array $fields Which fields to return. Single or all fields (string), or array 
  164. * of fields. Accepts 'ID', 'display_name', 'user_login',  
  165. * 'user_nicename', 'user_email', 'user_url', 'user_registered'. 
  166. * Use 'all' for all fields and 'all_with_meta' to include 
  167. * meta fields. Default 'all'. 
  168. * @type string $who Type of users to query. Accepts 'authors'. 
  169. * Default empty (all users). 
  170. * @type bool|array $has_published_posts Pass an array of post types to filter results to users who have 
  171. * published posts in those post types. `true` is an alias for all 
  172. * public post types. 
  173. * @type string $nicename The user nicename. Default empty. 
  174. * @type array $nicename__in An array of nicenames to include. Users matching one of these 
  175. * nicenames will be included in results. Default empty array. 
  176. * @type array $nicename__not_in An array of nicenames to exclude. Users matching one of these 
  177. * nicenames will not be included in results. Default empty array. 
  178. * @type string $login The user login. Default empty. 
  179. * @type array $login__in An array of logins to include. Users matching one of these 
  180. * logins will be included in results. Default empty array. 
  181. * @type array $login__not_in An array of logins to exclude. Users matching one of these 
  182. * logins will not be included in results. Default empty array. 
  183. * } 
  184. */ 
  185. public function prepare_query( $query = array() ) { 
  186. global $wpdb; 
  187.  
  188. if ( empty( $this->query_vars ) || ! empty( $query ) ) { 
  189. $this->query_limit = null; 
  190. $this->query_vars = $this->fill_query_vars( $query ); 
  191.  
  192. /** 
  193. * Fires before the WP_User_Query has been parsed. 
  194. * The passed WP_User_Query object contains the query variables, not 
  195. * yet passed into SQL. 
  196. * @since 4.0.0 
  197. * @param WP_User_Query $this The current WP_User_Query instance,  
  198. * passed by reference. 
  199. */ 
  200. do_action( 'pre_get_users', $this ); 
  201.  
  202. // Ensure that query vars are filled after 'pre_get_users'. 
  203. $qv =& $this->query_vars; 
  204. $qv = $this->fill_query_vars( $qv ); 
  205.  
  206. if ( is_array( $qv['fields'] ) ) { 
  207. $qv['fields'] = array_unique( $qv['fields'] ); 
  208.  
  209. $this->query_fields = array(); 
  210. foreach ( $qv['fields'] as $field ) { 
  211. $field = 'ID' === $field ? 'ID' : sanitize_key( $field ); 
  212. $this->query_fields[] = "$wpdb->users.$field"; 
  213. $this->query_fields = implode( ', ', $this->query_fields ); 
  214. } elseif ( 'all' == $qv['fields'] ) { 
  215. $this->query_fields = "$wpdb->users.*"; 
  216. } else { 
  217. $this->query_fields = "$wpdb->users.ID"; 
  218.  
  219. if ( isset( $qv['count_total'] ) && $qv['count_total'] ) 
  220. $this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields; 
  221.  
  222. $this->query_from = "FROM $wpdb->users"; 
  223. $this->query_where = "WHERE 1=1"; 
  224.  
  225. // Parse and sanitize 'include', for use by 'orderby' as well as 'include' below. 
  226. if ( ! empty( $qv['include'] ) ) { 
  227. $include = wp_parse_id_list( $qv['include'] ); 
  228. } else { 
  229. $include = false; 
  230.  
  231. $blog_id = 0; 
  232. if ( isset( $qv['blog_id'] ) ) { 
  233. $blog_id = absint( $qv['blog_id'] ); 
  234.  
  235. if ( $qv['has_published_posts'] && $blog_id ) { 
  236. if ( true === $qv['has_published_posts'] ) { 
  237. $post_types = get_post_types( array( 'public' => true ) ); 
  238. } else { 
  239. $post_types = (array) $qv['has_published_posts']; 
  240.  
  241. foreach ( $post_types as &$post_type ) { 
  242. $post_type = $wpdb->prepare( '%s', $post_type ); 
  243.  
  244. $posts_table = $wpdb->get_blog_prefix( $blog_id ) . 'posts'; 
  245. $this->query_where .= " AND $wpdb->users.ID IN ( SELECT DISTINCT $posts_table.post_author FROM $posts_table WHERE $posts_table.post_status = 'publish' AND $posts_table.post_type IN ( " . join( ", ", $post_types ) . " ) )"; 
  246.  
  247. // nicename 
  248. if ( '' !== $qv['nicename']) { 
  249. $this->query_where .= $wpdb->prepare( ' AND user_nicename = %s', $qv['nicename'] ); 
  250.  
  251. if ( ! empty( $qv['nicename__in'] ) ) { 
  252. $sanitized_nicename__in = array_map( 'esc_sql', $qv['nicename__in'] ); 
  253. $nicename__in = implode( "', '", $sanitized_nicename__in ); 
  254. $this->query_where .= " AND user_nicename IN ( '$nicename__in' )"; 
  255.  
  256. if ( ! empty( $qv['nicename__not_in'] ) ) { 
  257. $sanitized_nicename__not_in = array_map( 'esc_sql', $qv['nicename__not_in'] ); 
  258. $nicename__not_in = implode( "', '", $sanitized_nicename__not_in ); 
  259. $this->query_where .= " AND user_nicename NOT IN ( '$nicename__not_in' )"; 
  260.  
  261. // login 
  262. if ( '' !== $qv['login']) { 
  263. $this->query_where .= $wpdb->prepare( ' AND user_login = %s', $qv['login'] ); 
  264.  
  265. if ( ! empty( $qv['login__in'] ) ) { 
  266. $sanitized_login__in = array_map( 'esc_sql', $qv['login__in'] ); 
  267. $login__in = implode( "', '", $sanitized_login__in ); 
  268. $this->query_where .= " AND user_login IN ( '$login__in' )"; 
  269.  
  270. if ( ! empty( $qv['login__not_in'] ) ) { 
  271. $sanitized_login__not_in = array_map( 'esc_sql', $qv['login__not_in'] ); 
  272. $login__not_in = implode( "', '", $sanitized_login__not_in ); 
  273. $this->query_where .= " AND user_login NOT IN ( '$login__not_in' )"; 
  274.  
  275. // Meta query. 
  276. $this->meta_query = new WP_Meta_Query(); 
  277. $this->meta_query->parse_query_vars( $qv ); 
  278.  
  279. if ( isset( $qv['who'] ) && 'authors' == $qv['who'] && $blog_id ) { 
  280. $who_query = array( 
  281. 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'user_level',  
  282. 'value' => 0,  
  283. 'compare' => '!=',  
  284. ); 
  285.  
  286. // Prevent extra meta query. 
  287. $qv['blog_id'] = $blog_id = 0; 
  288.  
  289. if ( empty( $this->meta_query->queries ) ) { 
  290. $this->meta_query->queries = array( $who_query ); 
  291. } else { 
  292. // Append the cap query to the original queries and reparse the query. 
  293. $this->meta_query->queries = array( 
  294. 'relation' => 'AND',  
  295. array( $this->meta_query->queries, $who_query ),  
  296. ); 
  297.  
  298. $this->meta_query->parse_query_vars( $this->meta_query->queries ); 
  299.  
  300. $roles = array(); 
  301. if ( isset( $qv['role'] ) ) { 
  302. if ( is_array( $qv['role'] ) ) { 
  303. $roles = $qv['role']; 
  304. } elseif ( is_string( $qv['role'] ) && ! empty( $qv['role'] ) ) { 
  305. $roles = array_map( 'trim', explode( ', ', $qv['role'] ) ); 
  306.  
  307. $role__in = array(); 
  308. if ( isset( $qv['role__in'] ) ) { 
  309. $role__in = (array) $qv['role__in']; 
  310.  
  311. $role__not_in = array(); 
  312. if ( isset( $qv['role__not_in'] ) ) { 
  313. $role__not_in = (array) $qv['role__not_in']; 
  314.  
  315. if ( $blog_id && ( ! empty( $roles ) || ! empty( $role__in ) || ! empty( $role__not_in ) || is_multisite() ) ) { 
  316. $role_queries = array(); 
  317.  
  318. $roles_clauses = array( 'relation' => 'AND' ); 
  319. if ( ! empty( $roles ) ) { 
  320. foreach ( $roles as $role ) { 
  321. $roles_clauses[] = array( 
  322. 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',  
  323. 'value' => '"' . $role . '"',  
  324. 'compare' => 'LIKE',  
  325. ); 
  326.  
  327. $role_queries[] = $roles_clauses; 
  328.  
  329. $role__in_clauses = array( 'relation' => 'OR' ); 
  330. if ( ! empty( $role__in ) ) { 
  331. foreach ( $role__in as $role ) { 
  332. $role__in_clauses[] = array( 
  333. 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',  
  334. 'value' => '"' . $role . '"',  
  335. 'compare' => 'LIKE',  
  336. ); 
  337.  
  338. $role_queries[] = $role__in_clauses; 
  339.  
  340. $role__not_in_clauses = array( 'relation' => 'AND' ); 
  341. if ( ! empty( $role__not_in ) ) { 
  342. foreach ( $role__not_in as $role ) { 
  343. $role__not_in_clauses[] = array( 
  344. 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',  
  345. 'value' => '"' . $role . '"',  
  346. 'compare' => 'NOT LIKE',  
  347. ); 
  348.  
  349. $role_queries[] = $role__not_in_clauses; 
  350.  
  351. // If there are no specific roles named, make sure the user is a member of the site. 
  352. if ( empty( $role_queries ) ) { 
  353. $role_queries[] = array( 
  354. 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',  
  355. 'compare' => 'EXISTS',  
  356. ); 
  357.  
  358. // Specify that role queries should be joined with AND. 
  359. $role_queries['relation'] = 'AND'; 
  360.  
  361. if ( empty( $this->meta_query->queries ) ) { 
  362. $this->meta_query->queries = $role_queries; 
  363. } else { 
  364. // Append the cap query to the original queries and reparse the query. 
  365. $this->meta_query->queries = array( 
  366. 'relation' => 'AND',  
  367. array( $this->meta_query->queries, $role_queries ),  
  368. ); 
  369.  
  370. $this->meta_query->parse_query_vars( $this->meta_query->queries ); 
  371.  
  372. if ( ! empty( $this->meta_query->queries ) ) { 
  373. $clauses = $this->meta_query->get_sql( 'user', $wpdb->users, 'ID', $this ); 
  374. $this->query_from .= $clauses['join']; 
  375. $this->query_where .= $clauses['where']; 
  376.  
  377. if ( $this->meta_query->has_or_relation() ) { 
  378. $this->query_fields = 'DISTINCT ' . $this->query_fields; 
  379.  
  380. // sorting 
  381. $qv['order'] = isset( $qv['order'] ) ? strtoupper( $qv['order'] ) : ''; 
  382. $order = $this->parse_order( $qv['order'] ); 
  383.  
  384. if ( empty( $qv['orderby'] ) ) { 
  385. // Default order is by 'user_login'. 
  386. $ordersby = array( 'user_login' => $order ); 
  387. } elseif ( is_array( $qv['orderby'] ) ) { 
  388. $ordersby = $qv['orderby']; 
  389. } else { 
  390. // 'orderby' values may be a comma- or space-separated list. 
  391. $ordersby = preg_split( '/[, \s]+/', $qv['orderby'] ); 
  392.  
  393. $orderby_array = array(); 
  394. foreach ( $ordersby as $_key => $_value ) { 
  395. if ( ! $_value ) { 
  396. continue; 
  397.  
  398. if ( is_int( $_key ) ) { 
  399. // Integer key means this is a flat array of 'orderby' fields. 
  400. $_orderby = $_value; 
  401. $_order = $order; 
  402. } else { 
  403. // Non-integer key means this the key is the field and the value is ASC/DESC. 
  404. $_orderby = $_key; 
  405. $_order = $_value; 
  406.  
  407. $parsed = $this->parse_orderby( $_orderby ); 
  408.  
  409. if ( ! $parsed ) { 
  410. continue; 
  411.  
  412. if ( 'nicename__in' === $_orderby || 'login__in' === $_orderby ) { 
  413. $orderby_array[] = $parsed; 
  414. } else { 
  415. $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order ); 
  416.  
  417. // If no valid clauses were found, order by user_login. 
  418. if ( empty( $orderby_array ) ) { 
  419. $orderby_array[] = "user_login $order"; 
  420.  
  421. $this->query_orderby = 'ORDER BY ' . implode( ', ', $orderby_array ); 
  422.  
  423. // limit 
  424. if ( isset( $qv['number'] ) && $qv['number'] > 0 ) { 
  425. if ( $qv['offset'] ) { 
  426. $this->query_limit = $wpdb->prepare("LIMIT %d, %d", $qv['offset'], $qv['number']); 
  427. } else { 
  428. $this->query_limit = $wpdb->prepare( "LIMIT %d, %d", $qv['number'] * ( $qv['paged'] - 1 ), $qv['number'] ); 
  429.  
  430. $search = ''; 
  431. if ( isset( $qv['search'] ) ) 
  432. $search = trim( $qv['search'] ); 
  433.  
  434. if ( $search ) { 
  435. $leading_wild = ( ltrim($search, '*') != $search ); 
  436. $trailing_wild = ( rtrim($search, '*') != $search ); 
  437. if ( $leading_wild && $trailing_wild ) 
  438. $wild = 'both'; 
  439. elseif ( $leading_wild ) 
  440. $wild = 'leading'; 
  441. elseif ( $trailing_wild ) 
  442. $wild = 'trailing'; 
  443. else 
  444. $wild = false; 
  445. if ( $wild ) 
  446. $search = trim($search, '*'); 
  447.  
  448. $search_columns = array(); 
  449. if ( $qv['search_columns'] ) 
  450. $search_columns = array_intersect( $qv['search_columns'], array( 'ID', 'user_login', 'user_email', 'user_url', 'user_nicename' ) ); 
  451. if ( ! $search_columns ) { 
  452. if ( false !== strpos( $search, '@') ) 
  453. $search_columns = array('user_email'); 
  454. elseif ( is_numeric($search) ) 
  455. $search_columns = array('user_login', 'ID'); 
  456. elseif ( preg_match('|^https?://|', $search) && ! ( is_multisite() && wp_is_large_network( 'users' ) ) ) 
  457. $search_columns = array('user_url'); 
  458. else 
  459. $search_columns = array('user_login', 'user_url', 'user_email', 'user_nicename', 'display_name'); 
  460.  
  461. /** 
  462. * Filters the columns to search in a WP_User_Query search. 
  463. * The default columns depend on the search term, and include 'user_email',  
  464. * 'user_login', 'ID', 'user_url', 'display_name', and 'user_nicename'. 
  465. * @since 3.6.0 
  466. * @param array $search_columns Array of column names to be searched. 
  467. * @param string $search Text being searched. 
  468. * @param WP_User_Query $this The current WP_User_Query instance. 
  469. */ 
  470. $search_columns = apply_filters( 'user_search_columns', $search_columns, $search, $this ); 
  471.  
  472. $this->query_where .= $this->get_search_sql( $search, $search_columns, $wild ); 
  473.  
  474. if ( ! empty( $include ) ) { 
  475. // Sanitized earlier. 
  476. $ids = implode( ', ', $include ); 
  477. $this->query_where .= " AND $wpdb->users.ID IN ($ids)"; 
  478. } elseif ( ! empty( $qv['exclude'] ) ) { 
  479. $ids = implode( ', ', wp_parse_id_list( $qv['exclude'] ) ); 
  480. $this->query_where .= " AND $wpdb->users.ID NOT IN ($ids)"; 
  481.  
  482. // Date queries are allowed for the user_registered field. 
  483. if ( ! empty( $qv['date_query'] ) && is_array( $qv['date_query'] ) ) { 
  484. $date_query = new WP_Date_Query( $qv['date_query'], 'user_registered' ); 
  485. $this->query_where .= $date_query->get_sql(); 
  486.  
  487. /** 
  488. * Fires after the WP_User_Query has been parsed, and before 
  489. * the query is executed. 
  490. * The passed WP_User_Query object contains SQL parts formed 
  491. * from parsing the given query. 
  492. * @since 3.1.0 
  493. * @param WP_User_Query $this The current WP_User_Query instance,  
  494. * passed by reference. 
  495. */ 
  496. do_action_ref_array( 'pre_user_query', array( &$this ) ); 
  497.  
  498. /** 
  499. * Execute the query, with the current variables. 
  500. * @since 3.1.0 
  501. * @global wpdb $wpdb WordPress database abstraction object. 
  502. */ 
  503. public function query() { 
  504. global $wpdb; 
  505.  
  506. $qv =& $this->query_vars; 
  507.  
  508. $this->request = "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit"; 
  509.  
  510. if ( is_array( $qv['fields'] ) || 'all' == $qv['fields'] ) { 
  511. $this->results = $wpdb->get_results( $this->request ); 
  512. } else { 
  513. $this->results = $wpdb->get_col( $this->request ); 
  514.  
  515. /** 
  516. * Filters SELECT FOUND_ROWS() query for the current WP_User_Query instance. 
  517. * @since 3.2.0 
  518. * @global wpdb $wpdb WordPress database abstraction object. 
  519. * @param string $sql The SELECT FOUND_ROWS() query for the current WP_User_Query. 
  520. */ 
  521. if ( isset( $qv['count_total'] ) && $qv['count_total'] ) 
  522. $this->total_users = $wpdb->get_var( apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()' ) ); 
  523.  
  524. if ( !$this->results ) 
  525. return; 
  526.  
  527. if ( 'all_with_meta' == $qv['fields'] ) { 
  528. cache_users( $this->results ); 
  529.  
  530. $r = array(); 
  531. foreach ( $this->results as $userid ) 
  532. $r[ $userid ] = new WP_User( $userid, '', $qv['blog_id'] ); 
  533.  
  534. $this->results = $r; 
  535. } elseif ( 'all' == $qv['fields'] ) { 
  536. foreach ( $this->results as $key => $user ) { 
  537. $this->results[ $key ] = new WP_User( $user, '', $qv['blog_id'] ); 
  538.  
  539. /** 
  540. * Retrieve query variable. 
  541. * @since 3.5.0 
  542. * @access public 
  543. * @param string $query_var Query variable key. 
  544. * @return mixed 
  545. */ 
  546. public function get( $query_var ) { 
  547. if ( isset( $this->query_vars[$query_var] ) ) 
  548. return $this->query_vars[$query_var]; 
  549.  
  550. return null; 
  551.  
  552. /** 
  553. * Set query variable. 
  554. * @since 3.5.0 
  555. * @access public 
  556. * @param string $query_var Query variable key. 
  557. * @param mixed $value Query variable value. 
  558. */ 
  559. public function set( $query_var, $value ) { 
  560. $this->query_vars[$query_var] = $value; 
  561.  
  562. /** 
  563. * Used internally to generate an SQL string for searching across multiple columns 
  564. * @access protected 
  565. * @since 3.1.0 
  566. * @global wpdb $wpdb WordPress database abstraction object. 
  567. * @param string $string 
  568. * @param array $cols 
  569. * @param bool $wild Whether to allow wildcard searches. Default is false for Network Admin, true for single site. 
  570. * Single site allows leading and trailing wildcards, Network Admin only trailing. 
  571. * @return string 
  572. */ 
  573. protected function get_search_sql( $string, $cols, $wild = false ) { 
  574. global $wpdb; 
  575.  
  576. $searches = array(); 
  577. $leading_wild = ( 'leading' == $wild || 'both' == $wild ) ? '%' : ''; 
  578. $trailing_wild = ( 'trailing' == $wild || 'both' == $wild ) ? '%' : ''; 
  579. $like = $leading_wild . $wpdb->esc_like( $string ) . $trailing_wild; 
  580.  
  581. foreach ( $cols as $col ) { 
  582. if ( 'ID' == $col ) { 
  583. $searches[] = $wpdb->prepare( "$col = %s", $string ); 
  584. } else { 
  585. $searches[] = $wpdb->prepare( "$col LIKE %s", $like ); 
  586.  
  587. return ' AND (' . implode(' OR ', $searches) . ')'; 
  588.  
  589. /** 
  590. * Return the list of users. 
  591. * @since 3.1.0 
  592. * @access public 
  593. * @return array Array of results. 
  594. */ 
  595. public function get_results() { 
  596. return $this->results; 
  597.  
  598. /** 
  599. * Return the total number of users for the current query. 
  600. * @since 3.1.0 
  601. * @access public 
  602. * @return int Number of total users. 
  603. */ 
  604. public function get_total() { 
  605. return $this->total_users; 
  606.  
  607. /** 
  608. * Parse and sanitize 'orderby' keys passed to the user query. 
  609. * @since 4.2.0 
  610. * @access protected 
  611. * @global wpdb $wpdb WordPress database abstraction object. 
  612. * @param string $orderby Alias for the field to order by. 
  613. * @return string Value to used in the ORDER clause, if `$orderby` is valid. 
  614. */ 
  615. protected function parse_orderby( $orderby ) { 
  616. global $wpdb; 
  617.  
  618. $meta_query_clauses = $this->meta_query->get_clauses(); 
  619.  
  620. $_orderby = ''; 
  621. if ( in_array( $orderby, array( 'login', 'nicename', 'email', 'url', 'registered' ) ) ) { 
  622. $_orderby = 'user_' . $orderby; 
  623. } elseif ( in_array( $orderby, array( 'user_login', 'user_nicename', 'user_email', 'user_url', 'user_registered' ) ) ) { 
  624. $_orderby = $orderby; 
  625. } elseif ( 'name' == $orderby || 'display_name' == $orderby ) { 
  626. $_orderby = 'display_name'; 
  627. } elseif ( 'post_count' == $orderby ) { 
  628. // todo: avoid the JOIN 
  629. $where = get_posts_by_author_sql( 'post' ); 
  630. $this->query_from .= " LEFT OUTER JOIN ( 
  631. SELECT post_author, COUNT(*) as post_count 
  632. FROM $wpdb->posts 
  633. $where 
  634. GROUP BY post_author 
  635. ) p ON ({$wpdb->users}.ID = p.post_author) 
  636. "; 
  637. $_orderby = 'post_count'; 
  638. } elseif ( 'ID' == $orderby || 'id' == $orderby ) { 
  639. $_orderby = 'ID'; 
  640. } elseif ( 'meta_value' == $orderby || $this->get( 'meta_key' ) == $orderby ) { 
  641. $_orderby = "$wpdb->usermeta.meta_value"; 
  642. } elseif ( 'meta_value_num' == $orderby ) { 
  643. $_orderby = "$wpdb->usermeta.meta_value+0"; 
  644. } elseif ( 'include' === $orderby && ! empty( $this->query_vars['include'] ) ) { 
  645. $include = wp_parse_id_list( $this->query_vars['include'] ); 
  646. $include_sql = implode( ', ', $include ); 
  647. $_orderby = "FIELD( $wpdb->users.ID, $include_sql )"; 
  648. } elseif ( 'nicename__in' === $orderby ) { 
  649. $sanitized_nicename__in = array_map( 'esc_sql', $this->query_vars['nicename__in'] ); 
  650. $nicename__in = implode( "', '", $sanitized_nicename__in ); 
  651. $_orderby = "FIELD( user_nicename, '$nicename__in' )"; 
  652. } elseif ( 'login__in' === $orderby ) { 
  653. $sanitized_login__in = array_map( 'esc_sql', $this->query_vars['login__in'] ); 
  654. $login__in = implode( "', '", $sanitized_login__in ); 
  655. $_orderby = "FIELD( user_login, '$login__in' )"; 
  656. } elseif ( isset( $meta_query_clauses[ $orderby ] ) ) { 
  657. $meta_clause = $meta_query_clauses[ $orderby ]; 
  658. $_orderby = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) ); 
  659.  
  660. return $_orderby; 
  661.  
  662. /** 
  663. * Parse an 'order' query variable and cast it to ASC or DESC as necessary. 
  664. * @since 4.2.0 
  665. * @access protected 
  666. * @param string $order The 'order' query variable. 
  667. * @return string The sanitized 'order' query variable. 
  668. */ 
  669. protected function parse_order( $order ) { 
  670. if ( ! is_string( $order ) || empty( $order ) ) { 
  671. return 'DESC'; 
  672.  
  673. if ( 'ASC' === strtoupper( $order ) ) { 
  674. return 'ASC'; 
  675. } else { 
  676. return 'DESC'; 
  677.  
  678. /** 
  679. * Make private properties readable for backward compatibility. 
  680. * @since 4.0.0 
  681. * @access public 
  682. * @param string $name Property to get. 
  683. * @return mixed Property. 
  684. */ 
  685. public function __get( $name ) { 
  686. if ( in_array( $name, $this->compat_fields ) ) { 
  687. return $this->$name; 
  688.  
  689. /** 
  690. * Make private properties settable for backward compatibility. 
  691. * @since 4.0.0 
  692. * @access public 
  693. * @param string $name Property to check if set. 
  694. * @param mixed $value Property value. 
  695. * @return mixed Newly-set property. 
  696. */ 
  697. public function __set( $name, $value ) { 
  698. if ( in_array( $name, $this->compat_fields ) ) { 
  699. return $this->$name = $value; 
  700.  
  701. /** 
  702. * Make private properties checkable for backward compatibility. 
  703. * @since 4.0.0 
  704. * @access public 
  705. * @param string $name Property to check if set. 
  706. * @return bool Whether the property is set. 
  707. */ 
  708. public function __isset( $name ) { 
  709. if ( in_array( $name, $this->compat_fields ) ) { 
  710. return isset( $this->$name ); 
  711.  
  712. /** 
  713. * Make private properties un-settable for backward compatibility. 
  714. * @since 4.0.0 
  715. * @access public 
  716. * @param string $name Property to unset. 
  717. */ 
  718. public function __unset( $name ) { 
  719. if ( in_array( $name, $this->compat_fields ) ) { 
  720. unset( $this->$name ); 
  721.  
  722. /** 
  723. * Make private/protected methods readable for backward compatibility. 
  724. * @since 4.0.0 
  725. * @access public 
  726. * @param callable $name Method to call. 
  727. * @param array $arguments Arguments to pass when calling. 
  728. * @return mixed Return value of the callback, false otherwise. 
  729. */ 
  730. public function __call( $name, $arguments ) { 
  731. if ( 'get_search_sql' === $name ) { 
  732. return call_user_func_array( array( $this, $name ), $arguments ); 
  733. return false;