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