home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / class-wp-query.php < prev    next >
Encoding:
PHP Script  |  2018-01-24  |  121.1 KB  |  4,095 lines

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