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