wp/wp-includes/class-wp-query.php
changeset 7 cf61fcea0001
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
       
     1 <?php
       
     2 /**
       
     3  * Query API: WP_Query class
       
     4  *
       
     5  * @package WordPress
       
     6  * @subpackage Query
       
     7  * @since 4.7.0
       
     8  */
       
     9 
       
    10 /**
       
    11  * The WordPress Query class.
       
    12  *
       
    13  * @link https://codex.wordpress.org/Function_Reference/WP_Query Codex page.
       
    14  *
       
    15  * @since 1.5.0
       
    16  * @since 4.5.0 Removed the `$comments_popup` property.
       
    17  */
       
    18 class WP_Query {
       
    19 
       
    20 	/**
       
    21 	 * Query vars set by the user
       
    22 	 *
       
    23 	 * @since 1.5.0
       
    24 	 * @var array
       
    25 	 */
       
    26 	public $query;
       
    27 
       
    28 	/**
       
    29 	 * Query vars, after parsing
       
    30 	 *
       
    31 	 * @since 1.5.0
       
    32 	 * @var array
       
    33 	 */
       
    34 	public $query_vars = array();
       
    35 
       
    36 	/**
       
    37 	 * Taxonomy query, as passed to get_tax_sql()
       
    38 	 *
       
    39 	 * @since 3.1.0
       
    40 	 * @var object WP_Tax_Query
       
    41 	 */
       
    42 	public $tax_query;
       
    43 
       
    44 	/**
       
    45 	 * Metadata query container
       
    46 	 *
       
    47 	 * @since 3.2.0
       
    48 	 * @var object WP_Meta_Query
       
    49 	 */
       
    50 	public $meta_query = false;
       
    51 
       
    52 	/**
       
    53 	 * Date query container
       
    54 	 *
       
    55 	 * @since 3.7.0
       
    56 	 * @var object WP_Date_Query
       
    57 	 */
       
    58 	public $date_query = false;
       
    59 
       
    60 	/**
       
    61 	 * Holds the data for a single object that is queried.
       
    62 	 *
       
    63 	 * Holds the contents of a post, page, category, attachment.
       
    64 	 *
       
    65 	 * @since 1.5.0
       
    66 	 * @var object|array
       
    67 	 */
       
    68 	public $queried_object;
       
    69 
       
    70 	/**
       
    71 	 * The ID of the queried object.
       
    72 	 *
       
    73 	 * @since 1.5.0
       
    74 	 * @var int
       
    75 	 */
       
    76 	public $queried_object_id;
       
    77 
       
    78 	/**
       
    79 	 * Get post database query.
       
    80 	 *
       
    81 	 * @since 2.0.1
       
    82 	 * @var string
       
    83 	 */
       
    84 	public $request;
       
    85 
       
    86 	/**
       
    87 	 * List of posts.
       
    88 	 *
       
    89 	 * @since 1.5.0
       
    90 	 * @var array
       
    91 	 */
       
    92 	public $posts;
       
    93 
       
    94 	/**
       
    95 	 * The amount of posts for the current query.
       
    96 	 *
       
    97 	 * @since 1.5.0
       
    98 	 * @var int
       
    99 	 */
       
   100 	public $post_count = 0;
       
   101 
       
   102 	/**
       
   103 	 * Index of the current item in the loop.
       
   104 	 *
       
   105 	 * @since 1.5.0
       
   106 	 * @var int
       
   107 	 */
       
   108 	public $current_post = -1;
       
   109 
       
   110 	/**
       
   111 	 * Whether the loop has started and the caller is in the loop.
       
   112 	 *
       
   113 	 * @since 2.0.0
       
   114 	 * @var bool
       
   115 	 */
       
   116 	public $in_the_loop = false;
       
   117 
       
   118 	/**
       
   119 	 * The current post.
       
   120 	 *
       
   121 	 * @since 1.5.0
       
   122 	 * @var WP_Post
       
   123 	 */
       
   124 	public $post;
       
   125 
       
   126 	/**
       
   127 	 * The list of comments for current post.
       
   128 	 *
       
   129 	 * @since 2.2.0
       
   130 	 * @var array
       
   131 	 */
       
   132 	public $comments;
       
   133 
       
   134 	/**
       
   135 	 * The amount of comments for the posts.
       
   136 	 *
       
   137 	 * @since 2.2.0
       
   138 	 * @var int
       
   139 	 */
       
   140 	public $comment_count = 0;
       
   141 
       
   142 	/**
       
   143 	 * The index of the comment in the comment loop.
       
   144 	 *
       
   145 	 * @since 2.2.0
       
   146 	 * @var int
       
   147 	 */
       
   148 	public $current_comment = -1;
       
   149 
       
   150 	/**
       
   151 	 * Current comment ID.
       
   152 	 *
       
   153 	 * @since 2.2.0
       
   154 	 * @var int
       
   155 	 */
       
   156 	public $comment;
       
   157 
       
   158 	/**
       
   159 	 * The amount of found posts for the current query.
       
   160 	 *
       
   161 	 * If limit clause was not used, equals $post_count.
       
   162 	 *
       
   163 	 * @since 2.1.0
       
   164 	 * @var int
       
   165 	 */
       
   166 	public $found_posts = 0;
       
   167 
       
   168 	/**
       
   169 	 * The amount of pages.
       
   170 	 *
       
   171 	 * @since 2.1.0
       
   172 	 * @var int
       
   173 	 */
       
   174 	public $max_num_pages = 0;
       
   175 
       
   176 	/**
       
   177 	 * The amount of comment pages.
       
   178 	 *
       
   179 	 * @since 2.7.0
       
   180 	 * @var int
       
   181 	 */
       
   182 	public $max_num_comment_pages = 0;
       
   183 
       
   184 	/**
       
   185 	 * Signifies whether the current query is for a single post.
       
   186 	 *
       
   187 	 * @since 1.5.0
       
   188 	 * @var bool
       
   189 	 */
       
   190 	public $is_single = false;
       
   191 
       
   192 	/**
       
   193 	 * Signifies whether the current query is for a preview.
       
   194 	 *
       
   195 	 * @since 2.0.0
       
   196 	 * @var bool
       
   197 	 */
       
   198 	public $is_preview = false;
       
   199 
       
   200 	/**
       
   201 	 * Signifies whether the current query is for a page.
       
   202 	 *
       
   203 	 * @since 1.5.0
       
   204 	 * @var bool
       
   205 	 */
       
   206 	public $is_page = false;
       
   207 
       
   208 	/**
       
   209 	 * Signifies whether the current query is for an archive.
       
   210 	 *
       
   211 	 * @since 1.5.0
       
   212 	 * @var bool
       
   213 	 */
       
   214 	public $is_archive = false;
       
   215 
       
   216 	/**
       
   217 	 * Signifies whether the current query is for a date archive.
       
   218 	 *
       
   219 	 * @since 1.5.0
       
   220 	 * @var bool
       
   221 	 */
       
   222 	public $is_date = false;
       
   223 
       
   224 	/**
       
   225 	 * Signifies whether the current query is for a year archive.
       
   226 	 *
       
   227 	 * @since 1.5.0
       
   228 	 * @var bool
       
   229 	 */
       
   230 	public $is_year = false;
       
   231 
       
   232 	/**
       
   233 	 * Signifies whether the current query is for a month archive.
       
   234 	 *
       
   235 	 * @since 1.5.0
       
   236 	 * @var bool
       
   237 	 */
       
   238 	public $is_month = false;
       
   239 
       
   240 	/**
       
   241 	 * Signifies whether the current query is for a day archive.
       
   242 	 *
       
   243 	 * @since 1.5.0
       
   244 	 * @var bool
       
   245 	 */
       
   246 	public $is_day = false;
       
   247 
       
   248 	/**
       
   249 	 * Signifies whether the current query is for a specific time.
       
   250 	 *
       
   251 	 * @since 1.5.0
       
   252 	 * @var bool
       
   253 	 */
       
   254 	public $is_time = false;
       
   255 
       
   256 	/**
       
   257 	 * Signifies whether the current query is for an author archive.
       
   258 	 *
       
   259 	 * @since 1.5.0
       
   260 	 * @var bool
       
   261 	 */
       
   262 	public $is_author = false;
       
   263 
       
   264 	/**
       
   265 	 * Signifies whether the current query is for a category archive.
       
   266 	 *
       
   267 	 * @since 1.5.0
       
   268 	 * @var bool
       
   269 	 */
       
   270 	public $is_category = false;
       
   271 
       
   272 	/**
       
   273 	 * Signifies whether the current query is for a tag archive.
       
   274 	 *
       
   275 	 * @since 2.3.0
       
   276 	 * @var bool
       
   277 	 */
       
   278 	public $is_tag = false;
       
   279 
       
   280 	/**
       
   281 	 * Signifies whether the current query is for a taxonomy archive.
       
   282 	 *
       
   283 	 * @since 2.5.0
       
   284 	 * @var bool
       
   285 	 */
       
   286 	public $is_tax = false;
       
   287 
       
   288 	/**
       
   289 	 * Signifies whether the current query is for a search.
       
   290 	 *
       
   291 	 * @since 1.5.0
       
   292 	 * @var bool
       
   293 	 */
       
   294 	public $is_search = false;
       
   295 
       
   296 	/**
       
   297 	 * Signifies whether the current query is for a feed.
       
   298 	 *
       
   299 	 * @since 1.5.0
       
   300 	 * @var bool
       
   301 	 */
       
   302 	public $is_feed = false;
       
   303 
       
   304 	/**
       
   305 	 * Signifies whether the current query is for a comment feed.
       
   306 	 *
       
   307 	 * @since 2.2.0
       
   308 	 * @var bool
       
   309 	 */
       
   310 	public $is_comment_feed = false;
       
   311 
       
   312 	/**
       
   313 	 * Signifies whether the current query is for trackback endpoint call.
       
   314 	 *
       
   315 	 * @since 1.5.0
       
   316 	 * @var bool
       
   317 	 */
       
   318 	public $is_trackback = false;
       
   319 
       
   320 	/**
       
   321 	 * Signifies whether the current query is for the site homepage.
       
   322 	 *
       
   323 	 * @since 1.5.0
       
   324 	 * @var bool
       
   325 	 */
       
   326 	public $is_home = false;
       
   327 
       
   328 	/**
       
   329 	 * Signifies whether the current query couldn't find anything.
       
   330 	 *
       
   331 	 * @since 1.5.0
       
   332 	 * @var bool
       
   333 	 */
       
   334 	public $is_404 = false;
       
   335 
       
   336 	/**
       
   337 	 * Signifies whether the current query is for an embed.
       
   338 	 *
       
   339 	 * @since 4.4.0
       
   340 	 * @var bool
       
   341 	 */
       
   342 	public $is_embed = false;
       
   343 
       
   344 	/**
       
   345 	 * Signifies whether the current query is for a paged result and not for the first page.
       
   346 	 *
       
   347 	 * @since 1.5.0
       
   348 	 * @var bool
       
   349 	 */
       
   350 	public $is_paged = false;
       
   351 
       
   352 	/**
       
   353 	 * Signifies whether the current query is for an administrative interface page.
       
   354 	 *
       
   355 	 * @since 1.5.0
       
   356 	 * @var bool
       
   357 	 */
       
   358 	public $is_admin = false;
       
   359 
       
   360 	/**
       
   361 	 * Signifies whether the current query is for an attachment page.
       
   362 	 *
       
   363 	 * @since 2.0.0
       
   364 	 * @var bool
       
   365 	 */
       
   366 	public $is_attachment = false;
       
   367 
       
   368 	/**
       
   369 	 * Signifies whether the current query is for an existing single post of any post type
       
   370 	 * (post, attachment, page, custom post types).
       
   371 	 *
       
   372 	 * @since 2.1.0
       
   373 	 * @var bool
       
   374 	 */
       
   375 	public $is_singular = false;
       
   376 
       
   377 	/**
       
   378 	 * Signifies whether the current query is for the robots.txt file.
       
   379 	 *
       
   380 	 * @since 2.1.0
       
   381 	 * @var bool
       
   382 	 */
       
   383 	public $is_robots = false;
       
   384 
       
   385 	/**
       
   386 	 * Signifies whether the current query is for the page_for_posts page.
       
   387 	 *
       
   388 	 * Basically, the homepage if the option isn't set for the static homepage.
       
   389 	 *
       
   390 	 * @since 2.1.0
       
   391 	 * @var bool
       
   392 	 */
       
   393 	public $is_posts_page = false;
       
   394 
       
   395 	/**
       
   396 	 * Signifies whether the current query is for a post type archive.
       
   397 	 *
       
   398 	 * @since 3.1.0
       
   399 	 * @var bool
       
   400 	 */
       
   401 	public $is_post_type_archive = false;
       
   402 
       
   403 	/**
       
   404 	 * Stores the ->query_vars state like md5(serialize( $this->query_vars ) ) so we know
       
   405 	 * whether we have to re-parse because something has changed
       
   406 	 *
       
   407 	 * @since 3.1.0
       
   408 	 * @var bool|string
       
   409 	 */
       
   410 	private $query_vars_hash = false;
       
   411 
       
   412 	/**
       
   413 	 * Whether query vars have changed since the initial parse_query() call. Used to catch modifications to query vars made
       
   414 	 * via pre_get_posts hooks.
       
   415 	 *
       
   416 	 * @since 3.1.1
       
   417 	 */
       
   418 	private $query_vars_changed = true;
       
   419 
       
   420 	/**
       
   421 	 * Set if post thumbnails are cached
       
   422 	 *
       
   423 	 * @since 3.2.0
       
   424 	 * @var bool
       
   425 	 */
       
   426 	 public $thumbnails_cached = false;
       
   427 
       
   428 	/**
       
   429 	 * Cached list of search stopwords.
       
   430 	 *
       
   431 	 * @since 3.7.0
       
   432 	 * @var array
       
   433 	 */
       
   434 	private $stopwords;
       
   435 
       
   436 	private $compat_fields = array( 'query_vars_hash', 'query_vars_changed' );
       
   437 
       
   438 	private $compat_methods = array( 'init_query_flags', 'parse_tax_query' );
       
   439 
       
   440 	/**
       
   441 	 * Resets query flags to false.
       
   442 	 *
       
   443 	 * The query flags are what page info WordPress was able to figure out.
       
   444 	 *
       
   445 	 * @since 2.0.0
       
   446 	 */
       
   447 	private function init_query_flags() {
       
   448 		$this->is_single = false;
       
   449 		$this->is_preview = false;
       
   450 		$this->is_page = false;
       
   451 		$this->is_archive = false;
       
   452 		$this->is_date = false;
       
   453 		$this->is_year = false;
       
   454 		$this->is_month = false;
       
   455 		$this->is_day = false;
       
   456 		$this->is_time = false;
       
   457 		$this->is_author = false;
       
   458 		$this->is_category = false;
       
   459 		$this->is_tag = false;
       
   460 		$this->is_tax = false;
       
   461 		$this->is_search = false;
       
   462 		$this->is_feed = false;
       
   463 		$this->is_comment_feed = false;
       
   464 		$this->is_trackback = false;
       
   465 		$this->is_home = false;
       
   466 		$this->is_404 = false;
       
   467 		$this->is_paged = false;
       
   468 		$this->is_admin = false;
       
   469 		$this->is_attachment = false;
       
   470 		$this->is_singular = false;
       
   471 		$this->is_robots = false;
       
   472 		$this->is_posts_page = false;
       
   473 		$this->is_post_type_archive = false;
       
   474 	}
       
   475 
       
   476 	/**
       
   477 	 * Initiates object properties and sets default values.
       
   478 	 *
       
   479 	 * @since 1.5.0
       
   480 	 */
       
   481 	public function init() {
       
   482 		unset($this->posts);
       
   483 		unset($this->query);
       
   484 		$this->query_vars = array();
       
   485 		unset($this->queried_object);
       
   486 		unset($this->queried_object_id);
       
   487 		$this->post_count = 0;
       
   488 		$this->current_post = -1;
       
   489 		$this->in_the_loop = false;
       
   490 		unset( $this->request );
       
   491 		unset( $this->post );
       
   492 		unset( $this->comments );
       
   493 		unset( $this->comment );
       
   494 		$this->comment_count = 0;
       
   495 		$this->current_comment = -1;
       
   496 		$this->found_posts = 0;
       
   497 		$this->max_num_pages = 0;
       
   498 		$this->max_num_comment_pages = 0;
       
   499 
       
   500 		$this->init_query_flags();
       
   501 	}
       
   502 
       
   503 	/**
       
   504 	 * Reparse the query vars.
       
   505 	 *
       
   506 	 * @since 1.5.0
       
   507 	 */
       
   508 	public function parse_query_vars() {
       
   509 		$this->parse_query();
       
   510 	}
       
   511 
       
   512 	/**
       
   513 	 * Fills in the query variables, which do not exist within the parameter.
       
   514 	 *
       
   515 	 * @since 2.1.0
       
   516 	 * @since 4.4.0 Removed the `comments_popup` public query variable.
       
   517 	 *
       
   518 	 * @param array $array Defined query variables.
       
   519 	 * @return array Complete query variables with undefined ones filled in empty.
       
   520 	 */
       
   521 	public function fill_query_vars($array) {
       
   522 		$keys = array(
       
   523 			'error'
       
   524 			, 'm'
       
   525 			, 'p'
       
   526 			, 'post_parent'
       
   527 			, 'subpost'
       
   528 			, 'subpost_id'
       
   529 			, 'attachment'
       
   530 			, 'attachment_id'
       
   531 			, 'name'
       
   532 			, 'static'
       
   533 			, 'pagename'
       
   534 			, 'page_id'
       
   535 			, 'second'
       
   536 			, 'minute'
       
   537 			, 'hour'
       
   538 			, 'day'
       
   539 			, 'monthnum'
       
   540 			, 'year'
       
   541 			, 'w'
       
   542 			, 'category_name'
       
   543 			, 'tag'
       
   544 			, 'cat'
       
   545 			, 'tag_id'
       
   546 			, 'author'
       
   547 			, 'author_name'
       
   548 			, 'feed'
       
   549 			, 'tb'
       
   550 			, 'paged'
       
   551 			, 'meta_key'
       
   552 			, 'meta_value'
       
   553 			, 'preview'
       
   554 			, 's'
       
   555 			, 'sentence'
       
   556 			, 'title'
       
   557 			, 'fields'
       
   558 			, 'menu_order'
       
   559 			, 'embed'
       
   560 		);
       
   561 
       
   562 		foreach ( $keys as $key ) {
       
   563 			if ( !isset($array[$key]) )
       
   564 				$array[$key] = '';
       
   565 		}
       
   566 
       
   567 		$array_keys = array( 'category__in', 'category__not_in', 'category__and', 'post__in', 'post__not_in', 'post_name__in',
       
   568 			'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'post_parent__in', 'post_parent__not_in',
       
   569 			'author__in', 'author__not_in' );
       
   570 
       
   571 		foreach ( $array_keys as $key ) {
       
   572 			if ( !isset($array[$key]) )
       
   573 				$array[$key] = array();
       
   574 		}
       
   575 		return $array;
       
   576 	}
       
   577 
       
   578 	/**
       
   579 	 * Parse a query string and set query type booleans.
       
   580 	 *
       
   581 	 * @since 1.5.0
       
   582 	 * @since 4.2.0 Introduced the ability to order by specific clauses of a `$meta_query`, by passing the clause's
       
   583 	 *              array key to `$orderby`.
       
   584 	 * @since 4.4.0 Introduced `$post_name__in` and `$title` parameters. `$s` was updated to support excluded
       
   585 	 *              search terms, by prepending a hyphen.
       
   586 	 * @since 4.5.0 Removed the `$comments_popup` parameter.
       
   587 	 *              Introduced the `$comment_status` and `$ping_status` parameters.
       
   588 	 *              Introduced `RAND(x)` syntax for `$orderby`, which allows an integer seed value to random sorts.
       
   589 	 * @since 4.6.0 Added 'post_name__in' support for `$orderby`. Introduced the `$lazy_load_term_meta` argument.
       
   590 	 * @since 4.9.0 Introduced the `$comment_count` parameter.
       
   591 	 *
       
   592 	 * @param string|array $query {
       
   593 	 *     Optional. Array or string of Query parameters.
       
   594 	 *
       
   595 	 *     @type int          $attachment_id           Attachment post ID. Used for 'attachment' post_type.
       
   596 	 *     @type int|string   $author                  Author ID, or comma-separated list of IDs.
       
   597 	 *     @type string       $author_name             User 'user_nicename'.
       
   598 	 *     @type array        $author__in              An array of author IDs to query from.
       
   599 	 *     @type array        $author__not_in          An array of author IDs not to query from.
       
   600 	 *     @type bool         $cache_results           Whether to cache post information. Default true.
       
   601 	 *     @type int|string   $cat                     Category ID or comma-separated list of IDs (this or any children).
       
   602 	 *     @type array        $category__and           An array of category IDs (AND in).
       
   603 	 *     @type array        $category__in            An array of category IDs (OR in, no children).
       
   604 	 *     @type array        $category__not_in        An array of category IDs (NOT in).
       
   605 	 *     @type string       $category_name           Use category slug (not name, this or any children).
       
   606 	 *     @type array|int    $comment_count           Filter results by comment count. Provide an integer to match
       
   607 	 *                                                 comment count exactly. Provide an array with integer 'value'
       
   608 	 *                                                 and 'compare' operator ('=', '!=', '>', '>=', '<', '<=' ) to
       
   609 	 *                                                 compare against comment_count in a specific way.
       
   610 	 *     @type string       $comment_status          Comment status.
       
   611 	 *     @type int          $comments_per_page       The number of comments to return per page.
       
   612 	 *                                                 Default 'comments_per_page' option.
       
   613 	 *     @type array        $date_query              An associative array of WP_Date_Query arguments.
       
   614 	 *                                                 See WP_Date_Query::__construct().
       
   615 	 *     @type int          $day                     Day of the month. Default empty. Accepts numbers 1-31.
       
   616 	 *     @type bool         $exact                   Whether to search by exact keyword. Default false.
       
   617 	 *     @type string|array $fields                  Which fields to return. Single field or all fields (string),
       
   618 	 *                                                 or array of fields. 'id=>parent' uses 'id' and 'post_parent'.
       
   619 	 *                                                 Default all fields. Accepts 'ids', 'id=>parent'.
       
   620 	 *     @type int          $hour                    Hour of the day. Default empty. Accepts numbers 0-23.
       
   621 	 *     @type int|bool     $ignore_sticky_posts     Whether to ignore sticky posts or not. Setting this to false
       
   622 	 *                                                 excludes stickies from 'post__in'. Accepts 1|true, 0|false.
       
   623 	 *                                                 Default 0|false.
       
   624 	 *     @type int          $m                       Combination YearMonth. Accepts any four-digit year and month
       
   625 	 *                                                 numbers 1-12. Default empty.
       
   626 	 *     @type string       $meta_compare            Comparison operator to test the 'meta_value'.
       
   627 	 *     @type string       $meta_key                Custom field key.
       
   628 	 *     @type array        $meta_query              An associative array of WP_Meta_Query arguments. See WP_Meta_Query.
       
   629 	 *     @type string       $meta_value              Custom field value.
       
   630 	 *     @type int          $meta_value_num          Custom field value number.
       
   631 	 *     @type int          $menu_order              The menu order of the posts.
       
   632 	 *     @type int          $monthnum                The two-digit month. Default empty. Accepts numbers 1-12.
       
   633 	 *     @type string       $name                    Post slug.
       
   634 	 *     @type bool         $nopaging                Show all posts (true) or paginate (false). Default false.
       
   635 	 *     @type bool         $no_found_rows           Whether to skip counting the total rows found. Enabling can improve
       
   636 	 *                                                 performance. Default false.
       
   637 	 *     @type int          $offset                  The number of posts to offset before retrieval.
       
   638 	 *     @type string       $order                   Designates ascending or descending order of posts. Default 'DESC'.
       
   639 	 *                                                 Accepts 'ASC', 'DESC'.
       
   640 	 *     @type string|array $orderby                 Sort retrieved posts by parameter. One or more options may be
       
   641 	 *                                                 passed. To use 'meta_value', or 'meta_value_num',
       
   642 	 *                                                 'meta_key=keyname' must be also be defined. To sort by a
       
   643 	 *                                                 specific `$meta_query` clause, use that clause's array key.
       
   644 	 *                                                 Accepts 'none', 'name', 'author', 'date', 'title',
       
   645 	 *                                                 'modified', 'menu_order', 'parent', 'ID', 'rand',
       
   646 	 *                                                 'relevance', 'RAND(x)' (where 'x' is an integer seed value),
       
   647 	 *                                                 'comment_count', 'meta_value', 'meta_value_num', 'post__in',
       
   648 	 *                                                 'post_name__in', 'post_parent__in', and the array keys
       
   649 	 *                                                 of `$meta_query`. Default is 'date', except when a search
       
   650 	 *                                                 is being performed, when the default is 'relevance'.
       
   651 	 *
       
   652 	 *     @type int          $p                       Post ID.
       
   653 	 *     @type int          $page                    Show the number of posts that would show up on page X of a
       
   654 	 *                                                 static front page.
       
   655 	 *     @type int          $paged                   The number of the current page.
       
   656 	 *     @type int          $page_id                 Page ID.
       
   657 	 *     @type string       $pagename                Page slug.
       
   658 	 *     @type string       $perm                    Show posts if user has the appropriate capability.
       
   659 	 *     @type string       $ping_status             Ping status.
       
   660 	 *     @type array        $post__in                An array of post IDs to retrieve, sticky posts will be included
       
   661 	 *     @type string       $post_mime_type          The mime type of the post. Used for 'attachment' post_type.
       
   662 	 *     @type array        $post__not_in            An array of post IDs not to retrieve. Note: a string of comma-
       
   663 	 *                                                 separated IDs will NOT work.
       
   664 	 *     @type int          $post_parent             Page ID to retrieve child pages for. Use 0 to only retrieve
       
   665 	 *                                                 top-level pages.
       
   666 	 *     @type array        $post_parent__in         An array containing parent page IDs to query child pages from.
       
   667 	 *     @type array        $post_parent__not_in     An array containing parent page IDs not to query child pages from.
       
   668 	 *     @type string|array $post_type               A post type slug (string) or array of post type slugs.
       
   669 	 *                                                 Default 'any' if using 'tax_query'.
       
   670 	 *     @type string|array $post_status             A post status (string) or array of post statuses.
       
   671 	 *     @type int          $posts_per_page          The number of posts to query for. Use -1 to request all posts.
       
   672 	 *     @type int          $posts_per_archive_page  The number of posts to query for by archive page. Overrides
       
   673 	 *                                                 'posts_per_page' when is_archive(), or is_search() are true.
       
   674 	 *     @type array        $post_name__in           An array of post slugs that results must match.
       
   675 	 *     @type string       $s                       Search keyword(s). Prepending a term with a hyphen will
       
   676 	 *                                                 exclude posts matching that term. Eg, 'pillow -sofa' will
       
   677 	 *                                                 return posts containing 'pillow' but not 'sofa'. The
       
   678 	 *                                                 character used for exclusion can be modified using the
       
   679 	 *                                                 the 'wp_query_search_exclusion_prefix' filter.
       
   680 	 *     @type int          $second                  Second of the minute. Default empty. Accepts numbers 0-60.
       
   681 	 *     @type bool         $sentence                Whether to search by phrase. Default false.
       
   682 	 *     @type bool         $suppress_filters        Whether to suppress filters. Default false.
       
   683 	 *     @type string       $tag                     Tag slug. Comma-separated (either), Plus-separated (all).
       
   684 	 *     @type array        $tag__and                An array of tag ids (AND in).
       
   685 	 *     @type array        $tag__in                 An array of tag ids (OR in).
       
   686 	 *     @type array        $tag__not_in             An array of tag ids (NOT in).
       
   687 	 *     @type int          $tag_id                  Tag id or comma-separated list of IDs.
       
   688 	 *     @type array        $tag_slug__and           An array of tag slugs (AND in).
       
   689 	 *     @type array        $tag_slug__in            An array of tag slugs (OR in). unless 'ignore_sticky_posts' is
       
   690 	 *                                                 true. Note: a string of comma-separated IDs will NOT work.
       
   691 	 *     @type array        $tax_query               An associative array of WP_Tax_Query arguments.
       
   692 	 *                                                 See WP_Tax_Query->queries.
       
   693 	 *     @type string       $title                   Post title.
       
   694 	 *     @type bool         $update_post_meta_cache  Whether to update the post meta cache. Default true.
       
   695 	 *     @type bool         $update_post_term_cache  Whether to update the post term cache. Default true.
       
   696 	 *     @type bool         $lazy_load_term_meta     Whether to lazy-load term meta. Setting to false will
       
   697 	 *                                                 disable cache priming for term meta, so that each
       
   698 	 *                                                 get_term_meta() call will hit the database.
       
   699 	 *                                                 Defaults to the value of `$update_post_term_cache`.
       
   700 	 *     @type int          $w                       The week number of the year. Default empty. Accepts numbers 0-53.
       
   701 	 *     @type int          $year                    The four-digit year. Default empty. Accepts any four-digit year.
       
   702 	 * }
       
   703 	 */
       
   704 	public function parse_query( $query =  '' ) {
       
   705 		if ( ! empty( $query ) ) {
       
   706 			$this->init();
       
   707 			$this->query = $this->query_vars = wp_parse_args( $query );
       
   708 		} elseif ( ! isset( $this->query ) ) {
       
   709 			$this->query = $this->query_vars;
       
   710 		}
       
   711 
       
   712 		$this->query_vars = $this->fill_query_vars($this->query_vars);
       
   713 		$qv = &$this->query_vars;
       
   714 		$this->query_vars_changed = true;
       
   715 
       
   716 		if ( ! empty($qv['robots']) )
       
   717 			$this->is_robots = true;
       
   718 
       
   719 		if ( ! is_scalar( $qv['p'] ) || $qv['p'] < 0 ) {
       
   720 			$qv['p'] = 0;
       
   721 			$qv['error'] = '404';
       
   722 		} else {
       
   723 			$qv['p'] = intval( $qv['p'] );
       
   724 		}
       
   725 
       
   726 		$qv['page_id'] =  absint($qv['page_id']);
       
   727 		$qv['year'] = absint($qv['year']);
       
   728 		$qv['monthnum'] = absint($qv['monthnum']);
       
   729 		$qv['day'] = absint($qv['day']);
       
   730 		$qv['w'] = absint($qv['w']);
       
   731 		$qv['m'] = is_scalar( $qv['m'] ) ? preg_replace( '|[^0-9]|', '', $qv['m'] ) : '';
       
   732 		$qv['paged'] = absint($qv['paged']);
       
   733 		$qv['cat'] = preg_replace( '|[^0-9,-]|', '', $qv['cat'] ); // comma separated list of positive or negative integers
       
   734 		$qv['author'] = preg_replace( '|[^0-9,-]|', '', $qv['author'] ); // comma separated list of positive or negative integers
       
   735 		$qv['pagename'] = trim( $qv['pagename'] );
       
   736 		$qv['name'] = trim( $qv['name'] );
       
   737 		$qv['title'] = trim( $qv['title'] );
       
   738 		if ( '' !== $qv['hour'] ) $qv['hour'] = absint($qv['hour']);
       
   739 		if ( '' !== $qv['minute'] ) $qv['minute'] = absint($qv['minute']);
       
   740 		if ( '' !== $qv['second'] ) $qv['second'] = absint($qv['second']);
       
   741 		if ( '' !== $qv['menu_order'] ) $qv['menu_order'] = absint($qv['menu_order']);
       
   742 
       
   743 		// Fairly insane upper bound for search string lengths.
       
   744 		if ( ! is_scalar( $qv['s'] ) || ( ! empty( $qv['s'] ) && strlen( $qv['s'] ) > 1600 ) ) {
       
   745 			$qv['s'] = '';
       
   746 		}
       
   747 
       
   748 		// Compat. Map subpost to attachment.
       
   749 		if ( '' != $qv['subpost'] )
       
   750 			$qv['attachment'] = $qv['subpost'];
       
   751 		if ( '' != $qv['subpost_id'] )
       
   752 			$qv['attachment_id'] = $qv['subpost_id'];
       
   753 
       
   754 		$qv['attachment_id'] = absint($qv['attachment_id']);
       
   755 
       
   756 		if ( ('' != $qv['attachment']) || !empty($qv['attachment_id']) ) {
       
   757 			$this->is_single = true;
       
   758 			$this->is_attachment = true;
       
   759 		} elseif ( '' != $qv['name'] ) {
       
   760 			$this->is_single = true;
       
   761 		} elseif ( $qv['p'] ) {
       
   762 			$this->is_single = true;
       
   763 		} elseif ( ('' !== $qv['hour']) && ('' !== $qv['minute']) &&('' !== $qv['second']) && ('' != $qv['year']) && ('' != $qv['monthnum']) && ('' != $qv['day']) ) {
       
   764 			// If year, month, day, hour, minute, and second are set, a single
       
   765 			// post is being queried.
       
   766 			$this->is_single = true;
       
   767 		} elseif ( '' != $qv['static'] || '' != $qv['pagename'] || !empty($qv['page_id']) ) {
       
   768 			$this->is_page = true;
       
   769 			$this->is_single = false;
       
   770 		} else {
       
   771 			// Look for archive queries. Dates, categories, authors, search, post type archives.
       
   772 
       
   773 			if ( isset( $this->query['s'] ) ) {
       
   774 				$this->is_search = true;
       
   775 			}
       
   776 
       
   777 			if ( '' !== $qv['second'] ) {
       
   778 				$this->is_time = true;
       
   779 				$this->is_date = true;
       
   780 			}
       
   781 
       
   782 			if ( '' !== $qv['minute'] ) {
       
   783 				$this->is_time = true;
       
   784 				$this->is_date = true;
       
   785 			}
       
   786 
       
   787 			if ( '' !== $qv['hour'] ) {
       
   788 				$this->is_time = true;
       
   789 				$this->is_date = true;
       
   790 			}
       
   791 
       
   792 			if ( $qv['day'] ) {
       
   793 				if ( ! $this->is_date ) {
       
   794 					$date = sprintf( '%04d-%02d-%02d', $qv['year'], $qv['monthnum'], $qv['day'] );
       
   795 					if ( $qv['monthnum'] && $qv['year'] && ! wp_checkdate( $qv['monthnum'], $qv['day'], $qv['year'], $date ) ) {
       
   796 						$qv['error'] = '404';
       
   797 					} else {
       
   798 						$this->is_day = true;
       
   799 						$this->is_date = true;
       
   800 					}
       
   801 				}
       
   802 			}
       
   803 
       
   804 			if ( $qv['monthnum'] ) {
       
   805 				if ( ! $this->is_date ) {
       
   806 					if ( 12 < $qv['monthnum'] ) {
       
   807 						$qv['error'] = '404';
       
   808 					} else {
       
   809 						$this->is_month = true;
       
   810 						$this->is_date = true;
       
   811 					}
       
   812 				}
       
   813 			}
       
   814 
       
   815 			if ( $qv['year'] ) {
       
   816 				if ( ! $this->is_date ) {
       
   817 					$this->is_year = true;
       
   818 					$this->is_date = true;
       
   819 				}
       
   820 			}
       
   821 
       
   822 			if ( $qv['m'] ) {
       
   823 				$this->is_date = true;
       
   824 				if ( strlen($qv['m']) > 9 ) {
       
   825 					$this->is_time = true;
       
   826 				} elseif ( strlen( $qv['m'] ) > 7 ) {
       
   827 					$this->is_day = true;
       
   828 				} elseif ( strlen( $qv['m'] ) > 5 ) {
       
   829 					$this->is_month = true;
       
   830 				} else {
       
   831 					$this->is_year = true;
       
   832 				}
       
   833 			}
       
   834 
       
   835 			if ( '' != $qv['w'] ) {
       
   836 				$this->is_date = true;
       
   837 			}
       
   838 
       
   839 			$this->query_vars_hash = false;
       
   840 			$this->parse_tax_query( $qv );
       
   841 
       
   842 			foreach ( $this->tax_query->queries as $tax_query ) {
       
   843 				if ( ! is_array( $tax_query ) ) {
       
   844 					continue;
       
   845 				}
       
   846 
       
   847 				if ( isset( $tax_query['operator'] ) && 'NOT IN' != $tax_query['operator'] ) {
       
   848 					switch ( $tax_query['taxonomy'] ) {
       
   849 						case 'category':
       
   850 							$this->is_category = true;
       
   851 							break;
       
   852 						case 'post_tag':
       
   853 							$this->is_tag = true;
       
   854 							break;
       
   855 						default:
       
   856 							$this->is_tax = true;
       
   857 					}
       
   858 				}
       
   859 			}
       
   860 			unset( $tax_query );
       
   861 
       
   862 			if ( empty($qv['author']) || ($qv['author'] == '0') ) {
       
   863 				$this->is_author = false;
       
   864 			} else {
       
   865 				$this->is_author = true;
       
   866 			}
       
   867 
       
   868 			if ( '' != $qv['author_name'] )
       
   869 				$this->is_author = true;
       
   870 
       
   871 			if ( !empty( $qv['post_type'] ) && ! is_array( $qv['post_type'] ) ) {
       
   872 				$post_type_obj = get_post_type_object( $qv['post_type'] );
       
   873 				if ( ! empty( $post_type_obj->has_archive ) )
       
   874 					$this->is_post_type_archive = true;
       
   875 			}
       
   876 
       
   877 			if ( $this->is_post_type_archive || $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax )
       
   878 				$this->is_archive = true;
       
   879 		}
       
   880 
       
   881 		if ( '' != $qv['feed'] )
       
   882 			$this->is_feed = true;
       
   883 
       
   884 		if ( '' != $qv['embed'] ) {
       
   885 			$this->is_embed = true;
       
   886 		}
       
   887 
       
   888 		if ( '' != $qv['tb'] )
       
   889 			$this->is_trackback = true;
       
   890 
       
   891 		if ( '' != $qv['paged'] && ( intval($qv['paged']) > 1 ) )
       
   892 			$this->is_paged = true;
       
   893 
       
   894 		// if we're previewing inside the write screen
       
   895 		if ( '' != $qv['preview'] )
       
   896 			$this->is_preview = true;
       
   897 
       
   898 		if ( is_admin() )
       
   899 			$this->is_admin = true;
       
   900 
       
   901 		if ( false !== strpos($qv['feed'], 'comments-') ) {
       
   902 			$qv['feed'] = str_replace('comments-', '', $qv['feed']);
       
   903 			$qv['withcomments'] = 1;
       
   904 		}
       
   905 
       
   906 		$this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
       
   907 
       
   908 		if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) )
       
   909 			$this->is_comment_feed = true;
       
   910 
       
   911 		if ( !( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots ) )
       
   912 			$this->is_home = true;
       
   913 
       
   914 		// Correct is_* for page_on_front and page_for_posts
       
   915 		if ( $this->is_home && 'page' == get_option('show_on_front') && get_option('page_on_front') ) {
       
   916 			$_query = wp_parse_args($this->query);
       
   917 			// pagename can be set and empty depending on matched rewrite rules. Ignore an empty pagename.
       
   918 			if ( isset($_query['pagename']) && '' == $_query['pagename'] )
       
   919 				unset($_query['pagename']);
       
   920 
       
   921 			unset( $_query['embed'] );
       
   922 
       
   923 			if ( empty($_query) || !array_diff( array_keys($_query), array('preview', 'page', 'paged', 'cpage') ) ) {
       
   924 				$this->is_page = true;
       
   925 				$this->is_home = false;
       
   926 				$qv['page_id'] = get_option('page_on_front');
       
   927 				// Correct <!--nextpage--> for page_on_front
       
   928 				if ( !empty($qv['paged']) ) {
       
   929 					$qv['page'] = $qv['paged'];
       
   930 					unset($qv['paged']);
       
   931 				}
       
   932 			}
       
   933 		}
       
   934 
       
   935 		if ( '' != $qv['pagename'] ) {
       
   936 			$this->queried_object = get_page_by_path( $qv['pagename'] );
       
   937 
       
   938 			if ( $this->queried_object && 'attachment' == $this->queried_object->post_type ) {
       
   939 				if ( preg_match( "/^[^%]*%(?:postname)%/", get_option( 'permalink_structure' ) ) ) {
       
   940 					// See if we also have a post with the same slug
       
   941 					$post = get_page_by_path( $qv['pagename'], OBJECT, 'post' );
       
   942 					if ( $post ) {
       
   943 						$this->queried_object = $post;
       
   944 						$this->is_page = false;
       
   945 						$this->is_single = true;
       
   946 					}
       
   947 				}
       
   948 			}
       
   949 
       
   950 			if ( ! empty( $this->queried_object ) ) {
       
   951 				$this->queried_object_id = (int) $this->queried_object->ID;
       
   952 			} else {
       
   953 				unset( $this->queried_object );
       
   954 			}
       
   955 
       
   956 			if  ( 'page' == get_option('show_on_front') && isset($this->queried_object_id) && $this->queried_object_id == get_option('page_for_posts') ) {
       
   957 				$this->is_page = false;
       
   958 				$this->is_home = true;
       
   959 				$this->is_posts_page = true;
       
   960 			}
       
   961 		}
       
   962 
       
   963 		if ( $qv['page_id'] ) {
       
   964 			if  ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) {
       
   965 				$this->is_page = false;
       
   966 				$this->is_home = true;
       
   967 				$this->is_posts_page = true;
       
   968 			}
       
   969 		}
       
   970 
       
   971 		if ( !empty($qv['post_type']) ) {
       
   972 			if ( is_array($qv['post_type']) )
       
   973 				$qv['post_type'] = array_map('sanitize_key', $qv['post_type']);
       
   974 			else
       
   975 				$qv['post_type'] = sanitize_key($qv['post_type']);
       
   976 		}
       
   977 
       
   978 		if ( ! empty( $qv['post_status'] ) ) {
       
   979 			if ( is_array( $qv['post_status'] ) )
       
   980 				$qv['post_status'] = array_map('sanitize_key', $qv['post_status']);
       
   981 			else
       
   982 				$qv['post_status'] = preg_replace('|[^a-z0-9_,-]|', '', $qv['post_status']);
       
   983 		}
       
   984 
       
   985 		if ( $this->is_posts_page && ( ! isset($qv['withcomments']) || ! $qv['withcomments'] ) )
       
   986 			$this->is_comment_feed = false;
       
   987 
       
   988 		$this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
       
   989 		// Done correcting is_* for page_on_front and page_for_posts
       
   990 
       
   991 		if ( '404' == $qv['error'] )
       
   992 			$this->set_404();
       
   993 
       
   994 		$this->is_embed = $this->is_embed && ( $this->is_singular || $this->is_404 );
       
   995 
       
   996 		$this->query_vars_hash = md5( serialize( $this->query_vars ) );
       
   997 		$this->query_vars_changed = false;
       
   998 
       
   999 		/**
       
  1000 		 * Fires after the main query vars have been parsed.
       
  1001 		 *
       
  1002 		 * @since 1.5.0
       
  1003 		 *
       
  1004 		 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  1005 		 */
       
  1006 		do_action_ref_array( 'parse_query', array( &$this ) );
       
  1007 	}
       
  1008 
       
  1009 	/**
       
  1010 	 * Parses various taxonomy related query vars.
       
  1011 	 *
       
  1012 	 * For BC, this method is not marked as protected. See [28987].
       
  1013 	 *
       
  1014 	 * @since 3.1.0
       
  1015 	 *
       
  1016 	 * @param array $q The query variables. Passed by reference.
       
  1017 	 */
       
  1018 	public function parse_tax_query( &$q ) {
       
  1019 		if ( ! empty( $q['tax_query'] ) && is_array( $q['tax_query'] ) ) {
       
  1020 			$tax_query = $q['tax_query'];
       
  1021 		} else {
       
  1022 			$tax_query = array();
       
  1023 		}
       
  1024 
       
  1025 		if ( !empty($q['taxonomy']) && !empty($q['term']) ) {
       
  1026 			$tax_query[] = array(
       
  1027 				'taxonomy' => $q['taxonomy'],
       
  1028 				'terms' => array( $q['term'] ),
       
  1029 				'field' => 'slug',
       
  1030 			);
       
  1031 		}
       
  1032 
       
  1033 		foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t ) {
       
  1034 			if ( 'post_tag' == $taxonomy )
       
  1035 				continue;	// Handled further down in the $q['tag'] block
       
  1036 
       
  1037 			if ( $t->query_var && !empty( $q[$t->query_var] ) ) {
       
  1038 				$tax_query_defaults = array(
       
  1039 					'taxonomy' => $taxonomy,
       
  1040 					'field' => 'slug',
       
  1041 				);
       
  1042 
       
  1043  				if ( isset( $t->rewrite['hierarchical'] ) && $t->rewrite['hierarchical'] ) {
       
  1044 					$q[$t->query_var] = wp_basename( $q[$t->query_var] );
       
  1045 				}
       
  1046 
       
  1047 				$term = $q[$t->query_var];
       
  1048 
       
  1049 				if ( is_array( $term ) ) {
       
  1050 					$term = implode( ',', $term );
       
  1051 				}
       
  1052 
       
  1053 				if ( strpos($term, '+') !== false ) {
       
  1054 					$terms = preg_split( '/[+]+/', $term );
       
  1055 					foreach ( $terms as $term ) {
       
  1056 						$tax_query[] = array_merge( $tax_query_defaults, array(
       
  1057 							'terms' => array( $term )
       
  1058 						) );
       
  1059 					}
       
  1060 				} else {
       
  1061 					$tax_query[] = array_merge( $tax_query_defaults, array(
       
  1062 						'terms' => preg_split( '/[,]+/', $term )
       
  1063 					) );
       
  1064 				}
       
  1065 			}
       
  1066 		}
       
  1067 
       
  1068 		// If querystring 'cat' is an array, implode it.
       
  1069 		if ( is_array( $q['cat'] ) ) {
       
  1070 			$q['cat'] = implode( ',', $q['cat'] );
       
  1071 		}
       
  1072 
       
  1073 		// Category stuff
       
  1074 		if ( ! empty( $q['cat'] ) && ! $this->is_singular ) {
       
  1075 			$cat_in = $cat_not_in = array();
       
  1076 
       
  1077 			$cat_array = preg_split( '/[,\s]+/', urldecode( $q['cat'] ) );
       
  1078 			$cat_array = array_map( 'intval', $cat_array );
       
  1079 			$q['cat'] = implode( ',', $cat_array );
       
  1080 
       
  1081 			foreach ( $cat_array as $cat ) {
       
  1082 				if ( $cat > 0 )
       
  1083 					$cat_in[] = $cat;
       
  1084 				elseif ( $cat < 0 )
       
  1085 					$cat_not_in[] = abs( $cat );
       
  1086 			}
       
  1087 
       
  1088 			if ( ! empty( $cat_in ) ) {
       
  1089 				$tax_query[] = array(
       
  1090 					'taxonomy' => 'category',
       
  1091 					'terms' => $cat_in,
       
  1092 					'field' => 'term_id',
       
  1093 					'include_children' => true
       
  1094 				);
       
  1095 			}
       
  1096 
       
  1097 			if ( ! empty( $cat_not_in ) ) {
       
  1098 				$tax_query[] = array(
       
  1099 					'taxonomy' => 'category',
       
  1100 					'terms' => $cat_not_in,
       
  1101 					'field' => 'term_id',
       
  1102 					'operator' => 'NOT IN',
       
  1103 					'include_children' => true
       
  1104 				);
       
  1105 			}
       
  1106 			unset( $cat_array, $cat_in, $cat_not_in );
       
  1107 		}
       
  1108 
       
  1109 		if ( ! empty( $q['category__and'] ) && 1 === count( (array) $q['category__and'] ) ) {
       
  1110 			$q['category__and'] = (array) $q['category__and'];
       
  1111 			if ( ! isset( $q['category__in'] ) )
       
  1112 				$q['category__in'] = array();
       
  1113 			$q['category__in'][] = absint( reset( $q['category__and'] ) );
       
  1114 			unset( $q['category__and'] );
       
  1115 		}
       
  1116 
       
  1117 		if ( ! empty( $q['category__in'] ) ) {
       
  1118 			$q['category__in'] = array_map( 'absint', array_unique( (array) $q['category__in'] ) );
       
  1119 			$tax_query[] = array(
       
  1120 				'taxonomy' => 'category',
       
  1121 				'terms' => $q['category__in'],
       
  1122 				'field' => 'term_id',
       
  1123 				'include_children' => false
       
  1124 			);
       
  1125 		}
       
  1126 
       
  1127 		if ( ! empty($q['category__not_in']) ) {
       
  1128 			$q['category__not_in'] = array_map( 'absint', array_unique( (array) $q['category__not_in'] ) );
       
  1129 			$tax_query[] = array(
       
  1130 				'taxonomy' => 'category',
       
  1131 				'terms' => $q['category__not_in'],
       
  1132 				'operator' => 'NOT IN',
       
  1133 				'include_children' => false
       
  1134 			);
       
  1135 		}
       
  1136 
       
  1137 		if ( ! empty($q['category__and']) ) {
       
  1138 			$q['category__and'] = array_map( 'absint', array_unique( (array) $q['category__and'] ) );
       
  1139 			$tax_query[] = array(
       
  1140 				'taxonomy' => 'category',
       
  1141 				'terms' => $q['category__and'],
       
  1142 				'field' => 'term_id',
       
  1143 				'operator' => 'AND',
       
  1144 				'include_children' => false
       
  1145 			);
       
  1146 		}
       
  1147 
       
  1148 		// If querystring 'tag' is array, implode it.
       
  1149 		if ( is_array( $q['tag'] ) ) {
       
  1150 			$q['tag'] = implode( ',', $q['tag'] );
       
  1151 		}
       
  1152 
       
  1153 		// Tag stuff
       
  1154 		if ( '' != $q['tag'] && !$this->is_singular && $this->query_vars_changed ) {
       
  1155 			if ( strpos($q['tag'], ',') !== false ) {
       
  1156 				$tags = preg_split('/[,\r\n\t ]+/', $q['tag']);
       
  1157 				foreach ( (array) $tags as $tag ) {
       
  1158 					$tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
       
  1159 					$q['tag_slug__in'][] = $tag;
       
  1160 				}
       
  1161 			} elseif ( preg_match('/[+\r\n\t ]+/', $q['tag'] ) || ! empty( $q['cat'] ) ) {
       
  1162 				$tags = preg_split('/[+\r\n\t ]+/', $q['tag']);
       
  1163 				foreach ( (array) $tags as $tag ) {
       
  1164 					$tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
       
  1165 					$q['tag_slug__and'][] = $tag;
       
  1166 				}
       
  1167 			} else {
       
  1168 				$q['tag'] = sanitize_term_field('slug', $q['tag'], 0, 'post_tag', 'db');
       
  1169 				$q['tag_slug__in'][] = $q['tag'];
       
  1170 			}
       
  1171 		}
       
  1172 
       
  1173 		if ( !empty($q['tag_id']) ) {
       
  1174 			$q['tag_id'] = absint( $q['tag_id'] );
       
  1175 			$tax_query[] = array(
       
  1176 				'taxonomy' => 'post_tag',
       
  1177 				'terms' => $q['tag_id']
       
  1178 			);
       
  1179 		}
       
  1180 
       
  1181 		if ( !empty($q['tag__in']) ) {
       
  1182 			$q['tag__in'] = array_map('absint', array_unique( (array) $q['tag__in'] ) );
       
  1183 			$tax_query[] = array(
       
  1184 				'taxonomy' => 'post_tag',
       
  1185 				'terms' => $q['tag__in']
       
  1186 			);
       
  1187 		}
       
  1188 
       
  1189 		if ( !empty($q['tag__not_in']) ) {
       
  1190 			$q['tag__not_in'] = array_map('absint', array_unique( (array) $q['tag__not_in'] ) );
       
  1191 			$tax_query[] = array(
       
  1192 				'taxonomy' => 'post_tag',
       
  1193 				'terms' => $q['tag__not_in'],
       
  1194 				'operator' => 'NOT IN'
       
  1195 			);
       
  1196 		}
       
  1197 
       
  1198 		if ( !empty($q['tag__and']) ) {
       
  1199 			$q['tag__and'] = array_map('absint', array_unique( (array) $q['tag__and'] ) );
       
  1200 			$tax_query[] = array(
       
  1201 				'taxonomy' => 'post_tag',
       
  1202 				'terms' => $q['tag__and'],
       
  1203 				'operator' => 'AND'
       
  1204 			);
       
  1205 		}
       
  1206 
       
  1207 		if ( !empty($q['tag_slug__in']) ) {
       
  1208 			$q['tag_slug__in'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__in'] ) );
       
  1209 			$tax_query[] = array(
       
  1210 				'taxonomy' => 'post_tag',
       
  1211 				'terms' => $q['tag_slug__in'],
       
  1212 				'field' => 'slug'
       
  1213 			);
       
  1214 		}
       
  1215 
       
  1216 		if ( !empty($q['tag_slug__and']) ) {
       
  1217 			$q['tag_slug__and'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__and'] ) );
       
  1218 			$tax_query[] = array(
       
  1219 				'taxonomy' => 'post_tag',
       
  1220 				'terms' => $q['tag_slug__and'],
       
  1221 				'field' => 'slug',
       
  1222 				'operator' => 'AND'
       
  1223 			);
       
  1224 		}
       
  1225 
       
  1226 		$this->tax_query = new WP_Tax_Query( $tax_query );
       
  1227 
       
  1228 		/**
       
  1229 		 * Fires after taxonomy-related query vars have been parsed.
       
  1230 		 *
       
  1231 		 * @since 3.7.0
       
  1232 		 *
       
  1233 		 * @param WP_Query $this The WP_Query instance.
       
  1234 		 */
       
  1235 		do_action( 'parse_tax_query', $this );
       
  1236 	}
       
  1237 
       
  1238 	/**
       
  1239 	 * Generates SQL for the WHERE clause based on passed search terms.
       
  1240 	 *
       
  1241 	 * @since 3.7.0
       
  1242 	 *
       
  1243 	 * @global wpdb $wpdb WordPress database abstraction object.
       
  1244 	 *
       
  1245 	 * @param array $q Query variables.
       
  1246 	 * @return string WHERE clause.
       
  1247 	 */
       
  1248 	protected function parse_search( &$q ) {
       
  1249 		global $wpdb;
       
  1250 
       
  1251 		$search = '';
       
  1252 
       
  1253 		// added slashes screw with quote grouping when done early, so done later
       
  1254 		$q['s'] = stripslashes( $q['s'] );
       
  1255 		if ( empty( $_GET['s'] ) && $this->is_main_query() )
       
  1256 			$q['s'] = urldecode( $q['s'] );
       
  1257 		// there are no line breaks in <input /> fields
       
  1258 		$q['s'] = str_replace( array( "\r", "\n" ), '', $q['s'] );
       
  1259 		$q['search_terms_count'] = 1;
       
  1260 		if ( ! empty( $q['sentence'] ) ) {
       
  1261 			$q['search_terms'] = array( $q['s'] );
       
  1262 		} else {
       
  1263 			if ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $q['s'], $matches ) ) {
       
  1264 				$q['search_terms_count'] = count( $matches[0] );
       
  1265 				$q['search_terms'] = $this->parse_search_terms( $matches[0] );
       
  1266 				// if the search string has only short terms or stopwords, or is 10+ terms long, match it as sentence
       
  1267 				if ( empty( $q['search_terms'] ) || count( $q['search_terms'] ) > 9 )
       
  1268 					$q['search_terms'] = array( $q['s'] );
       
  1269 			} else {
       
  1270 				$q['search_terms'] = array( $q['s'] );
       
  1271 			}
       
  1272 		}
       
  1273 
       
  1274 		$n = ! empty( $q['exact'] ) ? '' : '%';
       
  1275 		$searchand = '';
       
  1276 		$q['search_orderby_title'] = array();
       
  1277 
       
  1278 		/**
       
  1279 		 * Filters the prefix that indicates that a search term should be excluded from results.
       
  1280 		 *
       
  1281 		 * @since 4.7.0
       
  1282 		 *
       
  1283 		 * @param string $exclusion_prefix The prefix. Default '-'. Returning
       
  1284 		 *                                 an empty value disables exclusions.
       
  1285 		 */
       
  1286 		$exclusion_prefix = apply_filters( 'wp_query_search_exclusion_prefix', '-' );
       
  1287 
       
  1288 		foreach ( $q['search_terms'] as $term ) {
       
  1289 			// If there is an $exclusion_prefix, terms prefixed with it should be excluded.
       
  1290 			$exclude = $exclusion_prefix && ( $exclusion_prefix === substr( $term, 0, 1 ) );
       
  1291 			if ( $exclude ) {
       
  1292 				$like_op  = 'NOT LIKE';
       
  1293 				$andor_op = 'AND';
       
  1294 				$term     = substr( $term, 1 );
       
  1295 			} else {
       
  1296 				$like_op  = 'LIKE';
       
  1297 				$andor_op = 'OR';
       
  1298 			}
       
  1299 
       
  1300 			if ( $n && ! $exclude ) {
       
  1301 				$like = '%' . $wpdb->esc_like( $term ) . '%';
       
  1302 				$q['search_orderby_title'][] = $wpdb->prepare( "{$wpdb->posts}.post_title LIKE %s", $like );
       
  1303 			}
       
  1304 
       
  1305 			$like = $n . $wpdb->esc_like( $term ) . $n;
       
  1306 			$search .= $wpdb->prepare( "{$searchand}(({$wpdb->posts}.post_title $like_op %s) $andor_op ({$wpdb->posts}.post_excerpt $like_op %s) $andor_op ({$wpdb->posts}.post_content $like_op %s))", $like, $like, $like );
       
  1307 			$searchand = ' AND ';
       
  1308 		}
       
  1309 
       
  1310 		if ( ! empty( $search ) ) {
       
  1311 			$search = " AND ({$search}) ";
       
  1312 			if ( ! is_user_logged_in() ) {
       
  1313 				$search .= " AND ({$wpdb->posts}.post_password = '') ";
       
  1314 			}
       
  1315 		}
       
  1316 
       
  1317 		return $search;
       
  1318 	}
       
  1319 
       
  1320 	/**
       
  1321 	 * Check if the terms are suitable for searching.
       
  1322 	 *
       
  1323 	 * Uses an array of stopwords (terms) that are excluded from the separate
       
  1324 	 * term matching when searching for posts. The list of English stopwords is
       
  1325 	 * the approximate search engines list, and is translatable.
       
  1326 	 *
       
  1327 	 * @since 3.7.0
       
  1328 	 *
       
  1329 	 * @param array $terms Terms to check.
       
  1330 	 * @return array Terms that are not stopwords.
       
  1331 	 */
       
  1332 	protected function parse_search_terms( $terms ) {
       
  1333 		$strtolower = function_exists( 'mb_strtolower' ) ? 'mb_strtolower' : 'strtolower';
       
  1334 		$checked = array();
       
  1335 
       
  1336 		$stopwords = $this->get_search_stopwords();
       
  1337 
       
  1338 		foreach ( $terms as $term ) {
       
  1339 			// keep before/after spaces when term is for exact match
       
  1340 			if ( preg_match( '/^".+"$/', $term ) )
       
  1341 				$term = trim( $term, "\"'" );
       
  1342 			else
       
  1343 				$term = trim( $term, "\"' " );
       
  1344 
       
  1345 			// Avoid single A-Z and single dashes.
       
  1346 			if ( ! $term || ( 1 === strlen( $term ) && preg_match( '/^[a-z\-]$/i', $term ) ) )
       
  1347 				continue;
       
  1348 
       
  1349 			if ( in_array( call_user_func( $strtolower, $term ), $stopwords, true ) )
       
  1350 				continue;
       
  1351 
       
  1352 			$checked[] = $term;
       
  1353 		}
       
  1354 
       
  1355 		return $checked;
       
  1356 	}
       
  1357 
       
  1358 	/**
       
  1359 	 * Retrieve stopwords used when parsing search terms.
       
  1360 	 *
       
  1361 	 * @since 3.7.0
       
  1362 	 *
       
  1363 	 * @return array Stopwords.
       
  1364 	 */
       
  1365 	protected function get_search_stopwords() {
       
  1366 		if ( isset( $this->stopwords ) )
       
  1367 			return $this->stopwords;
       
  1368 
       
  1369 		/* translators: This is a comma-separated list of very common words that should be excluded from a search,
       
  1370 		 * like a, an, and the. These are usually called "stopwords". You should not simply translate these individual
       
  1371 		 * words into your language. Instead, look for and provide commonly accepted stopwords in your language.
       
  1372 		 */
       
  1373 		$words = explode( ',', _x( 'about,an,are,as,at,be,by,com,for,from,how,in,is,it,of,on,or,that,the,this,to,was,what,when,where,who,will,with,www',
       
  1374 			'Comma-separated list of search stopwords in your language' ) );
       
  1375 
       
  1376 		$stopwords = array();
       
  1377 		foreach ( $words as $word ) {
       
  1378 			$word = trim( $word, "\r\n\t " );
       
  1379 			if ( $word )
       
  1380 				$stopwords[] = $word;
       
  1381 		}
       
  1382 
       
  1383 		/**
       
  1384 		 * Filters stopwords used when parsing search terms.
       
  1385 		 *
       
  1386 		 * @since 3.7.0
       
  1387 		 *
       
  1388 		 * @param array $stopwords Stopwords.
       
  1389 		 */
       
  1390 		$this->stopwords = apply_filters( 'wp_search_stopwords', $stopwords );
       
  1391 		return $this->stopwords;
       
  1392 	}
       
  1393 
       
  1394 	/**
       
  1395 	 * Generates SQL for the ORDER BY condition based on passed search terms.
       
  1396 	 *
       
  1397 	 * @since 3.7.0
       
  1398 	 *
       
  1399 	 * @global wpdb $wpdb WordPress database abstraction object.
       
  1400 	 *
       
  1401 	 * @param array $q Query variables.
       
  1402 	 * @return string ORDER BY clause.
       
  1403 	 */
       
  1404 	protected function parse_search_order( &$q ) {
       
  1405 		global $wpdb;
       
  1406 
       
  1407 		if ( $q['search_terms_count'] > 1 ) {
       
  1408 			$num_terms = count( $q['search_orderby_title'] );
       
  1409 
       
  1410 			// If the search terms contain negative queries, don't bother ordering by sentence matches.
       
  1411 			$like = '';
       
  1412 			if ( ! preg_match( '/(?:\s|^)\-/', $q['s'] ) ) {
       
  1413 				$like = '%' . $wpdb->esc_like( $q['s'] ) . '%';
       
  1414 			}
       
  1415 
       
  1416 			$search_orderby = '';
       
  1417 
       
  1418 			// sentence match in 'post_title'
       
  1419 			if ( $like ) {
       
  1420 				$search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_title LIKE %s THEN 1 ", $like );
       
  1421 			}
       
  1422 
       
  1423 			// sanity limit, sort as sentence when more than 6 terms
       
  1424 			// (few searches are longer than 6 terms and most titles are not)
       
  1425 			if ( $num_terms < 7 ) {
       
  1426 				// all words in title
       
  1427 				$search_orderby .= 'WHEN ' . implode( ' AND ', $q['search_orderby_title'] ) . ' THEN 2 ';
       
  1428 				// any word in title, not needed when $num_terms == 1
       
  1429 				if ( $num_terms > 1 )
       
  1430 					$search_orderby .= 'WHEN ' . implode( ' OR ', $q['search_orderby_title'] ) . ' THEN 3 ';
       
  1431 			}
       
  1432 
       
  1433 			// Sentence match in 'post_content' and 'post_excerpt'.
       
  1434 			if ( $like ) {
       
  1435 				$search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_excerpt LIKE %s THEN 4 ", $like );
       
  1436 				$search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_content LIKE %s THEN 5 ", $like );
       
  1437 			}
       
  1438 
       
  1439 			if ( $search_orderby ) {
       
  1440 				$search_orderby = '(CASE ' . $search_orderby . 'ELSE 6 END)';
       
  1441 			}
       
  1442 		} else {
       
  1443 			// single word or sentence search
       
  1444 			$search_orderby = reset( $q['search_orderby_title'] ) . ' DESC';
       
  1445 		}
       
  1446 
       
  1447 		return $search_orderby;
       
  1448 	}
       
  1449 
       
  1450 	/**
       
  1451 	 * Converts the given orderby alias (if allowed) to a properly-prefixed value.
       
  1452 	 *
       
  1453 	 * @since 4.0.0
       
  1454 	 *
       
  1455 	 * @global wpdb $wpdb WordPress database abstraction object.
       
  1456 	 *
       
  1457 	 * @param string $orderby Alias for the field to order by.
       
  1458 	 * @return string|false Table-prefixed value to used in the ORDER clause. False otherwise.
       
  1459 	 */
       
  1460 	protected function parse_orderby( $orderby ) {
       
  1461 		global $wpdb;
       
  1462 
       
  1463 		// Used to filter values.
       
  1464 		$allowed_keys = array(
       
  1465 			'post_name', 'post_author', 'post_date', 'post_title', 'post_modified',
       
  1466 			'post_parent', 'post_type', 'name', 'author', 'date', 'title', 'modified',
       
  1467 			'parent', 'type', 'ID', 'menu_order', 'comment_count', 'rand',
       
  1468 		);
       
  1469 
       
  1470 		$primary_meta_key = '';
       
  1471 		$primary_meta_query = false;
       
  1472 		$meta_clauses = $this->meta_query->get_clauses();
       
  1473 		if ( ! empty( $meta_clauses ) ) {
       
  1474 			$primary_meta_query = reset( $meta_clauses );
       
  1475 
       
  1476 			if ( ! empty( $primary_meta_query['key'] ) ) {
       
  1477 				$primary_meta_key = $primary_meta_query['key'];
       
  1478 				$allowed_keys[] = $primary_meta_key;
       
  1479 			}
       
  1480 
       
  1481 			$allowed_keys[] = 'meta_value';
       
  1482 			$allowed_keys[] = 'meta_value_num';
       
  1483 			$allowed_keys   = array_merge( $allowed_keys, array_keys( $meta_clauses ) );
       
  1484 		}
       
  1485 
       
  1486 		// If RAND() contains a seed value, sanitize and add to allowed keys.
       
  1487 		$rand_with_seed = false;
       
  1488 		if ( preg_match( '/RAND\(([0-9]+)\)/i', $orderby, $matches ) ) {
       
  1489 			$orderby = sprintf( 'RAND(%s)', intval( $matches[1] ) );
       
  1490 			$allowed_keys[] = $orderby;
       
  1491 			$rand_with_seed = true;
       
  1492 		}
       
  1493 
       
  1494 		if ( ! in_array( $orderby, $allowed_keys, true ) ) {
       
  1495 			return false;
       
  1496 		}
       
  1497 
       
  1498 		switch ( $orderby ) {
       
  1499 			case 'post_name':
       
  1500 			case 'post_author':
       
  1501 			case 'post_date':
       
  1502 			case 'post_title':
       
  1503 			case 'post_modified':
       
  1504 			case 'post_parent':
       
  1505 			case 'post_type':
       
  1506 			case 'ID':
       
  1507 			case 'menu_order':
       
  1508 			case 'comment_count':
       
  1509 				$orderby_clause = "{$wpdb->posts}.{$orderby}";
       
  1510 				break;
       
  1511 			case 'rand':
       
  1512 				$orderby_clause = 'RAND()';
       
  1513 				break;
       
  1514 			case $primary_meta_key:
       
  1515 			case 'meta_value':
       
  1516 				if ( ! empty( $primary_meta_query['type'] ) ) {
       
  1517 					$orderby_clause = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})";
       
  1518 				} else {
       
  1519 					$orderby_clause = "{$primary_meta_query['alias']}.meta_value";
       
  1520 				}
       
  1521 				break;
       
  1522 			case 'meta_value_num':
       
  1523 				$orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
       
  1524 				break;
       
  1525 			default:
       
  1526 				if ( array_key_exists( $orderby, $meta_clauses ) ) {
       
  1527 					// $orderby corresponds to a meta_query clause.
       
  1528 					$meta_clause = $meta_clauses[ $orderby ];
       
  1529 					$orderby_clause = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})";
       
  1530 				} elseif ( $rand_with_seed ) {
       
  1531 					$orderby_clause = $orderby;
       
  1532 				} else {
       
  1533 					// Default: order by post field.
       
  1534 					$orderby_clause = "{$wpdb->posts}.post_" . sanitize_key( $orderby );
       
  1535 				}
       
  1536 
       
  1537 				break;
       
  1538 		}
       
  1539 
       
  1540 		return $orderby_clause;
       
  1541 	}
       
  1542 
       
  1543 	/**
       
  1544 	 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
       
  1545 	 *
       
  1546 	 * @since 4.0.0
       
  1547 	 *
       
  1548 	 * @param string $order The 'order' query variable.
       
  1549 	 * @return string The sanitized 'order' query variable.
       
  1550 	 */
       
  1551 	protected function parse_order( $order ) {
       
  1552 		if ( ! is_string( $order ) || empty( $order ) ) {
       
  1553 			return 'DESC';
       
  1554 		}
       
  1555 
       
  1556 		if ( 'ASC' === strtoupper( $order ) ) {
       
  1557 			return 'ASC';
       
  1558 		} else {
       
  1559 			return 'DESC';
       
  1560 		}
       
  1561 	}
       
  1562 
       
  1563 	/**
       
  1564 	 * Sets the 404 property and saves whether query is feed.
       
  1565 	 *
       
  1566 	 * @since 2.0.0
       
  1567 	 */
       
  1568 	public function set_404() {
       
  1569 		$is_feed = $this->is_feed;
       
  1570 
       
  1571 		$this->init_query_flags();
       
  1572 		$this->is_404 = true;
       
  1573 
       
  1574 		$this->is_feed = $is_feed;
       
  1575 	}
       
  1576 
       
  1577 	/**
       
  1578 	 * Retrieve query variable.
       
  1579 	 *
       
  1580 	 * @since 1.5.0
       
  1581 	 * @since 3.9.0 The `$default` argument was introduced.
       
  1582 	 *
       
  1583 	 *
       
  1584 	 * @param string $query_var Query variable key.
       
  1585 	 * @param mixed  $default   Optional. Value to return if the query variable is not set. Default empty.
       
  1586 	 * @return mixed Contents of the query variable.
       
  1587 	 */
       
  1588 	public function get( $query_var, $default = '' ) {
       
  1589 		if ( isset( $this->query_vars[ $query_var ] ) ) {
       
  1590 			return $this->query_vars[ $query_var ];
       
  1591 		}
       
  1592 
       
  1593 		return $default;
       
  1594 	}
       
  1595 
       
  1596 	/**
       
  1597 	 * Set query variable.
       
  1598 	 *
       
  1599 	 * @since 1.5.0
       
  1600 	 *
       
  1601 	 * @param string $query_var Query variable key.
       
  1602 	 * @param mixed  $value     Query variable value.
       
  1603 	 */
       
  1604 	public function set($query_var, $value) {
       
  1605 		$this->query_vars[$query_var] = $value;
       
  1606 	}
       
  1607 
       
  1608 	/**
       
  1609 	 * Retrieve the posts based on query variables.
       
  1610 	 *
       
  1611 	 * There are a few filters and actions that can be used to modify the post
       
  1612 	 * database query.
       
  1613 	 *
       
  1614 	 * @since 1.5.0
       
  1615 	 *
       
  1616 	 * @return array List of posts.
       
  1617 	 */
       
  1618 	public function get_posts() {
       
  1619 		global $wpdb;
       
  1620 
       
  1621 		$this->parse_query();
       
  1622 
       
  1623 		/**
       
  1624 		 * Fires after the query variable object is created, but before the actual query is run.
       
  1625 		 *
       
  1626 		 * Note: If using conditional tags, use the method versions within the passed instance
       
  1627 		 * (e.g. $this->is_main_query() instead of is_main_query()). This is because the functions
       
  1628 		 * like is_main_query() test against the global $wp_query instance, not the passed one.
       
  1629 		 *
       
  1630 		 * @since 2.0.0
       
  1631 		 *
       
  1632 		 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  1633 		 */
       
  1634 		do_action_ref_array( 'pre_get_posts', array( &$this ) );
       
  1635 
       
  1636 		// Shorthand.
       
  1637 		$q = &$this->query_vars;
       
  1638 
       
  1639 		// Fill again in case pre_get_posts unset some vars.
       
  1640 		$q = $this->fill_query_vars($q);
       
  1641 
       
  1642 		// Parse meta query
       
  1643 		$this->meta_query = new WP_Meta_Query();
       
  1644 		$this->meta_query->parse_query_vars( $q );
       
  1645 
       
  1646 		// Set a flag if a pre_get_posts hook changed the query vars.
       
  1647 		$hash = md5( serialize( $this->query_vars ) );
       
  1648 		if ( $hash != $this->query_vars_hash ) {
       
  1649 			$this->query_vars_changed = true;
       
  1650 			$this->query_vars_hash = $hash;
       
  1651 		}
       
  1652 		unset($hash);
       
  1653 
       
  1654 		// First let's clear some variables
       
  1655 		$distinct = '';
       
  1656 		$whichauthor = '';
       
  1657 		$whichmimetype = '';
       
  1658 		$where = '';
       
  1659 		$limits = '';
       
  1660 		$join = '';
       
  1661 		$search = '';
       
  1662 		$groupby = '';
       
  1663 		$post_status_join = false;
       
  1664 		$page = 1;
       
  1665 
       
  1666 		if ( isset( $q['caller_get_posts'] ) ) {
       
  1667 			_deprecated_argument( 'WP_Query', '3.1.0',
       
  1668 				/* translators: 1: caller_get_posts, 2: ignore_sticky_posts */
       
  1669 				sprintf( __( '%1$s is deprecated. Use %2$s instead.' ),
       
  1670 					'<code>caller_get_posts</code>',
       
  1671 					'<code>ignore_sticky_posts</code>'
       
  1672 				)
       
  1673 			);
       
  1674 
       
  1675 			if ( ! isset( $q['ignore_sticky_posts'] ) ) {
       
  1676 				$q['ignore_sticky_posts'] = $q['caller_get_posts'];
       
  1677 			}
       
  1678 		}
       
  1679 
       
  1680 		if ( !isset( $q['ignore_sticky_posts'] ) )
       
  1681 			$q['ignore_sticky_posts'] = false;
       
  1682 
       
  1683 		if ( !isset($q['suppress_filters']) )
       
  1684 			$q['suppress_filters'] = false;
       
  1685 
       
  1686 		if ( !isset($q['cache_results']) ) {
       
  1687 			if ( wp_using_ext_object_cache() )
       
  1688 				$q['cache_results'] = false;
       
  1689 			else
       
  1690 				$q['cache_results'] = true;
       
  1691 		}
       
  1692 
       
  1693 		if ( !isset($q['update_post_term_cache']) )
       
  1694 			$q['update_post_term_cache'] = true;
       
  1695 
       
  1696 		if ( ! isset( $q['lazy_load_term_meta'] ) ) {
       
  1697 			$q['lazy_load_term_meta'] = $q['update_post_term_cache'];
       
  1698 		}
       
  1699 
       
  1700 		if ( !isset($q['update_post_meta_cache']) )
       
  1701 			$q['update_post_meta_cache'] = true;
       
  1702 
       
  1703 		if ( !isset($q['post_type']) ) {
       
  1704 			if ( $this->is_search )
       
  1705 				$q['post_type'] = 'any';
       
  1706 			else
       
  1707 				$q['post_type'] = '';
       
  1708 		}
       
  1709 		$post_type = $q['post_type'];
       
  1710 		if ( empty( $q['posts_per_page'] ) ) {
       
  1711 			$q['posts_per_page'] = get_option( 'posts_per_page' );
       
  1712 		}
       
  1713 		if ( isset($q['showposts']) && $q['showposts'] ) {
       
  1714 			$q['showposts'] = (int) $q['showposts'];
       
  1715 			$q['posts_per_page'] = $q['showposts'];
       
  1716 		}
       
  1717 		if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) )
       
  1718 			$q['posts_per_page'] = $q['posts_per_archive_page'];
       
  1719 		if ( !isset($q['nopaging']) ) {
       
  1720 			if ( $q['posts_per_page'] == -1 ) {
       
  1721 				$q['nopaging'] = true;
       
  1722 			} else {
       
  1723 				$q['nopaging'] = false;
       
  1724 			}
       
  1725 		}
       
  1726 
       
  1727 		if ( $this->is_feed ) {
       
  1728 			// This overrides posts_per_page.
       
  1729 			if ( ! empty( $q['posts_per_rss'] ) ) {
       
  1730 				$q['posts_per_page'] = $q['posts_per_rss'];
       
  1731 			} else {
       
  1732 				$q['posts_per_page'] = get_option( 'posts_per_rss' );
       
  1733 			}
       
  1734 			$q['nopaging'] = false;
       
  1735 		}
       
  1736 		$q['posts_per_page'] = (int) $q['posts_per_page'];
       
  1737 		if ( $q['posts_per_page'] < -1 )
       
  1738 			$q['posts_per_page'] = abs($q['posts_per_page']);
       
  1739 		elseif ( $q['posts_per_page'] == 0 )
       
  1740 			$q['posts_per_page'] = 1;
       
  1741 
       
  1742 		if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 )
       
  1743 			$q['comments_per_page'] = get_option('comments_per_page');
       
  1744 
       
  1745 		if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
       
  1746 			$this->is_page = true;
       
  1747 			$this->is_home = false;
       
  1748 			$q['page_id'] = get_option('page_on_front');
       
  1749 		}
       
  1750 
       
  1751 		if ( isset($q['page']) ) {
       
  1752 			$q['page'] = trim($q['page'], '/');
       
  1753 			$q['page'] = absint($q['page']);
       
  1754 		}
       
  1755 
       
  1756 		// If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present.
       
  1757 		if ( isset($q['no_found_rows']) )
       
  1758 			$q['no_found_rows'] = (bool) $q['no_found_rows'];
       
  1759 		else
       
  1760 			$q['no_found_rows'] = false;
       
  1761 
       
  1762 		switch ( $q['fields'] ) {
       
  1763 			case 'ids':
       
  1764 				$fields = "{$wpdb->posts}.ID";
       
  1765 				break;
       
  1766 			case 'id=>parent':
       
  1767 				$fields = "{$wpdb->posts}.ID, {$wpdb->posts}.post_parent";
       
  1768 				break;
       
  1769 			default:
       
  1770 				$fields = "{$wpdb->posts}.*";
       
  1771 		}
       
  1772 
       
  1773 		if ( '' !== $q['menu_order'] ) {
       
  1774 			$where .= " AND {$wpdb->posts}.menu_order = " . $q['menu_order'];
       
  1775 		}
       
  1776 		// The "m" parameter is meant for months but accepts datetimes of varying specificity
       
  1777 		if ( $q['m'] ) {
       
  1778 			$where .= " AND YEAR({$wpdb->posts}.post_date)=" . substr($q['m'], 0, 4);
       
  1779 			if ( strlen($q['m']) > 5 ) {
       
  1780 				$where .= " AND MONTH({$wpdb->posts}.post_date)=" . substr($q['m'], 4, 2);
       
  1781 			}
       
  1782 			if ( strlen($q['m']) > 7 ) {
       
  1783 				$where .= " AND DAYOFMONTH({$wpdb->posts}.post_date)=" . substr($q['m'], 6, 2);
       
  1784 			}
       
  1785 			if ( strlen($q['m']) > 9 ) {
       
  1786 				$where .= " AND HOUR({$wpdb->posts}.post_date)=" . substr($q['m'], 8, 2);
       
  1787 			}
       
  1788 			if ( strlen($q['m']) > 11 ) {
       
  1789 				$where .= " AND MINUTE({$wpdb->posts}.post_date)=" . substr($q['m'], 10, 2);
       
  1790 			}
       
  1791 			if ( strlen($q['m']) > 13 ) {
       
  1792 				$where .= " AND SECOND({$wpdb->posts}.post_date)=" . substr($q['m'], 12, 2);
       
  1793 			}
       
  1794 		}
       
  1795 
       
  1796 		// Handle the other individual date parameters
       
  1797 		$date_parameters = array();
       
  1798 
       
  1799 		if ( '' !== $q['hour'] )
       
  1800 			$date_parameters['hour'] = $q['hour'];
       
  1801 
       
  1802 		if ( '' !== $q['minute'] )
       
  1803 			$date_parameters['minute'] = $q['minute'];
       
  1804 
       
  1805 		if ( '' !== $q['second'] )
       
  1806 			$date_parameters['second'] = $q['second'];
       
  1807 
       
  1808 		if ( $q['year'] )
       
  1809 			$date_parameters['year'] = $q['year'];
       
  1810 
       
  1811 		if ( $q['monthnum'] )
       
  1812 			$date_parameters['monthnum'] = $q['monthnum'];
       
  1813 
       
  1814 		if ( $q['w'] )
       
  1815 			$date_parameters['week'] = $q['w'];
       
  1816 
       
  1817 		if ( $q['day'] )
       
  1818 			$date_parameters['day'] = $q['day'];
       
  1819 
       
  1820 		if ( $date_parameters ) {
       
  1821 			$date_query = new WP_Date_Query( array( $date_parameters ) );
       
  1822 			$where .= $date_query->get_sql();
       
  1823 		}
       
  1824 		unset( $date_parameters, $date_query );
       
  1825 
       
  1826 		// Handle complex date queries
       
  1827 		if ( ! empty( $q['date_query'] ) ) {
       
  1828 			$this->date_query = new WP_Date_Query( $q['date_query'] );
       
  1829 			$where .= $this->date_query->get_sql();
       
  1830 		}
       
  1831 
       
  1832 
       
  1833 		// If we've got a post_type AND it's not "any" post_type.
       
  1834 		if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) {
       
  1835 			foreach ( (array)$q['post_type'] as $_post_type ) {
       
  1836 				$ptype_obj = get_post_type_object($_post_type);
       
  1837 				if ( !$ptype_obj || !$ptype_obj->query_var || empty($q[ $ptype_obj->query_var ]) )
       
  1838 					continue;
       
  1839 
       
  1840 				if ( ! $ptype_obj->hierarchical ) {
       
  1841 					// Non-hierarchical post types can directly use 'name'.
       
  1842 					$q['name'] = $q[ $ptype_obj->query_var ];
       
  1843 				} else {
       
  1844 					// Hierarchical post types will operate through 'pagename'.
       
  1845 					$q['pagename'] = $q[ $ptype_obj->query_var ];
       
  1846 					$q['name'] = '';
       
  1847 				}
       
  1848 
       
  1849 				// Only one request for a slug is possible, this is why name & pagename are overwritten above.
       
  1850 				break;
       
  1851 			} //end foreach
       
  1852 			unset($ptype_obj);
       
  1853 		}
       
  1854 
       
  1855 		if ( '' !== $q['title'] ) {
       
  1856 			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_title = %s", stripslashes( $q['title'] ) );
       
  1857 		}
       
  1858 
       
  1859 		// Parameters related to 'post_name'.
       
  1860 		if ( '' != $q['name'] ) {
       
  1861 			$q['name'] = sanitize_title_for_query( $q['name'] );
       
  1862 			$where .= " AND {$wpdb->posts}.post_name = '" . $q['name'] . "'";
       
  1863 		} elseif ( '' != $q['pagename'] ) {
       
  1864 			if ( isset($this->queried_object_id) ) {
       
  1865 				$reqpage = $this->queried_object_id;
       
  1866 			} else {
       
  1867 				if ( 'page' != $q['post_type'] ) {
       
  1868 					foreach ( (array)$q['post_type'] as $_post_type ) {
       
  1869 						$ptype_obj = get_post_type_object($_post_type);
       
  1870 						if ( !$ptype_obj || !$ptype_obj->hierarchical )
       
  1871 							continue;
       
  1872 
       
  1873 						$reqpage = get_page_by_path($q['pagename'], OBJECT, $_post_type);
       
  1874 						if ( $reqpage )
       
  1875 							break;
       
  1876 					}
       
  1877 					unset($ptype_obj);
       
  1878 				} else {
       
  1879 					$reqpage = get_page_by_path($q['pagename']);
       
  1880 				}
       
  1881 				if ( !empty($reqpage) )
       
  1882 					$reqpage = $reqpage->ID;
       
  1883 				else
       
  1884 					$reqpage = 0;
       
  1885 			}
       
  1886 
       
  1887 			$page_for_posts = get_option('page_for_posts');
       
  1888 			if  ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) {
       
  1889 				$q['pagename'] = sanitize_title_for_query( wp_basename( $q['pagename'] ) );
       
  1890 				$q['name'] = $q['pagename'];
       
  1891 				$where .= " AND ({$wpdb->posts}.ID = '$reqpage')";
       
  1892 				$reqpage_obj = get_post( $reqpage );
       
  1893 				if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) {
       
  1894 					$this->is_attachment = true;
       
  1895 					$post_type = $q['post_type'] = 'attachment';
       
  1896 					$this->is_page = true;
       
  1897 					$q['attachment_id'] = $reqpage;
       
  1898 				}
       
  1899 			}
       
  1900 		} elseif ( '' != $q['attachment'] ) {
       
  1901 			$q['attachment'] = sanitize_title_for_query( wp_basename( $q['attachment'] ) );
       
  1902 			$q['name'] = $q['attachment'];
       
  1903 			$where .= " AND {$wpdb->posts}.post_name = '" . $q['attachment'] . "'";
       
  1904 		} elseif ( is_array( $q['post_name__in'] ) && ! empty( $q['post_name__in'] ) ) {
       
  1905 			$q['post_name__in'] = array_map( 'sanitize_title_for_query', $q['post_name__in'] );
       
  1906 			$post_name__in = "'" . implode( "','", $q['post_name__in'] ) . "'";
       
  1907 			$where .= " AND {$wpdb->posts}.post_name IN ($post_name__in)";
       
  1908 		}
       
  1909 
       
  1910 		// If an attachment is requested by number, let it supersede any post number.
       
  1911 		if ( $q['attachment_id'] )
       
  1912 			$q['p'] = absint($q['attachment_id']);
       
  1913 
       
  1914 		// If a post number is specified, load that post
       
  1915 		if ( $q['p'] ) {
       
  1916 			$where .= " AND {$wpdb->posts}.ID = " . $q['p'];
       
  1917 		} elseif ( $q['post__in'] ) {
       
  1918 			$post__in = implode(',', array_map( 'absint', $q['post__in'] ));
       
  1919 			$where .= " AND {$wpdb->posts}.ID IN ($post__in)";
       
  1920 		} elseif ( $q['post__not_in'] ) {
       
  1921 			$post__not_in = implode(',',  array_map( 'absint', $q['post__not_in'] ));
       
  1922 			$where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
       
  1923 		}
       
  1924 
       
  1925 		if ( is_numeric( $q['post_parent'] ) ) {
       
  1926 			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_parent = %d ", $q['post_parent'] );
       
  1927 		} elseif ( $q['post_parent__in'] ) {
       
  1928 			$post_parent__in = implode( ',', array_map( 'absint', $q['post_parent__in'] ) );
       
  1929 			$where .= " AND {$wpdb->posts}.post_parent IN ($post_parent__in)";
       
  1930 		} elseif ( $q['post_parent__not_in'] ) {
       
  1931 			$post_parent__not_in = implode( ',',  array_map( 'absint', $q['post_parent__not_in'] ) );
       
  1932 			$where .= " AND {$wpdb->posts}.post_parent NOT IN ($post_parent__not_in)";
       
  1933 		}
       
  1934 
       
  1935 		if ( $q['page_id'] ) {
       
  1936 			if  ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
       
  1937 				$q['p'] = $q['page_id'];
       
  1938 				$where = " AND {$wpdb->posts}.ID = " . $q['page_id'];
       
  1939 			}
       
  1940 		}
       
  1941 
       
  1942 		// If a search pattern is specified, load the posts that match.
       
  1943 		if ( strlen( $q['s'] ) ) {
       
  1944 			$search = $this->parse_search( $q );
       
  1945 		}
       
  1946 
       
  1947 		if ( ! $q['suppress_filters'] ) {
       
  1948 			/**
       
  1949 			 * Filters the search SQL that is used in the WHERE clause of WP_Query.
       
  1950 			 *
       
  1951 			 * @since 3.0.0
       
  1952 			 *
       
  1953 			 * @param string   $search Search SQL for WHERE clause.
       
  1954 			 * @param WP_Query $this   The current WP_Query object.
       
  1955 			 */
       
  1956 			$search = apply_filters_ref_array( 'posts_search', array( $search, &$this ) );
       
  1957 		}
       
  1958 
       
  1959 		// Taxonomies
       
  1960 		if ( !$this->is_singular ) {
       
  1961 			$this->parse_tax_query( $q );
       
  1962 
       
  1963 			$clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' );
       
  1964 
       
  1965 			$join .= $clauses['join'];
       
  1966 			$where .= $clauses['where'];
       
  1967 		}
       
  1968 
       
  1969 		if ( $this->is_tax ) {
       
  1970 			if ( empty($post_type) ) {
       
  1971 				// Do a fully inclusive search for currently registered post types of queried taxonomies
       
  1972 				$post_type = array();
       
  1973 				$taxonomies = array_keys( $this->tax_query->queried_terms );
       
  1974 				foreach ( get_post_types( array( 'exclude_from_search' => false ) ) as $pt ) {
       
  1975 					$object_taxonomies = $pt === 'attachment' ? get_taxonomies_for_attachments() : get_object_taxonomies( $pt );
       
  1976 					if ( array_intersect( $taxonomies, $object_taxonomies ) )
       
  1977 						$post_type[] = $pt;
       
  1978 				}
       
  1979 				if ( ! $post_type )
       
  1980 					$post_type = 'any';
       
  1981 				elseif ( count( $post_type ) == 1 )
       
  1982 					$post_type = $post_type[0];
       
  1983 
       
  1984 				$post_status_join = true;
       
  1985 			} elseif ( in_array('attachment', (array) $post_type) ) {
       
  1986 				$post_status_join = true;
       
  1987 			}
       
  1988 		}
       
  1989 
       
  1990 		/*
       
  1991 		 * Ensure that 'taxonomy', 'term', 'term_id', 'cat', and
       
  1992 		 * 'category_name' vars are set for backward compatibility.
       
  1993 		 */
       
  1994 		if ( ! empty( $this->tax_query->queried_terms ) ) {
       
  1995 
       
  1996 			/*
       
  1997 			 * Set 'taxonomy', 'term', and 'term_id' to the
       
  1998 			 * first taxonomy other than 'post_tag' or 'category'.
       
  1999 			 */
       
  2000 			if ( ! isset( $q['taxonomy'] ) ) {
       
  2001 				foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
       
  2002 					if ( empty( $queried_items['terms'][0] ) ) {
       
  2003 						continue;
       
  2004 					}
       
  2005 
       
  2006 					if ( ! in_array( $queried_taxonomy, array( 'category', 'post_tag' ) ) ) {
       
  2007 						$q['taxonomy'] = $queried_taxonomy;
       
  2008 
       
  2009 						if ( 'slug' === $queried_items['field'] ) {
       
  2010 							$q['term'] = $queried_items['terms'][0];
       
  2011 						} else {
       
  2012 							$q['term_id'] = $queried_items['terms'][0];
       
  2013 						}
       
  2014 
       
  2015 						// Take the first one we find.
       
  2016 						break;
       
  2017 					}
       
  2018 				}
       
  2019 			}
       
  2020 
       
  2021 			// 'cat', 'category_name', 'tag_id'
       
  2022 			foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
       
  2023 				if ( empty( $queried_items['terms'][0] ) ) {
       
  2024 					continue;
       
  2025 				}
       
  2026 
       
  2027 				if ( 'category' === $queried_taxonomy ) {
       
  2028 					$the_cat = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'category' );
       
  2029 					if ( $the_cat ) {
       
  2030 						$this->set( 'cat', $the_cat->term_id );
       
  2031 						$this->set( 'category_name', $the_cat->slug );
       
  2032 					}
       
  2033 					unset( $the_cat );
       
  2034 				}
       
  2035 
       
  2036 				if ( 'post_tag' === $queried_taxonomy ) {
       
  2037 					$the_tag = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'post_tag' );
       
  2038 					if ( $the_tag ) {
       
  2039 						$this->set( 'tag_id', $the_tag->term_id );
       
  2040 					}
       
  2041 					unset( $the_tag );
       
  2042 				}
       
  2043 			}
       
  2044 		}
       
  2045 
       
  2046 		if ( !empty( $this->tax_query->queries ) || !empty( $this->meta_query->queries ) ) {
       
  2047 			$groupby = "{$wpdb->posts}.ID";
       
  2048 		}
       
  2049 
       
  2050 		// Author/user stuff
       
  2051 
       
  2052 		if ( ! empty( $q['author'] ) && $q['author'] != '0' ) {
       
  2053 			$q['author'] = addslashes_gpc( '' . urldecode( $q['author'] ) );
       
  2054 			$authors = array_unique( array_map( 'intval', preg_split( '/[,\s]+/', $q['author'] ) ) );
       
  2055 			foreach ( $authors as $author ) {
       
  2056 				$key = $author > 0 ? 'author__in' : 'author__not_in';
       
  2057 				$q[$key][] = abs( $author );
       
  2058 			}
       
  2059 			$q['author'] = implode( ',', $authors );
       
  2060 		}
       
  2061 
       
  2062 		if ( ! empty( $q['author__not_in'] ) ) {
       
  2063 			$author__not_in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__not_in'] ) ) );
       
  2064 			$where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
       
  2065 		} elseif ( ! empty( $q['author__in'] ) ) {
       
  2066 			$author__in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__in'] ) ) );
       
  2067 			$where .= " AND {$wpdb->posts}.post_author IN ($author__in) ";
       
  2068 		}
       
  2069 
       
  2070 		// Author stuff for nice URLs
       
  2071 
       
  2072 		if ( '' != $q['author_name'] ) {
       
  2073 			if ( strpos($q['author_name'], '/') !== false ) {
       
  2074 				$q['author_name'] = explode('/', $q['author_name']);
       
  2075 				if ( $q['author_name'][ count($q['author_name'])-1 ] ) {
       
  2076 					$q['author_name'] = $q['author_name'][count($q['author_name'])-1]; // no trailing slash
       
  2077 				} else {
       
  2078 					$q['author_name'] = $q['author_name'][count($q['author_name'])-2]; // there was a trailing slash
       
  2079 				}
       
  2080 			}
       
  2081 			$q['author_name'] = sanitize_title_for_query( $q['author_name'] );
       
  2082 			$q['author'] = get_user_by('slug', $q['author_name']);
       
  2083 			if ( $q['author'] )
       
  2084 				$q['author'] = $q['author']->ID;
       
  2085 			$whichauthor .= " AND ({$wpdb->posts}.post_author = " . absint($q['author']) . ')';
       
  2086 		}
       
  2087 
       
  2088 		// Matching by comment count.
       
  2089 		if ( isset( $q['comment_count'] ) ) {
       
  2090 			// Numeric comment count is converted to array format.
       
  2091 			if ( is_numeric( $q['comment_count'] ) ) {
       
  2092 				$q['comment_count'] = array(
       
  2093 					'value' => intval( $q['comment_count'] ),
       
  2094 				);
       
  2095 			}
       
  2096 
       
  2097 			if ( isset( $q['comment_count']['value'] ) ) {
       
  2098 				$q['comment_count'] = array_merge( array(
       
  2099 					'compare' => '=',
       
  2100 				), $q['comment_count'] );
       
  2101 
       
  2102 				// Fallback for invalid compare operators is '='.
       
  2103 				$compare_operators = array( '=', '!=', '>', '>=', '<', '<=' );
       
  2104 				if ( ! in_array( $q['comment_count']['compare'], $compare_operators, true ) ) {
       
  2105 					$q['comment_count']['compare'] = '=';
       
  2106 				}
       
  2107 
       
  2108 				$where .= $wpdb->prepare( " AND {$wpdb->posts}.comment_count {$q['comment_count']['compare']} %d", $q['comment_count']['value'] );
       
  2109 			}
       
  2110 		}
       
  2111 
       
  2112 		// MIME-Type stuff for attachment browsing
       
  2113 
       
  2114 		if ( isset( $q['post_mime_type'] ) && '' != $q['post_mime_type'] ) {
       
  2115 			$whichmimetype = wp_post_mime_type_where( $q['post_mime_type'], $wpdb->posts );
       
  2116 		}
       
  2117 		$where .= $search . $whichauthor . $whichmimetype;
       
  2118 
       
  2119 		if ( ! empty( $this->meta_query->queries ) ) {
       
  2120 			$clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
       
  2121 			$join   .= $clauses['join'];
       
  2122 			$where  .= $clauses['where'];
       
  2123 		}
       
  2124 
       
  2125 		$rand = ( isset( $q['orderby'] ) && 'rand' === $q['orderby'] );
       
  2126 		if ( ! isset( $q['order'] ) ) {
       
  2127 			$q['order'] = $rand ? '' : 'DESC';
       
  2128 		} else {
       
  2129 			$q['order'] = $rand ? '' : $this->parse_order( $q['order'] );
       
  2130 		}
       
  2131 
       
  2132 		// Order by.
       
  2133 		if ( empty( $q['orderby'] ) ) {
       
  2134 			/*
       
  2135 			 * Boolean false or empty array blanks out ORDER BY,
       
  2136 			 * while leaving the value unset or otherwise empty sets the default.
       
  2137 			 */
       
  2138 			if ( isset( $q['orderby'] ) && ( is_array( $q['orderby'] ) || false === $q['orderby'] ) ) {
       
  2139 				$orderby = '';
       
  2140 			} else {
       
  2141 				$orderby = "{$wpdb->posts}.post_date " . $q['order'];
       
  2142 			}
       
  2143 		} elseif ( 'none' == $q['orderby'] ) {
       
  2144 			$orderby = '';
       
  2145 		} elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
       
  2146 			$orderby = "FIELD( {$wpdb->posts}.ID, $post__in )";
       
  2147 		} elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
       
  2148 			$orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
       
  2149 		} elseif ( $q['orderby'] == 'post_name__in' && ! empty( $post_name__in ) ) {
       
  2150 			$orderby = "FIELD( {$wpdb->posts}.post_name, $post_name__in )";
       
  2151 		} else {
       
  2152 			$orderby_array = array();
       
  2153 			if ( is_array( $q['orderby'] ) ) {
       
  2154 				foreach ( $q['orderby'] as $_orderby => $order ) {
       
  2155 					$orderby = addslashes_gpc( urldecode( $_orderby ) );
       
  2156 					$parsed  = $this->parse_orderby( $orderby );
       
  2157 
       
  2158 					if ( ! $parsed ) {
       
  2159 						continue;
       
  2160 					}
       
  2161 
       
  2162 					$orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
       
  2163 				}
       
  2164 				$orderby = implode( ', ', $orderby_array );
       
  2165 
       
  2166 			} else {
       
  2167 				$q['orderby'] = urldecode( $q['orderby'] );
       
  2168 				$q['orderby'] = addslashes_gpc( $q['orderby'] );
       
  2169 
       
  2170 				foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
       
  2171 					$parsed = $this->parse_orderby( $orderby );
       
  2172 					// Only allow certain values for safety.
       
  2173 					if ( ! $parsed ) {
       
  2174 						continue;
       
  2175 					}
       
  2176 
       
  2177 					$orderby_array[] = $parsed;
       
  2178 				}
       
  2179 				$orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
       
  2180 
       
  2181 				if ( empty( $orderby ) ) {
       
  2182 					$orderby = "{$wpdb->posts}.post_date " . $q['order'];
       
  2183 				} elseif ( ! empty( $q['order'] ) ) {
       
  2184 					$orderby .= " {$q['order']}";
       
  2185 				}
       
  2186 			}
       
  2187 		}
       
  2188 
       
  2189 		// Order search results by relevance only when another "orderby" is not specified in the query.
       
  2190 		if ( ! empty( $q['s'] ) ) {
       
  2191 			$search_orderby = '';
       
  2192 			if ( ! empty( $q['search_orderby_title'] ) && ( empty( $q['orderby'] ) && ! $this->is_feed ) || ( isset( $q['orderby'] ) && 'relevance' === $q['orderby'] ) )
       
  2193 				$search_orderby = $this->parse_search_order( $q );
       
  2194 
       
  2195 			if ( ! $q['suppress_filters'] ) {
       
  2196 				/**
       
  2197 				 * Filters the ORDER BY used when ordering search results.
       
  2198 				 *
       
  2199 				 * @since 3.7.0
       
  2200 				 *
       
  2201 				 * @param string   $search_orderby The ORDER BY clause.
       
  2202 				 * @param WP_Query $this           The current WP_Query instance.
       
  2203 				 */
       
  2204 				$search_orderby = apply_filters( 'posts_search_orderby', $search_orderby, $this );
       
  2205 			}
       
  2206 
       
  2207 			if ( $search_orderby )
       
  2208 				$orderby = $orderby ? $search_orderby . ', ' . $orderby : $search_orderby;
       
  2209 		}
       
  2210 
       
  2211 		if ( is_array( $post_type ) && count( $post_type ) > 1 ) {
       
  2212 			$post_type_cap = 'multiple_post_type';
       
  2213 		} else {
       
  2214 			if ( is_array( $post_type ) )
       
  2215 				$post_type = reset( $post_type );
       
  2216 			$post_type_object = get_post_type_object( $post_type );
       
  2217 			if ( empty( $post_type_object ) )
       
  2218 				$post_type_cap = $post_type;
       
  2219 		}
       
  2220 
       
  2221 		if ( isset( $q['post_password'] ) ) {
       
  2222 			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_password = %s", $q['post_password'] );
       
  2223 			if ( empty( $q['perm'] ) ) {
       
  2224 				$q['perm'] = 'readable';
       
  2225 			}
       
  2226 		} elseif ( isset( $q['has_password'] ) ) {
       
  2227 			$where .= sprintf( " AND {$wpdb->posts}.post_password %s ''", $q['has_password'] ? '!=' : '=' );
       
  2228 		}
       
  2229 
       
  2230 		if ( ! empty( $q['comment_status'] ) ) {
       
  2231 			$where .= $wpdb->prepare( " AND {$wpdb->posts}.comment_status = %s ", $q['comment_status'] );
       
  2232 		}
       
  2233 
       
  2234 		if ( ! empty( $q['ping_status'] ) )  {
       
  2235 			$where .= $wpdb->prepare( " AND {$wpdb->posts}.ping_status = %s ", $q['ping_status'] );
       
  2236 		}
       
  2237 
       
  2238 		if ( 'any' == $post_type ) {
       
  2239 			$in_search_post_types = get_post_types( array('exclude_from_search' => false) );
       
  2240 			if ( empty( $in_search_post_types ) ) {
       
  2241 				$where .= ' AND 1=0 ';
       
  2242 			} else {
       
  2243 				$where .= " AND {$wpdb->posts}.post_type IN ('" . join( "', '", array_map( 'esc_sql', $in_search_post_types ) ) . "')";
       
  2244 			}
       
  2245 		} elseif ( !empty( $post_type ) && is_array( $post_type ) ) {
       
  2246 			$where .= " AND {$wpdb->posts}.post_type IN ('" . join("', '", esc_sql( $post_type ) ) . "')";
       
  2247 		} elseif ( ! empty( $post_type ) ) {
       
  2248 			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s", $post_type );
       
  2249 			$post_type_object = get_post_type_object ( $post_type );
       
  2250 		} elseif ( $this->is_attachment ) {
       
  2251 			$where .= " AND {$wpdb->posts}.post_type = 'attachment'";
       
  2252 			$post_type_object = get_post_type_object ( 'attachment' );
       
  2253 		} elseif ( $this->is_page ) {
       
  2254 			$where .= " AND {$wpdb->posts}.post_type = 'page'";
       
  2255 			$post_type_object = get_post_type_object ( 'page' );
       
  2256 		} else {
       
  2257 			$where .= " AND {$wpdb->posts}.post_type = 'post'";
       
  2258 			$post_type_object = get_post_type_object ( 'post' );
       
  2259 		}
       
  2260 
       
  2261 		$edit_cap = 'edit_post';
       
  2262 		$read_cap = 'read_post';
       
  2263 
       
  2264 		if ( ! empty( $post_type_object ) ) {
       
  2265 			$edit_others_cap = $post_type_object->cap->edit_others_posts;
       
  2266 			$read_private_cap = $post_type_object->cap->read_private_posts;
       
  2267 		} else {
       
  2268 			$edit_others_cap = 'edit_others_' . $post_type_cap . 's';
       
  2269 			$read_private_cap = 'read_private_' . $post_type_cap . 's';
       
  2270 		}
       
  2271 
       
  2272 		$user_id = get_current_user_id();
       
  2273 
       
  2274 		$q_status = array();
       
  2275 		if ( ! empty( $q['post_status'] ) ) {
       
  2276 			$statuswheres = array();
       
  2277 			$q_status = $q['post_status'];
       
  2278 			if ( ! is_array( $q_status ) )
       
  2279 				$q_status = explode(',', $q_status);
       
  2280 			$r_status = array();
       
  2281 			$p_status = array();
       
  2282 			$e_status = array();
       
  2283 			if ( in_array( 'any', $q_status ) ) {
       
  2284 				foreach ( get_post_stati( array( 'exclude_from_search' => true ) ) as $status ) {
       
  2285 					if ( ! in_array( $status, $q_status ) ) {
       
  2286 						$e_status[] = "{$wpdb->posts}.post_status <> '$status'";
       
  2287 					}
       
  2288 				}
       
  2289 			} else {
       
  2290 				foreach ( get_post_stati() as $status ) {
       
  2291 					if ( in_array( $status, $q_status ) ) {
       
  2292 						if ( 'private' == $status ) {
       
  2293 							$p_status[] = "{$wpdb->posts}.post_status = '$status'";
       
  2294 						} else {
       
  2295 							$r_status[] = "{$wpdb->posts}.post_status = '$status'";
       
  2296 						}
       
  2297 					}
       
  2298 				}
       
  2299 			}
       
  2300 
       
  2301 			if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) {
       
  2302 				$r_status = array_merge($r_status, $p_status);
       
  2303 				unset($p_status);
       
  2304 			}
       
  2305 
       
  2306 			if ( !empty($e_status) ) {
       
  2307 				$statuswheres[] = "(" . join( ' AND ', $e_status ) . ")";
       
  2308 			}
       
  2309 			if ( !empty($r_status) ) {
       
  2310 				if ( !empty($q['perm'] ) && 'editable' == $q['perm'] && !current_user_can($edit_others_cap) ) {
       
  2311 					$statuswheres[] = "({$wpdb->posts}.post_author = $user_id " . "AND (" . join( ' OR ', $r_status ) . "))";
       
  2312 				} else {
       
  2313 					$statuswheres[] = "(" . join( ' OR ', $r_status ) . ")";
       
  2314 				}
       
  2315 			}
       
  2316 			if ( !empty($p_status) ) {
       
  2317 				if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can($read_private_cap) ) {
       
  2318 					$statuswheres[] = "({$wpdb->posts}.post_author = $user_id " . "AND (" . join( ' OR ', $p_status ) . "))";
       
  2319 				} else {
       
  2320 					$statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
       
  2321 				}
       
  2322 			}
       
  2323 			if ( $post_status_join ) {
       
  2324 				$join .= " LEFT JOIN {$wpdb->posts} AS p2 ON ({$wpdb->posts}.post_parent = p2.ID) ";
       
  2325 				foreach ( $statuswheres as $index => $statuswhere ) {
       
  2326 					$statuswheres[$index] = "($statuswhere OR ({$wpdb->posts}.post_status = 'inherit' AND " . str_replace( $wpdb->posts, 'p2', $statuswhere ) . "))";
       
  2327 				}
       
  2328 			}
       
  2329 			$where_status = implode( ' OR ', $statuswheres );
       
  2330 			if ( ! empty( $where_status ) ) {
       
  2331 				$where .= " AND ($where_status)";
       
  2332 			}
       
  2333 		} elseif ( !$this->is_singular ) {
       
  2334 			$where .= " AND ({$wpdb->posts}.post_status = 'publish'";
       
  2335 
       
  2336 			// Add public states.
       
  2337 			$public_states = get_post_stati( array('public' => true) );
       
  2338 			foreach ( (array) $public_states as $state ) {
       
  2339 				if ( 'publish' == $state ) // Publish is hard-coded above.
       
  2340 					continue;
       
  2341 				$where .= " OR {$wpdb->posts}.post_status = '$state'";
       
  2342 			}
       
  2343 
       
  2344 			if ( $this->is_admin ) {
       
  2345 				// Add protected states that should show in the admin all list.
       
  2346 				$admin_all_states = get_post_stati( array('protected' => true, 'show_in_admin_all_list' => true) );
       
  2347 				foreach ( (array) $admin_all_states as $state ) {
       
  2348 					$where .= " OR {$wpdb->posts}.post_status = '$state'";
       
  2349 				}
       
  2350 			}
       
  2351 
       
  2352 			if ( is_user_logged_in() ) {
       
  2353 				// Add private states that are limited to viewing by the author of a post or someone who has caps to read private states.
       
  2354 				$private_states = get_post_stati( array('private' => true) );
       
  2355 				foreach ( (array) $private_states as $state ) {
       
  2356 					$where .= current_user_can( $read_private_cap ) ? " OR {$wpdb->posts}.post_status = '$state'" : " OR {$wpdb->posts}.post_author = $user_id AND {$wpdb->posts}.post_status = '$state'";
       
  2357 				}
       
  2358 			}
       
  2359 
       
  2360 			$where .= ')';
       
  2361 		}
       
  2362 
       
  2363 		/*
       
  2364 		 * Apply filters on where and join prior to paging so that any
       
  2365 		 * manipulations to them are reflected in the paging by day queries.
       
  2366 		 */
       
  2367 		if ( !$q['suppress_filters'] ) {
       
  2368 			/**
       
  2369 			 * Filters the WHERE clause of the query.
       
  2370 			 *
       
  2371 			 * @since 1.5.0
       
  2372 			 *
       
  2373 			 * @param string   $where The WHERE clause of the query.
       
  2374 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  2375 			 */
       
  2376 			$where = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );
       
  2377 
       
  2378 			/**
       
  2379 			 * Filters the JOIN clause of the query.
       
  2380 			 *
       
  2381 			 * @since 1.5.0
       
  2382 			 *
       
  2383 			 * @param string   $join  The JOIN clause of the query.
       
  2384 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  2385 			 */
       
  2386 			$join = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
       
  2387 		}
       
  2388 
       
  2389 		// Paging
       
  2390 		if ( empty($q['nopaging']) && !$this->is_singular ) {
       
  2391 			$page = absint($q['paged']);
       
  2392 			if ( !$page )
       
  2393 				$page = 1;
       
  2394 
       
  2395 			// If 'offset' is provided, it takes precedence over 'paged'.
       
  2396 			if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) ) {
       
  2397 				$q['offset'] = absint( $q['offset'] );
       
  2398 				$pgstrt = $q['offset'] . ', ';
       
  2399 			} else {
       
  2400 				$pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
       
  2401 			}
       
  2402 			$limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
       
  2403 		}
       
  2404 
       
  2405 		// Comments feeds
       
  2406 		if ( $this->is_comment_feed && ! $this->is_singular ) {
       
  2407 			if ( $this->is_archive || $this->is_search ) {
       
  2408 				$cjoin = "JOIN {$wpdb->posts} ON ({$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID) $join ";
       
  2409 				$cwhere = "WHERE comment_approved = '1' $where";
       
  2410 				$cgroupby = "{$wpdb->comments}.comment_id";
       
  2411 			} else { // Other non singular e.g. front
       
  2412 				$cjoin = "JOIN {$wpdb->posts} ON ( {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID )";
       
  2413 				$cwhere = "WHERE ( post_status = 'publish' OR ( post_status = 'inherit' AND post_type = 'attachment' ) ) AND comment_approved = '1'";
       
  2414 				$cgroupby = '';
       
  2415 			}
       
  2416 
       
  2417 			if ( !$q['suppress_filters'] ) {
       
  2418 				/**
       
  2419 				 * Filters the JOIN clause of the comments feed query before sending.
       
  2420 				 *
       
  2421 				 * @since 2.2.0
       
  2422 				 *
       
  2423 				 * @param string   $cjoin The JOIN clause of the query.
       
  2424 				 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  2425 				 */
       
  2426 				$cjoin = apply_filters_ref_array( 'comment_feed_join', array( $cjoin, &$this ) );
       
  2427 
       
  2428 				/**
       
  2429 				 * Filters the WHERE clause of the comments feed query before sending.
       
  2430 				 *
       
  2431 				 * @since 2.2.0
       
  2432 				 *
       
  2433 				 * @param string   $cwhere The WHERE clause of the query.
       
  2434 				 * @param WP_Query $this   The WP_Query instance (passed by reference).
       
  2435 				 */
       
  2436 				$cwhere = apply_filters_ref_array( 'comment_feed_where', array( $cwhere, &$this ) );
       
  2437 
       
  2438 				/**
       
  2439 				 * Filters the GROUP BY clause of the comments feed query before sending.
       
  2440 				 *
       
  2441 				 * @since 2.2.0
       
  2442 				 *
       
  2443 				 * @param string   $cgroupby The GROUP BY clause of the query.
       
  2444 				 * @param WP_Query $this     The WP_Query instance (passed by reference).
       
  2445 				 */
       
  2446 				$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( $cgroupby, &$this ) );
       
  2447 
       
  2448 				/**
       
  2449 				 * Filters the ORDER BY clause of the comments feed query before sending.
       
  2450 				 *
       
  2451 				 * @since 2.8.0
       
  2452 				 *
       
  2453 				 * @param string   $corderby The ORDER BY clause of the query.
       
  2454 				 * @param WP_Query $this     The WP_Query instance (passed by reference).
       
  2455 				 */
       
  2456 				$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
       
  2457 
       
  2458 				/**
       
  2459 				 * Filters the LIMIT clause of the comments feed query before sending.
       
  2460 				 *
       
  2461 				 * @since 2.8.0
       
  2462 				 *
       
  2463 				 * @param string   $climits The JOIN clause of the query.
       
  2464 				 * @param WP_Query $this    The WP_Query instance (passed by reference).
       
  2465 				 */
       
  2466 				$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
       
  2467 			}
       
  2468 			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
       
  2469 			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
       
  2470 
       
  2471 			$comments = (array) $wpdb->get_results("SELECT $distinct {$wpdb->comments}.* FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits");
       
  2472 			// Convert to WP_Comment
       
  2473 			$this->comments = array_map( 'get_comment', $comments );
       
  2474 			$this->comment_count = count($this->comments);
       
  2475 
       
  2476 			$post_ids = array();
       
  2477 
       
  2478 			foreach ( $this->comments as $comment )
       
  2479 				$post_ids[] = (int) $comment->comment_post_ID;
       
  2480 
       
  2481 			$post_ids = join(',', $post_ids);
       
  2482 			$join = '';
       
  2483 			if ( $post_ids ) {
       
  2484 				$where = "AND {$wpdb->posts}.ID IN ($post_ids) ";
       
  2485 			} else {
       
  2486 				$where = "AND 0";
       
  2487 			}
       
  2488 		}
       
  2489 
       
  2490 		$pieces = array( 'where', 'groupby', 'join', 'orderby', 'distinct', 'fields', 'limits' );
       
  2491 
       
  2492 		/*
       
  2493 		 * Apply post-paging filters on where and join. Only plugins that
       
  2494 		 * manipulate paging queries should use these hooks.
       
  2495 		 */
       
  2496 		if ( !$q['suppress_filters'] ) {
       
  2497 			/**
       
  2498 			 * Filters the WHERE clause of the query.
       
  2499 			 *
       
  2500 			 * Specifically for manipulating paging queries.
       
  2501 			 *
       
  2502 			 * @since 1.5.0
       
  2503 			 *
       
  2504 			 * @param string   $where The WHERE clause of the query.
       
  2505 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  2506 			 */
       
  2507 			$where = apply_filters_ref_array( 'posts_where_paged', array( $where, &$this ) );
       
  2508 
       
  2509 			/**
       
  2510 			 * Filters the GROUP BY clause of the query.
       
  2511 			 *
       
  2512 			 * @since 2.0.0
       
  2513 			 *
       
  2514 			 * @param string   $groupby The GROUP BY clause of the query.
       
  2515 			 * @param WP_Query $this    The WP_Query instance (passed by reference).
       
  2516 			 */
       
  2517 			$groupby = apply_filters_ref_array( 'posts_groupby', array( $groupby, &$this ) );
       
  2518 
       
  2519 			/**
       
  2520 			 * Filters the JOIN clause of the query.
       
  2521 			 *
       
  2522 			 * Specifically for manipulating paging queries.
       
  2523 			 *
       
  2524 			 * @since 1.5.0
       
  2525 			 *
       
  2526 			 * @param string   $join  The JOIN clause of the query.
       
  2527 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  2528 			 */
       
  2529 			$join = apply_filters_ref_array( 'posts_join_paged', array( $join, &$this ) );
       
  2530 
       
  2531 			/**
       
  2532 			 * Filters the ORDER BY clause of the query.
       
  2533 			 *
       
  2534 			 * @since 1.5.1
       
  2535 			 *
       
  2536 			 * @param string   $orderby The ORDER BY clause of the query.
       
  2537 			 * @param WP_Query $this    The WP_Query instance (passed by reference).
       
  2538 			 */
       
  2539 			$orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
       
  2540 
       
  2541 			/**
       
  2542 			 * Filters the DISTINCT clause of the query.
       
  2543 			 *
       
  2544 			 * @since 2.1.0
       
  2545 			 *
       
  2546 			 * @param string   $distinct The DISTINCT clause of the query.
       
  2547 			 * @param WP_Query $this     The WP_Query instance (passed by reference).
       
  2548 			 */
       
  2549 			$distinct = apply_filters_ref_array( 'posts_distinct', array( $distinct, &$this ) );
       
  2550 
       
  2551 			/**
       
  2552 			 * Filters the LIMIT clause of the query.
       
  2553 			 *
       
  2554 			 * @since 2.1.0
       
  2555 			 *
       
  2556 			 * @param string   $limits The LIMIT clause of the query.
       
  2557 			 * @param WP_Query $this   The WP_Query instance (passed by reference).
       
  2558 			 */
       
  2559 			$limits = apply_filters_ref_array( 'post_limits', array( $limits, &$this ) );
       
  2560 
       
  2561 			/**
       
  2562 			 * Filters the SELECT clause of the query.
       
  2563 			 *
       
  2564 			 * @since 2.1.0
       
  2565 			 *
       
  2566 			 * @param string   $fields The SELECT clause of the query.
       
  2567 			 * @param WP_Query $this   The WP_Query instance (passed by reference).
       
  2568 			 */
       
  2569 			$fields = apply_filters_ref_array( 'posts_fields', array( $fields, &$this ) );
       
  2570 
       
  2571 			/**
       
  2572 			 * Filters all query clauses at once, for convenience.
       
  2573 			 *
       
  2574 			 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
       
  2575 			 * fields (SELECT), and LIMITS clauses.
       
  2576 			 *
       
  2577 			 * @since 3.1.0
       
  2578 			 *
       
  2579 			 * @param array    $clauses The list of clauses for the query.
       
  2580 			 * @param WP_Query $this    The WP_Query instance (passed by reference).
       
  2581 			 */
       
  2582 			$clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
       
  2583 
       
  2584 			$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
       
  2585 			$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
       
  2586 			$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
       
  2587 			$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
       
  2588 			$distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
       
  2589 			$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
       
  2590 			$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
       
  2591 		}
       
  2592 
       
  2593 		/**
       
  2594 		 * Fires to announce the query's current selection parameters.
       
  2595 		 *
       
  2596 		 * For use by caching plugins.
       
  2597 		 *
       
  2598 		 * @since 2.3.0
       
  2599 		 *
       
  2600 		 * @param string $selection The assembled selection query.
       
  2601 		 */
       
  2602 		do_action( 'posts_selection', $where . $groupby . $orderby . $limits . $join );
       
  2603 
       
  2604 		/*
       
  2605 		 * Filters again for the benefit of caching plugins.
       
  2606 		 * Regular plugins should use the hooks above.
       
  2607 		 */
       
  2608 		if ( !$q['suppress_filters'] ) {
       
  2609 			/**
       
  2610 			 * Filters the WHERE clause of the query.
       
  2611 			 *
       
  2612 			 * For use by caching plugins.
       
  2613 			 *
       
  2614 			 * @since 2.5.0
       
  2615 			 *
       
  2616 			 * @param string   $where The WHERE clause of the query.
       
  2617 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  2618 			 */
       
  2619 			$where = apply_filters_ref_array( 'posts_where_request', array( $where, &$this ) );
       
  2620 
       
  2621 			/**
       
  2622 			 * Filters the GROUP BY clause of the query.
       
  2623 			 *
       
  2624 			 * For use by caching plugins.
       
  2625 			 *
       
  2626 			 * @since 2.5.0
       
  2627 			 *
       
  2628 			 * @param string   $groupby The GROUP BY clause of the query.
       
  2629 			 * @param WP_Query $this    The WP_Query instance (passed by reference).
       
  2630 			 */
       
  2631 			$groupby = apply_filters_ref_array( 'posts_groupby_request', array( $groupby, &$this ) );
       
  2632 
       
  2633 			/**
       
  2634 			 * Filters the JOIN clause of the query.
       
  2635 			 *
       
  2636 			 * For use by caching plugins.
       
  2637 			 *
       
  2638 			 * @since 2.5.0
       
  2639 			 *
       
  2640 			 * @param string   $join  The JOIN clause of the query.
       
  2641 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  2642 			 */
       
  2643 			$join = apply_filters_ref_array( 'posts_join_request', array( $join, &$this ) );
       
  2644 
       
  2645 			/**
       
  2646 			 * Filters the ORDER BY clause of the query.
       
  2647 			 *
       
  2648 			 * For use by caching plugins.
       
  2649 			 *
       
  2650 			 * @since 2.5.0
       
  2651 			 *
       
  2652 			 * @param string   $orderby The ORDER BY clause of the query.
       
  2653 			 * @param WP_Query $this    The WP_Query instance (passed by reference).
       
  2654 			 */
       
  2655 			$orderby = apply_filters_ref_array( 'posts_orderby_request', array( $orderby, &$this ) );
       
  2656 
       
  2657 			/**
       
  2658 			 * Filters the DISTINCT clause of the query.
       
  2659 			 *
       
  2660 			 * For use by caching plugins.
       
  2661 			 *
       
  2662 			 * @since 2.5.0
       
  2663 			 *
       
  2664 			 * @param string   $distinct The DISTINCT clause of the query.
       
  2665 			 * @param WP_Query $this     The WP_Query instance (passed by reference).
       
  2666 			 */
       
  2667 			$distinct = apply_filters_ref_array( 'posts_distinct_request', array( $distinct, &$this ) );
       
  2668 
       
  2669 			/**
       
  2670 			 * Filters the SELECT clause of the query.
       
  2671 			 *
       
  2672 			 * For use by caching plugins.
       
  2673 			 *
       
  2674 			 * @since 2.5.0
       
  2675 			 *
       
  2676 			 * @param string   $fields The SELECT clause of the query.
       
  2677 			 * @param WP_Query $this   The WP_Query instance (passed by reference).
       
  2678 			 */
       
  2679 			$fields = apply_filters_ref_array( 'posts_fields_request', array( $fields, &$this ) );
       
  2680 
       
  2681 			/**
       
  2682 			 * Filters the LIMIT clause of the query.
       
  2683 			 *
       
  2684 			 * For use by caching plugins.
       
  2685 			 *
       
  2686 			 * @since 2.5.0
       
  2687 			 *
       
  2688 			 * @param string   $limits The LIMIT clause of the query.
       
  2689 			 * @param WP_Query $this   The WP_Query instance (passed by reference).
       
  2690 			 */
       
  2691 			$limits = apply_filters_ref_array( 'post_limits_request', array( $limits, &$this ) );
       
  2692 
       
  2693 			/**
       
  2694 			 * Filters all query clauses at once, for convenience.
       
  2695 			 *
       
  2696 			 * For use by caching plugins.
       
  2697 			 *
       
  2698 			 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
       
  2699 			 * fields (SELECT), and LIMITS clauses.
       
  2700 			 *
       
  2701 			 * @since 3.1.0
       
  2702 			 *
       
  2703 			 * @param array    $pieces The pieces of the query.
       
  2704 			 * @param WP_Query $this   The WP_Query instance (passed by reference).
       
  2705 			 */
       
  2706 			$clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );
       
  2707 
       
  2708 			$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
       
  2709 			$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
       
  2710 			$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
       
  2711 			$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
       
  2712 			$distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
       
  2713 			$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
       
  2714 			$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
       
  2715 		}
       
  2716 
       
  2717 		if ( ! empty($groupby) )
       
  2718 			$groupby = 'GROUP BY ' . $groupby;
       
  2719 		if ( !empty( $orderby ) )
       
  2720 			$orderby = 'ORDER BY ' . $orderby;
       
  2721 
       
  2722 		$found_rows = '';
       
  2723 		if ( !$q['no_found_rows'] && !empty($limits) )
       
  2724 			$found_rows = 'SQL_CALC_FOUND_ROWS';
       
  2725 
       
  2726 		$this->request = $old_request = "SELECT $found_rows $distinct $fields FROM {$wpdb->posts} $join WHERE 1=1 $where $groupby $orderby $limits";
       
  2727 
       
  2728 		if ( !$q['suppress_filters'] ) {
       
  2729 			/**
       
  2730 			 * Filters the completed SQL query before sending.
       
  2731 			 *
       
  2732 			 * @since 2.0.0
       
  2733 			 *
       
  2734 			 * @param string   $request The complete SQL query.
       
  2735 			 * @param WP_Query $this    The WP_Query instance (passed by reference).
       
  2736 			 */
       
  2737 			$this->request = apply_filters_ref_array( 'posts_request', array( $this->request, &$this ) );
       
  2738 		}
       
  2739 
       
  2740 		/**
       
  2741 		 * Filters the posts array before the query takes place.
       
  2742 		 *
       
  2743 		 * Return a non-null value to bypass WordPress's default post queries.
       
  2744 		 *
       
  2745 		 * Filtering functions that require pagination information are encouraged to set
       
  2746 		 * the `found_posts` and `max_num_pages` properties of the WP_Query object,
       
  2747 		 * passed to the filter by reference. If WP_Query does not perform a database
       
  2748 		 * query, it will not have enough information to generate these values itself.
       
  2749 		 *
       
  2750 		 * @since 4.6.0
       
  2751 		 *
       
  2752 		 * @param array|null $posts Return an array of post data to short-circuit WP's query,
       
  2753 		 *                          or null to allow WP to run its normal queries.
       
  2754 		 * @param WP_Query   $this  The WP_Query instance (passed by reference).
       
  2755 		 */
       
  2756 		$this->posts = apply_filters_ref_array( 'posts_pre_query', array( null, &$this ) );
       
  2757 
       
  2758 		if ( 'ids' == $q['fields'] ) {
       
  2759 			if ( null === $this->posts ) {
       
  2760 				$this->posts = $wpdb->get_col( $this->request );
       
  2761 			}
       
  2762 
       
  2763 			$this->posts = array_map( 'intval', $this->posts );
       
  2764 			$this->post_count = count( $this->posts );
       
  2765 			$this->set_found_posts( $q, $limits );
       
  2766 
       
  2767 			return $this->posts;
       
  2768 		}
       
  2769 
       
  2770 		if ( 'id=>parent' == $q['fields'] ) {
       
  2771 			if ( null === $this->posts ) {
       
  2772 				$this->posts = $wpdb->get_results( $this->request );
       
  2773 			}
       
  2774 
       
  2775 			$this->post_count = count( $this->posts );
       
  2776 			$this->set_found_posts( $q, $limits );
       
  2777 
       
  2778 			$r = array();
       
  2779 			foreach ( $this->posts as $key => $post ) {
       
  2780 				$this->posts[ $key ]->ID = (int) $post->ID;
       
  2781 				$this->posts[ $key ]->post_parent = (int) $post->post_parent;
       
  2782 
       
  2783 				$r[ (int) $post->ID ] = (int) $post->post_parent;
       
  2784 			}
       
  2785 
       
  2786 			return $r;
       
  2787 		}
       
  2788 
       
  2789 		if ( null === $this->posts ) {
       
  2790 			$split_the_query = ( $old_request == $this->request && "{$wpdb->posts}.*" == $fields && !empty( $limits ) && $q['posts_per_page'] < 500 );
       
  2791 
       
  2792 			/**
       
  2793 			 * Filters whether to split the query.
       
  2794 			 *
       
  2795 			 * Splitting the query will cause it to fetch just the IDs of the found posts
       
  2796 			 * (and then individually fetch each post by ID), rather than fetching every
       
  2797 			 * complete row at once. One massive result vs. many small results.
       
  2798 			 *
       
  2799 			 * @since 3.4.0
       
  2800 			 *
       
  2801 			 * @param bool     $split_the_query Whether or not to split the query.
       
  2802 			 * @param WP_Query $this            The WP_Query instance.
       
  2803 			 */
       
  2804 			$split_the_query = apply_filters( 'split_the_query', $split_the_query, $this );
       
  2805 
       
  2806 			if ( $split_the_query ) {
       
  2807 				// First get the IDs and then fill in the objects
       
  2808 
       
  2809 				$this->request = "SELECT $found_rows $distinct {$wpdb->posts}.ID FROM {$wpdb->posts} $join WHERE 1=1 $where $groupby $orderby $limits";
       
  2810 
       
  2811 				/**
       
  2812 				 * Filters the Post IDs SQL request before sending.
       
  2813 				 *
       
  2814 				 * @since 3.4.0
       
  2815 				 *
       
  2816 				 * @param string   $request The post ID request.
       
  2817 				 * @param WP_Query $this    The WP_Query instance.
       
  2818 				 */
       
  2819 				$this->request = apply_filters( 'posts_request_ids', $this->request, $this );
       
  2820 
       
  2821 				$ids = $wpdb->get_col( $this->request );
       
  2822 
       
  2823 				if ( $ids ) {
       
  2824 					$this->posts = $ids;
       
  2825 					$this->set_found_posts( $q, $limits );
       
  2826 					_prime_post_caches( $ids, $q['update_post_term_cache'], $q['update_post_meta_cache'] );
       
  2827 				} else {
       
  2828 					$this->posts = array();
       
  2829 				}
       
  2830 			} else {
       
  2831 				$this->posts = $wpdb->get_results( $this->request );
       
  2832 				$this->set_found_posts( $q, $limits );
       
  2833 			}
       
  2834 		}
       
  2835 
       
  2836 		// Convert to WP_Post objects.
       
  2837 		if ( $this->posts ) {
       
  2838 			$this->posts = array_map( 'get_post', $this->posts );
       
  2839 		}
       
  2840 
       
  2841 		if ( ! $q['suppress_filters'] ) {
       
  2842 			/**
       
  2843 			 * Filters the raw post results array, prior to status checks.
       
  2844 			 *
       
  2845 			 * @since 2.3.0
       
  2846 			 *
       
  2847 			 * @param array    $posts The post results array.
       
  2848 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  2849 			 */
       
  2850 			$this->posts = apply_filters_ref_array( 'posts_results', array( $this->posts, &$this ) );
       
  2851 		}
       
  2852 
       
  2853 		if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
       
  2854 			/** This filter is documented in wp-includes/query.php */
       
  2855 			$cjoin = apply_filters_ref_array( 'comment_feed_join', array( '', &$this ) );
       
  2856 
       
  2857 			/** This filter is documented in wp-includes/query.php */
       
  2858 			$cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
       
  2859 
       
  2860 			/** This filter is documented in wp-includes/query.php */
       
  2861 			$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( '', &$this ) );
       
  2862 			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
       
  2863 
       
  2864 			/** This filter is documented in wp-includes/query.php */
       
  2865 			$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
       
  2866 			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
       
  2867 
       
  2868 			/** This filter is documented in wp-includes/query.php */
       
  2869 			$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
       
  2870 
       
  2871 			$comments_request = "SELECT {$wpdb->comments}.* FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits";
       
  2872 			$comments = $wpdb->get_results($comments_request);
       
  2873 			// Convert to WP_Comment
       
  2874 			$this->comments = array_map( 'get_comment', $comments );
       
  2875 			$this->comment_count = count($this->comments);
       
  2876 		}
       
  2877 
       
  2878 		// Check post status to determine if post should be displayed.
       
  2879 		if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) {
       
  2880 			$status = get_post_status($this->posts[0]);
       
  2881 			if ( 'attachment' === $this->posts[0]->post_type && 0 === (int) $this->posts[0]->post_parent ) {
       
  2882 				$this->is_page = false;
       
  2883 				$this->is_single = true;
       
  2884 				$this->is_attachment = true;
       
  2885 			}
       
  2886 			$post_status_obj = get_post_status_object($status);
       
  2887 
       
  2888 			// If the post_status was specifically requested, let it pass through.
       
  2889 			if ( !$post_status_obj->public && ! in_array( $status, $q_status ) ) {
       
  2890 
       
  2891 				if ( ! is_user_logged_in() ) {
       
  2892 					// User must be logged in to view unpublished posts.
       
  2893 					$this->posts = array();
       
  2894 				} else {
       
  2895 					if  ( $post_status_obj->protected ) {
       
  2896 						// User must have edit permissions on the draft to preview.
       
  2897 						if ( ! current_user_can($edit_cap, $this->posts[0]->ID) ) {
       
  2898 							$this->posts = array();
       
  2899 						} else {
       
  2900 							$this->is_preview = true;
       
  2901 							if ( 'future' != $status )
       
  2902 								$this->posts[0]->post_date = current_time('mysql');
       
  2903 						}
       
  2904 					} elseif ( $post_status_obj->private ) {
       
  2905 						if ( ! current_user_can($read_cap, $this->posts[0]->ID) )
       
  2906 							$this->posts = array();
       
  2907 					} else {
       
  2908 						$this->posts = array();
       
  2909 					}
       
  2910 				}
       
  2911 			}
       
  2912 
       
  2913 			if ( $this->is_preview && $this->posts && current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
       
  2914 				/**
       
  2915 				 * Filters the single post for preview mode.
       
  2916 				 *
       
  2917 				 * @since 2.7.0
       
  2918 				 *
       
  2919 				 * @param WP_Post  $post_preview  The Post object.
       
  2920 				 * @param WP_Query $this          The WP_Query instance (passed by reference).
       
  2921 				 */
       
  2922 				$this->posts[0] = get_post( apply_filters_ref_array( 'the_preview', array( $this->posts[0], &$this ) ) );
       
  2923 			}
       
  2924 		}
       
  2925 
       
  2926 		// Put sticky posts at the top of the posts array
       
  2927 		$sticky_posts = get_option('sticky_posts');
       
  2928 		if ( $this->is_home && $page <= 1 && is_array($sticky_posts) && !empty($sticky_posts) && !$q['ignore_sticky_posts'] ) {
       
  2929 			$num_posts = count($this->posts);
       
  2930 			$sticky_offset = 0;
       
  2931 			// Loop over posts and relocate stickies to the front.
       
  2932 			for ( $i = 0; $i < $num_posts; $i++ ) {
       
  2933 				if ( in_array($this->posts[$i]->ID, $sticky_posts) ) {
       
  2934 					$sticky_post = $this->posts[$i];
       
  2935 					// Remove sticky from current position
       
  2936 					array_splice($this->posts, $i, 1);
       
  2937 					// Move to front, after other stickies
       
  2938 					array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
       
  2939 					// Increment the sticky offset. The next sticky will be placed at this offset.
       
  2940 					$sticky_offset++;
       
  2941 					// Remove post from sticky posts array
       
  2942 					$offset = array_search($sticky_post->ID, $sticky_posts);
       
  2943 					unset( $sticky_posts[$offset] );
       
  2944 				}
       
  2945 			}
       
  2946 
       
  2947 			// If any posts have been excluded specifically, Ignore those that are sticky.
       
  2948 			if ( !empty($sticky_posts) && !empty($q['post__not_in']) )
       
  2949 				$sticky_posts = array_diff($sticky_posts, $q['post__not_in']);
       
  2950 
       
  2951 			// Fetch sticky posts that weren't in the query results
       
  2952 			if ( !empty($sticky_posts) ) {
       
  2953 				$stickies = get_posts( array(
       
  2954 					'post__in' => $sticky_posts,
       
  2955 					'post_type' => $post_type,
       
  2956 					'post_status' => 'publish',
       
  2957 					'nopaging' => true
       
  2958 				) );
       
  2959 
       
  2960 				foreach ( $stickies as $sticky_post ) {
       
  2961 					array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
       
  2962 					$sticky_offset++;
       
  2963 				}
       
  2964 			}
       
  2965 		}
       
  2966 
       
  2967 		// If comments have been fetched as part of the query, make sure comment meta lazy-loading is set up.
       
  2968 		if ( ! empty( $this->comments ) ) {
       
  2969 			wp_queue_comments_for_comment_meta_lazyload( $this->comments );
       
  2970 		}
       
  2971 
       
  2972 		if ( ! $q['suppress_filters'] ) {
       
  2973 			/**
       
  2974 			 * Filters the array of retrieved posts after they've been fetched and
       
  2975 			 * internally processed.
       
  2976 			 *
       
  2977 			 * @since 1.5.0
       
  2978 			 *
       
  2979 			 * @param array    $posts The array of retrieved posts.
       
  2980 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  2981 			 */
       
  2982 			$this->posts = apply_filters_ref_array( 'the_posts', array( $this->posts, &$this ) );
       
  2983 		}
       
  2984 
       
  2985 		// Ensure that any posts added/modified via one of the filters above are
       
  2986 		// of the type WP_Post and are filtered.
       
  2987 		if ( $this->posts ) {
       
  2988 			$this->post_count = count( $this->posts );
       
  2989 
       
  2990 			$this->posts = array_map( 'get_post', $this->posts );
       
  2991 
       
  2992 			if ( $q['cache_results'] )
       
  2993 				update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);
       
  2994 
       
  2995 			$this->post = reset( $this->posts );
       
  2996 		} else {
       
  2997 			$this->post_count = 0;
       
  2998 			$this->posts = array();
       
  2999 		}
       
  3000 
       
  3001 		if ( $q['lazy_load_term_meta'] ) {
       
  3002 			wp_queue_posts_for_term_meta_lazyload( $this->posts );
       
  3003 		}
       
  3004 
       
  3005 		return $this->posts;
       
  3006 	}
       
  3007 
       
  3008 	/**
       
  3009 	 * Set up the amount of found posts and the number of pages (if limit clause was used)
       
  3010 	 * for the current query.
       
  3011 	 *
       
  3012 	 * @since 3.5.0
       
  3013 	 *
       
  3014 	 * @param array  $q      Query variables.
       
  3015 	 * @param string $limits LIMIT clauses of the query.
       
  3016 	 */
       
  3017 	private function set_found_posts( $q, $limits ) {
       
  3018 		global $wpdb;
       
  3019 		// Bail if posts is an empty array. Continue if posts is an empty string,
       
  3020 		// null, or false to accommodate caching plugins that fill posts later.
       
  3021 		if ( $q['no_found_rows'] || ( is_array( $this->posts ) && ! $this->posts ) )
       
  3022 			return;
       
  3023 
       
  3024 		if ( ! empty( $limits ) ) {
       
  3025 			/**
       
  3026 			 * Filters the query to run for retrieving the found posts.
       
  3027 			 *
       
  3028 			 * @since 2.1.0
       
  3029 			 *
       
  3030 			 * @param string   $found_posts The query to run to find the found posts.
       
  3031 			 * @param WP_Query $this        The WP_Query instance (passed by reference).
       
  3032 			 */
       
  3033 			$this->found_posts = $wpdb->get_var( apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) ) );
       
  3034 		} else {
       
  3035 			if ( is_array( $this->posts ) ) {
       
  3036 				$this->found_posts = count( $this->posts );
       
  3037 			} else {
       
  3038 				if ( null === $this->posts ) {  
       
  3039 					$this->found_posts = 0;
       
  3040 				} else {
       
  3041 					$this->found_posts = 1;
       
  3042 				}
       
  3043 			}
       
  3044 		}
       
  3045 
       
  3046 		/**
       
  3047 		 * Filters the number of found posts for the query.
       
  3048 		 *
       
  3049 		 * @since 2.1.0
       
  3050 		 *
       
  3051 		 * @param int      $found_posts The number of posts found.
       
  3052 		 * @param WP_Query $this        The WP_Query instance (passed by reference).
       
  3053 		 */
       
  3054 		$this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
       
  3055 
       
  3056 		if ( ! empty( $limits ) )
       
  3057 			$this->max_num_pages = ceil( $this->found_posts / $q['posts_per_page'] );
       
  3058 	}
       
  3059 
       
  3060 	/**
       
  3061 	 * Set up the next post and iterate current post index.
       
  3062 	 *
       
  3063 	 * @since 1.5.0
       
  3064 	 *
       
  3065 	 * @return WP_Post Next post.
       
  3066 	 */
       
  3067 	public function next_post() {
       
  3068 
       
  3069 		$this->current_post++;
       
  3070 
       
  3071 		$this->post = $this->posts[$this->current_post];
       
  3072 		return $this->post;
       
  3073 	}
       
  3074 
       
  3075 	/**
       
  3076 	 * Sets up the current post.
       
  3077 	 *
       
  3078 	 * Retrieves the next post, sets up the post, sets the 'in the loop'
       
  3079 	 * property to true.
       
  3080 	 *
       
  3081 	 * @since 1.5.0
       
  3082 	 *
       
  3083 	 * @global WP_Post $post
       
  3084 	 */
       
  3085 	public function the_post() {
       
  3086 		global $post;
       
  3087 		$this->in_the_loop = true;
       
  3088 
       
  3089 		if ( $this->current_post == -1 ) // loop has just started
       
  3090 			/**
       
  3091 			 * Fires once the loop is started.
       
  3092 			 *
       
  3093 			 * @since 2.0.0
       
  3094 			 *
       
  3095 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  3096 			 */
       
  3097 			do_action_ref_array( 'loop_start', array( &$this ) );
       
  3098 
       
  3099 		$post = $this->next_post();
       
  3100 		$this->setup_postdata( $post );
       
  3101 	}
       
  3102 
       
  3103 	/**
       
  3104 	 * Determines whether there are more posts available in the loop.
       
  3105 	 *
       
  3106 	 * Calls the {@see 'loop_end'} action when the loop is complete.
       
  3107 	 *
       
  3108 	 * @since 1.5.0
       
  3109 	 *
       
  3110 	 * @return bool True if posts are available, false if end of loop.
       
  3111 	 */
       
  3112 	public function have_posts() {
       
  3113 		if ( $this->current_post + 1 < $this->post_count ) {
       
  3114 			return true;
       
  3115 		} elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
       
  3116 			/**
       
  3117 			 * Fires once the loop has ended.
       
  3118 			 *
       
  3119 			 * @since 2.0.0
       
  3120 			 *
       
  3121 			 * @param WP_Query $this The WP_Query instance (passed by reference).
       
  3122 			 */
       
  3123 			do_action_ref_array( 'loop_end', array( &$this ) );
       
  3124 			// Do some cleaning up after the loop
       
  3125 			$this->rewind_posts();
       
  3126 		} elseif ( 0 === $this->post_count ) {
       
  3127 			/**
       
  3128 			 * Fires if no results are found in a post query.
       
  3129 			 *
       
  3130 			 * @since 4.9.0
       
  3131 			 *
       
  3132 			 * @param WP_Query $this The WP_Query instance.
       
  3133 			 */
       
  3134 			do_action( 'loop_no_results', $this );
       
  3135 		}
       
  3136 
       
  3137 		$this->in_the_loop = false;
       
  3138 		return false;
       
  3139 	}
       
  3140 
       
  3141 	/**
       
  3142 	 * Rewind the posts and reset post index.
       
  3143 	 *
       
  3144 	 * @since 1.5.0
       
  3145 	 */
       
  3146 	public function rewind_posts() {
       
  3147 		$this->current_post = -1;
       
  3148 		if ( $this->post_count > 0 ) {
       
  3149 			$this->post = $this->posts[0];
       
  3150 		}
       
  3151 	}
       
  3152 
       
  3153 	/**
       
  3154 	 * Iterate current comment index and return WP_Comment object.
       
  3155 	 *
       
  3156 	 * @since 2.2.0
       
  3157 	 *
       
  3158 	 * @return WP_Comment Comment object.
       
  3159 	 */
       
  3160 	public function next_comment() {
       
  3161 		$this->current_comment++;
       
  3162 
       
  3163 		$this->comment = $this->comments[$this->current_comment];
       
  3164 		return $this->comment;
       
  3165 	}
       
  3166 
       
  3167 	/**
       
  3168 	 * Sets up the current comment.
       
  3169 	 *
       
  3170 	 * @since 2.2.0
       
  3171 	 * @global WP_Comment $comment Current comment.
       
  3172 	 */
       
  3173 	public function the_comment() {
       
  3174 		global $comment;
       
  3175 
       
  3176 		$comment = $this->next_comment();
       
  3177 
       
  3178 		if ( $this->current_comment == 0 ) {
       
  3179 			/**
       
  3180 			 * Fires once the comment loop is started.
       
  3181 			 *
       
  3182 			 * @since 2.2.0
       
  3183 			 */
       
  3184 			do_action( 'comment_loop_start' );
       
  3185 		}
       
  3186 	}
       
  3187 
       
  3188 	/**
       
  3189 	 * Whether there are more comments available.
       
  3190 	 *
       
  3191 	 * Automatically rewinds comments when finished.
       
  3192 	 *
       
  3193 	 * @since 2.2.0
       
  3194 	 *
       
  3195 	 * @return bool True, if more comments. False, if no more posts.
       
  3196 	 */
       
  3197 	public function have_comments() {
       
  3198 		if ( $this->current_comment + 1 < $this->comment_count ) {
       
  3199 			return true;
       
  3200 		} elseif ( $this->current_comment + 1 == $this->comment_count ) {
       
  3201 			$this->rewind_comments();
       
  3202 		}
       
  3203 
       
  3204 		return false;
       
  3205 	}
       
  3206 
       
  3207 	/**
       
  3208 	 * Rewind the comments, resets the comment index and comment to first.
       
  3209 	 *
       
  3210 	 * @since 2.2.0
       
  3211 	 */
       
  3212 	public function rewind_comments() {
       
  3213 		$this->current_comment = -1;
       
  3214 		if ( $this->comment_count > 0 ) {
       
  3215 			$this->comment = $this->comments[0];
       
  3216 		}
       
  3217 	}
       
  3218 
       
  3219 	/**
       
  3220 	 * Sets up the WordPress query by parsing query string.
       
  3221 	 *
       
  3222 	 * @since 1.5.0
       
  3223 	 *
       
  3224 	 * @param string|array $query URL query string or array of query arguments.
       
  3225 	 * @return array List of posts.
       
  3226 	 */
       
  3227 	public function query( $query ) {
       
  3228 		$this->init();
       
  3229 		$this->query = $this->query_vars = wp_parse_args( $query );
       
  3230 		return $this->get_posts();
       
  3231 	}
       
  3232 
       
  3233 	/**
       
  3234 	 * Retrieve queried object.
       
  3235 	 *
       
  3236 	 * If queried object is not set, then the queried object will be set from
       
  3237 	 * the category, tag, taxonomy, posts page, single post, page, or author
       
  3238 	 * query variable. After it is set up, it will be returned.
       
  3239 	 *
       
  3240 	 * @since 1.5.0
       
  3241 	 *
       
  3242 	 * @return object
       
  3243 	 */
       
  3244 	public function get_queried_object() {
       
  3245 		if ( isset($this->queried_object) )
       
  3246 			return $this->queried_object;
       
  3247 
       
  3248 		$this->queried_object = null;
       
  3249 		$this->queried_object_id = null;
       
  3250 
       
  3251 		if ( $this->is_category || $this->is_tag || $this->is_tax ) {
       
  3252 			if ( $this->is_category ) {
       
  3253 				if ( $this->get( 'cat' ) ) {
       
  3254 					$term = get_term( $this->get( 'cat' ), 'category' );
       
  3255 				} elseif ( $this->get( 'category_name' ) ) {
       
  3256 					$term = get_term_by( 'slug', $this->get( 'category_name' ), 'category' );
       
  3257 				}
       
  3258 			} elseif ( $this->is_tag ) {
       
  3259 				if ( $this->get( 'tag_id' ) ) {
       
  3260 					$term = get_term( $this->get( 'tag_id' ), 'post_tag' );
       
  3261 				} elseif ( $this->get( 'tag' ) ) {
       
  3262 					$term = get_term_by( 'slug', $this->get( 'tag' ), 'post_tag' );
       
  3263 				}
       
  3264 			} else {
       
  3265 				// For other tax queries, grab the first term from the first clause.
       
  3266 				if ( ! empty( $this->tax_query->queried_terms ) ) {
       
  3267 					$queried_taxonomies = array_keys( $this->tax_query->queried_terms );
       
  3268 					$matched_taxonomy = reset( $queried_taxonomies );
       
  3269 					$query = $this->tax_query->queried_terms[ $matched_taxonomy ];
       
  3270 
       
  3271 					if ( ! empty( $query['terms'] ) ) {
       
  3272 						if ( 'term_id' == $query['field'] ) {
       
  3273 							$term = get_term( reset( $query['terms'] ), $matched_taxonomy );
       
  3274 						} else {
       
  3275 							$term = get_term_by( $query['field'], reset( $query['terms'] ), $matched_taxonomy );
       
  3276 						}
       
  3277 					}
       
  3278 				}
       
  3279 			}
       
  3280 
       
  3281 			if ( ! empty( $term ) && ! is_wp_error( $term ) )  {
       
  3282 				$this->queried_object = $term;
       
  3283 				$this->queried_object_id = (int) $term->term_id;
       
  3284 
       
  3285 				if ( $this->is_category && 'category' === $this->queried_object->taxonomy )
       
  3286 					_make_cat_compat( $this->queried_object );
       
  3287 			}
       
  3288 		} elseif ( $this->is_post_type_archive ) {
       
  3289 			$post_type = $this->get( 'post_type' );
       
  3290 			if ( is_array( $post_type ) )
       
  3291 				$post_type = reset( $post_type );
       
  3292 			$this->queried_object = get_post_type_object( $post_type );
       
  3293 		} elseif ( $this->is_posts_page ) {
       
  3294 			$page_for_posts = get_option('page_for_posts');
       
  3295 			$this->queried_object = get_post( $page_for_posts );
       
  3296 			$this->queried_object_id = (int) $this->queried_object->ID;
       
  3297 		} elseif ( $this->is_singular && ! empty( $this->post ) ) {
       
  3298 			$this->queried_object = $this->post;
       
  3299 			$this->queried_object_id = (int) $this->post->ID;
       
  3300 		} elseif ( $this->is_author ) {
       
  3301 			$this->queried_object_id = (int) $this->get('author');
       
  3302 			$this->queried_object = get_userdata( $this->queried_object_id );
       
  3303 		}
       
  3304 
       
  3305 		return $this->queried_object;
       
  3306 	}
       
  3307 
       
  3308 	/**
       
  3309 	 * Retrieve ID of the current queried object.
       
  3310 	 *
       
  3311 	 * @since 1.5.0
       
  3312 	 *
       
  3313 	 * @return int
       
  3314 	 */
       
  3315 	public function get_queried_object_id() {
       
  3316 		$this->get_queried_object();
       
  3317 
       
  3318 		if ( isset($this->queried_object_id) ) {
       
  3319 			return $this->queried_object_id;
       
  3320 		}
       
  3321 
       
  3322 		return 0;
       
  3323 	}
       
  3324 
       
  3325 	/**
       
  3326 	 * Constructor.
       
  3327 	 *
       
  3328 	 * Sets up the WordPress query, if parameter is not empty.
       
  3329 	 *
       
  3330 	 * @since 1.5.0
       
  3331 	 *
       
  3332 	 * @param string|array $query URL query string or array of vars.
       
  3333 	 */
       
  3334 	public function __construct( $query = '' ) {
       
  3335 		if ( ! empty( $query ) ) {
       
  3336 			$this->query( $query );
       
  3337 		}
       
  3338 	}
       
  3339 
       
  3340 	/**
       
  3341 	 * Make private properties readable for backward compatibility.
       
  3342 	 *
       
  3343 	 * @since 4.0.0
       
  3344 	 *
       
  3345 	 * @param string $name Property to get.
       
  3346 	 * @return mixed Property.
       
  3347 	 */
       
  3348 	public function __get( $name ) {
       
  3349 		if ( in_array( $name, $this->compat_fields ) ) {
       
  3350 			return $this->$name;
       
  3351 		}
       
  3352 	}
       
  3353 
       
  3354 	/**
       
  3355 	 * Make private properties checkable for backward compatibility.
       
  3356 	 *
       
  3357 	 * @since 4.0.0
       
  3358 	 *
       
  3359 	 * @param string $name Property to check if set.
       
  3360 	 * @return bool Whether the property is set.
       
  3361 	 */
       
  3362 	public function __isset( $name ) {
       
  3363 		if ( in_array( $name, $this->compat_fields ) ) {
       
  3364 			return isset( $this->$name );
       
  3365 		}
       
  3366 	}
       
  3367 
       
  3368 	/**
       
  3369 	 * Make private/protected methods readable for backward compatibility.
       
  3370 	 *
       
  3371 	 * @since 4.0.0
       
  3372 	 *
       
  3373 	 * @param callable $name      Method to call.
       
  3374 	 * @param array    $arguments Arguments to pass when calling.
       
  3375 	 * @return mixed|false Return value of the callback, false otherwise.
       
  3376 	 */
       
  3377 	public function __call( $name, $arguments ) {
       
  3378 		if ( in_array( $name, $this->compat_methods ) ) {
       
  3379 			return call_user_func_array( array( $this, $name ), $arguments );
       
  3380 		}
       
  3381 		return false;
       
  3382 	}
       
  3383 
       
  3384 	/**
       
  3385  	 * Is the query for an existing archive page?
       
  3386  	 *
       
  3387  	 * Month, Year, Category, Author, Post Type archive...
       
  3388 	 *
       
  3389  	 * @since 3.1.0
       
  3390  	 *
       
  3391  	 * @return bool
       
  3392  	 */
       
  3393 	public function is_archive() {
       
  3394 		return (bool) $this->is_archive;
       
  3395 	}
       
  3396 
       
  3397 	/**
       
  3398 	 * Is the query for an existing post type archive page?
       
  3399 	 *
       
  3400 	 * @since 3.1.0
       
  3401 	 *
       
  3402 	 * @param mixed $post_types Optional. Post type or array of posts types to check against.
       
  3403 	 * @return bool
       
  3404 	 */
       
  3405 	public function is_post_type_archive( $post_types = '' ) {
       
  3406 		if ( empty( $post_types ) || ! $this->is_post_type_archive )
       
  3407 			return (bool) $this->is_post_type_archive;
       
  3408 
       
  3409 		$post_type = $this->get( 'post_type' );
       
  3410 		if ( is_array( $post_type ) )
       
  3411 			$post_type = reset( $post_type );
       
  3412 		$post_type_object = get_post_type_object( $post_type );
       
  3413 
       
  3414 		return in_array( $post_type_object->name, (array) $post_types );
       
  3415 	}
       
  3416 
       
  3417 	/**
       
  3418 	 * Is the query for an existing attachment page?
       
  3419 	 *
       
  3420 	 * @since 3.1.0
       
  3421 	 *
       
  3422 	 * @param mixed $attachment Attachment ID, title, slug, or array of such.
       
  3423 	 * @return bool
       
  3424 	 */
       
  3425 	public function is_attachment( $attachment = '' ) {
       
  3426 		if ( ! $this->is_attachment ) {
       
  3427 			return false;
       
  3428 		}
       
  3429 
       
  3430 		if ( empty( $attachment ) ) {
       
  3431 			return true;
       
  3432 		}
       
  3433 
       
  3434 		$attachment = array_map( 'strval', (array) $attachment );
       
  3435 
       
  3436 		$post_obj = $this->get_queried_object();
       
  3437 
       
  3438 		if ( in_array( (string) $post_obj->ID, $attachment ) ) {
       
  3439 			return true;
       
  3440 		} elseif ( in_array( $post_obj->post_title, $attachment ) ) {
       
  3441 			return true;
       
  3442 		} elseif ( in_array( $post_obj->post_name, $attachment ) ) {
       
  3443 			return true;
       
  3444 		}
       
  3445 		return false;
       
  3446 	}
       
  3447 
       
  3448 	/**
       
  3449 	 * Is the query for an existing author archive page?
       
  3450 	 *
       
  3451 	 * If the $author parameter is specified, this function will additionally
       
  3452 	 * check if the query is for one of the authors specified.
       
  3453 	 *
       
  3454 	 * @since 3.1.0
       
  3455 	 *
       
  3456 	 * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
       
  3457 	 * @return bool
       
  3458 	 */
       
  3459 	public function is_author( $author = '' ) {
       
  3460 		if ( !$this->is_author )
       
  3461 			return false;
       
  3462 
       
  3463 		if ( empty($author) )
       
  3464 			return true;
       
  3465 
       
  3466 		$author_obj = $this->get_queried_object();
       
  3467 
       
  3468 		$author = array_map( 'strval', (array) $author );
       
  3469 
       
  3470 		if ( in_array( (string) $author_obj->ID, $author ) )
       
  3471 			return true;
       
  3472 		elseif ( in_array( $author_obj->nickname, $author ) )
       
  3473 			return true;
       
  3474 		elseif ( in_array( $author_obj->user_nicename, $author ) )
       
  3475 			return true;
       
  3476 
       
  3477 		return false;
       
  3478 	}
       
  3479 
       
  3480 	/**
       
  3481 	 * Is the query for an existing category archive page?
       
  3482 	 *
       
  3483 	 * If the $category parameter is specified, this function will additionally
       
  3484 	 * check if the query is for one of the categories specified.
       
  3485 	 *
       
  3486 	 * @since 3.1.0
       
  3487 	 *
       
  3488 	 * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
       
  3489 	 * @return bool
       
  3490 	 */
       
  3491 	public function is_category( $category = '' ) {
       
  3492 		if ( !$this->is_category )
       
  3493 			return false;
       
  3494 
       
  3495 		if ( empty($category) )
       
  3496 			return true;
       
  3497 
       
  3498 		$cat_obj = $this->get_queried_object();
       
  3499 
       
  3500 		$category = array_map( 'strval', (array) $category );
       
  3501 
       
  3502 		if ( in_array( (string) $cat_obj->term_id, $category ) )
       
  3503 			return true;
       
  3504 		elseif ( in_array( $cat_obj->name, $category ) )
       
  3505 			return true;
       
  3506 		elseif ( in_array( $cat_obj->slug, $category ) )
       
  3507 			return true;
       
  3508 
       
  3509 		return false;
       
  3510 	}
       
  3511 
       
  3512 	/**
       
  3513 	 * Is the query for an existing tag archive page?
       
  3514 	 *
       
  3515 	 * If the $tag parameter is specified, this function will additionally
       
  3516 	 * check if the query is for one of the tags specified.
       
  3517 	 *
       
  3518 	 * @since 3.1.0
       
  3519 	 *
       
  3520 	 * @param mixed $tag Optional. Tag ID, name, slug, or array of Tag IDs, names, and slugs.
       
  3521 	 * @return bool
       
  3522 	 */
       
  3523 	public function is_tag( $tag = '' ) {
       
  3524 		if ( ! $this->is_tag )
       
  3525 			return false;
       
  3526 
       
  3527 		if ( empty( $tag ) )
       
  3528 			return true;
       
  3529 
       
  3530 		$tag_obj = $this->get_queried_object();
       
  3531 
       
  3532 		$tag = array_map( 'strval', (array) $tag );
       
  3533 
       
  3534 		if ( in_array( (string) $tag_obj->term_id, $tag ) )
       
  3535 			return true;
       
  3536 		elseif ( in_array( $tag_obj->name, $tag ) )
       
  3537 			return true;
       
  3538 		elseif ( in_array( $tag_obj->slug, $tag ) )
       
  3539 			return true;
       
  3540 
       
  3541 		return false;
       
  3542 	}
       
  3543 
       
  3544 	/**
       
  3545 	 * Is the query for an existing custom taxonomy archive page?
       
  3546 	 *
       
  3547 	 * If the $taxonomy parameter is specified, this function will additionally
       
  3548 	 * check if the query is for that specific $taxonomy.
       
  3549 	 *
       
  3550 	 * If the $term parameter is specified in addition to the $taxonomy parameter,
       
  3551 	 * this function will additionally check if the query is for one of the terms
       
  3552 	 * specified.
       
  3553 	 *
       
  3554 	 * @since 3.1.0
       
  3555 	 *
       
  3556 	 * @global array $wp_taxonomies
       
  3557 	 *
       
  3558 	 * @param mixed $taxonomy Optional. Taxonomy slug or slugs.
       
  3559 	 * @param mixed $term     Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
       
  3560 	 * @return bool True for custom taxonomy archive pages, false for built-in taxonomies (category and tag archives).
       
  3561 	 */
       
  3562 	public function is_tax( $taxonomy = '', $term = '' ) {
       
  3563 		global $wp_taxonomies;
       
  3564 
       
  3565 		if ( !$this->is_tax )
       
  3566 			return false;
       
  3567 
       
  3568 		if ( empty( $taxonomy ) )
       
  3569 			return true;
       
  3570 
       
  3571 		$queried_object = $this->get_queried_object();
       
  3572 		$tax_array = array_intersect( array_keys( $wp_taxonomies ), (array) $taxonomy );
       
  3573 		$term_array = (array) $term;
       
  3574 
       
  3575 		// Check that the taxonomy matches.
       
  3576 		if ( ! ( isset( $queried_object->taxonomy ) && count( $tax_array ) && in_array( $queried_object->taxonomy, $tax_array ) ) )
       
  3577 			return false;
       
  3578 
       
  3579 		// Only a Taxonomy provided.
       
  3580 		if ( empty( $term ) )
       
  3581 			return true;
       
  3582 
       
  3583 		return isset( $queried_object->term_id ) &&
       
  3584 			count( array_intersect(
       
  3585 				array( $queried_object->term_id, $queried_object->name, $queried_object->slug ),
       
  3586 				$term_array
       
  3587 			) );
       
  3588 	}
       
  3589 
       
  3590 	/**
       
  3591 	 * Whether the current URL is within the comments popup window.
       
  3592 	 *
       
  3593 	 * @since 3.1.0
       
  3594 	 * @deprecated 4.5.0
       
  3595 	 *
       
  3596 	 * @return bool
       
  3597 	 */
       
  3598 	public function is_comments_popup() {
       
  3599 		_deprecated_function( __FUNCTION__, '4.5.0' );
       
  3600 
       
  3601 		return false;
       
  3602 	}
       
  3603 
       
  3604 	/**
       
  3605 	 * Is the query for an existing date archive?
       
  3606 	 *
       
  3607 	 * @since 3.1.0
       
  3608 	 *
       
  3609 	 * @return bool
       
  3610 	 */
       
  3611 	public function is_date() {
       
  3612 		return (bool) $this->is_date;
       
  3613 	}
       
  3614 
       
  3615 	/**
       
  3616 	 * Is the query for an existing day archive?
       
  3617 	 *
       
  3618 	 * @since 3.1.0
       
  3619 	 *
       
  3620 	 * @return bool
       
  3621 	 */
       
  3622 	public function is_day() {
       
  3623 		return (bool) $this->is_day;
       
  3624 	}
       
  3625 
       
  3626 	/**
       
  3627 	 * Is the query for a feed?
       
  3628 	 *
       
  3629 	 * @since 3.1.0
       
  3630 	 *
       
  3631 	 * @param string|array $feeds Optional feed types to check.
       
  3632 	 * @return bool
       
  3633 	 */
       
  3634 	public function is_feed( $feeds = '' ) {
       
  3635 		if ( empty( $feeds ) || ! $this->is_feed )
       
  3636 			return (bool) $this->is_feed;
       
  3637 		$qv = $this->get( 'feed' );
       
  3638 		if ( 'feed' == $qv )
       
  3639 			$qv = get_default_feed();
       
  3640 		return in_array( $qv, (array) $feeds );
       
  3641 	}
       
  3642 
       
  3643 	/**
       
  3644 	 * Is the query for a comments feed?
       
  3645 	 *
       
  3646 	 * @since 3.1.0
       
  3647 	 *
       
  3648 	 * @return bool
       
  3649 	 */
       
  3650 	public function is_comment_feed() {
       
  3651 		return (bool) $this->is_comment_feed;
       
  3652 	}
       
  3653 
       
  3654 	/**
       
  3655 	 * Is the query for the front page of the site?
       
  3656 	 *
       
  3657 	 * This is for what is displayed at your site's main URL.
       
  3658 	 *
       
  3659 	 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
       
  3660 	 *
       
  3661 	 * If you set a static page for the front page of your site, this function will return
       
  3662 	 * true when viewing that page.
       
  3663 	 *
       
  3664 	 * Otherwise the same as @see WP_Query::is_home()
       
  3665 	 *
       
  3666 	 * @since 3.1.0
       
  3667 	 *
       
  3668 	 * @return bool True, if front of site.
       
  3669 	 */
       
  3670 	public function is_front_page() {
       
  3671 		// most likely case
       
  3672 		if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
       
  3673 			return true;
       
  3674 		elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
       
  3675 			return true;
       
  3676 		else
       
  3677 			return false;
       
  3678 	}
       
  3679 
       
  3680 	/**
       
  3681 	 * Is the query for the blog homepage?
       
  3682 	 *
       
  3683 	 * This is the page which shows the time based blog content of your site.
       
  3684 	 *
       
  3685 	 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
       
  3686 	 *
       
  3687 	 * If you set a static page for the front page of your site, this function will return
       
  3688 	 * true only on the page you set as the "Posts page".
       
  3689 	 *
       
  3690 	 * @see WP_Query::is_front_page()
       
  3691 	 *
       
  3692 	 * @since 3.1.0
       
  3693 	 *
       
  3694 	 * @return bool True if blog view homepage.
       
  3695 	 */
       
  3696 	public function is_home() {
       
  3697 		return (bool) $this->is_home;
       
  3698 	}
       
  3699 
       
  3700 	/**
       
  3701 	 * Is the query for an existing month archive?
       
  3702 	 *
       
  3703 	 * @since 3.1.0
       
  3704 	 *
       
  3705 	 * @return bool
       
  3706 	 */
       
  3707 	public function is_month() {
       
  3708 		return (bool) $this->is_month;
       
  3709 	}
       
  3710 
       
  3711 	/**
       
  3712 	 * Is the query for an existing single page?
       
  3713 	 *
       
  3714 	 * If the $page parameter is specified, this function will additionally
       
  3715 	 * check if the query is for one of the pages specified.
       
  3716 	 *
       
  3717 	 * @see WP_Query::is_single()
       
  3718 	 * @see WP_Query::is_singular()
       
  3719 	 *
       
  3720 	 * @since 3.1.0
       
  3721 	 *
       
  3722 	 * @param int|string|array $page Optional. Page ID, title, slug, path, or array of such. Default empty.
       
  3723 	 * @return bool Whether the query is for an existing single page.
       
  3724 	 */
       
  3725 	public function is_page( $page = '' ) {
       
  3726 		if ( !$this->is_page )
       
  3727 			return false;
       
  3728 
       
  3729 		if ( empty( $page ) )
       
  3730 			return true;
       
  3731 
       
  3732 		$page_obj = $this->get_queried_object();
       
  3733 
       
  3734 		$page = array_map( 'strval', (array) $page );
       
  3735 
       
  3736 		if ( in_array( (string) $page_obj->ID, $page ) ) {
       
  3737 			return true;
       
  3738 		} elseif ( in_array( $page_obj->post_title, $page ) ) {
       
  3739 			return true;
       
  3740 		} elseif ( in_array( $page_obj->post_name, $page ) ) {
       
  3741 			return true;
       
  3742 		} else {
       
  3743 			foreach ( $page as $pagepath ) {
       
  3744 				if ( ! strpos( $pagepath, '/' ) ) {
       
  3745 					continue;
       
  3746 				}
       
  3747 				$pagepath_obj = get_page_by_path( $pagepath );
       
  3748 
       
  3749 				if ( $pagepath_obj && ( $pagepath_obj->ID == $page_obj->ID ) ) {
       
  3750 					return true;
       
  3751 				}
       
  3752 			}
       
  3753 		}
       
  3754 
       
  3755 		return false;
       
  3756 	}
       
  3757 
       
  3758 	/**
       
  3759 	 * Is the query for paged result and not for the first page?
       
  3760 	 *
       
  3761 	 * @since 3.1.0
       
  3762 	 *
       
  3763 	 * @return bool
       
  3764 	 */
       
  3765 	public function is_paged() {
       
  3766 		return (bool) $this->is_paged;
       
  3767 	}
       
  3768 
       
  3769 	/**
       
  3770 	 * Is the query for a post or page preview?
       
  3771 	 *
       
  3772 	 * @since 3.1.0
       
  3773 	 *
       
  3774 	 * @return bool
       
  3775 	 */
       
  3776 	public function is_preview() {
       
  3777 		return (bool) $this->is_preview;
       
  3778 	}
       
  3779 
       
  3780 	/**
       
  3781 	 * Is the query for the robots file?
       
  3782 	 *
       
  3783 	 * @since 3.1.0
       
  3784 	 *
       
  3785 	 * @return bool
       
  3786 	 */
       
  3787 	public function is_robots() {
       
  3788 		return (bool) $this->is_robots;
       
  3789 	}
       
  3790 
       
  3791 	/**
       
  3792 	 * Is the query for a search?
       
  3793 	 *
       
  3794 	 * @since 3.1.0
       
  3795 	 *
       
  3796 	 * @return bool
       
  3797 	 */
       
  3798 	public function is_search() {
       
  3799 		return (bool) $this->is_search;
       
  3800 	}
       
  3801 
       
  3802 	/**
       
  3803 	 * Is the query for an existing single post?
       
  3804 	 *
       
  3805 	 * Works for any post type excluding pages.
       
  3806 	 *
       
  3807 	 * If the $post parameter is specified, this function will additionally
       
  3808 	 * check if the query is for one of the Posts specified.
       
  3809 	 *
       
  3810 	 * @see WP_Query::is_page()
       
  3811 	 * @see WP_Query::is_singular()
       
  3812 	 *
       
  3813 	 * @since 3.1.0
       
  3814 	 *
       
  3815 	 * @param int|string|array $post Optional. Post ID, title, slug, path, or array of such. Default empty.
       
  3816 	 * @return bool Whether the query is for an existing single post.
       
  3817 	 */
       
  3818 	public function is_single( $post = '' ) {
       
  3819 		if ( !$this->is_single )
       
  3820 			return false;
       
  3821 
       
  3822 		if ( empty($post) )
       
  3823 			return true;
       
  3824 
       
  3825 		$post_obj = $this->get_queried_object();
       
  3826 
       
  3827 		$post = array_map( 'strval', (array) $post );
       
  3828 
       
  3829 		if ( in_array( (string) $post_obj->ID, $post ) ) {
       
  3830 			return true;
       
  3831 		} elseif ( in_array( $post_obj->post_title, $post ) ) {
       
  3832 			return true;
       
  3833 		} elseif ( in_array( $post_obj->post_name, $post ) ) {
       
  3834 			return true;
       
  3835 		} else {
       
  3836 			foreach ( $post as $postpath ) {
       
  3837 				if ( ! strpos( $postpath, '/' ) ) {
       
  3838 					continue;
       
  3839 				}
       
  3840 				$postpath_obj = get_page_by_path( $postpath, OBJECT, $post_obj->post_type );
       
  3841 
       
  3842 				if ( $postpath_obj && ( $postpath_obj->ID == $post_obj->ID ) ) {
       
  3843 					return true;
       
  3844 				}
       
  3845 			}
       
  3846 		}
       
  3847 		return false;
       
  3848 	}
       
  3849 
       
  3850 	/**
       
  3851 	 * Is the query for an existing single post of any post type (post, attachment, page,
       
  3852 	 * custom post types)?
       
  3853 	 *
       
  3854 	 * If the $post_types parameter is specified, this function will additionally
       
  3855 	 * check if the query is for one of the Posts Types specified.
       
  3856 	 *
       
  3857 	 * @see WP_Query::is_page()
       
  3858 	 * @see WP_Query::is_single()
       
  3859 	 *
       
  3860 	 * @since 3.1.0
       
  3861 	 *
       
  3862 	 * @param string|array $post_types Optional. Post type or array of post types. Default empty.
       
  3863 	 * @return bool Whether the query is for an existing single post of any of the given post types.
       
  3864 	 */
       
  3865 	public function is_singular( $post_types = '' ) {
       
  3866 		if ( empty( $post_types ) || !$this->is_singular )
       
  3867 			return (bool) $this->is_singular;
       
  3868 
       
  3869 		$post_obj = $this->get_queried_object();
       
  3870 
       
  3871 		return in_array( $post_obj->post_type, (array) $post_types );
       
  3872 	}
       
  3873 
       
  3874 	/**
       
  3875 	 * Is the query for a specific time?
       
  3876 	 *
       
  3877 	 * @since 3.1.0
       
  3878 	 *
       
  3879 	 * @return bool
       
  3880 	 */
       
  3881 	public function is_time() {
       
  3882 		return (bool) $this->is_time;
       
  3883 	}
       
  3884 
       
  3885 	/**
       
  3886 	 * Is the query for a trackback endpoint call?
       
  3887 	 *
       
  3888 	 * @since 3.1.0
       
  3889 	 *
       
  3890 	 * @return bool
       
  3891 	 */
       
  3892 	public function is_trackback() {
       
  3893 		return (bool) $this->is_trackback;
       
  3894 	}
       
  3895 
       
  3896 	/**
       
  3897 	 * Is the query for an existing year archive?
       
  3898 	 *
       
  3899 	 * @since 3.1.0
       
  3900 	 *
       
  3901 	 * @return bool
       
  3902 	 */
       
  3903 	public function is_year() {
       
  3904 		return (bool) $this->is_year;
       
  3905 	}
       
  3906 
       
  3907 	/**
       
  3908 	 * Is the query a 404 (returns no results)?
       
  3909 	 *
       
  3910 	 * @since 3.1.0
       
  3911 	 *
       
  3912 	 * @return bool
       
  3913 	 */
       
  3914 	public function is_404() {
       
  3915 		return (bool) $this->is_404;
       
  3916 	}
       
  3917 
       
  3918 	/**
       
  3919 	 * Is the query for an embedded post?
       
  3920 	 *
       
  3921 	 * @since 4.4.0
       
  3922 	 *
       
  3923 	 * @return bool
       
  3924 	 */
       
  3925 	public function is_embed() {
       
  3926 		return (bool) $this->is_embed;
       
  3927 	}
       
  3928 
       
  3929 	/**
       
  3930 	 * Is the query the main query?
       
  3931 	 *
       
  3932 	 * @since 3.3.0
       
  3933 	 *
       
  3934 	 * @global WP_Query $wp_query Global WP_Query instance.
       
  3935 	 *
       
  3936 	 * @return bool
       
  3937 	 */
       
  3938 	public function is_main_query() {
       
  3939 		global $wp_the_query;
       
  3940 		return $wp_the_query === $this;
       
  3941 	}
       
  3942 
       
  3943 	/**
       
  3944 	 * Set up global post data.
       
  3945 	 *
       
  3946 	 * @since 4.1.0
       
  3947 	 * @since 4.4.0 Added the ability to pass a post ID to `$post`.
       
  3948 	 *
       
  3949 	 * @global int             $id
       
  3950 	 * @global WP_User         $authordata
       
  3951 	 * @global string|int|bool $currentday
       
  3952 	 * @global string|int|bool $currentmonth
       
  3953 	 * @global int             $page
       
  3954 	 * @global array           $pages
       
  3955 	 * @global int             $multipage
       
  3956 	 * @global int             $more
       
  3957 	 * @global int             $numpages
       
  3958 	 *
       
  3959 	 * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
       
  3960 	 * @return true True when finished.
       
  3961 	 */
       
  3962 	public function setup_postdata( $post ) {
       
  3963 		global $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages;
       
  3964 
       
  3965 		if ( ! ( $post instanceof WP_Post ) ) {
       
  3966 			$post = get_post( $post );
       
  3967 		}
       
  3968 
       
  3969 		if ( ! $post ) {
       
  3970 			return;
       
  3971 		}
       
  3972 
       
  3973 		$id = (int) $post->ID;
       
  3974 
       
  3975 		$authordata = get_userdata($post->post_author);
       
  3976 
       
  3977 		$currentday = mysql2date('d.m.y', $post->post_date, false);
       
  3978 		$currentmonth = mysql2date('m', $post->post_date, false);
       
  3979 		$numpages = 1;
       
  3980 		$multipage = 0;
       
  3981 		$page = $this->get( 'page' );
       
  3982 		if ( ! $page )
       
  3983 			$page = 1;
       
  3984 
       
  3985 		/*
       
  3986 		 * Force full post content when viewing the permalink for the $post,
       
  3987 		 * or when on an RSS feed. Otherwise respect the 'more' tag.
       
  3988 		 */
       
  3989 		if ( $post->ID === get_queried_object_id() && ( $this->is_page() || $this->is_single() ) ) {
       
  3990 			$more = 1;
       
  3991 		} elseif ( $this->is_feed() ) {
       
  3992 			$more = 1;
       
  3993 		} else {
       
  3994 			$more = 0;
       
  3995 		}
       
  3996 
       
  3997 		$content = $post->post_content;
       
  3998 		if ( false !== strpos( $content, '<!--nextpage-->' ) ) {
       
  3999 			$content = str_replace( "\n<!--nextpage-->\n", '<!--nextpage-->', $content );
       
  4000 			$content = str_replace( "\n<!--nextpage-->", '<!--nextpage-->', $content );
       
  4001 			$content = str_replace( "<!--nextpage-->\n", '<!--nextpage-->', $content );
       
  4002 
       
  4003 			// Ignore nextpage at the beginning of the content.
       
  4004 			if ( 0 === strpos( $content, '<!--nextpage-->' ) )
       
  4005 				$content = substr( $content, 15 );
       
  4006 
       
  4007 			$pages = explode('<!--nextpage-->', $content);
       
  4008 		} else {
       
  4009 			$pages = array( $post->post_content );
       
  4010 		}
       
  4011 
       
  4012 		/**
       
  4013 		 * Filters the "pages" derived from splitting the post content.
       
  4014 		 *
       
  4015 		 * "Pages" are determined by splitting the post content based on the presence
       
  4016 		 * of `<!-- nextpage -->` tags.
       
  4017 		 *
       
  4018 		 * @since 4.4.0
       
  4019 		 *
       
  4020 		 * @param array   $pages Array of "pages" derived from the post content.
       
  4021 		 *                       of `<!-- nextpage -->` tags..
       
  4022 		 * @param WP_Post $post  Current post object.
       
  4023 		 */
       
  4024 		$pages = apply_filters( 'content_pagination', $pages, $post );
       
  4025 
       
  4026 		$numpages = count( $pages );
       
  4027 
       
  4028 		if ( $numpages > 1 ) {
       
  4029 			if ( $page > 1 ) {
       
  4030 				$more = 1;
       
  4031 			}
       
  4032 			$multipage = 1;
       
  4033 		} else {
       
  4034 	 		$multipage = 0;
       
  4035 	 	}
       
  4036 
       
  4037 		/**
       
  4038 		 * Fires once the post data has been setup.
       
  4039 		 *
       
  4040 		 * @since 2.8.0
       
  4041 		 * @since 4.1.0 Introduced `$this` parameter.
       
  4042 		 *
       
  4043 		 * @param WP_Post  $post The Post object (passed by reference).
       
  4044 		 * @param WP_Query $this The current Query object (passed by reference).
       
  4045 		 */
       
  4046 		do_action_ref_array( 'the_post', array( &$post, &$this ) );
       
  4047 
       
  4048 		return true;
       
  4049 	}
       
  4050 	/**
       
  4051 	 * After looping through a nested query, this function
       
  4052 	 * restores the $post global to the current post in this query.
       
  4053 	 *
       
  4054 	 * @since 3.7.0
       
  4055 	 *
       
  4056 	 * @global WP_Post $post
       
  4057 	 */
       
  4058 	public function reset_postdata() {
       
  4059 		if ( ! empty( $this->post ) ) {
       
  4060 			$GLOBALS['post'] = $this->post;
       
  4061 			$this->setup_postdata( $this->post );
       
  4062 		}
       
  4063 	}
       
  4064 
       
  4065 	/**
       
  4066 	 * Lazyload term meta for posts in the loop.
       
  4067 	 *
       
  4068 	 * @since 4.4.0
       
  4069 	 * @deprecated 4.5.0 See wp_queue_posts_for_term_meta_lazyload().
       
  4070 	 *
       
  4071 	 * @param mixed $check
       
  4072 	 * @param int   $term_id
       
  4073 	 * @return mixed
       
  4074 	 */
       
  4075 	public function lazyload_term_meta( $check, $term_id ) {
       
  4076 		_deprecated_function( __METHOD__, '4.5.0' );
       
  4077 		return $check;
       
  4078 	}
       
  4079 
       
  4080 	/**
       
  4081 	 * Lazyload comment meta for comments in the loop.
       
  4082 	 *
       
  4083 	 * @since 4.4.0
       
  4084 	 * @deprecated 4.5.0 See wp_queue_comments_for_comment_meta_lazyload().
       
  4085 	 *
       
  4086 	 * @param mixed $check
       
  4087 	 * @param int   $comment_id
       
  4088 	 * @return mixed
       
  4089 	 */
       
  4090 	public function lazyload_comment_meta( $check, $comment_id ) {
       
  4091 		_deprecated_function( __METHOD__, '4.5.0' );
       
  4092 		return $check;
       
  4093 	}
       
  4094 }