[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/ -> class-wp-user-query.php (source)

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


Generated: Sun Sep 15 01:00:03 2019 Cross-referenced by PHPXref 0.7.1