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