Make WordPress Core

Changeset 38351 for trunk


Ignore:
Timestamp:
08/25/2016 05:19:47 PM (8 years ago)
Author:
wonderboymusic
Message:

Query: move WP_Query into its own file via svn cp.

See #37827.

Location:
trunk/src
Files:
2 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-query.php

    r38350 r38351  
    11<?php
    22/**
    3  * WordPress Query API
    4  *
    5  * The query API attempts to get which part of WordPress the user is on. It
    6  * also provides functionality for getting URL query information.
    7  *
    8  * @link https://codex.wordpress.org/The_Loop More information on The Loop.
     3 * Query API: WP_Query class
    94 *
    105 * @package WordPress
    116 * @subpackage Query
    12  */
    13 
    14 /**
    15  * Retrieve variable in the WP_Query class.
    16  *
    17  * @since 1.5.0
    18  * @since 3.9.0 The `$default` argument was introduced.
    19  *
    20  * @global WP_Query $wp_query Global WP_Query instance.
    21  *
    22  * @param string $var       The variable key to retrieve.
    23  * @param mixed  $default   Optional. Value to return if the query variable is not set. Default empty.
    24  * @return mixed Contents of the query variable.
    25  */
    26 function get_query_var( $var, $default = '' ) {
    27     global $wp_query;
    28     return $wp_query->get( $var, $default );
    29 }
    30 
    31 /**
    32  * Retrieve the currently-queried object.
    33  *
    34  * Wrapper for WP_Query::get_queried_object().
    35  *
    36  * @since 3.1.0
    37  * @access public
    38  *
    39  * @global WP_Query $wp_query Global WP_Query instance.
    40  *
    41  * @return object Queried object.
    42  */
    43 function get_queried_object() {
    44     global $wp_query;
    45     return $wp_query->get_queried_object();
    46 }
    47 
    48 /**
    49  * Retrieve ID of the current queried object.
    50  *
    51  * Wrapper for WP_Query::get_queried_object_id().
    52  *
    53  * @since 3.1.0
    54  *
    55  * @global WP_Query $wp_query Global WP_Query instance.
    56  *
    57  * @return int ID of the queried object.
    58  */
    59 function get_queried_object_id() {
    60     global $wp_query;
    61     return $wp_query->get_queried_object_id();
    62 }
    63 
    64 /**
    65  * Set query variable.
    66  *
    67  * @since 2.2.0
    68  *
    69  * @global WP_Query $wp_query Global WP_Query instance.
    70  *
    71  * @param string $var   Query variable key.
    72  * @param mixed  $value Query variable value.
    73  */
    74 function set_query_var( $var, $value ) {
    75     global $wp_query;
    76     $wp_query->set( $var, $value );
    77 }
    78 
    79 /**
    80  * Sets up The Loop with query parameters.
    81  *
    82  * Note: This function will completely override the main query and isn't intended for use
    83  * by plugins or themes. Its overly-simplistic approach to modifying the main query can be
    84  * problematic and should be avoided wherever possible. In most cases, there are better,
    85  * more performant options for modifying the main query such as via the {@see 'pre_get_posts'}
    86  * action within WP_Query.
    87  *
    88  * This must not be used within the WordPress Loop.
    89  *
    90  * @since 1.5.0
    91  *
    92  * @global WP_Query $wp_query Global WP_Query instance.
    93  *
    94  * @param array|string $query Array or string of WP_Query arguments.
    95  * @return array List of post objects.
    96  */
    97 function query_posts($query) {
    98     $GLOBALS['wp_query'] = new WP_Query();
    99     return $GLOBALS['wp_query']->query($query);
    100 }
    101 
    102 /**
    103  * Destroys the previous query and sets up a new query.
    104  *
    105  * This should be used after query_posts() and before another query_posts().
    106  * This will remove obscure bugs that occur when the previous WP_Query object
    107  * is not destroyed properly before another is set up.
    108  *
    109  * @since 2.3.0
    110  *
    111  * @global WP_Query $wp_query     Global WP_Query instance.
    112  * @global WP_Query $wp_the_query Copy of the global WP_Query instance created during wp_reset_query().
    113  */
    114 function wp_reset_query() {
    115     $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
    116     wp_reset_postdata();
    117 }
    118 
    119 /**
    120  * After looping through a separate query, this function restores
    121  * the $post global to the current post in the main query.
    122  *
    123  * @since 3.0.0
    124  *
    125  * @global WP_Query $wp_query Global WP_Query instance.
    126  */
    127 function wp_reset_postdata() {
    128     global $wp_query;
    129 
    130     if ( isset( $wp_query ) ) {
    131         $wp_query->reset_postdata();
    132     }
    133 }
    134 
    135 /*
    136  * Query type checks.
    137  */
    138 
    139 /**
    140  * Is the query for an existing archive page?
    141  *
    142  * Month, Year, Category, Author, Post Type archive...
    143  *
    144  * @since 1.5.0
    145  *
    146  * @global WP_Query $wp_query Global WP_Query instance.
    147  *
    148  * @return bool
    149  */
    150 function is_archive() {
    151     global $wp_query;
    152 
    153     if ( ! isset( $wp_query ) ) {
    154         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    155         return false;
    156     }
    157 
    158     return $wp_query->is_archive();
    159 }
    160 
    161 /**
    162  * Is the query for an existing post type archive page?
    163  *
    164  * @since 3.1.0
    165  *
    166  * @global WP_Query $wp_query Global WP_Query instance.
    167  *
    168  * @param string|array $post_types Optional. Post type or array of posts types to check against.
    169  * @return bool
    170  */
    171 function is_post_type_archive( $post_types = '' ) {
    172     global $wp_query;
    173 
    174     if ( ! isset( $wp_query ) ) {
    175         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    176         return false;
    177     }
    178 
    179     return $wp_query->is_post_type_archive( $post_types );
    180 }
    181 
    182 /**
    183  * Is the query for an existing attachment page?
    184  *
    185  * @since 2.0.0
    186  *
    187  * @global WP_Query $wp_query Global WP_Query instance.
    188  *
    189  * @param int|string|array|object $attachment Attachment ID, title, slug, or array of such.
    190  * @return bool
    191  */
    192 function is_attachment( $attachment = '' ) {
    193     global $wp_query;
    194 
    195     if ( ! isset( $wp_query ) ) {
    196         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    197         return false;
    198     }
    199 
    200     return $wp_query->is_attachment( $attachment );
    201 }
    202 
    203 /**
    204  * Is the query for an existing author archive page?
    205  *
    206  * If the $author parameter is specified, this function will additionally
    207  * check if the query is for one of the authors specified.
    208  *
    209  * @since 1.5.0
    210  *
    211  * @global WP_Query $wp_query Global WP_Query instance.
    212  *
    213  * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
    214  * @return bool
    215  */
    216 function is_author( $author = '' ) {
    217     global $wp_query;
    218 
    219     if ( ! isset( $wp_query ) ) {
    220         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    221         return false;
    222     }
    223 
    224     return $wp_query->is_author( $author );
    225 }
    226 
    227 /**
    228  * Is the query for an existing category archive page?
    229  *
    230  * If the $category parameter is specified, this function will additionally
    231  * check if the query is for one of the categories specified.
    232  *
    233  * @since 1.5.0
    234  *
    235  * @global WP_Query $wp_query Global WP_Query instance.
    236  *
    237  * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
    238  * @return bool
    239  */
    240 function is_category( $category = '' ) {
    241     global $wp_query;
    242 
    243     if ( ! isset( $wp_query ) ) {
    244         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    245         return false;
    246     }
    247 
    248     return $wp_query->is_category( $category );
    249 }
    250 
    251 /**
    252  * Is the query for an existing tag archive page?
    253  *
    254  * If the $tag parameter is specified, this function will additionally
    255  * check if the query is for one of the tags specified.
    256  *
    257  * @since 2.3.0
    258  *
    259  * @global WP_Query $wp_query Global WP_Query instance.
    260  *
    261  * @param mixed $tag Optional. Tag ID, name, slug, or array of Tag IDs, names, and slugs.
    262  * @return bool
    263  */
    264 function is_tag( $tag = '' ) {
    265     global $wp_query;
    266 
    267     if ( ! isset( $wp_query ) ) {
    268         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    269         return false;
    270     }
    271 
    272     return $wp_query->is_tag( $tag );
    273 }
    274 
    275 /**
    276  * Is the query for an existing custom taxonomy archive page?
    277  *
    278  * If the $taxonomy parameter is specified, this function will additionally
    279  * check if the query is for that specific $taxonomy.
    280  *
    281  * If the $term parameter is specified in addition to the $taxonomy parameter,
    282  * this function will additionally check if the query is for one of the terms
    283  * specified.
    284  *
    285  * @since 2.5.0
    286  *
    287  * @global WP_Query $wp_query Global WP_Query instance.
    288  *
    289  * @param string|array     $taxonomy Optional. Taxonomy slug or slugs.
    290  * @param int|string|array $term     Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
    291  * @return bool True for custom taxonomy archive pages, false for built-in taxonomies (category and tag archives).
    292  */
    293 function is_tax( $taxonomy = '', $term = '' ) {
    294     global $wp_query;
    295 
    296     if ( ! isset( $wp_query ) ) {
    297         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    298         return false;
    299     }
    300 
    301     return $wp_query->is_tax( $taxonomy, $term );
    302 }
    303 
    304 /**
    305  * Is the query for an existing date archive?
    306  *
    307  * @since 1.5.0
    308  *
    309  * @global WP_Query $wp_query Global WP_Query instance.
    310  *
    311  * @return bool
    312  */
    313 function is_date() {
    314     global $wp_query;
    315 
    316     if ( ! isset( $wp_query ) ) {
    317         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    318         return false;
    319     }
    320 
    321     return $wp_query->is_date();
    322 }
    323 
    324 /**
    325  * Is the query for an existing day archive?
    326  *
    327  * @since 1.5.0
    328  *
    329  * @global WP_Query $wp_query Global WP_Query instance.
    330  *
    331  * @return bool
    332  */
    333 function is_day() {
    334     global $wp_query;
    335 
    336     if ( ! isset( $wp_query ) ) {
    337         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    338         return false;
    339     }
    340 
    341     return $wp_query->is_day();
    342 }
    343 
    344 /**
    345  * Is the query for a feed?
    346  *
    347  * @since 1.5.0
    348  *
    349  * @global WP_Query $wp_query Global WP_Query instance.
    350  *
    351  * @param string|array $feeds Optional feed types to check.
    352  * @return bool
    353  */
    354 function is_feed( $feeds = '' ) {
    355     global $wp_query;
    356 
    357     if ( ! isset( $wp_query ) ) {
    358         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    359         return false;
    360     }
    361 
    362     return $wp_query->is_feed( $feeds );
    363 }
    364 
    365 /**
    366  * Is the query for a comments feed?
    367  *
    368  * @since 3.0.0
    369  *
    370  * @global WP_Query $wp_query Global WP_Query instance.
    371  *
    372  * @return bool
    373  */
    374 function is_comment_feed() {
    375     global $wp_query;
    376 
    377     if ( ! isset( $wp_query ) ) {
    378         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    379         return false;
    380     }
    381 
    382     return $wp_query->is_comment_feed();
    383 }
    384 
    385 /**
    386  * Is the query for the front page of the site?
    387  *
    388  * This is for what is displayed at your site's main URL.
    389  *
    390  * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
    391  *
    392  * If you set a static page for the front page of your site, this function will return
    393  * true when viewing that page.
    394  *
    395  * Otherwise the same as @see is_home()
    396  *
    397  * @since 2.5.0
    398  *
    399  * @global WP_Query $wp_query Global WP_Query instance.
    400  *
    401  * @return bool True, if front of site.
    402  */
    403 function is_front_page() {
    404     global $wp_query;
    405 
    406     if ( ! isset( $wp_query ) ) {
    407         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    408         return false;
    409     }
    410 
    411     return $wp_query->is_front_page();
    412 }
    413 
    414 /**
    415  * Determines if the query is for the blog homepage.
    416  *
    417  * The blog homepage is the page that shows the time-based blog content of the site.
    418  *
    419  * is_home() is dependent on the site's "Front page displays" Reading Settings 'show_on_front'
    420  * and 'page_for_posts'.
    421  *
    422  * If a static page is set for the front page of the site, this function will return true only
    423  * on the page you set as the "Posts page".
    424  *
    425  * @since 1.5.0
    426  *
    427  * @see is_front_page()
    428  * @global WP_Query $wp_query Global WP_Query instance.
    429  *
    430  * @return bool True if blog view homepage, otherwise false.
    431  */
    432 function is_home() {
    433     global $wp_query;
    434 
    435     if ( ! isset( $wp_query ) ) {
    436         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    437         return false;
    438     }
    439 
    440     return $wp_query->is_home();
    441 }
    442 
    443 /**
    444  * Is the query for an existing month archive?
    445  *
    446  * @since 1.5.0
    447  *
    448  * @global WP_Query $wp_query Global WP_Query instance.
    449  *
    450  * @return bool
    451  */
    452 function is_month() {
    453     global $wp_query;
    454 
    455     if ( ! isset( $wp_query ) ) {
    456         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    457         return false;
    458     }
    459 
    460     return $wp_query->is_month();
    461 }
    462 
    463 /**
    464  * Is the query for an existing single page?
    465  *
    466  * If the $page parameter is specified, this function will additionally
    467  * check if the query is for one of the pages specified.
    468  *
    469  * @see is_single()
    470  * @see is_singular()
    471  *
    472  * @since 1.5.0
    473  *
    474  * @global WP_Query $wp_query Global WP_Query instance.
    475  *
    476  * @param int|string|array $page Optional. Page ID, title, slug, or array of such. Default empty.
    477  * @return bool Whether the query is for an existing single page.
    478  */
    479 function is_page( $page = '' ) {
    480     global $wp_query;
    481 
    482     if ( ! isset( $wp_query ) ) {
    483         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    484         return false;
    485     }
    486 
    487     return $wp_query->is_page( $page );
    488 }
    489 
    490 /**
    491  * Is the query for paged result and not for the first page?
    492  *
    493  * @since 1.5.0
    494  *
    495  * @global WP_Query $wp_query Global WP_Query instance.
    496  *
    497  * @return bool
    498  */
    499 function is_paged() {
    500     global $wp_query;
    501 
    502     if ( ! isset( $wp_query ) ) {
    503         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    504         return false;
    505     }
    506 
    507     return $wp_query->is_paged();
    508 }
    509 
    510 /**
    511  * Is the query for a post or page preview?
    512  *
    513  * @since 2.0.0
    514  *
    515  * @global WP_Query $wp_query Global WP_Query instance.
    516  *
    517  * @return bool
    518  */
    519 function is_preview() {
    520     global $wp_query;
    521 
    522     if ( ! isset( $wp_query ) ) {
    523         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    524         return false;
    525     }
    526 
    527     return $wp_query->is_preview();
    528 }
    529 
    530 /**
    531  * Is the query for the robots file?
    532  *
    533  * @since 2.1.0
    534  *
    535  * @global WP_Query $wp_query Global WP_Query instance.
    536  *
    537  * @return bool
    538  */
    539 function is_robots() {
    540     global $wp_query;
    541 
    542     if ( ! isset( $wp_query ) ) {
    543         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    544         return false;
    545     }
    546 
    547     return $wp_query->is_robots();
    548 }
    549 
    550 /**
    551  * Is the query for a search?
    552  *
    553  * @since 1.5.0
    554  *
    555  * @global WP_Query $wp_query Global WP_Query instance.
    556  *
    557  * @return bool
    558  */
    559 function is_search() {
    560     global $wp_query;
    561 
    562     if ( ! isset( $wp_query ) ) {
    563         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    564         return false;
    565     }
    566 
    567     return $wp_query->is_search();
    568 }
    569 
    570 /**
    571  * Is the query for an existing single post?
    572  *
    573  * Works for any post type, except attachments and pages
    574  *
    575  * If the $post parameter is specified, this function will additionally
    576  * check if the query is for one of the Posts specified.
    577  *
    578  * @see is_page()
    579  * @see is_singular()
    580  *
    581  * @since 1.5.0
    582  *
    583  * @global WP_Query $wp_query Global WP_Query instance.
    584  *
    585  * @param int|string|array $post Optional. Post ID, title, slug, or array of such. Default empty.
    586  * @return bool Whether the query is for an existing single post.
    587  */
    588 function is_single( $post = '' ) {
    589     global $wp_query;
    590 
    591     if ( ! isset( $wp_query ) ) {
    592         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    593         return false;
    594     }
    595 
    596     return $wp_query->is_single( $post );
    597 }
    598 
    599 /**
    600  * Is the query for an existing single post of any post type (post, attachment, page, ... )?
    601  *
    602  * If the $post_types parameter is specified, this function will additionally
    603  * check if the query is for one of the Posts Types specified.
    604  *
    605  * @see is_page()
    606  * @see is_single()
    607  *
    608  * @since 1.5.0
    609  *
    610  * @global WP_Query $wp_query Global WP_Query instance.
    611  *
    612  * @param string|array $post_types Optional. Post type or array of post types. Default empty.
    613  * @return bool Whether the query is for an existing single post of any of the given post types.
    614  */
    615 function is_singular( $post_types = '' ) {
    616     global $wp_query;
    617 
    618     if ( ! isset( $wp_query ) ) {
    619         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    620         return false;
    621     }
    622 
    623     return $wp_query->is_singular( $post_types );
    624 }
    625 
    626 /**
    627  * Is the query for a specific time?
    628  *
    629  * @since 1.5.0
    630  *
    631  * @global WP_Query $wp_query Global WP_Query instance.
    632  *
    633  * @return bool
    634  */
    635 function is_time() {
    636     global $wp_query;
    637 
    638     if ( ! isset( $wp_query ) ) {
    639         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    640         return false;
    641     }
    642 
    643     return $wp_query->is_time();
    644 }
    645 
    646 /**
    647  * Is the query for a trackback endpoint call?
    648  *
    649  * @since 1.5.0
    650  *
    651  * @global WP_Query $wp_query Global WP_Query instance.
    652  *
    653  * @return bool
    654  */
    655 function is_trackback() {
    656     global $wp_query;
    657 
    658     if ( ! isset( $wp_query ) ) {
    659         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    660         return false;
    661     }
    662 
    663     return $wp_query->is_trackback();
    664 }
    665 
    666 /**
    667  * Is the query for an existing year archive?
    668  *
    669  * @since 1.5.0
    670  *
    671  * @global WP_Query $wp_query Global WP_Query instance.
    672  *
    673  * @return bool
    674  */
    675 function is_year() {
    676     global $wp_query;
    677 
    678     if ( ! isset( $wp_query ) ) {
    679         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    680         return false;
    681     }
    682 
    683     return $wp_query->is_year();
    684 }
    685 
    686 /**
    687  * Is the query a 404 (returns no results)?
    688  *
    689  * @since 1.5.0
    690  *
    691  * @global WP_Query $wp_query Global WP_Query instance.
    692  *
    693  * @return bool
    694  */
    695 function is_404() {
    696     global $wp_query;
    697 
    698     if ( ! isset( $wp_query ) ) {
    699         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    700         return false;
    701     }
    702 
    703     return $wp_query->is_404();
    704 }
    705 
    706 /**
    707  * Is the query for an embedded post?
    708  *
    709  * @since 4.4.0
    710  *
    711  * @global WP_Query $wp_query Global WP_Query instance.
    712  *
    713  * @return bool Whether we're in an embedded post or not.
    714  */
    715 function is_embed() {
    716     global $wp_query;
    717 
    718     if ( ! isset( $wp_query ) ) {
    719         _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );
    720         return false;
    721     }
    722 
    723     return $wp_query->is_embed();
    724 }
    725 
    726 /**
    727  * Is the query the main query?
    728  *
    729  * @since 3.3.0
    730  *
    731  * @global WP_Query $wp_query Global WP_Query instance.
    732  *
    733  * @return bool
    734  */
    735 function is_main_query() {
    736     if ( 'pre_get_posts' === current_filter() ) {
    737         $message = sprintf(
    738             /* translators: 1: pre_get_posts 2: WP_Query->is_main_query() 3: is_main_query() 4: link to codex is_main_query() page. */
    739             __( 'In %1$s, use the %2$s method, not the %3$s function. See %4$s.' ),
    740             '<code>pre_get_posts</code>',
    741             '<code>WP_Query->is_main_query()</code>',
    742             '<code>is_main_query()</code>',
    743             __( 'https://codex.wordpress.org/Function_Reference/is_main_query' )
    744         );
    745         _doing_it_wrong( __FUNCTION__, $message, '3.7.0' );
    746     }
    747 
    748     global $wp_query;
    749     return $wp_query->is_main_query();
    750 }
    751 
    752 /*
    753  * The Loop. Post loop control.
    754  */
    755 
    756 /**
    757  * Whether current WordPress query has results to loop over.
    758  *
    759  * @since 1.5.0
    760  *
    761  * @global WP_Query $wp_query Global WP_Query instance.
    762  *
    763  * @return bool
    764  */
    765 function have_posts() {
    766     global $wp_query;
    767     return $wp_query->have_posts();
    768 }
    769 
    770 /**
    771  * Whether the caller is in the Loop.
    772  *
    773  * @since 2.0.0
    774  *
    775  * @global WP_Query $wp_query Global WP_Query instance.
    776  *
    777  * @return bool True if caller is within loop, false if loop hasn't started or ended.
    778  */
    779 function in_the_loop() {
    780     global $wp_query;
    781     return $wp_query->in_the_loop;
    782 }
    783 
    784 /**
    785  * Rewind the loop posts.
    786  *
    787  * @since 1.5.0
    788  *
    789  * @global WP_Query $wp_query Global WP_Query instance.
    790  */
    791 function rewind_posts() {
    792     global $wp_query;
    793     $wp_query->rewind_posts();
    794 }
    795 
    796 /**
    797  * Iterate the post index in the loop.
    798  *
    799  * @since 1.5.0
    800  *
    801  * @global WP_Query $wp_query Global WP_Query instance.
    802  */
    803 function the_post() {
    804     global $wp_query;
    805     $wp_query->the_post();
    806 }
    807 
    808 /*
    809  * Comments loop.
    810  */
    811 
    812 /**
    813  * Whether there are comments to loop over.
    814  *
    815  * @since 2.2.0
    816  *
    817  * @global WP_Query $wp_query Global WP_Query instance.
    818  *
    819  * @return bool
    820  */
    821 function have_comments() {
    822     global $wp_query;
    823     return $wp_query->have_comments();
    824 }
    825 
    826 /**
    827  * Iterate comment index in the comment loop.
    828  *
    829  * @since 2.2.0
    830  *
    831  * @global WP_Query $wp_query Global WP_Query instance.
    832  *
    833  * @return object
    834  */
    835 function the_comment() {
    836     global $wp_query;
    837     return $wp_query->the_comment();
    838 }
    839 
    840 /*
    841  * WP_Query
     7 * @since 4.7.0
    8428 */
    8439
     
    49294095    }
    49304096}
    4931 
    4932 /**
    4933  * Redirect old slugs to the correct permalink.
    4934  *
    4935  * Attempts to find the current slug from the past slugs.
    4936  *
    4937  * @since 2.1.0
    4938  *
    4939  * @global WP_Query   $wp_query   Global WP_Query instance.
    4940  * @global wpdb       $wpdb       WordPress database abstraction object.
    4941  */
    4942 function wp_old_slug_redirect() {
    4943     global $wp_query;
    4944 
    4945     if ( is_404() && '' !== $wp_query->query_vars['name'] ) :
    4946         global $wpdb;
    4947 
    4948         // Guess the current post_type based on the query vars.
    4949         if ( get_query_var( 'post_type' ) ) {
    4950             $post_type = get_query_var( 'post_type' );
    4951         } elseif ( get_query_var( 'attachment' ) ) {
    4952             $post_type = 'attachment';
    4953         } elseif ( ! empty( $wp_query->query_vars['pagename'] ) ) {
    4954             $post_type = 'page';
    4955         } else {
    4956             $post_type = 'post';
    4957         }
    4958 
    4959         if ( is_array( $post_type ) ) {
    4960             if ( count( $post_type ) > 1 )
    4961                 return;
    4962             $post_type = reset( $post_type );
    4963         }
    4964 
    4965         // Do not attempt redirect for hierarchical post types
    4966         if ( is_post_type_hierarchical( $post_type ) )
    4967             return;
    4968 
    4969         $query = $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_slug' AND meta_value = %s", $post_type, $wp_query->query_vars['name']);
    4970 
    4971         // if year, monthnum, or day have been specified, make our query more precise
    4972         // just in case there are multiple identical _wp_old_slug values
    4973         if ( '' != $wp_query->query_vars['year'] )
    4974             $query .= $wpdb->prepare(" AND YEAR(post_date) = %d", $wp_query->query_vars['year']);
    4975         if ( '' != $wp_query->query_vars['monthnum'] )
    4976             $query .= $wpdb->prepare(" AND MONTH(post_date) = %d", $wp_query->query_vars['monthnum']);
    4977         if ( '' != $wp_query->query_vars['day'] )
    4978             $query .= $wpdb->prepare(" AND DAYOFMONTH(post_date) = %d", $wp_query->query_vars['day']);
    4979 
    4980         $id = (int) $wpdb->get_var($query);
    4981 
    4982         if ( ! $id )
    4983             return;
    4984 
    4985         $link = get_permalink( $id );
    4986 
    4987         if ( isset( $GLOBALS['wp_query']->query_vars['paged'] ) && $GLOBALS['wp_query']->query_vars['paged'] > 1 ) {
    4988             $link = user_trailingslashit( trailingslashit( $link ) . 'page/' . $GLOBALS['wp_query']->query_vars['paged'] );
    4989         } elseif( is_embed() ) {
    4990             $link = user_trailingslashit( trailingslashit( $link ) . 'embed' );
    4991         }
    4992 
    4993         /**
    4994          * Filters the old slug redirect URL.
    4995          *
    4996          * @since 4.4.0
    4997          *
    4998          * @param string $link The redirect URL.
    4999          */
    5000         $link = apply_filters( 'old_slug_redirect_url', $link );
    5001 
    5002         if ( ! $link ) {
    5003             return;
    5004         }
    5005 
    5006         wp_redirect( $link, 301 ); // Permanent redirect
    5007         exit;
    5008     endif;
    5009 }
    5010 
    5011 /**
    5012  * Set up global post data.
    5013  *
    5014  * @since 1.5.0
    5015  * @since 4.4.0 Added the ability to pass a post ID to `$post`.
    5016  *
    5017  * @global WP_Query $wp_query Global WP_Query instance.
    5018  *
    5019  * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
    5020  * @return bool True when finished.
    5021  */
    5022 function setup_postdata( $post ) {
    5023     global $wp_query;
    5024 
    5025     if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) {
    5026         return $wp_query->setup_postdata( $post );
    5027     }
    5028 
    5029     return false;
    5030 }
  • trunk/src/wp-includes/query.php

    r38288 r38351  
    838838}
    839839
    840 /*
    841  * WP_Query
    842  */
    843 
    844 /**
    845  * The WordPress Query class.
    846  *
    847  * @link https://codex.wordpress.org/Function_Reference/WP_Query Codex page.
    848  *
    849  * @since 1.5.0
    850  * @since 4.5.0 Removed the `$comments_popup` property.
    851  */
    852 class WP_Query {
    853 
    854     /**
    855      * Query vars set by the user
    856      *
    857      * @since 1.5.0
    858      * @access public
    859      * @var array
    860      */
    861     public $query;
    862 
    863     /**
    864      * Query vars, after parsing
    865      *
    866      * @since 1.5.0
    867      * @access public
    868      * @var array
    869      */
    870     public $query_vars = array();
    871 
    872     /**
    873      * Taxonomy query, as passed to get_tax_sql()
    874      *
    875      * @since 3.1.0
    876      * @access public
    877      * @var object WP_Tax_Query
    878      */
    879     public $tax_query;
    880 
    881     /**
    882      * Metadata query container
    883      *
    884      * @since 3.2.0
    885      * @access public
    886      * @var object WP_Meta_Query
    887      */
    888     public $meta_query = false;
    889 
    890     /**
    891      * Date query container
    892      *
    893      * @since 3.7.0
    894      * @access public
    895      * @var object WP_Date_Query
    896      */
    897     public $date_query = false;
    898 
    899     /**
    900      * Holds the data for a single object that is queried.
    901      *
    902      * Holds the contents of a post, page, category, attachment.
    903      *
    904      * @since 1.5.0
    905      * @access public
    906      * @var object|array
    907      */
    908     public $queried_object;
    909 
    910     /**
    911      * The ID of the queried object.
    912      *
    913      * @since 1.5.0
    914      * @access public
    915      * @var int
    916      */
    917     public $queried_object_id;
    918 
    919     /**
    920      * Get post database query.
    921      *
    922      * @since 2.0.1
    923      * @access public
    924      * @var string
    925      */
    926     public $request;
    927 
    928     /**
    929      * List of posts.
    930      *
    931      * @since 1.5.0
    932      * @access public
    933      * @var array
    934      */
    935     public $posts;
    936 
    937     /**
    938      * The amount of posts for the current query.
    939      *
    940      * @since 1.5.0
    941      * @access public
    942      * @var int
    943      */
    944     public $post_count = 0;
    945 
    946     /**
    947      * Index of the current item in the loop.
    948      *
    949      * @since 1.5.0
    950      * @access public
    951      * @var int
    952      */
    953     public $current_post = -1;
    954 
    955     /**
    956      * Whether the loop has started and the caller is in the loop.
    957      *
    958      * @since 2.0.0
    959      * @access public
    960      * @var bool
    961      */
    962     public $in_the_loop = false;
    963 
    964     /**
    965      * The current post.
    966      *
    967      * @since 1.5.0
    968      * @access public
    969      * @var WP_Post
    970      */
    971     public $post;
    972 
    973     /**
    974      * The list of comments for current post.
    975      *
    976      * @since 2.2.0
    977      * @access public
    978      * @var array
    979      */
    980     public $comments;
    981 
    982     /**
    983      * The amount of comments for the posts.
    984      *
    985      * @since 2.2.0
    986      * @access public
    987      * @var int
    988      */
    989     public $comment_count = 0;
    990 
    991     /**
    992      * The index of the comment in the comment loop.
    993      *
    994      * @since 2.2.0
    995      * @access public
    996      * @var int
    997      */
    998     public $current_comment = -1;
    999 
    1000     /**
    1001      * Current comment ID.
    1002      *
    1003      * @since 2.2.0
    1004      * @access public
    1005      * @var int
    1006      */
    1007     public $comment;
    1008 
    1009     /**
    1010      * The amount of found posts for the current query.
    1011      *
    1012      * If limit clause was not used, equals $post_count.
    1013      *
    1014      * @since 2.1.0
    1015      * @access public
    1016      * @var int
    1017      */
    1018     public $found_posts = 0;
    1019 
    1020     /**
    1021      * The amount of pages.
    1022      *
    1023      * @since 2.1.0
    1024      * @access public
    1025      * @var int
    1026      */
    1027     public $max_num_pages = 0;
    1028 
    1029     /**
    1030      * The amount of comment pages.
    1031      *
    1032      * @since 2.7.0
    1033      * @access public
    1034      * @var int
    1035      */
    1036     public $max_num_comment_pages = 0;
    1037 
    1038     /**
    1039      * Set if query is single post.
    1040      *
    1041      * @since 1.5.0
    1042      * @access public
    1043      * @var bool
    1044      */
    1045     public $is_single = false;
    1046 
    1047     /**
    1048      * Set if query is preview of blog.
    1049      *
    1050      * @since 2.0.0
    1051      * @access public
    1052      * @var bool
    1053      */
    1054     public $is_preview = false;
    1055 
    1056     /**
    1057      * Set if query returns a page.
    1058      *
    1059      * @since 1.5.0
    1060      * @access public
    1061      * @var bool
    1062      */
    1063     public $is_page = false;
    1064 
    1065     /**
    1066      * Set if query is an archive list.
    1067      *
    1068      * @since 1.5.0
    1069      * @access public
    1070      * @var bool
    1071      */
    1072     public $is_archive = false;
    1073 
    1074     /**
    1075      * Set if query is part of a date.
    1076      *
    1077      * @since 1.5.0
    1078      * @access public
    1079      * @var bool
    1080      */
    1081     public $is_date = false;
    1082 
    1083     /**
    1084      * Set if query contains a year.
    1085      *
    1086      * @since 1.5.0
    1087      * @access public
    1088      * @var bool
    1089      */
    1090     public $is_year = false;
    1091 
    1092     /**
    1093      * Set if query contains a month.
    1094      *
    1095      * @since 1.5.0
    1096      * @access public
    1097      * @var bool
    1098      */
    1099     public $is_month = false;
    1100 
    1101     /**
    1102      * Set if query contains a day.
    1103      *
    1104      * @since 1.5.0
    1105      * @access public
    1106      * @var bool
    1107      */
    1108     public $is_day = false;
    1109 
    1110     /**
    1111      * Set if query contains time.
    1112      *
    1113      * @since 1.5.0
    1114      * @access public
    1115      * @var bool
    1116      */
    1117     public $is_time = false;
    1118 
    1119     /**
    1120      * Set if query contains an author.
    1121      *
    1122      * @since 1.5.0
    1123      * @access public
    1124      * @var bool
    1125      */
    1126     public $is_author = false;
    1127 
    1128     /**
    1129      * Set if query contains category.
    1130      *
    1131      * @since 1.5.0
    1132      * @access public
    1133      * @var bool
    1134      */
    1135     public $is_category = false;
    1136 
    1137     /**
    1138      * Set if query contains tag.
    1139      *
    1140      * @since 2.3.0
    1141      * @access public
    1142      * @var bool
    1143      */
    1144     public $is_tag = false;
    1145 
    1146     /**
    1147      * Set if query contains taxonomy.
    1148      *
    1149      * @since 2.5.0
    1150      * @access public
    1151      * @var bool
    1152      */
    1153     public $is_tax = false;
    1154 
    1155     /**
    1156      * Set if query was part of a search result.
    1157      *
    1158      * @since 1.5.0
    1159      * @access public
    1160      * @var bool
    1161      */
    1162     public $is_search = false;
    1163 
    1164     /**
    1165      * Set if query is feed display.
    1166      *
    1167      * @since 1.5.0
    1168      * @access public
    1169      * @var bool
    1170      */
    1171     public $is_feed = false;
    1172 
    1173     /**
    1174      * Set if query is comment feed display.
    1175      *
    1176      * @since 2.2.0
    1177      * @access public
    1178      * @var bool
    1179      */
    1180     public $is_comment_feed = false;
    1181 
    1182     /**
    1183      * Set if query is trackback.
    1184      *
    1185      * @since 1.5.0
    1186      * @access public
    1187      * @var bool
    1188      */
    1189     public $is_trackback = false;
    1190 
    1191     /**
    1192      * Set if query is blog homepage.
    1193      *
    1194      * @since 1.5.0
    1195      * @access public
    1196      * @var bool
    1197      */
    1198     public $is_home = false;
    1199 
    1200     /**
    1201      * Set if query couldn't found anything.
    1202      *
    1203      * @since 1.5.0
    1204      * @access public
    1205      * @var bool
    1206      */
    1207     public $is_404 = false;
    1208 
    1209     /**
    1210      * Set if query is embed.
    1211      *
    1212      * @since 4.4.0
    1213      * @access public
    1214      * @var bool
    1215      */
    1216     public $is_embed = false;
    1217 
    1218     /**
    1219      * Set if query is paged
    1220      *
    1221      * @since 1.5.0
    1222      * @access public
    1223      * @var bool
    1224      */
    1225     public $is_paged = false;
    1226 
    1227     /**
    1228      * Set if query is part of administration page.
    1229      *
    1230      * @since 1.5.0
    1231      * @access public
    1232      * @var bool
    1233      */
    1234     public $is_admin = false;
    1235 
    1236     /**
    1237      * Set if query is an attachment.
    1238      *
    1239      * @since 2.0.0
    1240      * @access public
    1241      * @var bool
    1242      */
    1243     public $is_attachment = false;
    1244 
    1245     /**
    1246      * Set if is single, is a page, or is an attachment.
    1247      *
    1248      * @since 2.1.0
    1249      * @access public
    1250      * @var bool
    1251      */
    1252     public $is_singular = false;
    1253 
    1254     /**
    1255      * Set if query is for robots.
    1256      *
    1257      * @since 2.1.0
    1258      * @access public
    1259      * @var bool
    1260      */
    1261     public $is_robots = false;
    1262 
    1263     /**
    1264      * Set if query contains posts.
    1265      *
    1266      * Basically, the homepage if the option isn't set for the static homepage.
    1267      *
    1268      * @since 2.1.0
    1269      * @access public
    1270      * @var bool
    1271      */
    1272     public $is_posts_page = false;
    1273 
    1274     /**
    1275      * Set if query is for a post type archive.
    1276      *
    1277      * @since 3.1.0
    1278      * @access public
    1279      * @var bool
    1280      */
    1281     public $is_post_type_archive = false;
    1282 
    1283     /**
    1284      * Stores the ->query_vars state like md5(serialize( $this->query_vars ) ) so we know
    1285      * whether we have to re-parse because something has changed
    1286      *
    1287      * @since 3.1.0
    1288      * @access private
    1289      * @var bool|string
    1290      */
    1291     private $query_vars_hash = false;
    1292 
    1293     /**
    1294      * Whether query vars have changed since the initial parse_query() call. Used to catch modifications to query vars made
    1295      * via pre_get_posts hooks.
    1296      *
    1297      * @since 3.1.1
    1298      * @access private
    1299      */
    1300     private $query_vars_changed = true;
    1301 
    1302     /**
    1303      * Set if post thumbnails are cached
    1304      *
    1305      * @since 3.2.0
    1306      * @access public
    1307      * @var bool
    1308      */
    1309      public $thumbnails_cached = false;
    1310 
    1311     /**
    1312      * Cached list of search stopwords.
    1313      *
    1314      * @since 3.7.0
    1315      * @var array
    1316      */
    1317     private $stopwords;
    1318 
    1319     private $compat_fields = array( 'query_vars_hash', 'query_vars_changed' );
    1320 
    1321     private $compat_methods = array( 'init_query_flags', 'parse_tax_query' );
    1322 
    1323     /**
    1324      * @since 4.7.0
    1325      * @access protected
    1326      * @var wpdb
    1327      */
    1328     protected $db;
    1329 
    1330     /**
    1331      * Resets query flags to false.
    1332      *
    1333      * The query flags are what page info WordPress was able to figure out.
    1334      *
    1335      * @since 2.0.0
    1336      * @access private
    1337      */
    1338     private function init_query_flags() {
    1339         $this->is_single = false;
    1340         $this->is_preview = false;
    1341         $this->is_page = false;
    1342         $this->is_archive = false;
    1343         $this->is_date = false;
    1344         $this->is_year = false;
    1345         $this->is_month = false;
    1346         $this->is_day = false;
    1347         $this->is_time = false;
    1348         $this->is_author = false;
    1349         $this->is_category = false;
    1350         $this->is_tag = false;
    1351         $this->is_tax = false;
    1352         $this->is_search = false;
    1353         $this->is_feed = false;
    1354         $this->is_comment_feed = false;
    1355         $this->is_trackback = false;
    1356         $this->is_home = false;
    1357         $this->is_404 = false;
    1358         $this->is_paged = false;
    1359         $this->is_admin = false;
    1360         $this->is_attachment = false;
    1361         $this->is_singular = false;
    1362         $this->is_robots = false;
    1363         $this->is_posts_page = false;
    1364         $this->is_post_type_archive = false;
    1365     }
    1366 
    1367     /**
    1368      * Initiates object properties and sets default values.
    1369      *
    1370      * @since 1.5.0
    1371      * @access public
    1372      */
    1373     public function init() {
    1374         unset($this->posts);
    1375         unset($this->query);
    1376         $this->query_vars = array();
    1377         unset($this->queried_object);
    1378         unset($this->queried_object_id);
    1379         $this->post_count = 0;
    1380         $this->current_post = -1;
    1381         $this->in_the_loop = false;
    1382         unset( $this->request );
    1383         unset( $this->post );
    1384         unset( $this->comments );
    1385         unset( $this->comment );
    1386         $this->comment_count = 0;
    1387         $this->current_comment = -1;
    1388         $this->found_posts = 0;
    1389         $this->max_num_pages = 0;
    1390         $this->max_num_comment_pages = 0;
    1391 
    1392         $this->init_query_flags();
    1393     }
    1394 
    1395     /**
    1396      * Reparse the query vars.
    1397      *
    1398      * @since 1.5.0
    1399      * @access public
    1400      */
    1401     public function parse_query_vars() {
    1402         $this->parse_query();
    1403     }
    1404 
    1405     /**
    1406      * Fills in the query variables, which do not exist within the parameter.
    1407      *
    1408      * @since 2.1.0
    1409      * @since 4.4.0 Removed the `comments_popup` public query variable.
    1410      * @access public
    1411      *
    1412      * @param array $array Defined query variables.
    1413      * @return array Complete query variables with undefined ones filled in empty.
    1414      */
    1415     public function fill_query_vars($array) {
    1416         $keys = array(
    1417             'error'
    1418             , 'm'
    1419             , 'p'
    1420             , 'post_parent'
    1421             , 'subpost'
    1422             , 'subpost_id'
    1423             , 'attachment'
    1424             , 'attachment_id'
    1425             , 'name'
    1426             , 'static'
    1427             , 'pagename'
    1428             , 'page_id'
    1429             , 'second'
    1430             , 'minute'
    1431             , 'hour'
    1432             , 'day'
    1433             , 'monthnum'
    1434             , 'year'
    1435             , 'w'
    1436             , 'category_name'
    1437             , 'tag'
    1438             , 'cat'
    1439             , 'tag_id'
    1440             , 'author'
    1441             , 'author_name'
    1442             , 'feed'
    1443             , 'tb'
    1444             , 'paged'
    1445             , 'meta_key'
    1446             , 'meta_value'
    1447             , 'preview'
    1448             , 's'
    1449             , 'sentence'
    1450             , 'title'
    1451             , 'fields'
    1452             , 'menu_order'
    1453             , 'embed'
    1454         );
    1455 
    1456         foreach ( $keys as $key ) {
    1457             if ( !isset($array[$key]) )
    1458                 $array[$key] = '';
    1459         }
    1460 
    1461         $array_keys = array( 'category__in', 'category__not_in', 'category__and', 'post__in', 'post__not_in', 'post_name__in',
    1462             'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'post_parent__in', 'post_parent__not_in',
    1463             'author__in', 'author__not_in' );
    1464 
    1465         foreach ( $array_keys as $key ) {
    1466             if ( !isset($array[$key]) )
    1467                 $array[$key] = array();
    1468         }
    1469         return $array;
    1470     }
    1471 
    1472     /**
    1473      * Parse a query string and set query type booleans.
    1474      *
    1475      * @since 1.5.0
    1476      * @since 4.2.0 Introduced the ability to order by specific clauses of a `$meta_query`, by passing the clause's
    1477      *              array key to `$orderby`.
    1478      * @since 4.4.0 Introduced `$post_name__in` and `$title` parameters. `$s` was updated to support excluded
    1479      *              search terms, by prepending a hyphen.
    1480      * @since 4.5.0 Removed the `$comments_popup` parameter.
    1481      *              Introduced the `$comment_status` and `$ping_status` parameters.
    1482      *              Introduced `RAND(x)` syntax for `$orderby`, which allows an integer seed value to random sorts.
    1483      * @since 4.6.0 Added 'post_name__in' support for `$orderby`. Introduced the `$lazy_load_term_meta` argument.
    1484      * @access public
    1485      *
    1486      * @param string|array $query {
    1487      *     Optional. Array or string of Query parameters.
    1488      *
    1489      *     @type int          $attachment_id           Attachment post ID. Used for 'attachment' post_type.
    1490      *     @type int|string   $author                  Author ID, or comma-separated list of IDs.
    1491      *     @type string       $author_name             User 'user_nicename'.
    1492      *     @type array        $author__in              An array of author IDs to query from.
    1493      *     @type array        $author__not_in          An array of author IDs not to query from.
    1494      *     @type bool         $cache_results           Whether to cache post information. Default true.
    1495      *     @type int|string   $cat                     Category ID or comma-separated list of IDs (this or any children).
    1496      *     @type array        $category__and           An array of category IDs (AND in).
    1497      *     @type array        $category__in            An array of category IDs (OR in, no children).
    1498      *     @type array        $category__not_in        An array of category IDs (NOT in).
    1499      *     @type string       $category_name           Use category slug (not name, this or any children).
    1500      *     @type string       $comment_status          Comment status.
    1501      *     @type int          $comments_per_page       The number of comments to return per page.
    1502      *                                                 Default 'comments_per_page' option.
    1503      *     @type array        $date_query              An associative array of WP_Date_Query arguments.
    1504      *                                                 See WP_Date_Query::__construct().
    1505      *     @type int          $day                     Day of the month. Default empty. Accepts numbers 1-31.
    1506      *     @type bool         $exact                   Whether to search by exact keyword. Default false.
    1507      *     @type string|array $fields                  Which fields to return. Single field or all fields (string),
    1508      *                                                 or array of fields. 'id=>parent' uses 'id' and 'post_parent'.
    1509      *                                                 Default all fields. Accepts 'ids', 'id=>parent'.
    1510      *     @type int          $hour                    Hour of the day. Default empty. Accepts numbers 0-23.
    1511      *     @type int|bool     $ignore_sticky_posts     Whether to ignore sticky posts or not. Setting this to false
    1512      *                                                 excludes stickies from 'post__in'. Accepts 1|true, 0|false.
    1513      *                                                 Default 0|false.
    1514      *     @type int          $m                       Combination YearMonth. Accepts any four-digit year and month
    1515      *                                                 numbers 1-12. Default empty.
    1516      *     @type string       $meta_compare            Comparison operator to test the 'meta_value'.
    1517      *     @type string       $meta_key                Custom field key.
    1518      *     @type array        $meta_query              An associative array of WP_Meta_Query arguments. See WP_Meta_Query.
    1519      *     @type string       $meta_value              Custom field value.
    1520      *     @type int          $meta_value_num          Custom field value number.
    1521      *     @type int          $menu_order              The menu order of the posts.
    1522      *     @type int          $monthnum                The two-digit month. Default empty. Accepts numbers 1-12.
    1523      *     @type string       $name                    Post slug.
    1524      *     @type bool         $nopaging                Show all posts (true) or paginate (false). Default false.
    1525      *     @type bool         $no_found_rows           Whether to skip counting the total rows found. Enabling can improve
    1526      *                                                 performance. Default false.
    1527      *     @type int          $offset                  The number of posts to offset before retrieval.
    1528      *     @type string       $order                   Designates ascending or descending order of posts. Default 'DESC'.
    1529      *                                                 Accepts 'ASC', 'DESC'.
    1530      *     @type string|array $orderby                 Sort retrieved posts by parameter. One or more options may be
    1531      *                                                 passed. To use 'meta_value', or 'meta_value_num',
    1532      *                                                 'meta_key=keyname' must be also be defined. To sort by a
    1533      *                                                 specific `$meta_query` clause, use that clause's array key.
    1534      *                                                 Default 'date'. Accepts 'none', 'name', 'author', 'date',
    1535      *                                                 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand',
    1536      *                                                 'RAND(x)' (where 'x' is an integer seed value),
    1537      *                                                 'comment_count', 'meta_value', 'meta_value_num', 'post__in',
    1538      *                                                 'post_name__in', 'post_parent__in', and the array keys
    1539      *                                                 of `$meta_query`.
    1540      *     @type int          $p                       Post ID.
    1541      *     @type int          $page                    Show the number of posts that would show up on page X of a
    1542      *                                                 static front page.
    1543      *     @type int          $paged                   The number of the current page.
    1544      *     @type int          $page_id                 Page ID.
    1545      *     @type string       $pagename                Page slug.
    1546      *     @type string       $perm                    Show posts if user has the appropriate capability.
    1547      *     @type string       $ping_status             Ping status.
    1548      *     @type array        $post__in                An array of post IDs to retrieve, sticky posts will be included
    1549      *     @type string       $post_mime_type          The mime type of the post. Used for 'attachment' post_type.
    1550      *     @type array        $post__not_in            An array of post IDs not to retrieve. Note: a string of comma-
    1551      *                                                 separated IDs will NOT work.
    1552      *     @type int          $post_parent             Page ID to retrieve child pages for. Use 0 to only retrieve
    1553      *                                                 top-level pages.
    1554      *     @type array        $post_parent__in         An array containing parent page IDs to query child pages from.
    1555      *     @type array        $post_parent__not_in     An array containing parent page IDs not to query child pages from.
    1556      *     @type string|array $post_type               A post type slug (string) or array of post type slugs.
    1557      *                                                 Default 'any' if using 'tax_query'.
    1558      *     @type string|array $post_status             A post status (string) or array of post statuses.
    1559      *     @type int          $posts_per_page          The number of posts to query for. Use -1 to request all posts.
    1560      *     @type int          $posts_per_archive_page  The number of posts to query for by archive page. Overrides
    1561      *                                                 'posts_per_page' when is_archive(), or is_search() are true.
    1562      *     @type array        $post_name__in           An array of post slugs that results must match.
    1563      *     @type string       $s                       Search keyword(s). Prepending a term with a hyphen will
    1564      *                                                 exclude posts matching that term. Eg, 'pillow -sofa' will
    1565      *                                                 return posts containing 'pillow' but not 'sofa'.
    1566      *     @type int          $second                  Second of the minute. Default empty. Accepts numbers 0-60.
    1567      *     @type bool         $sentence                Whether to search by phrase. Default false.
    1568      *     @type bool         $suppress_filters        Whether to suppress filters. Default false.
    1569      *     @type string       $tag                     Tag slug. Comma-separated (either), Plus-separated (all).
    1570      *     @type array        $tag__and                An array of tag ids (AND in).
    1571      *     @type array        $tag__in                 An array of tag ids (OR in).
    1572      *     @type array        $tag__not_in             An array of tag ids (NOT in).
    1573      *     @type int          $tag_id                  Tag id or comma-separated list of IDs.
    1574      *     @type array        $tag_slug__and           An array of tag slugs (AND in).
    1575      *     @type array        $tag_slug__in            An array of tag slugs (OR in). unless 'ignore_sticky_posts' is
    1576      *                                                 true. Note: a string of comma-separated IDs will NOT work.
    1577      *     @type array        $tax_query               An associative array of WP_Tax_Query arguments.
    1578      *                                                 See WP_Tax_Query->queries.
    1579      *     @type string       $title                   Post title.
    1580      *     @type bool         $update_post_meta_cache  Whether to update the post meta cache. Default true.
    1581      *     @type bool         $update_post_term_cache  Whether to update the post term cache. Default true.
    1582      *     @type bool         $lazy_load_term_meta     Whether to lazy-load term meta. Setting to false will
    1583      *                                                 disable cache priming for term meta, so that each
    1584      *                                                 get_term_meta() call will hit the database.
    1585      *                                                 Defaults to the value of `$update_post_term_cache`.
    1586      *     @type int          $w                       The week number of the year. Default empty. Accepts numbers 0-53.
    1587      *     @type int          $year                    The four-digit year. Default empty. Accepts any four-digit year.
    1588      * }
    1589      */
    1590     public function parse_query( $query =  '' ) {
    1591         if ( ! empty( $query ) ) {
    1592             $this->init();
    1593             $this->query = $this->query_vars = wp_parse_args( $query );
    1594         } elseif ( ! isset( $this->query ) ) {
    1595             $this->query = $this->query_vars;
    1596         }
    1597 
    1598         $this->query_vars = $this->fill_query_vars($this->query_vars);
    1599         $qv = &$this->query_vars;
    1600         $this->query_vars_changed = true;
    1601 
    1602         if ( ! empty($qv['robots']) )
    1603             $this->is_robots = true;
    1604 
    1605         if ( ! is_scalar( $qv['p'] ) || $qv['p'] < 0 ) {
    1606             $qv['p'] = 0;
    1607             $qv['error'] = '404';
    1608         } else {
    1609             $qv['p'] = intval( $qv['p'] );
    1610         }
    1611 
    1612         $qv['page_id'] =  absint($qv['page_id']);
    1613         $qv['year'] = absint($qv['year']);
    1614         $qv['monthnum'] = absint($qv['monthnum']);
    1615         $qv['day'] = absint($qv['day']);
    1616         $qv['w'] = absint($qv['w']);
    1617         $qv['m'] = is_scalar( $qv['m'] ) ? preg_replace( '|[^0-9]|', '', $qv['m'] ) : '';
    1618         $qv['paged'] = absint($qv['paged']);
    1619         $qv['cat'] = preg_replace( '|[^0-9,-]|', '', $qv['cat'] ); // comma separated list of positive or negative integers
    1620         $qv['author'] = preg_replace( '|[^0-9,-]|', '', $qv['author'] ); // comma separated list of positive or negative integers
    1621         $qv['pagename'] = trim( $qv['pagename'] );
    1622         $qv['name'] = trim( $qv['name'] );
    1623         $qv['title'] = trim( $qv['title'] );
    1624         if ( '' !== $qv['hour'] ) $qv['hour'] = absint($qv['hour']);
    1625         if ( '' !== $qv['minute'] ) $qv['minute'] = absint($qv['minute']);
    1626         if ( '' !== $qv['second'] ) $qv['second'] = absint($qv['second']);
    1627         if ( '' !== $qv['menu_order'] ) $qv['menu_order'] = absint($qv['menu_order']);
    1628 
    1629         // Fairly insane upper bound for search string lengths.
    1630         if ( ! is_scalar( $qv['s'] ) || ( ! empty( $qv['s'] ) && strlen( $qv['s'] ) > 1600 ) ) {
    1631             $qv['s'] = '';
    1632         }
    1633 
    1634         // Compat. Map subpost to attachment.
    1635         if ( '' != $qv['subpost'] )
    1636             $qv['attachment'] = $qv['subpost'];
    1637         if ( '' != $qv['subpost_id'] )
    1638             $qv['attachment_id'] = $qv['subpost_id'];
    1639 
    1640         $qv['attachment_id'] = absint($qv['attachment_id']);
    1641 
    1642         if ( ('' != $qv['attachment']) || !empty($qv['attachment_id']) ) {
    1643             $this->is_single = true;
    1644             $this->is_attachment = true;
    1645         } elseif ( '' != $qv['name'] ) {
    1646             $this->is_single = true;
    1647         } elseif ( $qv['p'] ) {
    1648             $this->is_single = true;
    1649         } elseif ( ('' !== $qv['hour']) && ('' !== $qv['minute']) &&('' !== $qv['second']) && ('' != $qv['year']) && ('' != $qv['monthnum']) && ('' != $qv['day']) ) {
    1650             // If year, month, day, hour, minute, and second are set, a single
    1651             // post is being queried.
    1652             $this->is_single = true;
    1653         } elseif ( '' != $qv['static'] || '' != $qv['pagename'] || !empty($qv['page_id']) ) {
    1654             $this->is_page = true;
    1655             $this->is_single = false;
    1656         } else {
    1657             // Look for archive queries. Dates, categories, authors, search, post type archives.
    1658 
    1659             if ( isset( $this->query['s'] ) ) {
    1660                 $this->is_search = true;
    1661             }
    1662 
    1663             if ( '' !== $qv['second'] ) {
    1664                 $this->is_time = true;
    1665                 $this->is_date = true;
    1666             }
    1667 
    1668             if ( '' !== $qv['minute'] ) {
    1669                 $this->is_time = true;
    1670                 $this->is_date = true;
    1671             }
    1672 
    1673             if ( '' !== $qv['hour'] ) {
    1674                 $this->is_time = true;
    1675                 $this->is_date = true;
    1676             }
    1677 
    1678             if ( $qv['day'] ) {
    1679                 if ( ! $this->is_date ) {
    1680                     $date = sprintf( '%04d-%02d-%02d', $qv['year'], $qv['monthnum'], $qv['day'] );
    1681                     if ( $qv['monthnum'] && $qv['year'] && ! wp_checkdate( $qv['monthnum'], $qv['day'], $qv['year'], $date ) ) {
    1682                         $qv['error'] = '404';
    1683                     } else {
    1684                         $this->is_day = true;
    1685                         $this->is_date = true;
    1686                     }
    1687                 }
    1688             }
    1689 
    1690             if ( $qv['monthnum'] ) {
    1691                 if ( ! $this->is_date ) {
    1692                     if ( 12 < $qv['monthnum'] ) {
    1693                         $qv['error'] = '404';
    1694                     } else {
    1695                         $this->is_month = true;
    1696                         $this->is_date = true;
    1697                     }
    1698                 }
    1699             }
    1700 
    1701             if ( $qv['year'] ) {
    1702                 if ( ! $this->is_date ) {
    1703                     $this->is_year = true;
    1704                     $this->is_date = true;
    1705                 }
    1706             }
    1707 
    1708             if ( $qv['m'] ) {
    1709                 $this->is_date = true;
    1710                 if ( strlen($qv['m']) > 9 ) {
    1711                     $this->is_time = true;
    1712                 } elseif ( strlen( $qv['m'] ) > 7 ) {
    1713                     $this->is_day = true;
    1714                 } elseif ( strlen( $qv['m'] ) > 5 ) {
    1715                     $this->is_month = true;
    1716                 } else {
    1717                     $this->is_year = true;
    1718                 }
    1719             }
    1720 
    1721             if ( '' != $qv['w'] ) {
    1722                 $this->is_date = true;
    1723             }
    1724 
    1725             $this->query_vars_hash = false;
    1726             $this->parse_tax_query( $qv );
    1727 
    1728             foreach ( $this->tax_query->queries as $tax_query ) {
    1729                 if ( ! is_array( $tax_query ) ) {
    1730                     continue;
    1731                 }
    1732 
    1733                 if ( isset( $tax_query['operator'] ) && 'NOT IN' != $tax_query['operator'] ) {
    1734                     switch ( $tax_query['taxonomy'] ) {
    1735                         case 'category':
    1736                             $this->is_category = true;
    1737                             break;
    1738                         case 'post_tag':
    1739                             $this->is_tag = true;
    1740                             break;
    1741                         default:
    1742                             $this->is_tax = true;
    1743                     }
    1744                 }
    1745             }
    1746             unset( $tax_query );
    1747 
    1748             if ( empty($qv['author']) || ($qv['author'] == '0') ) {
    1749                 $this->is_author = false;
    1750             } else {
    1751                 $this->is_author = true;
    1752             }
    1753 
    1754             if ( '' != $qv['author_name'] )
    1755                 $this->is_author = true;
    1756 
    1757             if ( !empty( $qv['post_type'] ) && ! is_array( $qv['post_type'] ) ) {
    1758                 $post_type_obj = get_post_type_object( $qv['post_type'] );
    1759                 if ( ! empty( $post_type_obj->has_archive ) )
    1760                     $this->is_post_type_archive = true;
    1761             }
    1762 
    1763             if ( $this->is_post_type_archive || $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax )
    1764                 $this->is_archive = true;
    1765         }
    1766 
    1767         if ( '' != $qv['feed'] )
    1768             $this->is_feed = true;
    1769 
    1770         if ( '' != $qv['embed'] ) {
    1771             $this->is_embed = true;
    1772         }
    1773 
    1774         if ( '' != $qv['tb'] )
    1775             $this->is_trackback = true;
    1776 
    1777         if ( '' != $qv['paged'] && ( intval($qv['paged']) > 1 ) )
    1778             $this->is_paged = true;
    1779 
    1780         // if we're previewing inside the write screen
    1781         if ( '' != $qv['preview'] )
    1782             $this->is_preview = true;
    1783 
    1784         if ( is_admin() )
    1785             $this->is_admin = true;
    1786 
    1787         if ( false !== strpos($qv['feed'], 'comments-') ) {
    1788             $qv['feed'] = str_replace('comments-', '', $qv['feed']);
    1789             $qv['withcomments'] = 1;
    1790         }
    1791 
    1792         $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
    1793 
    1794         if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) )
    1795             $this->is_comment_feed = true;
    1796 
    1797         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 ) )
    1798             $this->is_home = true;
    1799 
    1800         // Correct is_* for page_on_front and page_for_posts
    1801         if ( $this->is_home && 'page' == get_option('show_on_front') && get_option('page_on_front') ) {
    1802             $_query = wp_parse_args($this->query);
    1803             // pagename can be set and empty depending on matched rewrite rules. Ignore an empty pagename.
    1804             if ( isset($_query['pagename']) && '' == $_query['pagename'] )
    1805                 unset($_query['pagename']);
    1806 
    1807             unset( $_query['embed'] );
    1808 
    1809             if ( empty($_query) || !array_diff( array_keys($_query), array('preview', 'page', 'paged', 'cpage') ) ) {
    1810                 $this->is_page = true;
    1811                 $this->is_home = false;
    1812                 $qv['page_id'] = get_option('page_on_front');
    1813                 // Correct <!--nextpage--> for page_on_front
    1814                 if ( !empty($qv['paged']) ) {
    1815                     $qv['page'] = $qv['paged'];
    1816                     unset($qv['paged']);
    1817                 }
    1818             }
    1819         }
    1820 
    1821         if ( '' != $qv['pagename'] ) {
    1822             $this->queried_object = get_page_by_path( $qv['pagename'] );
    1823 
    1824             if ( $this->queried_object && 'attachment' == $this->queried_object->post_type ) {
    1825                 if ( preg_match( "/^[^%]*%(?:postname)%/", get_option( 'permalink_structure' ) ) ) {
    1826                     // See if we also have a post with the same slug
    1827                     $post = get_page_by_path( $qv['pagename'], OBJECT, 'post' );
    1828                     if ( $post ) {
    1829                         $this->queried_object = $post;
    1830                         $this->is_page = false;
    1831                         $this->is_single = true;
    1832                     }
    1833                 }
    1834             }
    1835 
    1836             if ( ! empty( $this->queried_object ) ) {
    1837                 $this->queried_object_id = (int) $this->queried_object->ID;
    1838             } else {
    1839                 unset( $this->queried_object );
    1840             }
    1841 
    1842             if  ( 'page' == get_option('show_on_front') && isset($this->queried_object_id) && $this->queried_object_id == get_option('page_for_posts') ) {
    1843                 $this->is_page = false;
    1844                 $this->is_home = true;
    1845                 $this->is_posts_page = true;
    1846             }
    1847         }
    1848 
    1849         if ( $qv['page_id'] ) {
    1850             if  ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) {
    1851                 $this->is_page = false;
    1852                 $this->is_home = true;
    1853                 $this->is_posts_page = true;
    1854             }
    1855         }
    1856 
    1857         if ( !empty($qv['post_type']) ) {
    1858             if ( is_array($qv['post_type']) )
    1859                 $qv['post_type'] = array_map('sanitize_key', $qv['post_type']);
    1860             else
    1861                 $qv['post_type'] = sanitize_key($qv['post_type']);
    1862         }
    1863 
    1864         if ( ! empty( $qv['post_status'] ) ) {
    1865             if ( is_array( $qv['post_status'] ) )
    1866                 $qv['post_status'] = array_map('sanitize_key', $qv['post_status']);
    1867             else
    1868                 $qv['post_status'] = preg_replace('|[^a-z0-9_,-]|', '', $qv['post_status']);
    1869         }
    1870 
    1871         if ( $this->is_posts_page && ( ! isset($qv['withcomments']) || ! $qv['withcomments'] ) )
    1872             $this->is_comment_feed = false;
    1873 
    1874         $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
    1875         // Done correcting is_* for page_on_front and page_for_posts
    1876 
    1877         if ( '404' == $qv['error'] )
    1878             $this->set_404();
    1879 
    1880         $this->is_embed = $this->is_embed && ( $this->is_singular || $this->is_404 );
    1881 
    1882         $this->query_vars_hash = md5( serialize( $this->query_vars ) );
    1883         $this->query_vars_changed = false;
    1884 
    1885         /**
    1886          * Fires after the main query vars have been parsed.
    1887          *
    1888          * @since 1.5.0
    1889          *
    1890          * @param WP_Query &$this The WP_Query instance (passed by reference).
    1891          */
    1892         do_action_ref_array( 'parse_query', array( &$this ) );
    1893     }
    1894 
    1895     /**
    1896      * Parses various taxonomy related query vars.
    1897      *
    1898      * For BC, this method is not marked as protected. See [28987].
    1899      *
    1900      * @access protected
    1901      * @since 3.1.0
    1902      *
    1903      * @param array $q The query variables. Passed by reference.
    1904      */
    1905     public function parse_tax_query( &$q ) {
    1906         if ( ! empty( $q['tax_query'] ) && is_array( $q['tax_query'] ) ) {
    1907             $tax_query = $q['tax_query'];
    1908         } else {
    1909             $tax_query = array();
    1910         }
    1911 
    1912         if ( !empty($q['taxonomy']) && !empty($q['term']) ) {
    1913             $tax_query[] = array(
    1914                 'taxonomy' => $q['taxonomy'],
    1915                 'terms' => array( $q['term'] ),
    1916                 'field' => 'slug',
    1917             );
    1918         }
    1919 
    1920         foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t ) {
    1921             if ( 'post_tag' == $taxonomy )
    1922                 continue;   // Handled further down in the $q['tag'] block
    1923 
    1924             if ( $t->query_var && !empty( $q[$t->query_var] ) ) {
    1925                 $tax_query_defaults = array(
    1926                     'taxonomy' => $taxonomy,
    1927                     'field' => 'slug',
    1928                 );
    1929 
    1930                 if ( isset( $t->rewrite['hierarchical'] ) && $t->rewrite['hierarchical'] ) {
    1931                     $q[$t->query_var] = wp_basename( $q[$t->query_var] );
    1932                 }
    1933 
    1934                 $term = $q[$t->query_var];
    1935 
    1936                 if ( is_array( $term ) ) {
    1937                     $term = implode( ',', $term );
    1938                 }
    1939 
    1940                 if ( strpos($term, '+') !== false ) {
    1941                     $terms = preg_split( '/[+]+/', $term );
    1942                     foreach ( $terms as $term ) {
    1943                         $tax_query[] = array_merge( $tax_query_defaults, array(
    1944                             'terms' => array( $term )
    1945                         ) );
    1946                     }
    1947                 } else {
    1948                     $tax_query[] = array_merge( $tax_query_defaults, array(
    1949                         'terms' => preg_split( '/[,]+/', $term )
    1950                     ) );
    1951                 }
    1952             }
    1953         }
    1954 
    1955         // If querystring 'cat' is an array, implode it.
    1956         if ( is_array( $q['cat'] ) ) {
    1957             $q['cat'] = implode( ',', $q['cat'] );
    1958         }
    1959 
    1960         // Category stuff
    1961         if ( ! empty( $q['cat'] ) && ! $this->is_singular ) {
    1962             $cat_in = $cat_not_in = array();
    1963 
    1964             $cat_array = preg_split( '/[,\s]+/', urldecode( $q['cat'] ) );
    1965             $cat_array = array_map( 'intval', $cat_array );
    1966             $q['cat'] = implode( ',', $cat_array );
    1967 
    1968             foreach ( $cat_array as $cat ) {
    1969                 if ( $cat > 0 )
    1970                     $cat_in[] = $cat;
    1971                 elseif ( $cat < 0 )
    1972                     $cat_not_in[] = abs( $cat );
    1973             }
    1974 
    1975             if ( ! empty( $cat_in ) ) {
    1976                 $tax_query[] = array(
    1977                     'taxonomy' => 'category',
    1978                     'terms' => $cat_in,
    1979                     'field' => 'term_id',
    1980                     'include_children' => true
    1981                 );
    1982             }
    1983 
    1984             if ( ! empty( $cat_not_in ) ) {
    1985                 $tax_query[] = array(
    1986                     'taxonomy' => 'category',
    1987                     'terms' => $cat_not_in,
    1988                     'field' => 'term_id',
    1989                     'operator' => 'NOT IN',
    1990                     'include_children' => true
    1991                 );
    1992             }
    1993             unset( $cat_array, $cat_in, $cat_not_in );
    1994         }
    1995 
    1996         if ( ! empty( $q['category__and'] ) && 1 === count( (array) $q['category__and'] ) ) {
    1997             $q['category__and'] = (array) $q['category__and'];
    1998             if ( ! isset( $q['category__in'] ) )
    1999                 $q['category__in'] = array();
    2000             $q['category__in'][] = absint( reset( $q['category__and'] ) );
    2001             unset( $q['category__and'] );
    2002         }
    2003 
    2004         if ( ! empty( $q['category__in'] ) ) {
    2005             $q['category__in'] = array_map( 'absint', array_unique( (array) $q['category__in'] ) );
    2006             $tax_query[] = array(
    2007                 'taxonomy' => 'category',
    2008                 'terms' => $q['category__in'],
    2009                 'field' => 'term_id',
    2010                 'include_children' => false
    2011             );
    2012         }
    2013 
    2014         if ( ! empty($q['category__not_in']) ) {
    2015             $q['category__not_in'] = array_map( 'absint', array_unique( (array) $q['category__not_in'] ) );
    2016             $tax_query[] = array(
    2017                 'taxonomy' => 'category',
    2018                 'terms' => $q['category__not_in'],
    2019                 'operator' => 'NOT IN',
    2020                 'include_children' => false
    2021             );
    2022         }
    2023 
    2024         if ( ! empty($q['category__and']) ) {
    2025             $q['category__and'] = array_map( 'absint', array_unique( (array) $q['category__and'] ) );
    2026             $tax_query[] = array(
    2027                 'taxonomy' => 'category',
    2028                 'terms' => $q['category__and'],
    2029                 'field' => 'term_id',
    2030                 'operator' => 'AND',
    2031                 'include_children' => false
    2032             );
    2033         }
    2034 
    2035         // If querystring 'tag' is array, implode it.
    2036         if ( is_array( $q['tag'] ) ) {
    2037             $q['tag'] = implode( ',', $q['tag'] );
    2038         }
    2039 
    2040         // Tag stuff
    2041         if ( '' != $q['tag'] && !$this->is_singular && $this->query_vars_changed ) {
    2042             if ( strpos($q['tag'], ',') !== false ) {
    2043                 $tags = preg_split('/[,\r\n\t ]+/', $q['tag']);
    2044                 foreach ( (array) $tags as $tag ) {
    2045                     $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
    2046                     $q['tag_slug__in'][] = $tag;
    2047                 }
    2048             } elseif ( preg_match('/[+\r\n\t ]+/', $q['tag'] ) || ! empty( $q['cat'] ) ) {
    2049                 $tags = preg_split('/[+\r\n\t ]+/', $q['tag']);
    2050                 foreach ( (array) $tags as $tag ) {
    2051                     $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
    2052                     $q['tag_slug__and'][] = $tag;
    2053                 }
    2054             } else {
    2055                 $q['tag'] = sanitize_term_field('slug', $q['tag'], 0, 'post_tag', 'db');
    2056                 $q['tag_slug__in'][] = $q['tag'];
    2057             }
    2058         }
    2059 
    2060         if ( !empty($q['tag_id']) ) {
    2061             $q['tag_id'] = absint( $q['tag_id'] );
    2062             $tax_query[] = array(
    2063                 'taxonomy' => 'post_tag',
    2064                 'terms' => $q['tag_id']
    2065             );
    2066         }
    2067 
    2068         if ( !empty($q['tag__in']) ) {
    2069             $q['tag__in'] = array_map('absint', array_unique( (array) $q['tag__in'] ) );
    2070             $tax_query[] = array(
    2071                 'taxonomy' => 'post_tag',
    2072                 'terms' => $q['tag__in']
    2073             );
    2074         }
    2075 
    2076         if ( !empty($q['tag__not_in']) ) {
    2077             $q['tag__not_in'] = array_map('absint', array_unique( (array) $q['tag__not_in'] ) );
    2078             $tax_query[] = array(
    2079                 'taxonomy' => 'post_tag',
    2080                 'terms' => $q['tag__not_in'],
    2081                 'operator' => 'NOT IN'
    2082             );
    2083         }
    2084 
    2085         if ( !empty($q['tag__and']) ) {
    2086             $q['tag__and'] = array_map('absint', array_unique( (array) $q['tag__and'] ) );
    2087             $tax_query[] = array(
    2088                 'taxonomy' => 'post_tag',
    2089                 'terms' => $q['tag__and'],
    2090                 'operator' => 'AND'
    2091             );
    2092         }
    2093 
    2094         if ( !empty($q['tag_slug__in']) ) {
    2095             $q['tag_slug__in'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__in'] ) );
    2096             $tax_query[] = array(
    2097                 'taxonomy' => 'post_tag',
    2098                 'terms' => $q['tag_slug__in'],
    2099                 'field' => 'slug'
    2100             );
    2101         }
    2102 
    2103         if ( !empty($q['tag_slug__and']) ) {
    2104             $q['tag_slug__and'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__and'] ) );
    2105             $tax_query[] = array(
    2106                 'taxonomy' => 'post_tag',
    2107                 'terms' => $q['tag_slug__and'],
    2108                 'field' => 'slug',
    2109                 'operator' => 'AND'
    2110             );
    2111         }
    2112 
    2113         $this->tax_query = new WP_Tax_Query( $tax_query );
    2114 
    2115         /**
    2116          * Fires after taxonomy-related query vars have been parsed.
    2117          *
    2118          * @since 3.7.0
    2119          *
    2120          * @param WP_Query $this The WP_Query instance.
    2121          */
    2122         do_action( 'parse_tax_query', $this );
    2123     }
    2124 
    2125     /**
    2126      * Generate SQL for the WHERE clause based on passed search terms.
    2127      *
    2128      * @since 3.7.0
    2129      *
    2130      * @param array $q Query variables.
    2131      * @return string WHERE clause.
    2132      */
    2133     protected function parse_search( &$q ) {
    2134         $search = '';
    2135 
    2136         // added slashes screw with quote grouping when done early, so done later
    2137         $q['s'] = stripslashes( $q['s'] );
    2138         if ( empty( $_GET['s'] ) && $this->is_main_query() )
    2139             $q['s'] = urldecode( $q['s'] );
    2140         // there are no line breaks in <input /> fields
    2141         $q['s'] = str_replace( array( "\r", "\n" ), '', $q['s'] );
    2142         $q['search_terms_count'] = 1;
    2143         if ( ! empty( $q['sentence'] ) ) {
    2144             $q['search_terms'] = array( $q['s'] );
    2145         } else {
    2146             if ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $q['s'], $matches ) ) {
    2147                 $q['search_terms_count'] = count( $matches[0] );
    2148                 $q['search_terms'] = $this->parse_search_terms( $matches[0] );
    2149                 // if the search string has only short terms or stopwords, or is 10+ terms long, match it as sentence
    2150                 if ( empty( $q['search_terms'] ) || count( $q['search_terms'] ) > 9 )
    2151                     $q['search_terms'] = array( $q['s'] );
    2152             } else {
    2153                 $q['search_terms'] = array( $q['s'] );
    2154             }
    2155         }
    2156 
    2157         $n = ! empty( $q['exact'] ) ? '' : '%';
    2158         $searchand = '';
    2159         $q['search_orderby_title'] = array();
    2160         foreach ( $q['search_terms'] as $term ) {
    2161             // Terms prefixed with '-' should be excluded.
    2162             $include = '-' !== substr( $term, 0, 1 );
    2163             if ( $include ) {
    2164                 $like_op  = 'LIKE';
    2165                 $andor_op = 'OR';
    2166             } else {
    2167                 $like_op  = 'NOT LIKE';
    2168                 $andor_op = 'AND';
    2169                 $term     = substr( $term, 1 );
    2170             }
    2171 
    2172             if ( $n && $include ) {
    2173                 $like = '%' . $this->db->esc_like( $term ) . '%';
    2174                 $q['search_orderby_title'][] = $this->db->prepare( "{$this->db->posts}.post_title LIKE %s", $like );
    2175             }
    2176 
    2177             $like = $n . $this->db->esc_like( $term ) . $n;
    2178             $search .= $this->db->prepare( "{$searchand}(({$this->db->posts}.post_title $like_op %s) $andor_op ({$this->db->posts}.post_excerpt $like_op %s) $andor_op ({$this->db->posts}.post_content $like_op %s))", $like, $like, $like );
    2179             $searchand = ' AND ';
    2180         }
    2181 
    2182         if ( ! empty( $search ) ) {
    2183             $search = " AND ({$search}) ";
    2184             if ( ! is_user_logged_in() ) {
    2185                 $search .= " AND ({$this->db->posts}.post_password = '') ";
    2186             }
    2187         }
    2188 
    2189         return $search;
    2190     }
    2191 
    2192     /**
    2193      * Check if the terms are suitable for searching.
    2194      *
    2195      * Uses an array of stopwords (terms) that are excluded from the separate
    2196      * term matching when searching for posts. The list of English stopwords is
    2197      * the approximate search engines list, and is translatable.
    2198      *
    2199      * @since 3.7.0
    2200      *
    2201      * @param array $terms Terms to check.
    2202      * @return array Terms that are not stopwords.
    2203      */
    2204     protected function parse_search_terms( $terms ) {
    2205         $strtolower = function_exists( 'mb_strtolower' ) ? 'mb_strtolower' : 'strtolower';
    2206         $checked = array();
    2207 
    2208         $stopwords = $this->get_search_stopwords();
    2209 
    2210         foreach ( $terms as $term ) {
    2211             // keep before/after spaces when term is for exact match
    2212             if ( preg_match( '/^".+"$/', $term ) )
    2213                 $term = trim( $term, "\"'" );
    2214             else
    2215                 $term = trim( $term, "\"' " );
    2216 
    2217             // Avoid single A-Z and single dashes.
    2218             if ( ! $term || ( 1 === strlen( $term ) && preg_match( '/^[a-z\-]$/i', $term ) ) )
    2219                 continue;
    2220 
    2221             if ( in_array( call_user_func( $strtolower, $term ), $stopwords, true ) )
    2222                 continue;
    2223 
    2224             $checked[] = $term;
    2225         }
    2226 
    2227         return $checked;
    2228     }
    2229 
    2230     /**
    2231      * Retrieve stopwords used when parsing search terms.
    2232      *
    2233      * @since 3.7.0
    2234      *
    2235      * @return array Stopwords.
    2236      */
    2237     protected function get_search_stopwords() {
    2238         if ( isset( $this->stopwords ) )
    2239             return $this->stopwords;
    2240 
    2241         /* translators: This is a comma-separated list of very common words that should be excluded from a search,
    2242          * like a, an, and the. These are usually called "stopwords". You should not simply translate these individual
    2243          * words into your language. Instead, look for and provide commonly accepted stopwords in your language.
    2244          */
    2245         $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',
    2246             'Comma-separated list of search stopwords in your language' ) );
    2247 
    2248         $stopwords = array();
    2249         foreach ( $words as $word ) {
    2250             $word = trim( $word, "\r\n\t " );
    2251             if ( $word )
    2252                 $stopwords[] = $word;
    2253         }
    2254 
    2255         /**
    2256          * Filters stopwords used when parsing search terms.
    2257          *
    2258          * @since 3.7.0
    2259          *
    2260          * @param array $stopwords Stopwords.
    2261          */
    2262         $this->stopwords = apply_filters( 'wp_search_stopwords', $stopwords );
    2263         return $this->stopwords;
    2264     }
    2265 
    2266     /**
    2267      * Generate SQL for the ORDER BY condition based on passed search terms.
    2268      *
    2269      * @param array $q Query variables.
    2270      * @return string ORDER BY clause.
    2271      */
    2272     protected function parse_search_order( &$q ) {
    2273         if ( $q['search_terms_count'] > 1 ) {
    2274             $num_terms = count( $q['search_orderby_title'] );
    2275 
    2276             // If the search terms contain negative queries, don't bother ordering by sentence matches.
    2277             $like = '';
    2278             if ( ! preg_match( '/(?:\s|^)\-/', $q['s'] ) ) {
    2279                 $like = '%' . $this->db->esc_like( $q['s'] ) . '%';
    2280             }
    2281 
    2282             $search_orderby = '';
    2283 
    2284             // sentence match in 'post_title'
    2285             if ( $like ) {
    2286                 $search_orderby .= $this->db->prepare( "WHEN {$this->db->posts}.post_title LIKE %s THEN 1 ", $like );
    2287             }
    2288 
    2289             // sanity limit, sort as sentence when more than 6 terms
    2290             // (few searches are longer than 6 terms and most titles are not)
    2291             if ( $num_terms < 7 ) {
    2292                 // all words in title
    2293                 $search_orderby .= 'WHEN ' . implode( ' AND ', $q['search_orderby_title'] ) . ' THEN 2 ';
    2294                 // any word in title, not needed when $num_terms == 1
    2295                 if ( $num_terms > 1 )
    2296                     $search_orderby .= 'WHEN ' . implode( ' OR ', $q['search_orderby_title'] ) . ' THEN 3 ';
    2297             }
    2298 
    2299             // Sentence match in 'post_content' and 'post_excerpt'.
    2300             if ( $like ) {
    2301                 $search_orderby .= $this->db->prepare( "WHEN {$this->db->posts}.post_excerpt LIKE %s THEN 4 ", $like );
    2302                 $search_orderby .= $this->db->prepare( "WHEN {$this->db->posts}.post_content LIKE %s THEN 5 ", $like );
    2303             }
    2304 
    2305             if ( $search_orderby ) {
    2306                 $search_orderby = '(CASE ' . $search_orderby . 'ELSE 6 END)';
    2307             }
    2308         } else {
    2309             // single word or sentence search
    2310             $search_orderby = reset( $q['search_orderby_title'] ) . ' DESC';
    2311         }
    2312 
    2313         return $search_orderby;
    2314     }
    2315 
    2316     /**
    2317      * If the passed orderby value is allowed, convert the alias to a
    2318      * properly-prefixed orderby value.
    2319      *
    2320      * @since 4.0.0
    2321      * @access protected
    2322      *
    2323      * @param string $orderby Alias for the field to order by.
    2324      * @return string|false Table-prefixed value to used in the ORDER clause. False otherwise.
    2325      */
    2326     protected function parse_orderby( $orderby ) {
    2327         // Used to filter values.
    2328         $allowed_keys = array(
    2329             'post_name', 'post_author', 'post_date', 'post_title', 'post_modified',
    2330             'post_parent', 'post_type', 'name', 'author', 'date', 'title', 'modified',
    2331             'parent', 'type', 'ID', 'menu_order', 'comment_count', 'rand',
    2332         );
    2333 
    2334         $primary_meta_key = '';
    2335         $primary_meta_query = false;
    2336         $meta_clauses = $this->meta_query->get_clauses();
    2337         if ( ! empty( $meta_clauses ) ) {
    2338             $primary_meta_query = reset( $meta_clauses );
    2339 
    2340             if ( ! empty( $primary_meta_query['key'] ) ) {
    2341                 $primary_meta_key = $primary_meta_query['key'];
    2342                 $allowed_keys[] = $primary_meta_key;
    2343             }
    2344 
    2345             $allowed_keys[] = 'meta_value';
    2346             $allowed_keys[] = 'meta_value_num';
    2347             $allowed_keys   = array_merge( $allowed_keys, array_keys( $meta_clauses ) );
    2348         }
    2349 
    2350         // If RAND() contains a seed value, sanitize and add to allowed keys.
    2351         $rand_with_seed = false;
    2352         if ( preg_match( '/RAND\(([0-9]+)\)/i', $orderby, $matches ) ) {
    2353             $orderby = sprintf( 'RAND(%s)', intval( $matches[1] ) );
    2354             $allowed_keys[] = $orderby;
    2355             $rand_with_seed = true;
    2356         }
    2357 
    2358         if ( ! in_array( $orderby, $allowed_keys, true ) ) {
    2359             return false;
    2360         }
    2361 
    2362         switch ( $orderby ) {
    2363             case 'post_name':
    2364             case 'post_author':
    2365             case 'post_date':
    2366             case 'post_title':
    2367             case 'post_modified':
    2368             case 'post_parent':
    2369             case 'post_type':
    2370             case 'ID':
    2371             case 'menu_order':
    2372             case 'comment_count':
    2373                 $orderby_clause = "{$this->db->posts}.{$orderby}";
    2374                 break;
    2375             case 'rand':
    2376                 $orderby_clause = 'RAND()';
    2377                 break;
    2378             case $primary_meta_key:
    2379             case 'meta_value':
    2380                 if ( ! empty( $primary_meta_query['type'] ) ) {
    2381                     $orderby_clause = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})";
    2382                 } else {
    2383                     $orderby_clause = "{$primary_meta_query['alias']}.meta_value";
    2384                 }
    2385                 break;
    2386             case 'meta_value_num':
    2387                 $orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
    2388                 break;
    2389             default:
    2390                 if ( array_key_exists( $orderby, $meta_clauses ) ) {
    2391                     // $orderby corresponds to a meta_query clause.
    2392                     $meta_clause = $meta_clauses[ $orderby ];
    2393                     $orderby_clause = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})";
    2394                 } elseif ( $rand_with_seed ) {
    2395                     $orderby_clause = $orderby;
    2396                 } else {
    2397                     // Default: order by post field.
    2398                     $orderby_clause = "{$this->db->posts}.post_" . sanitize_key( $orderby );
    2399                 }
    2400 
    2401                 break;
    2402         }
    2403 
    2404         return $orderby_clause;
    2405     }
    2406 
    2407     /**
    2408      * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
    2409      *
    2410      * @since 4.0.0
    2411      * @access protected
    2412      *
    2413      * @param string $order The 'order' query variable.
    2414      * @return string The sanitized 'order' query variable.
    2415      */
    2416     protected function parse_order( $order ) {
    2417         if ( ! is_string( $order ) || empty( $order ) ) {
    2418             return 'DESC';
    2419         }
    2420 
    2421         if ( 'ASC' === strtoupper( $order ) ) {
    2422             return 'ASC';
    2423         } else {
    2424             return 'DESC';
    2425         }
    2426     }
    2427 
    2428     /**
    2429      * Sets the 404 property and saves whether query is feed.
    2430      *
    2431      * @since 2.0.0
    2432      * @access public
    2433      */
    2434     public function set_404() {
    2435         $is_feed = $this->is_feed;
    2436 
    2437         $this->init_query_flags();
    2438         $this->is_404 = true;
    2439 
    2440         $this->is_feed = $is_feed;
    2441     }
    2442 
    2443     /**
    2444      * Retrieve query variable.
    2445      *
    2446      * @since 1.5.0
    2447      * @since 3.9.0 The `$default` argument was introduced.
    2448      *
    2449      * @access public
    2450      *
    2451      * @param string $query_var Query variable key.
    2452      * @param mixed  $default   Optional. Value to return if the query variable is not set. Default empty.
    2453      * @return mixed Contents of the query variable.
    2454      */
    2455     public function get( $query_var, $default = '' ) {
    2456         if ( isset( $this->query_vars[ $query_var ] ) ) {
    2457             return $this->query_vars[ $query_var ];
    2458         }
    2459 
    2460         return $default;
    2461     }
    2462 
    2463     /**
    2464      * Set query variable.
    2465      *
    2466      * @since 1.5.0
    2467      * @access public
    2468      *
    2469      * @param string $query_var Query variable key.
    2470      * @param mixed  $value     Query variable value.
    2471      */
    2472     public function set($query_var, $value) {
    2473         $this->query_vars[$query_var] = $value;
    2474     }
    2475 
    2476     /**
    2477      * Retrieve the posts based on query variables.
    2478      *
    2479      * There are a few filters and actions that can be used to modify the post
    2480      * database query.
    2481      *
    2482      * @since 1.5.0
    2483      * @access public
    2484      *
    2485      * @return array List of posts.
    2486      */
    2487     public function get_posts() {
    2488         $this->parse_query();
    2489 
    2490         /**
    2491          * Fires after the query variable object is created, but before the actual query is run.
    2492          *
    2493          * Note: If using conditional tags, use the method versions within the passed instance
    2494          * (e.g. $this->is_main_query() instead of is_main_query()). This is because the functions
    2495          * like is_main_query() test against the global $wp_query instance, not the passed one.
    2496          *
    2497          * @since 2.0.0
    2498          *
    2499          * @param WP_Query &$this The WP_Query instance (passed by reference).
    2500          */
    2501         do_action_ref_array( 'pre_get_posts', array( &$this ) );
    2502 
    2503         // Shorthand.
    2504         $q = &$this->query_vars;
    2505 
    2506         // Fill again in case pre_get_posts unset some vars.
    2507         $q = $this->fill_query_vars($q);
    2508 
    2509         // Parse meta query
    2510         $this->meta_query = new WP_Meta_Query();
    2511         $this->meta_query->parse_query_vars( $q );
    2512 
    2513         // Set a flag if a pre_get_posts hook changed the query vars.
    2514         $hash = md5( serialize( $this->query_vars ) );
    2515         if ( $hash != $this->query_vars_hash ) {
    2516             $this->query_vars_changed = true;
    2517             $this->query_vars_hash = $hash;
    2518         }
    2519         unset($hash);
    2520 
    2521         // First let's clear some variables
    2522         $distinct = '';
    2523         $whichauthor = '';
    2524         $whichmimetype = '';
    2525         $where = '';
    2526         $limits = '';
    2527         $join = '';
    2528         $search = '';
    2529         $groupby = '';
    2530         $post_status_join = false;
    2531         $page = 1;
    2532 
    2533         if ( isset( $q['caller_get_posts'] ) ) {
    2534             _deprecated_argument( 'WP_Query', '3.1.0', __( '"caller_get_posts" is deprecated. Use "ignore_sticky_posts" instead.' ) );
    2535             if ( !isset( $q['ignore_sticky_posts'] ) )
    2536                 $q['ignore_sticky_posts'] = $q['caller_get_posts'];
    2537         }
    2538 
    2539         if ( !isset( $q['ignore_sticky_posts'] ) )
    2540             $q['ignore_sticky_posts'] = false;
    2541 
    2542         if ( !isset($q['suppress_filters']) )
    2543             $q['suppress_filters'] = false;
    2544 
    2545         if ( !isset($q['cache_results']) ) {
    2546             if ( wp_using_ext_object_cache() )
    2547                 $q['cache_results'] = false;
    2548             else
    2549                 $q['cache_results'] = true;
    2550         }
    2551 
    2552         if ( !isset($q['update_post_term_cache']) )
    2553             $q['update_post_term_cache'] = true;
    2554 
    2555         if ( ! isset( $q['lazy_load_term_meta'] ) ) {
    2556             $q['lazy_load_term_meta'] = $q['update_post_term_cache'];
    2557         }
    2558 
    2559         if ( !isset($q['update_post_meta_cache']) )
    2560             $q['update_post_meta_cache'] = true;
    2561 
    2562         if ( !isset($q['post_type']) ) {
    2563             if ( $this->is_search )
    2564                 $q['post_type'] = 'any';
    2565             else
    2566                 $q['post_type'] = '';
    2567         }
    2568         $post_type = $q['post_type'];
    2569         if ( empty( $q['posts_per_page'] ) ) {
    2570             $q['posts_per_page'] = get_option( 'posts_per_page' );
    2571         }
    2572         if ( isset($q['showposts']) && $q['showposts'] ) {
    2573             $q['showposts'] = (int) $q['showposts'];
    2574             $q['posts_per_page'] = $q['showposts'];
    2575         }
    2576         if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) )
    2577             $q['posts_per_page'] = $q['posts_per_archive_page'];
    2578         if ( !isset($q['nopaging']) ) {
    2579             if ( $q['posts_per_page'] == -1 ) {
    2580                 $q['nopaging'] = true;
    2581             } else {
    2582                 $q['nopaging'] = false;
    2583             }
    2584         }
    2585 
    2586         if ( $this->is_feed ) {
    2587             // This overrides posts_per_page.
    2588             if ( ! empty( $q['posts_per_rss'] ) ) {
    2589                 $q['posts_per_page'] = $q['posts_per_rss'];
    2590             } else {
    2591                 $q['posts_per_page'] = get_option( 'posts_per_rss' );
    2592             }
    2593             $q['nopaging'] = false;
    2594         }
    2595         $q['posts_per_page'] = (int) $q['posts_per_page'];
    2596         if ( $q['posts_per_page'] < -1 )
    2597             $q['posts_per_page'] = abs($q['posts_per_page']);
    2598         elseif ( $q['posts_per_page'] == 0 )
    2599             $q['posts_per_page'] = 1;
    2600 
    2601         if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 )
    2602             $q['comments_per_page'] = get_option('comments_per_page');
    2603 
    2604         if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
    2605             $this->is_page = true;
    2606             $this->is_home = false;
    2607             $q['page_id'] = get_option('page_on_front');
    2608         }
    2609 
    2610         if ( isset($q['page']) ) {
    2611             $q['page'] = trim($q['page'], '/');
    2612             $q['page'] = absint($q['page']);
    2613         }
    2614 
    2615         // If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present.
    2616         if ( isset($q['no_found_rows']) )
    2617             $q['no_found_rows'] = (bool) $q['no_found_rows'];
    2618         else
    2619             $q['no_found_rows'] = false;
    2620 
    2621         switch ( $q['fields'] ) {
    2622             case 'ids':
    2623                 $fields = "{$this->db->posts}.ID";
    2624                 break;
    2625             case 'id=>parent':
    2626                 $fields = "{$this->db->posts}.ID, {$this->db->posts}.post_parent";
    2627                 break;
    2628             default:
    2629                 $fields = "{$this->db->posts}.*";
    2630         }
    2631 
    2632         if ( '' !== $q['menu_order'] ) {
    2633             $where .= " AND {$this->db->posts}.menu_order = " . $q['menu_order'];
    2634         }
    2635         // The "m" parameter is meant for months but accepts datetimes of varying specificity
    2636         if ( $q['m'] ) {
    2637             $where .= " AND YEAR({$this->db->posts}.post_date)=" . substr($q['m'], 0, 4);
    2638             if ( strlen($q['m']) > 5 ) {
    2639                 $where .= " AND MONTH({$this->db->posts}.post_date)=" . substr($q['m'], 4, 2);
    2640             }
    2641             if ( strlen($q['m']) > 7 ) {
    2642                 $where .= " AND DAYOFMONTH({$this->db->posts}.post_date)=" . substr($q['m'], 6, 2);
    2643             }
    2644             if ( strlen($q['m']) > 9 ) {
    2645                 $where .= " AND HOUR({$this->db->posts}.post_date)=" . substr($q['m'], 8, 2);
    2646             }
    2647             if ( strlen($q['m']) > 11 ) {
    2648                 $where .= " AND MINUTE({$this->db->posts}.post_date)=" . substr($q['m'], 10, 2);
    2649             }
    2650             if ( strlen($q['m']) > 13 ) {
    2651                 $where .= " AND SECOND({$this->db->posts}.post_date)=" . substr($q['m'], 12, 2);
    2652             }
    2653         }
    2654 
    2655         // Handle the other individual date parameters
    2656         $date_parameters = array();
    2657 
    2658         if ( '' !== $q['hour'] )
    2659             $date_parameters['hour'] = $q['hour'];
    2660 
    2661         if ( '' !== $q['minute'] )
    2662             $date_parameters['minute'] = $q['minute'];
    2663 
    2664         if ( '' !== $q['second'] )
    2665             $date_parameters['second'] = $q['second'];
    2666 
    2667         if ( $q['year'] )
    2668             $date_parameters['year'] = $q['year'];
    2669 
    2670         if ( $q['monthnum'] )
    2671             $date_parameters['monthnum'] = $q['monthnum'];
    2672 
    2673         if ( $q['w'] )
    2674             $date_parameters['week'] = $q['w'];
    2675 
    2676         if ( $q['day'] )
    2677             $date_parameters['day'] = $q['day'];
    2678 
    2679         if ( $date_parameters ) {
    2680             $date_query = new WP_Date_Query( array( $date_parameters ) );
    2681             $where .= $date_query->get_sql();
    2682         }
    2683         unset( $date_parameters, $date_query );
    2684 
    2685         // Handle complex date queries
    2686         if ( ! empty( $q['date_query'] ) ) {
    2687             $this->date_query = new WP_Date_Query( $q['date_query'] );
    2688             $where .= $this->date_query->get_sql();
    2689         }
    2690 
    2691 
    2692         // If we've got a post_type AND it's not "any" post_type.
    2693         if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) {
    2694             foreach ( (array)$q['post_type'] as $_post_type ) {
    2695                 $ptype_obj = get_post_type_object($_post_type);
    2696                 if ( !$ptype_obj || !$ptype_obj->query_var || empty($q[ $ptype_obj->query_var ]) )
    2697                     continue;
    2698 
    2699                 if ( ! $ptype_obj->hierarchical ) {
    2700                     // Non-hierarchical post types can directly use 'name'.
    2701                     $q['name'] = $q[ $ptype_obj->query_var ];
    2702                 } else {
    2703                     // Hierarchical post types will operate through 'pagename'.
    2704                     $q['pagename'] = $q[ $ptype_obj->query_var ];
    2705                     $q['name'] = '';
    2706                 }
    2707 
    2708                 // Only one request for a slug is possible, this is why name & pagename are overwritten above.
    2709                 break;
    2710             } //end foreach
    2711             unset($ptype_obj);
    2712         }
    2713 
    2714         if ( '' !== $q['title'] ) {
    2715             $where .= $this->db->prepare( " AND {$this->db->posts}.post_title = %s", stripslashes( $q['title'] ) );
    2716         }
    2717 
    2718         // Parameters related to 'post_name'.
    2719         if ( '' != $q['name'] ) {
    2720             $q['name'] = sanitize_title_for_query( $q['name'] );
    2721             $where .= " AND {$this->db->posts}.post_name = '" . $q['name'] . "'";
    2722         } elseif ( '' != $q['pagename'] ) {
    2723             if ( isset($this->queried_object_id) ) {
    2724                 $reqpage = $this->queried_object_id;
    2725             } else {
    2726                 if ( 'page' != $q['post_type'] ) {
    2727                     foreach ( (array)$q['post_type'] as $_post_type ) {
    2728                         $ptype_obj = get_post_type_object($_post_type);
    2729                         if ( !$ptype_obj || !$ptype_obj->hierarchical )
    2730                             continue;
    2731 
    2732                         $reqpage = get_page_by_path($q['pagename'], OBJECT, $_post_type);
    2733                         if ( $reqpage )
    2734                             break;
    2735                     }
    2736                     unset($ptype_obj);
    2737                 } else {
    2738                     $reqpage = get_page_by_path($q['pagename']);
    2739                 }
    2740                 if ( !empty($reqpage) )
    2741                     $reqpage = $reqpage->ID;
    2742                 else
    2743                     $reqpage = 0;
    2744             }
    2745 
    2746             $page_for_posts = get_option('page_for_posts');
    2747             if  ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) {
    2748                 $q['pagename'] = sanitize_title_for_query( wp_basename( $q['pagename'] ) );
    2749                 $q['name'] = $q['pagename'];
    2750                 $where .= " AND ({$this->db->posts}.ID = '$reqpage')";
    2751                 $reqpage_obj = get_post( $reqpage );
    2752                 if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) {
    2753                     $this->is_attachment = true;
    2754                     $post_type = $q['post_type'] = 'attachment';
    2755                     $this->is_page = true;
    2756                     $q['attachment_id'] = $reqpage;
    2757                 }
    2758             }
    2759         } elseif ( '' != $q['attachment'] ) {
    2760             $q['attachment'] = sanitize_title_for_query( wp_basename( $q['attachment'] ) );
    2761             $q['name'] = $q['attachment'];
    2762             $where .= " AND {$this->db->posts}.post_name = '" . $q['attachment'] . "'";
    2763         } elseif ( is_array( $q['post_name__in'] ) && ! empty( $q['post_name__in'] ) ) {
    2764             $q['post_name__in'] = array_map( 'sanitize_title_for_query', $q['post_name__in'] );
    2765             $post_name__in = "'" . implode( "','", $q['post_name__in'] ) . "'";
    2766             $where .= " AND {$this->db->posts}.post_name IN ($post_name__in)";
    2767         }
    2768 
    2769         // If an attachment is requested by number, let it supersede any post number.
    2770         if ( $q['attachment_id'] )
    2771             $q['p'] = absint($q['attachment_id']);
    2772 
    2773         // If a post number is specified, load that post
    2774         if ( $q['p'] ) {
    2775             $where .= " AND {$this->db->posts}.ID = " . $q['p'];
    2776         } elseif ( $q['post__in'] ) {
    2777             $post__in = implode(',', array_map( 'absint', $q['post__in'] ));
    2778             $where .= " AND {$this->db->posts}.ID IN ($post__in)";
    2779         } elseif ( $q['post__not_in'] ) {
    2780             $post__not_in = implode(',',  array_map( 'absint', $q['post__not_in'] ));
    2781             $where .= " AND {$this->db->posts}.ID NOT IN ($post__not_in)";
    2782         }
    2783 
    2784         if ( is_numeric( $q['post_parent'] ) ) {
    2785             $where .= $this->db->prepare( " AND {$this->db->posts}.post_parent = %d ", $q['post_parent'] );
    2786         } elseif ( $q['post_parent__in'] ) {
    2787             $post_parent__in = implode( ',', array_map( 'absint', $q['post_parent__in'] ) );
    2788             $where .= " AND {$this->db->posts}.post_parent IN ($post_parent__in)";
    2789         } elseif ( $q['post_parent__not_in'] ) {
    2790             $post_parent__not_in = implode( ',',  array_map( 'absint', $q['post_parent__not_in'] ) );
    2791             $where .= " AND {$this->db->posts}.post_parent NOT IN ($post_parent__not_in)";
    2792         }
    2793 
    2794         if ( $q['page_id'] ) {
    2795             if  ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
    2796                 $q['p'] = $q['page_id'];
    2797                 $where = " AND {$this->db->posts}.ID = " . $q['page_id'];
    2798             }
    2799         }
    2800 
    2801         // If a search pattern is specified, load the posts that match.
    2802         if ( strlen( $q['s'] ) ) {
    2803             $search = $this->parse_search( $q );
    2804         }
    2805 
    2806         if ( ! $q['suppress_filters'] ) {
    2807             /**
    2808              * Filters the search SQL that is used in the WHERE clause of WP_Query.
    2809              *
    2810              * @since 3.0.0
    2811              *
    2812              * @param string   $search Search SQL for WHERE clause.
    2813              * @param WP_Query $this   The current WP_Query object.
    2814              */
    2815             $search = apply_filters_ref_array( 'posts_search', array( $search, &$this ) );
    2816         }
    2817 
    2818         // Taxonomies
    2819         if ( !$this->is_singular ) {
    2820             $this->parse_tax_query( $q );
    2821 
    2822             $clauses = $this->tax_query->get_sql( $this->db->posts, 'ID' );
    2823 
    2824             $join .= $clauses['join'];
    2825             $where .= $clauses['where'];
    2826         }
    2827 
    2828         if ( $this->is_tax ) {
    2829             if ( empty($post_type) ) {
    2830                 // Do a fully inclusive search for currently registered post types of queried taxonomies
    2831                 $post_type = array();
    2832                 $taxonomies = array_keys( $this->tax_query->queried_terms );
    2833                 foreach ( get_post_types( array( 'exclude_from_search' => false ) ) as $pt ) {
    2834                     $object_taxonomies = $pt === 'attachment' ? get_taxonomies_for_attachments() : get_object_taxonomies( $pt );
    2835                     if ( array_intersect( $taxonomies, $object_taxonomies ) )
    2836                         $post_type[] = $pt;
    2837                 }
    2838                 if ( ! $post_type )
    2839                     $post_type = 'any';
    2840                 elseif ( count( $post_type ) == 1 )
    2841                     $post_type = $post_type[0];
    2842 
    2843                 $post_status_join = true;
    2844             } elseif ( in_array('attachment', (array) $post_type) ) {
    2845                 $post_status_join = true;
    2846             }
    2847         }
    2848 
    2849         /*
    2850          * Ensure that 'taxonomy', 'term', 'term_id', 'cat', and
    2851          * 'category_name' vars are set for backward compatibility.
    2852          */
    2853         if ( ! empty( $this->tax_query->queried_terms ) ) {
    2854 
    2855             /*
    2856              * Set 'taxonomy', 'term', and 'term_id' to the
    2857              * first taxonomy other than 'post_tag' or 'category'.
    2858              */
    2859             if ( ! isset( $q['taxonomy'] ) ) {
    2860                 foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
    2861                     if ( empty( $queried_items['terms'][0] ) ) {
    2862                         continue;
    2863                     }
    2864 
    2865                     if ( ! in_array( $queried_taxonomy, array( 'category', 'post_tag' ) ) ) {
    2866                         $q['taxonomy'] = $queried_taxonomy;
    2867 
    2868                         if ( 'slug' === $queried_items['field'] ) {
    2869                             $q['term'] = $queried_items['terms'][0];
    2870                         } else {
    2871                             $q['term_id'] = $queried_items['terms'][0];
    2872                         }
    2873 
    2874                         // Take the first one we find.
    2875                         break;
    2876                     }
    2877                 }
    2878             }
    2879 
    2880             // 'cat', 'category_name', 'tag_id'
    2881             foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
    2882                 if ( empty( $queried_items['terms'][0] ) ) {
    2883                     continue;
    2884                 }
    2885 
    2886                 if ( 'category' === $queried_taxonomy ) {
    2887                     $the_cat = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'category' );
    2888                     if ( $the_cat ) {
    2889                         $this->set( 'cat', $the_cat->term_id );
    2890                         $this->set( 'category_name', $the_cat->slug );
    2891                     }
    2892                     unset( $the_cat );
    2893                 }
    2894 
    2895                 if ( 'post_tag' === $queried_taxonomy ) {
    2896                     $the_tag = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'post_tag' );
    2897                     if ( $the_tag ) {
    2898                         $this->set( 'tag_id', $the_tag->term_id );
    2899                     }
    2900                     unset( $the_tag );
    2901                 }
    2902             }
    2903         }
    2904 
    2905         if ( !empty( $this->tax_query->queries ) || !empty( $this->meta_query->queries ) ) {
    2906             $groupby = "{$this->db->posts}.ID";
    2907         }
    2908 
    2909         // Author/user stuff
    2910 
    2911         if ( ! empty( $q['author'] ) && $q['author'] != '0' ) {
    2912             $q['author'] = addslashes_gpc( '' . urldecode( $q['author'] ) );
    2913             $authors = array_unique( array_map( 'intval', preg_split( '/[,\s]+/', $q['author'] ) ) );
    2914             foreach ( $authors as $author ) {
    2915                 $key = $author > 0 ? 'author__in' : 'author__not_in';
    2916                 $q[$key][] = abs( $author );
    2917             }
    2918             $q['author'] = implode( ',', $authors );
    2919         }
    2920 
    2921         if ( ! empty( $q['author__not_in'] ) ) {
    2922             $author__not_in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__not_in'] ) ) );
    2923             $where .= " AND {$this->db->posts}.post_author NOT IN ($author__not_in) ";
    2924         } elseif ( ! empty( $q['author__in'] ) ) {
    2925             $author__in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__in'] ) ) );
    2926             $where .= " AND {$this->db->posts}.post_author IN ($author__in) ";
    2927         }
    2928 
    2929         // Author stuff for nice URLs
    2930 
    2931         if ( '' != $q['author_name'] ) {
    2932             if ( strpos($q['author_name'], '/') !== false ) {
    2933                 $q['author_name'] = explode('/', $q['author_name']);
    2934                 if ( $q['author_name'][ count($q['author_name'])-1 ] ) {
    2935                     $q['author_name'] = $q['author_name'][count($q['author_name'])-1]; // no trailing slash
    2936                 } else {
    2937                     $q['author_name'] = $q['author_name'][count($q['author_name'])-2]; // there was a trailing slash
    2938                 }
    2939             }
    2940             $q['author_name'] = sanitize_title_for_query( $q['author_name'] );
    2941             $q['author'] = get_user_by('slug', $q['author_name']);
    2942             if ( $q['author'] )
    2943                 $q['author'] = $q['author']->ID;
    2944             $whichauthor .= " AND ({$this->db->posts}.post_author = " . absint($q['author']) . ')';
    2945         }
    2946 
    2947         // MIME-Type stuff for attachment browsing
    2948 
    2949         if ( isset( $q['post_mime_type'] ) && '' != $q['post_mime_type'] ) {
    2950             $whichmimetype = wp_post_mime_type_where( $q['post_mime_type'], $this->db->posts );
    2951         }
    2952         $where .= $search . $whichauthor . $whichmimetype;
    2953 
    2954         if ( ! empty( $this->meta_query->queries ) ) {
    2955             $clauses = $this->meta_query->get_sql( 'post', $this->db->posts, 'ID', $this );
    2956             $join   .= $clauses['join'];
    2957             $where  .= $clauses['where'];
    2958         }
    2959 
    2960         $rand = ( isset( $q['orderby'] ) && 'rand' === $q['orderby'] );
    2961         if ( ! isset( $q['order'] ) ) {
    2962             $q['order'] = $rand ? '' : 'DESC';
    2963         } else {
    2964             $q['order'] = $rand ? '' : $this->parse_order( $q['order'] );
    2965         }
    2966 
    2967         // Order by.
    2968         if ( empty( $q['orderby'] ) ) {
    2969             /*
    2970              * Boolean false or empty array blanks out ORDER BY,
    2971              * while leaving the value unset or otherwise empty sets the default.
    2972              */
    2973             if ( isset( $q['orderby'] ) && ( is_array( $q['orderby'] ) || false === $q['orderby'] ) ) {
    2974                 $orderby = '';
    2975             } else {
    2976                 $orderby = "{$this->db->posts}.post_date " . $q['order'];
    2977             }
    2978         } elseif ( 'none' == $q['orderby'] ) {
    2979             $orderby = '';
    2980         } elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
    2981             $orderby = "FIELD( {$this->db->posts}.ID, $post__in )";
    2982         } elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
    2983             $orderby = "FIELD( {$this->db->posts}.post_parent, $post_parent__in )";
    2984         } elseif ( $q['orderby'] == 'post_name__in' && ! empty( $post_name__in ) ) {
    2985             $orderby = "FIELD( {$this->db->posts}.post_name, $post_name__in )";
    2986         } else {
    2987             $orderby_array = array();
    2988             if ( is_array( $q['orderby'] ) ) {
    2989                 foreach ( $q['orderby'] as $_orderby => $order ) {
    2990                     $orderby = addslashes_gpc( urldecode( $_orderby ) );
    2991                     $parsed  = $this->parse_orderby( $orderby );
    2992 
    2993                     if ( ! $parsed ) {
    2994                         continue;
    2995                     }
    2996 
    2997                     $orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
    2998                 }
    2999                 $orderby = implode( ', ', $orderby_array );
    3000 
    3001             } else {
    3002                 $q['orderby'] = urldecode( $q['orderby'] );
    3003                 $q['orderby'] = addslashes_gpc( $q['orderby'] );
    3004 
    3005                 foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
    3006                     $parsed = $this->parse_orderby( $orderby );
    3007                     // Only allow certain values for safety.
    3008                     if ( ! $parsed ) {
    3009                         continue;
    3010                     }
    3011 
    3012                     $orderby_array[] = $parsed;
    3013                 }
    3014                 $orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
    3015 
    3016                 if ( empty( $orderby ) ) {
    3017                     $orderby = "{$this->db->posts}.post_date " . $q['order'];
    3018                 } elseif ( ! empty( $q['order'] ) ) {
    3019                     $orderby .= " {$q['order']}";
    3020                 }
    3021             }
    3022         }
    3023 
    3024         // Order search results by relevance only when another "orderby" is not specified in the query.
    3025         if ( ! empty( $q['s'] ) ) {
    3026             $search_orderby = '';
    3027             if ( ! empty( $q['search_orderby_title'] ) && ( empty( $q['orderby'] ) && ! $this->is_feed ) || ( isset( $q['orderby'] ) && 'relevance' === $q['orderby'] ) )
    3028                 $search_orderby = $this->parse_search_order( $q );
    3029 
    3030             if ( ! $q['suppress_filters'] ) {
    3031                 /**
    3032                  * Filters the ORDER BY used when ordering search results.
    3033                  *
    3034                  * @since 3.7.0
    3035                  *
    3036                  * @param string   $search_orderby The ORDER BY clause.
    3037                  * @param WP_Query $this           The current WP_Query instance.
    3038                  */
    3039                 $search_orderby = apply_filters( 'posts_search_orderby', $search_orderby, $this );
    3040             }
    3041 
    3042             if ( $search_orderby )
    3043                 $orderby = $orderby ? $search_orderby . ', ' . $orderby : $search_orderby;
    3044         }
    3045 
    3046         if ( is_array( $post_type ) && count( $post_type ) > 1 ) {
    3047             $post_type_cap = 'multiple_post_type';
    3048         } else {
    3049             if ( is_array( $post_type ) )
    3050                 $post_type = reset( $post_type );
    3051             $post_type_object = get_post_type_object( $post_type );
    3052             if ( empty( $post_type_object ) )
    3053                 $post_type_cap = $post_type;
    3054         }
    3055 
    3056         if ( isset( $q['post_password'] ) ) {
    3057             $where .= $this->db->prepare( " AND {$this->db->posts}.post_password = %s", $q['post_password'] );
    3058             if ( empty( $q['perm'] ) ) {
    3059                 $q['perm'] = 'readable';
    3060             }
    3061         } elseif ( isset( $q['has_password'] ) ) {
    3062             $where .= sprintf( " AND {$this->db->posts}.post_password %s ''", $q['has_password'] ? '!=' : '=' );
    3063         }
    3064 
    3065         if ( ! empty( $q['comment_status'] ) ) {
    3066             $where .= $this->db->prepare( " AND {$this->db->posts}.comment_status = %s ", $q['comment_status'] );
    3067         }
    3068 
    3069         if ( ! empty( $q['ping_status'] ) )  {
    3070             $where .= $this->db->prepare( " AND {$this->db->posts}.ping_status = %s ", $q['ping_status'] );
    3071         }
    3072 
    3073         if ( 'any' == $post_type ) {
    3074             $in_search_post_types = get_post_types( array('exclude_from_search' => false) );
    3075             if ( empty( $in_search_post_types ) ) {
    3076                 $where .= ' AND 1=0 ';
    3077             } else {
    3078                 $where .= " AND {$this->db->posts}.post_type IN ('" . join("', '", $in_search_post_types ) . "')";
    3079             }
    3080         } elseif ( !empty( $post_type ) && is_array( $post_type ) ) {
    3081             $where .= " AND {$this->db->posts}.post_type IN ('" . join("', '", $post_type) . "')";
    3082         } elseif ( ! empty( $post_type ) ) {
    3083             $where .= " AND {$this->db->posts}.post_type = '$post_type'";
    3084             $post_type_object = get_post_type_object ( $post_type );
    3085         } elseif ( $this->is_attachment ) {
    3086             $where .= " AND {$this->db->posts}.post_type = 'attachment'";
    3087             $post_type_object = get_post_type_object ( 'attachment' );
    3088         } elseif ( $this->is_page ) {
    3089             $where .= " AND {$this->db->posts}.post_type = 'page'";
    3090             $post_type_object = get_post_type_object ( 'page' );
    3091         } else {
    3092             $where .= " AND {$this->db->posts}.post_type = 'post'";
    3093             $post_type_object = get_post_type_object ( 'post' );
    3094         }
    3095 
    3096         $edit_cap = 'edit_post';
    3097         $read_cap = 'read_post';
    3098 
    3099         if ( ! empty( $post_type_object ) ) {
    3100             $edit_others_cap = $post_type_object->cap->edit_others_posts;
    3101             $read_private_cap = $post_type_object->cap->read_private_posts;
    3102         } else {
    3103             $edit_others_cap = 'edit_others_' . $post_type_cap . 's';
    3104             $read_private_cap = 'read_private_' . $post_type_cap . 's';
    3105         }
    3106 
    3107         $user_id = get_current_user_id();
    3108 
    3109         $q_status = array();
    3110         if ( ! empty( $q['post_status'] ) ) {
    3111             $statuswheres = array();
    3112             $q_status = $q['post_status'];
    3113             if ( ! is_array( $q_status ) )
    3114                 $q_status = explode(',', $q_status);
    3115             $r_status = array();
    3116             $p_status = array();
    3117             $e_status = array();
    3118             if ( in_array( 'any', $q_status ) ) {
    3119                 foreach ( get_post_stati( array( 'exclude_from_search' => true ) ) as $status ) {
    3120                     if ( ! in_array( $status, $q_status ) ) {
    3121                         $e_status[] = "{$this->db->posts}.post_status <> '$status'";
    3122                     }
    3123                 }
    3124             } else {
    3125                 foreach ( get_post_stati() as $status ) {
    3126                     if ( in_array( $status, $q_status ) ) {
    3127                         if ( 'private' == $status ) {
    3128                             $p_status[] = "{$this->db->posts}.post_status = '$status'";
    3129                         } else {
    3130                             $r_status[] = "{$this->db->posts}.post_status = '$status'";
    3131                         }
    3132                     }
    3133                 }
    3134             }
    3135 
    3136             if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) {
    3137                 $r_status = array_merge($r_status, $p_status);
    3138                 unset($p_status);
    3139             }
    3140 
    3141             if ( !empty($e_status) ) {
    3142                 $statuswheres[] = "(" . join( ' AND ', $e_status ) . ")";
    3143             }
    3144             if ( !empty($r_status) ) {
    3145                 if ( !empty($q['perm'] ) && 'editable' == $q['perm'] && !current_user_can($edit_others_cap) ) {
    3146                     $statuswheres[] = "({$this->db->posts}.post_author = $user_id " . "AND (" . join( ' OR ', $r_status ) . "))";
    3147                 } else {
    3148                     $statuswheres[] = "(" . join( ' OR ', $r_status ) . ")";
    3149                 }
    3150             }
    3151             if ( !empty($p_status) ) {
    3152                 if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can($read_private_cap) ) {
    3153                     $statuswheres[] = "({$this->db->posts}.post_author = $user_id " . "AND (" . join( ' OR ', $p_status ) . "))";
    3154                 } else {
    3155                     $statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
    3156                 }
    3157             }
    3158             if ( $post_status_join ) {
    3159                 $join .= " LEFT JOIN {$this->db->posts} AS p2 ON ({$this->db->posts}.post_parent = p2.ID) ";
    3160                 foreach ( $statuswheres as $index => $statuswhere ) {
    3161                     $statuswheres[$index] = "($statuswhere OR ({$this->db->posts}.post_status = 'inherit' AND " . str_replace( $this->db->posts, 'p2', $statuswhere ) . "))";
    3162                 }
    3163             }
    3164             $where_status = implode( ' OR ', $statuswheres );
    3165             if ( ! empty( $where_status ) ) {
    3166                 $where .= " AND ($where_status)";
    3167             }
    3168         } elseif ( !$this->is_singular ) {
    3169             $where .= " AND ({$this->db->posts}.post_status = 'publish'";
    3170 
    3171             // Add public states.
    3172             $public_states = get_post_stati( array('public' => true) );
    3173             foreach ( (array) $public_states as $state ) {
    3174                 if ( 'publish' == $state ) // Publish is hard-coded above.
    3175                     continue;
    3176                 $where .= " OR {$this->db->posts}.post_status = '$state'";
    3177             }
    3178 
    3179             if ( $this->is_admin ) {
    3180                 // Add protected states that should show in the admin all list.
    3181                 $admin_all_states = get_post_stati( array('protected' => true, 'show_in_admin_all_list' => true) );
    3182                 foreach ( (array) $admin_all_states as $state ) {
    3183                     $where .= " OR {$this->db->posts}.post_status = '$state'";
    3184                 }
    3185             }
    3186 
    3187             if ( is_user_logged_in() ) {
    3188                 // Add private states that are limited to viewing by the author of a post or someone who has caps to read private states.
    3189                 $private_states = get_post_stati( array('private' => true) );
    3190                 foreach ( (array) $private_states as $state ) {
    3191                     $where .= current_user_can( $read_private_cap ) ? " OR {$this->db->posts}.post_status = '$state'" : " OR {$this->db->posts}.post_author = $user_id AND {$this->db->posts}.post_status = '$state'";
    3192                 }
    3193             }
    3194 
    3195             $where .= ')';
    3196         }
    3197 
    3198         /*
    3199          * Apply filters on where and join prior to paging so that any
    3200          * manipulations to them are reflected in the paging by day queries.
    3201          */
    3202         if ( !$q['suppress_filters'] ) {
    3203             /**
    3204              * Filters the WHERE clause of the query.
    3205              *
    3206              * @since 1.5.0
    3207              *
    3208              * @param string   $where The WHERE clause of the query.
    3209              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3210              */
    3211             $where = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );
    3212 
    3213             /**
    3214              * Filters the JOIN clause of the query.
    3215              *
    3216              * @since 1.5.0
    3217              *
    3218              * @param string   $where The JOIN clause of the query.
    3219              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3220              */
    3221             $join = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
    3222         }
    3223 
    3224         // Paging
    3225         if ( empty($q['nopaging']) && !$this->is_singular ) {
    3226             $page = absint($q['paged']);
    3227             if ( !$page )
    3228                 $page = 1;
    3229 
    3230             // If 'offset' is provided, it takes precedence over 'paged'.
    3231             if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) ) {
    3232                 $q['offset'] = absint( $q['offset'] );
    3233                 $pgstrt = $q['offset'] . ', ';
    3234             } else {
    3235                 $pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
    3236             }
    3237             $limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
    3238         }
    3239 
    3240         // Comments feeds
    3241         if ( $this->is_comment_feed && ! $this->is_singular ) {
    3242             if ( $this->is_archive || $this->is_search ) {
    3243                 $cjoin = "JOIN {$this->db->posts} ON ({$this->db->comments}.comment_post_ID = {$this->db->posts}.ID) $join ";
    3244                 $cwhere = "WHERE comment_approved = '1' $where";
    3245                 $cgroupby = "{$this->db->comments}.comment_id";
    3246             } else { // Other non singular e.g. front
    3247                 $cjoin = "JOIN {$this->db->posts} ON ( {$this->db->comments}.comment_post_ID = {$this->db->posts}.ID )";
    3248                 $cwhere = "WHERE ( post_status = 'publish' OR ( post_status = 'inherit' && post_type = 'attachment' ) ) AND comment_approved = '1'";
    3249                 $cgroupby = '';
    3250             }
    3251 
    3252             if ( !$q['suppress_filters'] ) {
    3253                 /**
    3254                  * Filters the JOIN clause of the comments feed query before sending.
    3255                  *
    3256                  * @since 2.2.0
    3257                  *
    3258                  * @param string   $cjoin The JOIN clause of the query.
    3259                  * @param WP_Query &$this The WP_Query instance (passed by reference).
    3260                  */
    3261                 $cjoin = apply_filters_ref_array( 'comment_feed_join', array( $cjoin, &$this ) );
    3262 
    3263                 /**
    3264                  * Filters the WHERE clause of the comments feed query before sending.
    3265                  *
    3266                  * @since 2.2.0
    3267                  *
    3268                  * @param string   $cwhere The WHERE clause of the query.
    3269                  * @param WP_Query &$this  The WP_Query instance (passed by reference).
    3270                  */
    3271                 $cwhere = apply_filters_ref_array( 'comment_feed_where', array( $cwhere, &$this ) );
    3272 
    3273                 /**
    3274                  * Filters the GROUP BY clause of the comments feed query before sending.
    3275                  *
    3276                  * @since 2.2.0
    3277                  *
    3278                  * @param string   $cgroupby The GROUP BY clause of the query.
    3279                  * @param WP_Query &$this    The WP_Query instance (passed by reference).
    3280                  */
    3281                 $cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( $cgroupby, &$this ) );
    3282 
    3283                 /**
    3284                  * Filters the ORDER BY clause of the comments feed query before sending.
    3285                  *
    3286                  * @since 2.8.0
    3287                  *
    3288                  * @param string   $corderby The ORDER BY clause of the query.
    3289                  * @param WP_Query &$this    The WP_Query instance (passed by reference).
    3290                  */
    3291                 $corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
    3292 
    3293                 /**
    3294                  * Filters the LIMIT clause of the comments feed query before sending.
    3295                  *
    3296                  * @since 2.8.0
    3297                  *
    3298                  * @param string   $climits The JOIN clause of the query.
    3299                  * @param WP_Query &$this   The WP_Query instance (passed by reference).
    3300                  */
    3301                 $climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
    3302             }
    3303             $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
    3304             $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
    3305 
    3306             $comments = (array) $this->db->get_results("SELECT $distinct {$this->db->comments}.* FROM {$this->db->comments} $cjoin $cwhere $cgroupby $corderby $climits");
    3307             // Convert to WP_Comment
    3308             $this->comments = array_map( 'get_comment', $comments );
    3309             $this->comment_count = count($this->comments);
    3310 
    3311             $post_ids = array();
    3312 
    3313             foreach ( $this->comments as $comment )
    3314                 $post_ids[] = (int) $comment->comment_post_ID;
    3315 
    3316             $post_ids = join(',', $post_ids);
    3317             $join = '';
    3318             if ( $post_ids ) {
    3319                 $where = "AND {$this->db->posts}.ID IN ($post_ids) ";
    3320             } else {
    3321                 $where = "AND 0";
    3322             }
    3323         }
    3324 
    3325         $pieces = array( 'where', 'groupby', 'join', 'orderby', 'distinct', 'fields', 'limits' );
    3326 
    3327         /*
    3328          * Apply post-paging filters on where and join. Only plugins that
    3329          * manipulate paging queries should use these hooks.
    3330          */
    3331         if ( !$q['suppress_filters'] ) {
    3332             /**
    3333              * Filters the WHERE clause of the query.
    3334              *
    3335              * Specifically for manipulating paging queries.
    3336              *
    3337              * @since 1.5.0
    3338              *
    3339              * @param string   $where The WHERE clause of the query.
    3340              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3341              */
    3342             $where = apply_filters_ref_array( 'posts_where_paged', array( $where, &$this ) );
    3343 
    3344             /**
    3345              * Filters the GROUP BY clause of the query.
    3346              *
    3347              * @since 2.0.0
    3348              *
    3349              * @param string   $groupby The GROUP BY clause of the query.
    3350              * @param WP_Query &$this   The WP_Query instance (passed by reference).
    3351              */
    3352             $groupby = apply_filters_ref_array( 'posts_groupby', array( $groupby, &$this ) );
    3353 
    3354             /**
    3355              * Filters the JOIN clause of the query.
    3356              *
    3357              * Specifically for manipulating paging queries.
    3358              *
    3359              * @since 1.5.0
    3360              *
    3361              * @param string   $join  The JOIN clause of the query.
    3362              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3363              */
    3364             $join = apply_filters_ref_array( 'posts_join_paged', array( $join, &$this ) );
    3365 
    3366             /**
    3367              * Filters the ORDER BY clause of the query.
    3368              *
    3369              * @since 1.5.1
    3370              *
    3371              * @param string   $orderby The ORDER BY clause of the query.
    3372              * @param WP_Query &$this   The WP_Query instance (passed by reference).
    3373              */
    3374             $orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
    3375 
    3376             /**
    3377              * Filters the DISTINCT clause of the query.
    3378              *
    3379              * @since 2.1.0
    3380              *
    3381              * @param string   $distinct The DISTINCT clause of the query.
    3382              * @param WP_Query &$this    The WP_Query instance (passed by reference).
    3383              */
    3384             $distinct = apply_filters_ref_array( 'posts_distinct', array( $distinct, &$this ) );
    3385 
    3386             /**
    3387              * Filters the LIMIT clause of the query.
    3388              *
    3389              * @since 2.1.0
    3390              *
    3391              * @param string   $limits The LIMIT clause of the query.
    3392              * @param WP_Query &$this  The WP_Query instance (passed by reference).
    3393              */
    3394             $limits = apply_filters_ref_array( 'post_limits', array( $limits, &$this ) );
    3395 
    3396             /**
    3397              * Filters the SELECT clause of the query.
    3398              *
    3399              * @since 2.1.0
    3400              *
    3401              * @param string   $fields The SELECT clause of the query.
    3402              * @param WP_Query &$this  The WP_Query instance (passed by reference).
    3403              */
    3404             $fields = apply_filters_ref_array( 'posts_fields', array( $fields, &$this ) );
    3405 
    3406             /**
    3407              * Filters all query clauses at once, for convenience.
    3408              *
    3409              * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
    3410              * fields (SELECT), and LIMITS clauses.
    3411              *
    3412              * @since 3.1.0
    3413              *
    3414              * @param array    $clauses The list of clauses for the query.
    3415              * @param WP_Query &$this   The WP_Query instance (passed by reference).
    3416              */
    3417             $clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
    3418 
    3419             $where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
    3420             $groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
    3421             $join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
    3422             $orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
    3423             $distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
    3424             $fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
    3425             $limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
    3426         }
    3427 
    3428         /**
    3429          * Fires to announce the query's current selection parameters.
    3430          *
    3431          * For use by caching plugins.
    3432          *
    3433          * @since 2.3.0
    3434          *
    3435          * @param string $selection The assembled selection query.
    3436          */
    3437         do_action( 'posts_selection', $where . $groupby . $orderby . $limits . $join );
    3438 
    3439         /*
    3440          * Filters again for the benefit of caching plugins.
    3441          * Regular plugins should use the hooks above.
    3442          */
    3443         if ( !$q['suppress_filters'] ) {
    3444             /**
    3445              * Filters the WHERE clause of the query.
    3446              *
    3447              * For use by caching plugins.
    3448              *
    3449              * @since 2.5.0
    3450              *
    3451              * @param string   $where The WHERE clause of the query.
    3452              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3453              */
    3454             $where = apply_filters_ref_array( 'posts_where_request', array( $where, &$this ) );
    3455 
    3456             /**
    3457              * Filters the GROUP BY clause of the query.
    3458              *
    3459              * For use by caching plugins.
    3460              *
    3461              * @since 2.5.0
    3462              *
    3463              * @param string   $groupby The GROUP BY clause of the query.
    3464              * @param WP_Query &$this   The WP_Query instance (passed by reference).
    3465              */
    3466             $groupby = apply_filters_ref_array( 'posts_groupby_request', array( $groupby, &$this ) );
    3467 
    3468             /**
    3469              * Filters the JOIN clause of the query.
    3470              *
    3471              * For use by caching plugins.
    3472              *
    3473              * @since 2.5.0
    3474              *
    3475              * @param string   $join  The JOIN clause of the query.
    3476              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3477              */
    3478             $join = apply_filters_ref_array( 'posts_join_request', array( $join, &$this ) );
    3479 
    3480             /**
    3481              * Filters the ORDER BY clause of the query.
    3482              *
    3483              * For use by caching plugins.
    3484              *
    3485              * @since 2.5.0
    3486              *
    3487              * @param string   $orderby The ORDER BY clause of the query.
    3488              * @param WP_Query &$this   The WP_Query instance (passed by reference).
    3489              */
    3490             $orderby = apply_filters_ref_array( 'posts_orderby_request', array( $orderby, &$this ) );
    3491 
    3492             /**
    3493              * Filters the DISTINCT clause of the query.
    3494              *
    3495              * For use by caching plugins.
    3496              *
    3497              * @since 2.5.0
    3498              *
    3499              * @param string   $distinct The DISTINCT clause of the query.
    3500              * @param WP_Query &$this    The WP_Query instance (passed by reference).
    3501              */
    3502             $distinct = apply_filters_ref_array( 'posts_distinct_request', array( $distinct, &$this ) );
    3503 
    3504             /**
    3505              * Filters the SELECT clause of the query.
    3506              *
    3507              * For use by caching plugins.
    3508              *
    3509              * @since 2.5.0
    3510              *
    3511              * @param string   $fields The SELECT clause of the query.
    3512              * @param WP_Query &$this  The WP_Query instance (passed by reference).
    3513              */
    3514             $fields = apply_filters_ref_array( 'posts_fields_request', array( $fields, &$this ) );
    3515 
    3516             /**
    3517              * Filters the LIMIT clause of the query.
    3518              *
    3519              * For use by caching plugins.
    3520              *
    3521              * @since 2.5.0
    3522              *
    3523              * @param string   $limits The LIMIT clause of the query.
    3524              * @param WP_Query &$this  The WP_Query instance (passed by reference).
    3525              */
    3526             $limits = apply_filters_ref_array( 'post_limits_request', array( $limits, &$this ) );
    3527 
    3528             /**
    3529              * Filters all query clauses at once, for convenience.
    3530              *
    3531              * For use by caching plugins.
    3532              *
    3533              * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
    3534              * fields (SELECT), and LIMITS clauses.
    3535              *
    3536              * @since 3.1.0
    3537              *
    3538              * @param array    $pieces The pieces of the query.
    3539              * @param WP_Query &$this  The WP_Query instance (passed by reference).
    3540              */
    3541             $clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );
    3542 
    3543             $where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
    3544             $groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
    3545             $join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
    3546             $orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
    3547             $distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
    3548             $fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
    3549             $limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
    3550         }
    3551 
    3552         if ( ! empty($groupby) )
    3553             $groupby = 'GROUP BY ' . $groupby;
    3554         if ( !empty( $orderby ) )
    3555             $orderby = 'ORDER BY ' . $orderby;
    3556 
    3557         $found_rows = '';
    3558         if ( !$q['no_found_rows'] && !empty($limits) )
    3559             $found_rows = 'SQL_CALC_FOUND_ROWS';
    3560 
    3561         $this->request = $old_request = "SELECT $found_rows $distinct $fields FROM {$this->db->posts} $join WHERE 1=1 $where $groupby $orderby $limits";
    3562 
    3563         if ( !$q['suppress_filters'] ) {
    3564             /**
    3565              * Filters the completed SQL query before sending.
    3566              *
    3567              * @since 2.0.0
    3568              *
    3569              * @param string   $request The complete SQL query.
    3570              * @param WP_Query &$this   The WP_Query instance (passed by reference).
    3571              */
    3572             $this->request = apply_filters_ref_array( 'posts_request', array( $this->request, &$this ) );
    3573         }
    3574 
    3575         /**
    3576          * Filters the posts array before the query takes place.
    3577          *
    3578          * Return a non-null value to bypass WordPress's default post queries.
    3579          *
    3580          * Filtering functions that require pagination information are encouraged to set
    3581          * the `found_posts` and `max_num_pages` properties of the WP_Query object,
    3582          * passed to the filter by reference. If WP_Query does not perform a database
    3583          * query, it will not have enough information to generate these values itself.
    3584          *
    3585          * @since 4.6.0
    3586          *
    3587          * @param array|null $posts Return an array of post data to short-circuit WP's query,
    3588          *                          or null to allow WP to run its normal queries.
    3589          * @param WP_Query   $this  The WP_Query instance, passed by reference.
    3590          */
    3591         $this->posts = apply_filters_ref_array( 'posts_pre_query', array( null, &$this ) );
    3592 
    3593         if ( 'ids' == $q['fields'] ) {
    3594             if ( null === $this->posts ) {
    3595                 $this->posts = $this->db->get_col( $this->request );
    3596             }
    3597 
    3598             $this->posts = array_map( 'intval', $this->posts );
    3599             $this->post_count = count( $this->posts );
    3600             $this->set_found_posts( $q, $limits );
    3601 
    3602             return $this->posts;
    3603         }
    3604 
    3605         if ( 'id=>parent' == $q['fields'] ) {
    3606             if ( null === $this->posts ) {
    3607                 $this->posts = $this->db->get_results( $this->request );
    3608             }
    3609 
    3610             $this->post_count = count( $this->posts );
    3611             $this->set_found_posts( $q, $limits );
    3612 
    3613             $r = array();
    3614             foreach ( $this->posts as $key => $post ) {
    3615                 $this->posts[ $key ]->ID = (int) $post->ID;
    3616                 $this->posts[ $key ]->post_parent = (int) $post->post_parent;
    3617 
    3618                 $r[ (int) $post->ID ] = (int) $post->post_parent;
    3619             }
    3620 
    3621             return $r;
    3622         }
    3623 
    3624         if ( null === $this->posts ) {
    3625             $split_the_query = ( $old_request == $this->request && "{$this->db->posts}.*" == $fields && !empty( $limits ) && $q['posts_per_page'] < 500 );
    3626 
    3627             /**
    3628              * Filters whether to split the query.
    3629              *
    3630              * Splitting the query will cause it to fetch just the IDs of the found posts
    3631              * (and then individually fetch each post by ID), rather than fetching every
    3632              * complete row at once. One massive result vs. many small results.
    3633              *
    3634              * @since 3.4.0
    3635              *
    3636              * @param bool     $split_the_query Whether or not to split the query.
    3637              * @param WP_Query $this            The WP_Query instance.
    3638              */
    3639             $split_the_query = apply_filters( 'split_the_query', $split_the_query, $this );
    3640 
    3641             if ( $split_the_query ) {
    3642                 // First get the IDs and then fill in the objects
    3643 
    3644                 $this->request = "SELECT $found_rows $distinct {$this->db->posts}.ID FROM {$this->db->posts} $join WHERE 1=1 $where $groupby $orderby $limits";
    3645 
    3646                 /**
    3647                  * Filters the Post IDs SQL request before sending.
    3648                  *
    3649                  * @since 3.4.0
    3650                  *
    3651                  * @param string   $request The post ID request.
    3652                  * @param WP_Query $this    The WP_Query instance.
    3653                  */
    3654                 $this->request = apply_filters( 'posts_request_ids', $this->request, $this );
    3655 
    3656                 $ids = $this->db->get_col( $this->request );
    3657 
    3658                 if ( $ids ) {
    3659                     $this->posts = $ids;
    3660                     $this->set_found_posts( $q, $limits );
    3661                     _prime_post_caches( $ids, $q['update_post_term_cache'], $q['update_post_meta_cache'] );
    3662                 } else {
    3663                     $this->posts = array();
    3664                 }
    3665             } else {
    3666                 $this->posts = $this->db->get_results( $this->request );
    3667                 $this->set_found_posts( $q, $limits );
    3668             }
    3669         }
    3670 
    3671         // Convert to WP_Post objects.
    3672         if ( $this->posts ) {
    3673             $this->posts = array_map( 'get_post', $this->posts );
    3674         }
    3675 
    3676         if ( ! $q['suppress_filters'] ) {
    3677             /**
    3678              * Filters the raw post results array, prior to status checks.
    3679              *
    3680              * @since 2.3.0
    3681              *
    3682              * @param array    $posts The post results array.
    3683              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3684              */
    3685             $this->posts = apply_filters_ref_array( 'posts_results', array( $this->posts, &$this ) );
    3686         }
    3687 
    3688         if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
    3689             /** This filter is documented in wp-includes/query.php */
    3690             $cjoin = apply_filters_ref_array( 'comment_feed_join', array( '', &$this ) );
    3691 
    3692             /** This filter is documented in wp-includes/query.php */
    3693             $cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
    3694 
    3695             /** This filter is documented in wp-includes/query.php */
    3696             $cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( '', &$this ) );
    3697             $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
    3698 
    3699             /** This filter is documented in wp-includes/query.php */
    3700             $corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
    3701             $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
    3702 
    3703             /** This filter is documented in wp-includes/query.php */
    3704             $climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
    3705 
    3706             $comments_request = "SELECT {$this->db->comments}.* FROM {$this->db->comments} $cjoin $cwhere $cgroupby $corderby $climits";
    3707             $comments = $this->db->get_results($comments_request);
    3708             // Convert to WP_Comment
    3709             $this->comments = array_map( 'get_comment', $comments );
    3710             $this->comment_count = count($this->comments);
    3711         }
    3712 
    3713         // Check post status to determine if post should be displayed.
    3714         if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) {
    3715             $status = get_post_status($this->posts[0]);
    3716             if ( 'attachment' === $this->posts[0]->post_type && 0 === (int) $this->posts[0]->post_parent ) {
    3717                 $this->is_page = false;
    3718                 $this->is_single = true;
    3719                 $this->is_attachment = true;
    3720             }
    3721             $post_status_obj = get_post_status_object($status);
    3722 
    3723             // If the post_status was specifically requested, let it pass through.
    3724             if ( !$post_status_obj->public && ! in_array( $status, $q_status ) ) {
    3725 
    3726                 if ( ! is_user_logged_in() ) {
    3727                     // User must be logged in to view unpublished posts.
    3728                     $this->posts = array();
    3729                 } else {
    3730                     if  ( $post_status_obj->protected ) {
    3731                         // User must have edit permissions on the draft to preview.
    3732                         if ( ! current_user_can($edit_cap, $this->posts[0]->ID) ) {
    3733                             $this->posts = array();
    3734                         } else {
    3735                             $this->is_preview = true;
    3736                             if ( 'future' != $status )
    3737                                 $this->posts[0]->post_date = current_time('mysql');
    3738                         }
    3739                     } elseif ( $post_status_obj->private ) {
    3740                         if ( ! current_user_can($read_cap, $this->posts[0]->ID) )
    3741                             $this->posts = array();
    3742                     } else {
    3743                         $this->posts = array();
    3744                     }
    3745                 }
    3746             }
    3747 
    3748             if ( $this->is_preview && $this->posts && current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
    3749                 /**
    3750                  * Filters the single post for preview mode.
    3751                  *
    3752                  * @since 2.7.0
    3753                  *
    3754                  * @param WP_Post  $post_preview  The Post object.
    3755                  * @param WP_Query &$this         The WP_Query instance (passed by reference).
    3756                  */
    3757                 $this->posts[0] = get_post( apply_filters_ref_array( 'the_preview', array( $this->posts[0], &$this ) ) );
    3758             }
    3759         }
    3760 
    3761         // Put sticky posts at the top of the posts array
    3762         $sticky_posts = get_option('sticky_posts');
    3763         if ( $this->is_home && $page <= 1 && is_array($sticky_posts) && !empty($sticky_posts) && !$q['ignore_sticky_posts'] ) {
    3764             $num_posts = count($this->posts);
    3765             $sticky_offset = 0;
    3766             // Loop over posts and relocate stickies to the front.
    3767             for ( $i = 0; $i < $num_posts; $i++ ) {
    3768                 if ( in_array($this->posts[$i]->ID, $sticky_posts) ) {
    3769                     $sticky_post = $this->posts[$i];
    3770                     // Remove sticky from current position
    3771                     array_splice($this->posts, $i, 1);
    3772                     // Move to front, after other stickies
    3773                     array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
    3774                     // Increment the sticky offset. The next sticky will be placed at this offset.
    3775                     $sticky_offset++;
    3776                     // Remove post from sticky posts array
    3777                     $offset = array_search($sticky_post->ID, $sticky_posts);
    3778                     unset( $sticky_posts[$offset] );
    3779                 }
    3780             }
    3781 
    3782             // If any posts have been excluded specifically, Ignore those that are sticky.
    3783             if ( !empty($sticky_posts) && !empty($q['post__not_in']) )
    3784                 $sticky_posts = array_diff($sticky_posts, $q['post__not_in']);
    3785 
    3786             // Fetch sticky posts that weren't in the query results
    3787             if ( !empty($sticky_posts) ) {
    3788                 $stickies = get_posts( array(
    3789                     'post__in' => $sticky_posts,
    3790                     'post_type' => $post_type,
    3791                     'post_status' => 'publish',
    3792                     'nopaging' => true
    3793                 ) );
    3794 
    3795                 foreach ( $stickies as $sticky_post ) {
    3796                     array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
    3797                     $sticky_offset++;
    3798                 }
    3799             }
    3800         }
    3801 
    3802         // If comments have been fetched as part of the query, make sure comment meta lazy-loading is set up.
    3803         if ( ! empty( $this->comments ) ) {
    3804             wp_queue_comments_for_comment_meta_lazyload( $this->comments );
    3805         }
    3806 
    3807         if ( ! $q['suppress_filters'] ) {
    3808             /**
    3809              * Filters the array of retrieved posts after they've been fetched and
    3810              * internally processed.
    3811              *
    3812              * @since 1.5.0
    3813              *
    3814              * @param array    $posts The array of retrieved posts.
    3815              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3816              */
    3817             $this->posts = apply_filters_ref_array( 'the_posts', array( $this->posts, &$this ) );
    3818         }
    3819 
    3820         // Ensure that any posts added/modified via one of the filters above are
    3821         // of the type WP_Post and are filtered.
    3822         if ( $this->posts ) {
    3823             $this->post_count = count( $this->posts );
    3824 
    3825             $this->posts = array_map( 'get_post', $this->posts );
    3826 
    3827             if ( $q['cache_results'] )
    3828                 update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);
    3829 
    3830             $this->post = reset( $this->posts );
    3831         } else {
    3832             $this->post_count = 0;
    3833             $this->posts = array();
    3834         }
    3835 
    3836         if ( $q['lazy_load_term_meta'] ) {
    3837             wp_queue_posts_for_term_meta_lazyload( $this->posts );
    3838         }
    3839 
    3840         return $this->posts;
    3841     }
    3842 
    3843     /**
    3844      * Set up the amount of found posts and the number of pages (if limit clause was used)
    3845      * for the current query.
    3846      *
    3847      * @since 3.5.0
    3848      * @access private
    3849      *
    3850      * @param array  $q      Query variables.
    3851      * @param string $limits LIMIT clauses of the query.
    3852      */
    3853     private function set_found_posts( $q, $limits ) {
    3854         // Bail if posts is an empty array. Continue if posts is an empty string,
    3855         // null, or false to accommodate caching plugins that fill posts later.
    3856         if ( $q['no_found_rows'] || ( is_array( $this->posts ) && ! $this->posts ) )
    3857             return;
    3858 
    3859         if ( ! empty( $limits ) ) {
    3860             /**
    3861              * Filters the query to run for retrieving the found posts.
    3862              *
    3863              * @since 2.1.0
    3864              *
    3865              * @param string   $found_posts The query to run to find the found posts.
    3866              * @param WP_Query &$this       The WP_Query instance (passed by reference).
    3867              */
    3868             $this->found_posts = $this->db->get_var( apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) ) );
    3869         } else {
    3870             $this->found_posts = count( $this->posts );
    3871         }
    3872 
    3873         /**
    3874          * Filters the number of found posts for the query.
    3875          *
    3876          * @since 2.1.0
    3877          *
    3878          * @param int      $found_posts The number of posts found.
    3879          * @param WP_Query &$this       The WP_Query instance (passed by reference).
    3880          */
    3881         $this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
    3882 
    3883         if ( ! empty( $limits ) )
    3884             $this->max_num_pages = ceil( $this->found_posts / $q['posts_per_page'] );
    3885     }
    3886 
    3887     /**
    3888      * Set up the next post and iterate current post index.
    3889      *
    3890      * @since 1.5.0
    3891      * @access public
    3892      *
    3893      * @return WP_Post Next post.
    3894      */
    3895     public function next_post() {
    3896 
    3897         $this->current_post++;
    3898 
    3899         $this->post = $this->posts[$this->current_post];
    3900         return $this->post;
    3901     }
    3902 
    3903     /**
    3904      * Sets up the current post.
    3905      *
    3906      * Retrieves the next post, sets up the post, sets the 'in the loop'
    3907      * property to true.
    3908      *
    3909      * @since 1.5.0
    3910      * @access public
    3911      *
    3912      * @global WP_Post $post
    3913      */
    3914     public function the_post() {
    3915         global $post;
    3916         $this->in_the_loop = true;
    3917 
    3918         if ( $this->current_post == -1 ) // loop has just started
    3919             /**
    3920              * Fires once the loop is started.
    3921              *
    3922              * @since 2.0.0
    3923              *
    3924              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3925              */
    3926             do_action_ref_array( 'loop_start', array( &$this ) );
    3927 
    3928         $post = $this->next_post();
    3929         $this->setup_postdata( $post );
    3930     }
    3931 
    3932     /**
    3933      * Determines whether there are more posts available in the loop.
    3934      *
    3935      * Calls the {@see 'loop_end'} action when the loop is complete.
    3936      *
    3937      * @since 1.5.0
    3938      * @access public
    3939      *
    3940      * @return bool True if posts are available, false if end of loop.
    3941      */
    3942     public function have_posts() {
    3943         if ( $this->current_post + 1 < $this->post_count ) {
    3944             return true;
    3945         } elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
    3946             /**
    3947              * Fires once the loop has ended.
    3948              *
    3949              * @since 2.0.0
    3950              *
    3951              * @param WP_Query &$this The WP_Query instance (passed by reference).
    3952              */
    3953             do_action_ref_array( 'loop_end', array( &$this ) );
    3954             // Do some cleaning up after the loop
    3955             $this->rewind_posts();
    3956         }
    3957 
    3958         $this->in_the_loop = false;
    3959         return false;
    3960     }
    3961 
    3962     /**
    3963      * Rewind the posts and reset post index.
    3964      *
    3965      * @since 1.5.0
    3966      * @access public
    3967      */
    3968     public function rewind_posts() {
    3969         $this->current_post = -1;
    3970         if ( $this->post_count > 0 ) {
    3971             $this->post = $this->posts[0];
    3972         }
    3973     }
    3974 
    3975     /**
    3976      * Iterate current comment index and return WP_Comment object.
    3977      *
    3978      * @since 2.2.0
    3979      * @access public
    3980      *
    3981      * @return WP_Comment Comment object.
    3982      */
    3983     public function next_comment() {
    3984         $this->current_comment++;
    3985 
    3986         $this->comment = $this->comments[$this->current_comment];
    3987         return $this->comment;
    3988     }
    3989 
    3990     /**
    3991      * Sets up the current comment.
    3992      *
    3993      * @since 2.2.0
    3994      * @access public
    3995      * @global WP_Comment $comment Current comment.
    3996      */
    3997     public function the_comment() {
    3998         global $comment;
    3999 
    4000         $comment = $this->next_comment();
    4001 
    4002         if ( $this->current_comment == 0 ) {
    4003             /**
    4004              * Fires once the comment loop is started.
    4005              *
    4006              * @since 2.2.0
    4007              */
    4008             do_action( 'comment_loop_start' );
    4009         }
    4010     }
    4011 
    4012     /**
    4013      * Whether there are more comments available.
    4014      *
    4015      * Automatically rewinds comments when finished.
    4016      *
    4017      * @since 2.2.0
    4018      * @access public
    4019      *
    4020      * @return bool True, if more comments. False, if no more posts.
    4021      */
    4022     public function have_comments() {
    4023         if ( $this->current_comment + 1 < $this->comment_count ) {
    4024             return true;
    4025         } elseif ( $this->current_comment + 1 == $this->comment_count ) {
    4026             $this->rewind_comments();
    4027         }
    4028 
    4029         return false;
    4030     }
    4031 
    4032     /**
    4033      * Rewind the comments, resets the comment index and comment to first.
    4034      *
    4035      * @since 2.2.0
    4036      * @access public
    4037      */
    4038     public function rewind_comments() {
    4039         $this->current_comment = -1;
    4040         if ( $this->comment_count > 0 ) {
    4041             $this->comment = $this->comments[0];
    4042         }
    4043     }
    4044 
    4045     /**
    4046      * Sets up the WordPress query by parsing query string.
    4047      *
    4048      * @since 1.5.0
    4049      * @access public
    4050      *
    4051      * @param string $query URL query string.
    4052      * @return array List of posts.
    4053      */
    4054     public function query( $query ) {
    4055         $this->init();
    4056         $this->query = $this->query_vars = wp_parse_args( $query );
    4057         return $this->get_posts();
    4058     }
    4059 
    4060     /**
    4061      * Retrieve queried object.
    4062      *
    4063      * If queried object is not set, then the queried object will be set from
    4064      * the category, tag, taxonomy, posts page, single post, page, or author
    4065      * query variable. After it is set up, it will be returned.
    4066      *
    4067      * @since 1.5.0
    4068      * @access public
    4069      *
    4070      * @return object
    4071      */
    4072     public function get_queried_object() {
    4073         if ( isset($this->queried_object) )
    4074             return $this->queried_object;
    4075 
    4076         $this->queried_object = null;
    4077         $this->queried_object_id = null;
    4078 
    4079         if ( $this->is_category || $this->is_tag || $this->is_tax ) {
    4080             if ( $this->is_category ) {
    4081                 if ( $this->get( 'cat' ) ) {
    4082                     $term = get_term( $this->get( 'cat' ), 'category' );
    4083                 } elseif ( $this->get( 'category_name' ) ) {
    4084                     $term = get_term_by( 'slug', $this->get( 'category_name' ), 'category' );
    4085                 }
    4086             } elseif ( $this->is_tag ) {
    4087                 if ( $this->get( 'tag_id' ) ) {
    4088                     $term = get_term( $this->get( 'tag_id' ), 'post_tag' );
    4089                 } elseif ( $this->get( 'tag' ) ) {
    4090                     $term = get_term_by( 'slug', $this->get( 'tag' ), 'post_tag' );
    4091                 }
    4092             } else {
    4093                 // For other tax queries, grab the first term from the first clause.
    4094                 $tax_query_in_and = wp_list_filter( $this->tax_query->queried_terms, array( 'operator' => 'NOT IN' ), 'NOT' );
    4095 
    4096                 if ( ! empty( $tax_query_in_and ) ) {
    4097                     $queried_taxonomies = array_keys( $tax_query_in_and );
    4098                     $matched_taxonomy = reset( $queried_taxonomies );
    4099                     $query = $tax_query_in_and[ $matched_taxonomy ];
    4100 
    4101                     if ( $query['terms'] ) {
    4102                         if ( 'term_id' == $query['field'] ) {
    4103                             $term = get_term( reset( $query['terms'] ), $matched_taxonomy );
    4104                         } else {
    4105                             $term = get_term_by( $query['field'], reset( $query['terms'] ), $matched_taxonomy );
    4106                         }
    4107                     }
    4108                 }
    4109             }
    4110 
    4111             if ( ! empty( $term ) && ! is_wp_error( $term ) )  {
    4112                 $this->queried_object = $term;
    4113                 $this->queried_object_id = (int) $term->term_id;
    4114 
    4115                 if ( $this->is_category && 'category' === $this->queried_object->taxonomy )
    4116                     _make_cat_compat( $this->queried_object );
    4117             }
    4118         } elseif ( $this->is_post_type_archive ) {
    4119             $post_type = $this->get( 'post_type' );
    4120             if ( is_array( $post_type ) )
    4121                 $post_type = reset( $post_type );
    4122             $this->queried_object = get_post_type_object( $post_type );
    4123         } elseif ( $this->is_posts_page ) {
    4124             $page_for_posts = get_option('page_for_posts');
    4125             $this->queried_object = get_post( $page_for_posts );
    4126             $this->queried_object_id = (int) $this->queried_object->ID;
    4127         } elseif ( $this->is_singular && ! empty( $this->post ) ) {
    4128             $this->queried_object = $this->post;
    4129             $this->queried_object_id = (int) $this->post->ID;
    4130         } elseif ( $this->is_author ) {
    4131             $this->queried_object_id = (int) $this->get('author');
    4132             $this->queried_object = get_userdata( $this->queried_object_id );
    4133         }
    4134 
    4135         return $this->queried_object;
    4136     }
    4137 
    4138     /**
    4139      * Retrieve ID of the current queried object.
    4140      *
    4141      * @since 1.5.0
    4142      * @access public
    4143      *
    4144      * @return int
    4145      */
    4146     public function get_queried_object_id() {
    4147         $this->get_queried_object();
    4148 
    4149         if ( isset($this->queried_object_id) ) {
    4150             return $this->queried_object_id;
    4151         }
    4152 
    4153         return 0;
    4154     }
    4155 
    4156     /**
    4157      * Constructor.
    4158      *
    4159      * Sets up the WordPress query, if parameter is not empty.
    4160      *
    4161      * @since 1.5.0
    4162      * @access public
    4163      *
    4164      * @param string|array $query URL query string or array of vars.
    4165      */
    4166     public function __construct( $query = '' ) {
    4167         $this->db = $GLOBALS['wpdb'];
    4168 
    4169         if ( ! empty( $query ) ) {
    4170             $this->query( $query );
    4171         }
    4172     }
    4173 
    4174     /**
    4175      * Make private properties readable for backward compatibility.
    4176      *
    4177      * @since 4.0.0
    4178      * @access public
    4179      *
    4180      * @param string $name Property to get.
    4181      * @return mixed Property.
    4182      */
    4183     public function __get( $name ) {
    4184         if ( in_array( $name, $this->compat_fields ) ) {
    4185             return $this->$name;
    4186         }
    4187     }
    4188 
    4189     /**
    4190      * Make private properties checkable for backward compatibility.
    4191      *
    4192      * @since 4.0.0
    4193      * @access public
    4194      *
    4195      * @param string $name Property to check if set.
    4196      * @return bool Whether the property is set.
    4197      */
    4198     public function __isset( $name ) {
    4199         if ( in_array( $name, $this->compat_fields ) ) {
    4200             return isset( $this->$name );
    4201         }
    4202     }
    4203 
    4204     /**
    4205      * Make private/protected methods readable for backward compatibility.
    4206      *
    4207      * @since 4.0.0
    4208      * @access public
    4209      *
    4210      * @param callable $name      Method to call.
    4211      * @param array    $arguments Arguments to pass when calling.
    4212      * @return mixed|false Return value of the callback, false otherwise.
    4213      */
    4214     public function __call( $name, $arguments ) {
    4215         if ( in_array( $name, $this->compat_methods ) ) {
    4216             return call_user_func_array( array( $this, $name ), $arguments );
    4217         }
    4218         return false;
    4219     }
    4220 
    4221     /**
    4222      * Is the query for an existing archive page?
    4223      *
    4224      * Month, Year, Category, Author, Post Type archive...
    4225      *
    4226      * @since 3.1.0
    4227      *
    4228      * @return bool
    4229      */
    4230     public function is_archive() {
    4231         return (bool) $this->is_archive;
    4232     }
    4233 
    4234     /**
    4235      * Is the query for an existing post type archive page?
    4236      *
    4237      * @since 3.1.0
    4238      *
    4239      * @param mixed $post_types Optional. Post type or array of posts types to check against.
    4240      * @return bool
    4241      */
    4242     public function is_post_type_archive( $post_types = '' ) {
    4243         if ( empty( $post_types ) || ! $this->is_post_type_archive )
    4244             return (bool) $this->is_post_type_archive;
    4245 
    4246         $post_type = $this->get( 'post_type' );
    4247         if ( is_array( $post_type ) )
    4248             $post_type = reset( $post_type );
    4249         $post_type_object = get_post_type_object( $post_type );
    4250 
    4251         return in_array( $post_type_object->name, (array) $post_types );
    4252     }
    4253 
    4254     /**
    4255      * Is the query for an existing attachment page?
    4256      *
    4257      * @since 3.1.0
    4258      *
    4259      * @param mixed $attachment Attachment ID, title, slug, or array of such.
    4260      * @return bool
    4261      */
    4262     public function is_attachment( $attachment = '' ) {
    4263         if ( ! $this->is_attachment ) {
    4264             return false;
    4265         }
    4266 
    4267         if ( empty( $attachment ) ) {
    4268             return true;
    4269         }
    4270 
    4271         $attachment = array_map( 'strval', (array) $attachment );
    4272 
    4273         $post_obj = $this->get_queried_object();
    4274 
    4275         if ( in_array( (string) $post_obj->ID, $attachment ) ) {
    4276             return true;
    4277         } elseif ( in_array( $post_obj->post_title, $attachment ) ) {
    4278             return true;
    4279         } elseif ( in_array( $post_obj->post_name, $attachment ) ) {
    4280             return true;
    4281         }
    4282         return false;
    4283     }
    4284 
    4285     /**
    4286      * Is the query for an existing author archive page?
    4287      *
    4288      * If the $author parameter is specified, this function will additionally
    4289      * check if the query is for one of the authors specified.
    4290      *
    4291      * @since 3.1.0
    4292      *
    4293      * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
    4294      * @return bool
    4295      */
    4296     public function is_author( $author = '' ) {
    4297         if ( !$this->is_author )
    4298             return false;
    4299 
    4300         if ( empty($author) )
    4301             return true;
    4302 
    4303         $author_obj = $this->get_queried_object();
    4304 
    4305         $author = array_map( 'strval', (array) $author );
    4306 
    4307         if ( in_array( (string) $author_obj->ID, $author ) )
    4308             return true;
    4309         elseif ( in_array( $author_obj->nickname, $author ) )
    4310             return true;
    4311         elseif ( in_array( $author_obj->user_nicename, $author ) )
    4312             return true;
    4313 
    4314         return false;
    4315     }
    4316 
    4317     /**
    4318      * Is the query for an existing category archive page?
    4319      *
    4320      * If the $category parameter is specified, this function will additionally
    4321      * check if the query is for one of the categories specified.
    4322      *
    4323      * @since 3.1.0
    4324      *
    4325      * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
    4326      * @return bool
    4327      */
    4328     public function is_category( $category = '' ) {
    4329         if ( !$this->is_category )
    4330             return false;
    4331 
    4332         if ( empty($category) )
    4333             return true;
    4334 
    4335         $cat_obj = $this->get_queried_object();
    4336 
    4337         $category = array_map( 'strval', (array) $category );
    4338 
    4339         if ( in_array( (string) $cat_obj->term_id, $category ) )
    4340             return true;
    4341         elseif ( in_array( $cat_obj->name, $category ) )
    4342             return true;
    4343         elseif ( in_array( $cat_obj->slug, $category ) )
    4344             return true;
    4345 
    4346         return false;
    4347     }
    4348 
    4349     /**
    4350      * Is the query for an existing tag archive page?
    4351      *
    4352      * If the $tag parameter is specified, this function will additionally
    4353      * check if the query is for one of the tags specified.
    4354      *
    4355      * @since 3.1.0
    4356      *
    4357      * @param mixed $tag Optional. Tag ID, name, slug, or array of Tag IDs, names, and slugs.
    4358      * @return bool
    4359      */
    4360     public function is_tag( $tag = '' ) {
    4361         if ( ! $this->is_tag )
    4362             return false;
    4363 
    4364         if ( empty( $tag ) )
    4365             return true;
    4366 
    4367         $tag_obj = $this->get_queried_object();
    4368 
    4369         $tag = array_map( 'strval', (array) $tag );
    4370 
    4371         if ( in_array( (string) $tag_obj->term_id, $tag ) )
    4372             return true;
    4373         elseif ( in_array( $tag_obj->name, $tag ) )
    4374             return true;
    4375         elseif ( in_array( $tag_obj->slug, $tag ) )
    4376             return true;
    4377 
    4378         return false;
    4379     }
    4380 
    4381     /**
    4382      * Is the query for an existing custom taxonomy archive page?
    4383      *
    4384      * If the $taxonomy parameter is specified, this function will additionally
    4385      * check if the query is for that specific $taxonomy.
    4386      *
    4387      * If the $term parameter is specified in addition to the $taxonomy parameter,
    4388      * this function will additionally check if the query is for one of the terms
    4389      * specified.
    4390      *
    4391      * @since 3.1.0
    4392      *
    4393      * @global array $wp_taxonomies
    4394      *
    4395      * @param mixed $taxonomy Optional. Taxonomy slug or slugs.
    4396      * @param mixed $term     Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
    4397      * @return bool True for custom taxonomy archive pages, false for built-in taxonomies (category and tag archives).
    4398      */
    4399     public function is_tax( $taxonomy = '', $term = '' ) {
    4400         global $wp_taxonomies;
    4401 
    4402         if ( !$this->is_tax )
    4403             return false;
    4404 
    4405         if ( empty( $taxonomy ) )
    4406             return true;
    4407 
    4408         $queried_object = $this->get_queried_object();
    4409         $tax_array = array_intersect( array_keys( $wp_taxonomies ), (array) $taxonomy );
    4410         $term_array = (array) $term;
    4411 
    4412         // Check that the taxonomy matches.
    4413         if ( ! ( isset( $queried_object->taxonomy ) && count( $tax_array ) && in_array( $queried_object->taxonomy, $tax_array ) ) )
    4414             return false;
    4415 
    4416         // Only a Taxonomy provided.
    4417         if ( empty( $term ) )
    4418             return true;
    4419 
    4420         return isset( $queried_object->term_id ) &&
    4421             count( array_intersect(
    4422                 array( $queried_object->term_id, $queried_object->name, $queried_object->slug ),
    4423                 $term_array
    4424             ) );
    4425     }
    4426 
    4427     /**
    4428      * Whether the current URL is within the comments popup window.
    4429      *
    4430      * @since 3.1.0
    4431      * @deprecated 4.5.0
    4432      *
    4433      * @return bool
    4434      */
    4435     public function is_comments_popup() {
    4436         _deprecated_function( __FUNCTION__, '4.5.0' );
    4437 
    4438         return false;
    4439     }
    4440 
    4441     /**
    4442      * Is the query for an existing date archive?
    4443      *
    4444      * @since 3.1.0
    4445      *
    4446      * @return bool
    4447      */
    4448     public function is_date() {
    4449         return (bool) $this->is_date;
    4450     }
    4451 
    4452     /**
    4453      * Is the query for an existing day archive?
    4454      *
    4455      * @since 3.1.0
    4456      *
    4457      * @return bool
    4458      */
    4459     public function is_day() {
    4460         return (bool) $this->is_day;
    4461     }
    4462 
    4463     /**
    4464      * Is the query for a feed?
    4465      *
    4466      * @since 3.1.0
    4467      *
    4468      * @param string|array $feeds Optional feed types to check.
    4469      * @return bool
    4470      */
    4471     public function is_feed( $feeds = '' ) {
    4472         if ( empty( $feeds ) || ! $this->is_feed )
    4473             return (bool) $this->is_feed;
    4474         $qv = $this->get( 'feed' );
    4475         if ( 'feed' == $qv )
    4476             $qv = get_default_feed();
    4477         return in_array( $qv, (array) $feeds );
    4478     }
    4479 
    4480     /**
    4481      * Is the query for a comments feed?
    4482      *
    4483      * @since 3.1.0
    4484      *
    4485      * @return bool
    4486      */
    4487     public function is_comment_feed() {
    4488         return (bool) $this->is_comment_feed;
    4489     }
    4490 
    4491     /**
    4492      * Is the query for the front page of the site?
    4493      *
    4494      * This is for what is displayed at your site's main URL.
    4495      *
    4496      * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
    4497      *
    4498      * If you set a static page for the front page of your site, this function will return
    4499      * true when viewing that page.
    4500      *
    4501      * Otherwise the same as @see WP_Query::is_home()
    4502      *
    4503      * @since 3.1.0
    4504      *
    4505      * @return bool True, if front of site.
    4506      */
    4507     public function is_front_page() {
    4508         // most likely case
    4509         if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
    4510             return true;
    4511         elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
    4512             return true;
    4513         else
    4514             return false;
    4515     }
    4516 
    4517     /**
    4518      * Is the query for the blog homepage?
    4519      *
    4520      * This is the page which shows the time based blog content of your site.
    4521      *
    4522      * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
    4523      *
    4524      * If you set a static page for the front page of your site, this function will return
    4525      * true only on the page you set as the "Posts page".
    4526      *
    4527      * @see WP_Query::is_front_page()
    4528      *
    4529      * @since 3.1.0
    4530      *
    4531      * @return bool True if blog view homepage.
    4532      */
    4533     public function is_home() {
    4534         return (bool) $this->is_home;
    4535     }
    4536 
    4537     /**
    4538      * Is the query for an existing month archive?
    4539      *
    4540      * @since 3.1.0
    4541      *
    4542      * @return bool
    4543      */
    4544     public function is_month() {
    4545         return (bool) $this->is_month;
    4546     }
    4547 
    4548     /**
    4549      * Is the query for an existing single page?
    4550      *
    4551      * If the $page parameter is specified, this function will additionally
    4552      * check if the query is for one of the pages specified.
    4553      *
    4554      * @see WP_Query::is_single()
    4555      * @see WP_Query::is_singular()
    4556      *
    4557      * @since 3.1.0
    4558      *
    4559      * @param int|string|array $page Optional. Page ID, title, slug, path, or array of such. Default empty.
    4560      * @return bool Whether the query is for an existing single page.
    4561      */
    4562     public function is_page( $page = '' ) {
    4563         if ( !$this->is_page )
    4564             return false;
    4565 
    4566         if ( empty( $page ) )
    4567             return true;
    4568 
    4569         $page_obj = $this->get_queried_object();
    4570 
    4571         $page = array_map( 'strval', (array) $page );
    4572 
    4573         if ( in_array( (string) $page_obj->ID, $page ) ) {
    4574             return true;
    4575         } elseif ( in_array( $page_obj->post_title, $page ) ) {
    4576             return true;
    4577         } elseif ( in_array( $page_obj->post_name, $page ) ) {
    4578             return true;
    4579         } else {
    4580             foreach ( $page as $pagepath ) {
    4581                 if ( ! strpos( $pagepath, '/' ) ) {
    4582                     continue;
    4583                 }
    4584                 $pagepath_obj = get_page_by_path( $pagepath );
    4585 
    4586                 if ( $pagepath_obj && ( $pagepath_obj->ID == $page_obj->ID ) ) {
    4587                     return true;
    4588                 }
    4589             }
    4590         }
    4591 
    4592         return false;
    4593     }
    4594 
    4595     /**
    4596      * Is the query for paged result and not for the first page?
    4597      *
    4598      * @since 3.1.0
    4599      *
    4600      * @return bool
    4601      */
    4602     public function is_paged() {
    4603         return (bool) $this->is_paged;
    4604     }
    4605 
    4606     /**
    4607      * Is the query for a post or page preview?
    4608      *
    4609      * @since 3.1.0
    4610      *
    4611      * @return bool
    4612      */
    4613     public function is_preview() {
    4614         return (bool) $this->is_preview;
    4615     }
    4616 
    4617     /**
    4618      * Is the query for the robots file?
    4619      *
    4620      * @since 3.1.0
    4621      *
    4622      * @return bool
    4623      */
    4624     public function is_robots() {
    4625         return (bool) $this->is_robots;
    4626     }
    4627 
    4628     /**
    4629      * Is the query for a search?
    4630      *
    4631      * @since 3.1.0
    4632      *
    4633      * @return bool
    4634      */
    4635     public function is_search() {
    4636         return (bool) $this->is_search;
    4637     }
    4638 
    4639     /**
    4640      * Is the query for an existing single post?
    4641      *
    4642      * Works for any post type, except attachments and pages
    4643      *
    4644      * If the $post parameter is specified, this function will additionally
    4645      * check if the query is for one of the Posts specified.
    4646      *
    4647      * @see WP_Query::is_page()
    4648      * @see WP_Query::is_singular()
    4649      *
    4650      * @since 3.1.0
    4651      *
    4652      * @param int|string|array $post Optional. Post ID, title, slug, path, or array of such. Default empty.
    4653      * @return bool Whether the query is for an existing single post.
    4654      */
    4655     public function is_single( $post = '' ) {
    4656         if ( !$this->is_single )
    4657             return false;
    4658 
    4659         if ( empty($post) )
    4660             return true;
    4661 
    4662         $post_obj = $this->get_queried_object();
    4663 
    4664         $post = array_map( 'strval', (array) $post );
    4665 
    4666         if ( in_array( (string) $post_obj->ID, $post ) ) {
    4667             return true;
    4668         } elseif ( in_array( $post_obj->post_title, $post ) ) {
    4669             return true;
    4670         } elseif ( in_array( $post_obj->post_name, $post ) ) {
    4671             return true;
    4672         } else {
    4673             foreach ( $post as $postpath ) {
    4674                 if ( ! strpos( $postpath, '/' ) ) {
    4675                     continue;
    4676                 }
    4677                 $postpath_obj = get_page_by_path( $postpath, OBJECT, $post_obj->post_type );
    4678 
    4679                 if ( $postpath_obj && ( $postpath_obj->ID == $post_obj->ID ) ) {
    4680                     return true;
    4681                 }
    4682             }
    4683         }
    4684         return false;
    4685     }
    4686 
    4687     /**
    4688      * Is the query for an existing single post of any post type (post, attachment, page, ... )?
    4689      *
    4690      * If the $post_types parameter is specified, this function will additionally
    4691      * check if the query is for one of the Posts Types specified.
    4692      *
    4693      * @see WP_Query::is_page()
    4694      * @see WP_Query::is_single()
    4695      *
    4696      * @since 3.1.0
    4697      *
    4698      * @param string|array $post_types Optional. Post type or array of post types. Default empty.
    4699      * @return bool Whether the query is for an existing single post of any of the given post types.
    4700      */
    4701     public function is_singular( $post_types = '' ) {
    4702         if ( empty( $post_types ) || !$this->is_singular )
    4703             return (bool) $this->is_singular;
    4704 
    4705         $post_obj = $this->get_queried_object();
    4706 
    4707         return in_array( $post_obj->post_type, (array) $post_types );
    4708     }
    4709 
    4710     /**
    4711      * Is the query for a specific time?
    4712      *
    4713      * @since 3.1.0
    4714      *
    4715      * @return bool
    4716      */
    4717     public function is_time() {
    4718         return (bool) $this->is_time;
    4719     }
    4720 
    4721     /**
    4722      * Is the query for a trackback endpoint call?
    4723      *
    4724      * @since 3.1.0
    4725      *
    4726      * @return bool
    4727      */
    4728     public function is_trackback() {
    4729         return (bool) $this->is_trackback;
    4730     }
    4731 
    4732     /**
    4733      * Is the query for an existing year archive?
    4734      *
    4735      * @since 3.1.0
    4736      *
    4737      * @return bool
    4738      */
    4739     public function is_year() {
    4740         return (bool) $this->is_year;
    4741     }
    4742 
    4743     /**
    4744      * Is the query a 404 (returns no results)?
    4745      *
    4746      * @since 3.1.0
    4747      *
    4748      * @return bool
    4749      */
    4750     public function is_404() {
    4751         return (bool) $this->is_404;
    4752     }
    4753 
    4754     /**
    4755      * Is the query for an embedded post?
    4756      *
    4757      * @since 4.4.0
    4758      *
    4759      * @return bool
    4760      */
    4761     public function is_embed() {
    4762         return (bool) $this->is_embed;
    4763     }
    4764 
    4765     /**
    4766      * Is the query the main query?
    4767      *
    4768      * @since 3.3.0
    4769      *
    4770      * @global WP_Query $wp_query Global WP_Query instance.
    4771      *
    4772      * @return bool
    4773      */
    4774     public function is_main_query() {
    4775         global $wp_the_query;
    4776         return $wp_the_query === $this;
    4777     }
    4778 
    4779     /**
    4780      * Set up global post data.
    4781      *
    4782      * @since 4.1.0
    4783      * @since 4.4.0 Added the ability to pass a post ID to `$post`.
    4784      *
    4785      * @global int             $id
    4786      * @global WP_User         $authordata
    4787      * @global string|int|bool $currentday
    4788      * @global string|int|bool $currentmonth
    4789      * @global int             $page
    4790      * @global array           $pages
    4791      * @global int             $multipage
    4792      * @global int             $more
    4793      * @global int             $numpages
    4794      *
    4795      * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
    4796      * @return true True when finished.
    4797      */
    4798     public function setup_postdata( $post ) {
    4799         global $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages;
    4800 
    4801         if ( ! ( $post instanceof WP_Post ) ) {
    4802             $post = get_post( $post );
    4803         }
    4804 
    4805         if ( ! $post ) {
    4806             return;
    4807         }
    4808 
    4809         $id = (int) $post->ID;
    4810 
    4811         $authordata = get_userdata($post->post_author);
    4812 
    4813         $currentday = mysql2date('d.m.y', $post->post_date, false);
    4814         $currentmonth = mysql2date('m', $post->post_date, false);
    4815         $numpages = 1;
    4816         $multipage = 0;
    4817         $page = $this->get( 'page' );
    4818         if ( ! $page )
    4819             $page = 1;
    4820 
    4821         /*
    4822          * Force full post content when viewing the permalink for the $post,
    4823          * or when on an RSS feed. Otherwise respect the 'more' tag.
    4824          */
    4825         if ( $post->ID === get_queried_object_id() && ( $this->is_page() || $this->is_single() ) ) {
    4826             $more = 1;
    4827         } elseif ( $this->is_feed() ) {
    4828             $more = 1;
    4829         } else {
    4830             $more = 0;
    4831         }
    4832 
    4833         $content = $post->post_content;
    4834         if ( false !== strpos( $content, '<!--nextpage-->' ) ) {
    4835             $content = str_replace( "\n<!--nextpage-->\n", '<!--nextpage-->', $content );
    4836             $content = str_replace( "\n<!--nextpage-->", '<!--nextpage-->', $content );
    4837             $content = str_replace( "<!--nextpage-->\n", '<!--nextpage-->', $content );
    4838 
    4839             // Ignore nextpage at the beginning of the content.
    4840             if ( 0 === strpos( $content, '<!--nextpage-->' ) )
    4841                 $content = substr( $content, 15 );
    4842 
    4843             $pages = explode('<!--nextpage-->', $content);
    4844         } else {
    4845             $pages = array( $post->post_content );
    4846         }
    4847 
    4848         /**
    4849          * Filters the "pages" derived from splitting the post content.
    4850          *
    4851          * "Pages" are determined by splitting the post content based on the presence
    4852          * of `<!-- nextpage -->` tags.
    4853          *
    4854          * @since 4.4.0
    4855          *
    4856          * @param array   $pages Array of "pages" derived from the post content.
    4857          *                       of `<!-- nextpage -->` tags..
    4858          * @param WP_Post $post  Current post object.
    4859          */
    4860         $pages = apply_filters( 'content_pagination', $pages, $post );
    4861 
    4862         $numpages = count( $pages );
    4863 
    4864         if ( $numpages > 1 ) {
    4865             if ( $page > 1 ) {
    4866                 $more = 1;
    4867             }
    4868             $multipage = 1;
    4869         } else {
    4870             $multipage = 0;
    4871         }
    4872 
    4873         /**
    4874          * Fires once the post data has been setup.
    4875          *
    4876          * @since 2.8.0
    4877          * @since 4.1.0 Introduced `$this` parameter.
    4878          *
    4879          * @param WP_Post  &$post The Post object (passed by reference).
    4880          * @param WP_Query &$this The current Query object (passed by reference).
    4881          */
    4882         do_action_ref_array( 'the_post', array( &$post, &$this ) );
    4883 
    4884         return true;
    4885     }
    4886     /**
    4887      * After looping through a nested query, this function
    4888      * restores the $post global to the current post in this query.
    4889      *
    4890      * @since 3.7.0
    4891      *
    4892      * @global WP_Post $post
    4893      */
    4894     public function reset_postdata() {
    4895         if ( ! empty( $this->post ) ) {
    4896             $GLOBALS['post'] = $this->post;
    4897             $this->setup_postdata( $this->post );
    4898         }
    4899     }
    4900 
    4901     /**
    4902      * Lazyload term meta for posts in the loop.
    4903      *
    4904      * @since 4.4.0
    4905      * @deprecated 4.5.0 See wp_queue_posts_for_term_meta_lazyload().
    4906      *
    4907      * @param mixed $check
    4908      * @param int   $term_id
    4909      * @return mixed
    4910      */
    4911     public function lazyload_term_meta( $check, $term_id ) {
    4912         _deprecated_function( __METHOD__, '4.5.0' );
    4913         return $check;
    4914     }
    4915 
    4916     /**
    4917      * Lazyload comment meta for comments in the loop.
    4918      *
    4919      * @since 4.4.0
    4920      * @deprecated 4.5.0 See wp_queue_comments_for_comment_meta_lazyload().
    4921      *
    4922      * @param mixed $check
    4923      * @param int   $comment_id
    4924      * @return mixed
    4925      */
    4926     public function lazyload_comment_meta( $check, $comment_id ) {
    4927         _deprecated_function( __METHOD__, '4.5.0' );
    4928         return $check;
    4929     }
    4930 }
    4931 
    4932840/**
    4933841 * Redirect old slugs to the correct permalink.
  • trunk/src/wp-settings.php

    r38282 r38351  
    141141require( ABSPATH . WPINC . '/class-wp-role.php' );
    142142require( ABSPATH . WPINC . '/class-wp-user.php' );
     143require( ABSPATH . WPINC . '/class-wp-query.php' );
    143144require( ABSPATH . WPINC . '/query.php' );
    144145require( ABSPATH . WPINC . '/date.php' );
Note: See TracChangeset for help on using the changeset viewer.