Wordpress 3.5
[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 to the user is on. It
6  * also provides functionality to 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');
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 its 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
2174                 if ( $q['page_id'] ) {
2175                         if  ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
2176                                 $q['p'] = $q['page_id'];
2177                                 $where = " AND {$wpdb->posts}.ID = " . $q['page_id'];
2178                         }
2179                 }
2180
2181                 // If a search pattern is specified, load the posts that match
2182                 if ( !empty($q['s']) ) {
2183                         // added slashes screw with quote grouping when done early, so done later
2184                         $q['s'] = stripslashes($q['s']);
2185                         if ( empty( $_GET['s'] ) && $this->is_main_query() )
2186                                 $q['s'] = urldecode($q['s']);
2187                         if ( !empty($q['sentence']) ) {
2188                                 $q['search_terms'] = array($q['s']);
2189                         } else {
2190                                 preg_match_all('/".*?("|$)|((?<=[\r\n\t ",+])|^)[^\r\n\t ",+]+/', $q['s'], $matches);
2191                                 $q['search_terms'] = array_map('_search_terms_tidy', $matches[0]);
2192                         }
2193                         $n = !empty($q['exact']) ? '' : '%';
2194                         $searchand = '';
2195                         foreach( (array) $q['search_terms'] as $term ) {
2196                                 $term = esc_sql( like_escape( $term ) );
2197                                 $search .= "{$searchand}(($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}'))";
2198                                 $searchand = ' AND ';
2199                         }
2200
2201                         if ( !empty($search) ) {
2202                                 $search = " AND ({$search}) ";
2203                                 if ( !is_user_logged_in() )
2204                                         $search .= " AND ($wpdb->posts.post_password = '') ";
2205                         }
2206                 }
2207
2208                 // Allow plugins to contextually add/remove/modify the search section of the database query
2209                 $search = apply_filters_ref_array('posts_search', array( $search, &$this ) );
2210
2211                 // Taxonomies
2212                 if ( !$this->is_singular ) {
2213                         $this->parse_tax_query( $q );
2214
2215                         $clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' );
2216
2217                         $join .= $clauses['join'];
2218                         $where .= $clauses['where'];
2219                 }
2220
2221                 if ( $this->is_tax ) {
2222                         if ( empty($post_type) ) {
2223                                 // Do a fully inclusive search for currently registered post types of queried taxonomies
2224                                 $post_type = array();
2225                                 $taxonomies = wp_list_pluck( $this->tax_query->queries, 'taxonomy' );
2226                                 foreach ( get_post_types( array( 'exclude_from_search' => false ) ) as $pt ) {
2227                                         $object_taxonomies = $pt === 'attachment' ? get_taxonomies_for_attachments() : get_object_taxonomies( $pt );
2228                                         if ( array_intersect( $taxonomies, $object_taxonomies ) )
2229                                                 $post_type[] = $pt;
2230                                 }
2231                                 if ( ! $post_type )
2232                                         $post_type = 'any';
2233
2234                                 $post_status_join = true;
2235                         } elseif ( in_array('attachment', (array) $post_type) ) {
2236                                 $post_status_join = true;
2237                         }
2238                 }
2239
2240                 // Back-compat
2241                 if ( !empty($this->tax_query->queries) ) {
2242                         $tax_query_in_and = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'NOT IN' ), 'NOT' );
2243                         if ( !empty( $tax_query_in_and ) ) {
2244                                 if ( !isset( $q['taxonomy'] ) ) {
2245                                         foreach ( $tax_query_in_and as $a_tax_query ) {
2246                                                 if ( !in_array( $a_tax_query['taxonomy'], array( 'category', 'post_tag' ) ) ) {
2247                                                         $q['taxonomy'] = $a_tax_query['taxonomy'];
2248                                                         if ( 'slug' == $a_tax_query['field'] )
2249                                                                 $q['term'] = $a_tax_query['terms'][0];
2250                                                         else
2251                                                                 $q['term_id'] = $a_tax_query['terms'][0];
2252
2253                                                         break;
2254                                                 }
2255                                         }
2256                                 }
2257
2258                                 $cat_query = wp_list_filter( $tax_query_in_and, array( 'taxonomy' => 'category' ) );
2259                                 if ( !empty( $cat_query ) ) {
2260                                         $cat_query = reset( $cat_query );
2261                                         $the_cat = get_term_by( $cat_query['field'], $cat_query['terms'][0], 'category' );
2262                                         if ( $the_cat ) {
2263                                                 $this->set( 'cat', $the_cat->term_id );
2264                                                 $this->set( 'category_name', $the_cat->slug );
2265                                         }
2266                                         unset( $the_cat );
2267                                 }
2268                                 unset( $cat_query );
2269
2270                                 $tag_query = wp_list_filter( $tax_query_in_and, array( 'taxonomy' => 'post_tag' ) );
2271                                 if ( !empty( $tag_query ) ) {
2272                                         $tag_query = reset( $tag_query );
2273                                         $the_tag = get_term_by( $tag_query['field'], $tag_query['terms'][0], 'post_tag' );
2274                                         if ( $the_tag ) {
2275                                                 $this->set( 'tag_id', $the_tag->term_id );
2276                                         }
2277                                         unset( $the_tag );
2278                                 }
2279                                 unset( $tag_query );
2280                         }
2281                 }
2282
2283                 if ( !empty( $this->tax_query->queries ) || !empty( $this->meta_query->queries ) ) {
2284                         $groupby = "{$wpdb->posts}.ID";
2285                 }
2286
2287                 // Author/user stuff
2288
2289                 if ( empty($q['author']) || ($q['author'] == '0') ) {
2290                         $whichauthor = '';
2291                 } else {
2292                         $q['author'] = (string)urldecode($q['author']);
2293                         $q['author'] = addslashes_gpc($q['author']);
2294                         if ( strpos($q['author'], '-') !== false ) {
2295                                 $eq = '!=';
2296                                 $andor = 'AND';
2297                                 $q['author'] = explode('-', $q['author']);
2298                                 $q['author'] = (string)absint($q['author'][1]);
2299                         } else {
2300                                 $eq = '=';
2301                                 $andor = 'OR';
2302                         }
2303                         $author_array = preg_split('/[,\s]+/', $q['author']);
2304                         $_author_array = array();
2305                         foreach ( $author_array as $key => $_author )
2306                                 $_author_array[] = "$wpdb->posts.post_author " . $eq . ' ' . absint($_author);
2307                         $whichauthor .= ' AND (' . implode(" $andor ", $_author_array) . ')';
2308                         unset($author_array, $_author_array);
2309                 }
2310
2311                 // Author stuff for nice URLs
2312
2313                 if ( '' != $q['author_name'] ) {
2314                         if ( strpos($q['author_name'], '/') !== false ) {
2315                                 $q['author_name'] = explode('/', $q['author_name']);
2316                                 if ( $q['author_name'][ count($q['author_name'])-1 ] ) {
2317                                         $q['author_name'] = $q['author_name'][count($q['author_name'])-1]; // no trailing slash
2318                                 } else {
2319                                         $q['author_name'] = $q['author_name'][count($q['author_name'])-2]; // there was a trailing slash
2320                                 }
2321                         }
2322                         $q['author_name'] = sanitize_title_for_query( $q['author_name'] );
2323                         $q['author'] = get_user_by('slug', $q['author_name']);
2324                         if ( $q['author'] )
2325                                 $q['author'] = $q['author']->ID;
2326                         $whichauthor .= " AND ($wpdb->posts.post_author = " . absint($q['author']) . ')';
2327                 }
2328
2329                 // MIME-Type stuff for attachment browsing
2330
2331                 if ( isset( $q['post_mime_type'] ) && '' != $q['post_mime_type'] )
2332                         $whichmimetype = wp_post_mime_type_where( $q['post_mime_type'], $wpdb->posts );
2333
2334                 $where .= $search . $whichauthor . $whichmimetype;
2335
2336                 if ( empty($q['order']) || ((strtoupper($q['order']) != 'ASC') && (strtoupper($q['order']) != 'DESC')) )
2337                         $q['order'] = 'DESC';
2338
2339                 // Order by
2340                 if ( empty($q['orderby']) ) {
2341                         $orderby = "$wpdb->posts.post_date " . $q['order'];
2342                 } elseif ( 'none' == $q['orderby'] ) {
2343                         $orderby = '';
2344                 } elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
2345                         $orderby = "FIELD( {$wpdb->posts}.ID, $post__in )";
2346                 } else {
2347                         // Used to filter values
2348                         $allowed_keys = array('name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count');
2349                         if ( !empty($q['meta_key']) ) {
2350                                 $allowed_keys[] = $q['meta_key'];
2351                                 $allowed_keys[] = 'meta_value';
2352                                 $allowed_keys[] = 'meta_value_num';
2353                         }
2354                         $q['orderby'] = urldecode($q['orderby']);
2355                         $q['orderby'] = addslashes_gpc($q['orderby']);
2356
2357                         $orderby_array = array();
2358                         foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
2359                                 // Only allow certain values for safety
2360                                 if ( ! in_array($orderby, $allowed_keys) )
2361                                         continue;
2362
2363                                 switch ( $orderby ) {
2364                                         case 'menu_order':
2365                                                 $orderby = "$wpdb->posts.menu_order";
2366                                                 break;
2367                                         case 'ID':
2368                                                 $orderby = "$wpdb->posts.ID";
2369                                                 break;
2370                                         case 'rand':
2371                                                 $orderby = 'RAND()';
2372                                                 break;
2373                                         case $q['meta_key']:
2374                                         case 'meta_value':
2375                                                 $orderby = "$wpdb->postmeta.meta_value";
2376                                                 break;
2377                                         case 'meta_value_num':
2378                                                 $orderby = "$wpdb->postmeta.meta_value+0";
2379                                                 break;
2380                                         case 'comment_count':
2381                                                 $orderby = "$wpdb->posts.comment_count";
2382                                                 break;
2383                                         default:
2384                                                 $orderby = "$wpdb->posts.post_" . $orderby;
2385                                 }
2386
2387                                 $orderby_array[] = $orderby;
2388                         }
2389                         $orderby = implode( ',', $orderby_array );
2390
2391                         if ( empty( $orderby ) )
2392                                 $orderby = "$wpdb->posts.post_date ".$q['order'];
2393                         else
2394                                 $orderby .= " {$q['order']}";
2395                 }
2396
2397                 if ( is_array( $post_type ) ) {
2398                         $post_type_cap = 'multiple_post_type';
2399                 } else {
2400                         $post_type_object = get_post_type_object( $post_type );
2401                         if ( empty( $post_type_object ) )
2402                                 $post_type_cap = $post_type;
2403                 }
2404
2405                 if ( 'any' == $post_type ) {
2406                         $in_search_post_types = get_post_types( array('exclude_from_search' => false) );
2407                         if ( ! empty( $in_search_post_types ) )
2408                                 $where .= " AND $wpdb->posts.post_type IN ('" . join("', '", $in_search_post_types ) . "')";
2409                 } elseif ( !empty( $post_type ) && is_array( $post_type ) ) {
2410                         $where .= " AND $wpdb->posts.post_type IN ('" . join("', '", $post_type) . "')";
2411                 } elseif ( ! empty( $post_type ) ) {
2412                         $where .= " AND $wpdb->posts.post_type = '$post_type'";
2413                         $post_type_object = get_post_type_object ( $post_type );
2414                 } elseif ( $this->is_attachment ) {
2415                         $where .= " AND $wpdb->posts.post_type = 'attachment'";
2416                         $post_type_object = get_post_type_object ( 'attachment' );
2417                 } elseif ( $this->is_page ) {
2418                         $where .= " AND $wpdb->posts.post_type = 'page'";
2419                         $post_type_object = get_post_type_object ( 'page' );
2420                 } else {
2421                         $where .= " AND $wpdb->posts.post_type = 'post'";
2422                         $post_type_object = get_post_type_object ( 'post' );
2423                 }
2424
2425                 if ( ! empty( $post_type_object ) ) {
2426                         $edit_cap = $post_type_object->cap->edit_post;
2427                         $read_cap = $post_type_object->cap->read_post;
2428                         $edit_others_cap = $post_type_object->cap->edit_others_posts;
2429                         $read_private_cap = $post_type_object->cap->read_private_posts;
2430                 } else {
2431                         $edit_cap = 'edit_' . $post_type_cap;
2432                         $read_cap = 'read_' . $post_type_cap;
2433                         $edit_others_cap = 'edit_others_' . $post_type_cap . 's';
2434                         $read_private_cap = 'read_private_' . $post_type_cap . 's';
2435                 }
2436
2437                 if ( ! empty( $q['post_status'] ) ) {
2438                         $statuswheres = array();
2439                         $q_status = $q['post_status'];
2440                         if ( ! is_array( $q_status ) )
2441                                 $q_status = explode(',', $q_status);
2442                         $r_status = array();
2443                         $p_status = array();
2444                         $e_status = array();
2445                         if ( in_array('any', $q_status) ) {
2446                                 foreach ( get_post_stati( array('exclude_from_search' => true) ) as $status )
2447                                         $e_status[] = "$wpdb->posts.post_status <> '$status'";
2448                         } else {
2449                                 foreach ( get_post_stati() as $status ) {
2450                                         if ( in_array( $status, $q_status ) ) {
2451                                                 if ( 'private' == $status )
2452                                                         $p_status[] = "$wpdb->posts.post_status = '$status'";
2453                                                 else
2454                                                         $r_status[] = "$wpdb->posts.post_status = '$status'";
2455                                         }
2456                                 }
2457                         }
2458
2459                         if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) {
2460                                 $r_status = array_merge($r_status, $p_status);
2461                                 unset($p_status);
2462                         }
2463
2464                         if ( !empty($e_status) ) {
2465                                 $statuswheres[] = "(" . join( ' AND ', $e_status ) . ")";
2466                         }
2467                         if ( !empty($r_status) ) {
2468                                 if ( !empty($q['perm'] ) && 'editable' == $q['perm'] && !current_user_can($edit_others_cap) )
2469                                         $statuswheres[] = "($wpdb->posts.post_author = $user_ID " . "AND (" . join( ' OR ', $r_status ) . "))";
2470                                 else
2471                                         $statuswheres[] = "(" . join( ' OR ', $r_status ) . ")";
2472                         }
2473                         if ( !empty($p_status) ) {
2474                                 if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can($read_private_cap) )
2475                                         $statuswheres[] = "($wpdb->posts.post_author = $user_ID " . "AND (" . join( ' OR ', $p_status ) . "))";
2476                                 else
2477                                         $statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
2478                         }
2479                         if ( $post_status_join ) {
2480                                 $join .= " LEFT JOIN $wpdb->posts AS p2 ON ($wpdb->posts.post_parent = p2.ID) ";
2481                                 foreach ( $statuswheres as $index => $statuswhere )
2482                                         $statuswheres[$index] = "($statuswhere OR ($wpdb->posts.post_status = 'inherit' AND " . str_replace($wpdb->posts, 'p2', $statuswhere) . "))";
2483                         }
2484                         foreach ( $statuswheres as $statuswhere )
2485                                 $where .= " AND $statuswhere";
2486                 } elseif ( !$this->is_singular ) {
2487                         $where .= " AND ($wpdb->posts.post_status = 'publish'";
2488
2489                         // Add public states.
2490                         $public_states = get_post_stati( array('public' => true) );
2491                         foreach ( (array) $public_states as $state ) {
2492                                 if ( 'publish' == $state ) // Publish is hard-coded above.
2493                                         continue;
2494                                 $where .= " OR $wpdb->posts.post_status = '$state'";
2495                         }
2496
2497                         if ( $this->is_admin ) {
2498                                 // Add protected states that should show in the admin all list.
2499                                 $admin_all_states = get_post_stati( array('protected' => true, 'show_in_admin_all_list' => true) );
2500                                 foreach ( (array) $admin_all_states as $state )
2501                                         $where .= " OR $wpdb->posts.post_status = '$state'";
2502                         }
2503
2504                         if ( is_user_logged_in() ) {
2505                                 // Add private states that are limited to viewing by the author of a post or someone who has caps to read private states.
2506                                 $private_states = get_post_stati( array('private' => true) );
2507                                 foreach ( (array) $private_states as $state )
2508                                         $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'";
2509                         }
2510
2511                         $where .= ')';
2512                 }
2513
2514                 if ( !empty( $this->meta_query->queries ) ) {
2515                         $clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
2516                         $join .= $clauses['join'];
2517                         $where .= $clauses['where'];
2518                 }
2519
2520                 // Apply filters on where and join prior to paging so that any
2521                 // manipulations to them are reflected in the paging by day queries.
2522                 if ( !$q['suppress_filters'] ) {
2523                         $where = apply_filters_ref_array('posts_where', array( $where, &$this ) );
2524                         $join = apply_filters_ref_array('posts_join', array( $join, &$this ) );
2525                 }
2526
2527                 // Paging
2528                 if ( empty($q['nopaging']) && !$this->is_singular ) {
2529                         $page = absint($q['paged']);
2530                         if ( !$page )
2531                                 $page = 1;
2532
2533                         if ( empty($q['offset']) ) {
2534                                 $pgstrt = ($page - 1) * $q['posts_per_page'] . ', ';
2535                         } else { // we're ignoring $page and using 'offset'
2536                                 $q['offset'] = absint($q['offset']);
2537                                 $pgstrt = $q['offset'] . ', ';
2538                         }
2539                         $limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
2540                 }
2541
2542                 // Comments feeds
2543                 if ( $this->is_comment_feed && ( $this->is_archive || $this->is_search || !$this->is_singular ) ) {
2544                         if ( $this->is_archive || $this->is_search ) {
2545                                 $cjoin = "JOIN $wpdb->posts ON ($wpdb->comments.comment_post_ID = $wpdb->posts.ID) $join ";
2546                                 $cwhere = "WHERE comment_approved = '1' $where";
2547                                 $cgroupby = "$wpdb->comments.comment_id";
2548                         } else { // Other non singular e.g. front
2549                                 $cjoin = "JOIN $wpdb->posts ON ( $wpdb->comments.comment_post_ID = $wpdb->posts.ID )";
2550                                 $cwhere = "WHERE post_status = 'publish' AND comment_approved = '1'";
2551                                 $cgroupby = '';
2552                         }
2553
2554                         if ( !$q['suppress_filters'] ) {
2555                                 $cjoin = apply_filters_ref_array('comment_feed_join', array( $cjoin, &$this ) );
2556                                 $cwhere = apply_filters_ref_array('comment_feed_where', array( $cwhere, &$this ) );
2557                                 $cgroupby = apply_filters_ref_array('comment_feed_groupby', array( $cgroupby, &$this ) );
2558                                 $corderby = apply_filters_ref_array('comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
2559                                 $climits = apply_filters_ref_array('comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
2560                         }
2561                         $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
2562                         $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
2563
2564                         $this->comments = (array) $wpdb->get_results("SELECT $distinct $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere $cgroupby $corderby $climits");
2565                         $this->comment_count = count($this->comments);
2566
2567                         $post_ids = array();
2568
2569                         foreach ( $this->comments as $comment )
2570                                 $post_ids[] = (int) $comment->comment_post_ID;
2571
2572                         $post_ids = join(',', $post_ids);
2573                         $join = '';
2574                         if ( $post_ids )
2575                                 $where = "AND $wpdb->posts.ID IN ($post_ids) ";
2576                         else
2577                                 $where = "AND 0";
2578                 }
2579
2580                 $pieces = array( 'where', 'groupby', 'join', 'orderby', 'distinct', 'fields', 'limits' );
2581
2582                 // Apply post-paging filters on where and join. Only plugins that
2583                 // manipulate paging queries should use these hooks.
2584                 if ( !$q['suppress_filters'] ) {
2585                         $where          = apply_filters_ref_array( 'posts_where_paged', array( $where, &$this ) );
2586                         $groupby        = apply_filters_ref_array( 'posts_groupby',             array( $groupby, &$this ) );
2587                         $join           = apply_filters_ref_array( 'posts_join_paged',  array( $join, &$this ) );
2588                         $orderby        = apply_filters_ref_array( 'posts_orderby',             array( $orderby, &$this ) );
2589                         $distinct       = apply_filters_ref_array( 'posts_distinct',    array( $distinct, &$this ) );
2590                         $limits         = apply_filters_ref_array( 'post_limits',               array( $limits, &$this ) );
2591                         $fields         = apply_filters_ref_array( 'posts_fields',              array( $fields, &$this ) );
2592
2593                         // Filter all clauses at once, for convenience
2594                         $clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
2595                         foreach ( $pieces as $piece )
2596                                 $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
2597                 }
2598
2599                 // Announce current selection parameters. For use by caching plugins.
2600                 do_action( 'posts_selection', $where . $groupby . $orderby . $limits . $join );
2601
2602                 // Filter again for the benefit of caching plugins. Regular plugins should use the hooks above.
2603                 if ( !$q['suppress_filters'] ) {
2604                         $where          = apply_filters_ref_array( 'posts_where_request',               array( $where, &$this ) );
2605                         $groupby        = apply_filters_ref_array( 'posts_groupby_request',             array( $groupby, &$this ) );
2606                         $join           = apply_filters_ref_array( 'posts_join_request',                array( $join, &$this ) );
2607                         $orderby        = apply_filters_ref_array( 'posts_orderby_request',             array( $orderby, &$this ) );
2608                         $distinct       = apply_filters_ref_array( 'posts_distinct_request',    array( $distinct, &$this ) );
2609                         $fields         = apply_filters_ref_array( 'posts_fields_request',              array( $fields, &$this ) );
2610                         $limits         = apply_filters_ref_array( 'post_limits_request',               array( $limits, &$this ) );
2611
2612                         // Filter all clauses at once, for convenience
2613                         $clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );
2614                         foreach ( $pieces as $piece )
2615                                 $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
2616                 }
2617
2618                 if ( ! empty($groupby) )
2619                         $groupby = 'GROUP BY ' . $groupby;
2620                 if ( !empty( $orderby ) )
2621                         $orderby = 'ORDER BY ' . $orderby;
2622
2623                 $found_rows = '';
2624                 if ( !$q['no_found_rows'] && !empty($limits) )
2625                         $found_rows = 'SQL_CALC_FOUND_ROWS';
2626
2627                 $this->request = $old_request = "SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
2628
2629                 if ( !$q['suppress_filters'] ) {
2630                         $this->request = apply_filters_ref_array( 'posts_request', array( $this->request, &$this ) );
2631                 }
2632
2633                 if ( 'ids' == $q['fields'] ) {
2634                         $this->posts = $wpdb->get_col( $this->request );
2635                         $this->post_count = count( $this->posts );
2636                         $this->set_found_posts( $q, $limits );
2637
2638                         return $this->posts;
2639                 }
2640
2641                 if ( 'id=>parent' == $q['fields'] ) {
2642                         $this->posts = $wpdb->get_results( $this->request );
2643                         $this->post_count = count( $this->posts );
2644                         $this->set_found_posts( $q, $limits );
2645
2646                         $r = array();
2647                         foreach ( $this->posts as $post )
2648                                 $r[ $post->ID ] = $post->post_parent;
2649
2650                         return $r;
2651                 }
2652
2653                 $split_the_query = ( $old_request == $this->request && "$wpdb->posts.*" == $fields && !empty( $limits ) && $q['posts_per_page'] < 500 );
2654                 $split_the_query = apply_filters( 'split_the_query', $split_the_query, $this );
2655
2656                 if ( $split_the_query ) {
2657                         // First get the IDs and then fill in the objects
2658
2659                         $this->request = "SELECT $found_rows $distinct $wpdb->posts.ID FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
2660
2661                         $this->request = apply_filters( 'posts_request_ids', $this->request, $this );
2662
2663                         $ids = $wpdb->get_col( $this->request );
2664
2665                         if ( $ids ) {
2666                                 $this->posts = $ids;
2667                                 $this->set_found_posts( $q, $limits );
2668                                 _prime_post_caches( $ids, $q['update_post_term_cache'], $q['update_post_meta_cache'] );
2669                         } else {
2670                                 $this->posts = array();
2671                         }
2672                 } else {
2673                         $this->posts = $wpdb->get_results( $this->request );
2674                         $this->set_found_posts( $q, $limits );
2675                 }
2676
2677                 // Convert to WP_Post objects
2678                 if ( $this->posts )
2679                         $this->posts = array_map( 'get_post', $this->posts );
2680
2681                 // Raw results filter. Prior to status checks.
2682                 if ( !$q['suppress_filters'] )
2683                         $this->posts = apply_filters_ref_array('posts_results', array( $this->posts, &$this ) );
2684
2685                 if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
2686                         $cjoin = apply_filters_ref_array('comment_feed_join', array( '', &$this ) );
2687                         $cwhere = apply_filters_ref_array('comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
2688                         $cgroupby = apply_filters_ref_array('comment_feed_groupby', array( '', &$this ) );
2689                         $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
2690                         $corderby = apply_filters_ref_array('comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
2691                         $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
2692                         $climits = apply_filters_ref_array('comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
2693                         $comments_request = "SELECT $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere $cgroupby $corderby $climits";
2694                         $this->comments = $wpdb->get_results($comments_request);
2695                         $this->comment_count = count($this->comments);
2696                 }
2697
2698                 // Check post status to determine if post should be displayed.
2699                 if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) {
2700                         $status = get_post_status($this->posts[0]);
2701                         $post_status_obj = get_post_status_object($status);
2702                         //$type = get_post_type($this->posts[0]);
2703                         if ( !$post_status_obj->public ) {
2704                                 if ( ! is_user_logged_in() ) {
2705                                         // User must be logged in to view unpublished posts.
2706                                         $this->posts = array();
2707                                 } else {
2708                                         if  ( $post_status_obj->protected ) {
2709                                                 // User must have edit permissions on the draft to preview.
2710                                                 if ( ! current_user_can($edit_cap, $this->posts[0]->ID) ) {
2711                                                         $this->posts = array();
2712                                                 } else {
2713                                                         $this->is_preview = true;
2714                                                         if ( 'future' != $status )
2715                                                                 $this->posts[0]->post_date = current_time('mysql');
2716                                                 }
2717                                         } elseif ( $post_status_obj->private ) {
2718                                                 if ( ! current_user_can($read_cap, $this->posts[0]->ID) )
2719                                                         $this->posts = array();
2720                                         } else {
2721                                                 $this->posts = array();
2722                                         }
2723                                 }
2724                         }
2725
2726                         if ( $this->is_preview && $this->posts && current_user_can( $edit_cap, $this->posts[0]->ID ) )
2727                                 $this->posts[0] = get_post( apply_filters_ref_array( 'the_preview', array( $this->posts[0], &$this ) ) );
2728                 }
2729
2730                 // Put sticky posts at the top of the posts array
2731                 $sticky_posts = get_option('sticky_posts');
2732                 if ( $this->is_home && $page <= 1 && is_array($sticky_posts) && !empty($sticky_posts) && !$q['ignore_sticky_posts'] ) {
2733                         $num_posts = count($this->posts);
2734                         $sticky_offset = 0;
2735                         // Loop over posts and relocate stickies to the front.
2736                         for ( $i = 0; $i < $num_posts; $i++ ) {
2737                                 if ( in_array($this->posts[$i]->ID, $sticky_posts) ) {
2738                                         $sticky_post = $this->posts[$i];
2739                                         // Remove sticky from current position
2740                                         array_splice($this->posts, $i, 1);
2741                                         // Move to front, after other stickies
2742                                         array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
2743                                         // Increment the sticky offset. The next sticky will be placed at this offset.
2744                                         $sticky_offset++;
2745                                         // Remove post from sticky posts array
2746                                         $offset = array_search($sticky_post->ID, $sticky_posts);
2747                                         unset( $sticky_posts[$offset] );
2748                                 }
2749                         }
2750
2751                         // If any posts have been excluded specifically, Ignore those that are sticky.
2752                         if ( !empty($sticky_posts) && !empty($q['post__not_in']) )
2753                                 $sticky_posts = array_diff($sticky_posts, $q['post__not_in']);
2754
2755                         // Fetch sticky posts that weren't in the query results
2756                         if ( !empty($sticky_posts) ) {
2757                                 $stickies = get_posts( array(
2758                                         'post__in' => $sticky_posts,
2759                                         'post_type' => $post_type,
2760                                         'post_status' => 'publish',
2761                                         'nopaging' => true
2762                                 ) );
2763
2764                                 foreach ( $stickies as $sticky_post ) {
2765                                         array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
2766                                         $sticky_offset++;
2767                                 }
2768                         }
2769                 }
2770
2771                 if ( !$q['suppress_filters'] )
2772                         $this->posts = apply_filters_ref_array('the_posts', array( $this->posts, &$this ) );
2773
2774                 // Ensure that any posts added/modified via one of the filters above are
2775                 // of the type WP_Post and are filtered.
2776                 if ( $this->posts ) {
2777                         $this->post_count = count( $this->posts );
2778
2779                         $this->posts = array_map( 'get_post', $this->posts );
2780
2781                         if ( $q['cache_results'] )
2782                                 update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);
2783
2784                         $this->post = reset( $this->posts );
2785                 } else {
2786                         $this->post_count = 0;
2787                         $this->posts = array();
2788                 }
2789
2790                 return $this->posts;
2791         }
2792
2793         /**
2794          * Set up the amount of found posts and the number of pages (if limit clause was used)
2795          * for the current query.
2796          *
2797          * @since 3.5.0
2798          * @access private
2799          */
2800         function set_found_posts( $q, $limits ) {
2801                 global $wpdb;
2802
2803                 // Bail if posts is an empty array. Continue if posts is an empty string
2804                 // null, or false to accommodate caching plugins that fill posts later.
2805                 if ( $q['no_found_rows'] || ( is_array( $this->posts ) && ! $this->posts ) )
2806                         return;
2807
2808                 if ( ! empty( $limits ) )
2809                         $this->found_posts = $wpdb->get_var( apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) ) );
2810                 else
2811                         $this->found_posts = count( $this->posts );
2812
2813                 $this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
2814
2815                 if ( ! empty( $limits ) )
2816                         $this->max_num_pages = ceil( $this->found_posts / $q['posts_per_page'] );
2817         }
2818
2819         /**
2820          * Set up the next post and iterate current post index.
2821          *
2822          * @since 1.5.0
2823          * @access public
2824          *
2825          * @return WP_Post Next post.
2826          */
2827         function next_post() {
2828
2829                 $this->current_post++;
2830
2831                 $this->post = $this->posts[$this->current_post];
2832                 return $this->post;
2833         }
2834
2835         /**
2836          * Sets up the current post.
2837          *
2838          * Retrieves the next post, sets up the post, sets the 'in the loop'
2839          * property to true.
2840          *
2841          * @since 1.5.0
2842          * @access public
2843          * @uses $post
2844          * @uses do_action_ref_array() Calls 'loop_start' if loop has just started
2845          */
2846         function the_post() {
2847                 global $post;
2848                 $this->in_the_loop = true;
2849
2850                 if ( $this->current_post == -1 ) // loop has just started
2851                         do_action_ref_array('loop_start', array(&$this));
2852
2853                 $post = $this->next_post();
2854                 setup_postdata($post);
2855         }
2856
2857         /**
2858          * Whether there are more posts available in the loop.
2859          *
2860          * Calls action 'loop_end', when the loop is complete.
2861          *
2862          * @since 1.5.0
2863          * @access public
2864          * @uses do_action_ref_array() Calls 'loop_end' if loop is ended
2865          *
2866          * @return bool True if posts are available, false if end of loop.
2867          */
2868         function have_posts() {
2869                 if ( $this->current_post + 1 < $this->post_count ) {
2870                         return true;
2871                 } elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
2872                         do_action_ref_array('loop_end', array(&$this));
2873                         // Do some cleaning up after the loop
2874                         $this->rewind_posts();
2875                 }
2876
2877                 $this->in_the_loop = false;
2878                 return false;
2879         }
2880
2881         /**
2882          * Rewind the posts and reset post index.
2883          *
2884          * @since 1.5.0
2885          * @access public
2886          */
2887         function rewind_posts() {
2888                 $this->current_post = -1;
2889                 if ( $this->post_count > 0 ) {
2890                         $this->post = $this->posts[0];
2891                 }
2892         }
2893
2894         /**
2895          * Iterate current comment index and return comment object.
2896          *
2897          * @since 2.2.0
2898          * @access public
2899          *
2900          * @return object Comment object.
2901          */
2902         function next_comment() {
2903                 $this->current_comment++;
2904
2905                 $this->comment = $this->comments[$this->current_comment];
2906                 return $this->comment;
2907         }
2908
2909         /**
2910          * Sets up the current comment.
2911          *
2912          * @since 2.2.0
2913          * @access public
2914          * @global object $comment Current comment.
2915          * @uses do_action() Calls 'comment_loop_start' hook when first comment is processed.
2916          */
2917         function the_comment() {
2918                 global $comment;
2919
2920                 $comment = $this->next_comment();
2921
2922                 if ( $this->current_comment == 0 ) {
2923                         do_action('comment_loop_start');
2924                 }
2925         }
2926
2927         /**
2928          * Whether there are more comments available.
2929          *
2930          * Automatically rewinds comments when finished.
2931          *
2932          * @since 2.2.0
2933          * @access public
2934          *
2935          * @return bool True, if more comments. False, if no more posts.
2936          */
2937         function have_comments() {
2938                 if ( $this->current_comment + 1 < $this->comment_count ) {
2939                         return true;
2940                 } elseif ( $this->current_comment + 1 == $this->comment_count ) {
2941                         $this->rewind_comments();
2942                 }
2943
2944                 return false;
2945         }
2946
2947         /**
2948          * Rewind the comments, resets the comment index and comment to first.
2949          *
2950          * @since 2.2.0
2951          * @access public
2952          */
2953         function rewind_comments() {
2954                 $this->current_comment = -1;
2955                 if ( $this->comment_count > 0 ) {
2956                         $this->comment = $this->comments[0];
2957                 }
2958         }
2959
2960         /**
2961          * Sets up the WordPress query by parsing query string.
2962          *
2963          * @since 1.5.0
2964          * @access public
2965          *
2966          * @param string $query URL query string.
2967          * @return array List of posts.
2968          */
2969         function query( $query ) {
2970                 $this->init();
2971                 $this->query = $this->query_vars = wp_parse_args( $query );
2972                 return $this->get_posts();
2973         }
2974
2975         /**
2976          * Retrieve queried object.
2977          *
2978          * If queried object is not set, then the queried object will be set from
2979          * the category, tag, taxonomy, posts page, single post, page, or author
2980          * query variable. After it is set up, it will be returned.
2981          *
2982          * @since 1.5.0
2983          * @access public
2984          *
2985          * @return object
2986          */
2987         function get_queried_object() {
2988                 if ( isset($this->queried_object) )
2989                         return $this->queried_object;
2990
2991                 $this->queried_object = null;
2992                 $this->queried_object_id = 0;
2993
2994                 if ( $this->is_category || $this->is_tag || $this->is_tax ) {
2995                         $tax_query_in_and = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'NOT IN' ), 'NOT' );
2996
2997                         $query = reset( $tax_query_in_and );
2998
2999                         if ( 'term_id' == $query['field'] )
3000                                 $term = get_term( reset( $query['terms'] ), $query['taxonomy'] );
3001                         elseif ( $query['terms'] )
3002                                 $term = get_term_by( $query['field'], reset( $query['terms'] ), $query['taxonomy'] );
3003
3004                         if ( ! empty( $term ) && ! is_wp_error( $term ) )  {
3005                                 $this->queried_object = $term;
3006                                 $this->queried_object_id = (int) $term->term_id;
3007
3008                                 if ( $this->is_category )
3009                                         _make_cat_compat( $this->queried_object );
3010                         }
3011                 } elseif ( $this->is_post_type_archive ) {
3012                         $this->queried_object = get_post_type_object( $this->get('post_type') );
3013                 } elseif ( $this->is_posts_page ) {
3014                         $page_for_posts = get_option('page_for_posts');
3015                         $this->queried_object = get_post( $page_for_posts );
3016                         $this->queried_object_id = (int) $this->queried_object->ID;
3017                 } elseif ( $this->is_singular && !is_null($this->post) ) {
3018                         $this->queried_object = $this->post;
3019                         $this->queried_object_id = (int) $this->post->ID;
3020                 } elseif ( $this->is_author ) {
3021                         $this->queried_object_id = (int) $this->get('author');
3022                         $this->queried_object = get_userdata( $this->queried_object_id );
3023                 }
3024
3025                 return $this->queried_object;
3026         }
3027
3028         /**
3029          * Retrieve ID of the current queried object.
3030          *
3031          * @since 1.5.0
3032          * @access public
3033          *
3034          * @return int
3035          */
3036         function get_queried_object_id() {
3037                 $this->get_queried_object();
3038
3039                 if ( isset($this->queried_object_id) ) {
3040                         return $this->queried_object_id;
3041                 }
3042
3043                 return 0;
3044         }
3045
3046         /**
3047          * Constructor.
3048          *
3049          * Sets up the WordPress query, if parameter is not empty.
3050          *
3051          * @since 1.5.0
3052          * @access public
3053          *
3054          * @param string $query URL query string.
3055          * @return WP_Query
3056          */
3057         function __construct($query = '') {
3058                 if ( ! empty($query) ) {
3059                         $this->query($query);
3060                 }
3061         }
3062
3063         /**
3064          * Is the query for an existing archive page?
3065          *
3066          * Month, Year, Category, Author, Post Type archive...
3067          *
3068          * @since 3.1.0
3069          *
3070          * @return bool
3071          */
3072         function is_archive() {
3073                 return (bool) $this->is_archive;
3074         }
3075
3076         /**
3077          * Is the query for an existing post type archive page?
3078          *
3079          * @since 3.1.0
3080          *
3081          * @param mixed $post_types Optional. Post type or array of posts types to check against.
3082          * @return bool
3083          */
3084         function is_post_type_archive( $post_types = '' ) {
3085                 if ( empty( $post_types ) || !$this->is_post_type_archive )
3086                         return (bool) $this->is_post_type_archive;
3087
3088                 $post_type_object = $this->get_queried_object();
3089
3090                 return in_array( $post_type_object->name, (array) $post_types );
3091         }
3092
3093         /**
3094          * Is the query for an existing attachment page?
3095          *
3096          * @since 3.1.0
3097          *
3098          * @return bool
3099          */
3100         function is_attachment() {
3101                 return (bool) $this->is_attachment;
3102         }
3103
3104         /**
3105          * Is the query for an existing author archive page?
3106          *
3107          * If the $author parameter is specified, this function will additionally
3108          * check if the query is for one of the authors specified.
3109          *
3110          * @since 3.1.0
3111          *
3112          * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
3113          * @return bool
3114          */
3115         function is_author( $author = '' ) {
3116                 if ( !$this->is_author )
3117                         return false;
3118
3119                 if ( empty($author) )
3120                         return true;
3121
3122                 $author_obj = $this->get_queried_object();
3123
3124                 $author = (array) $author;
3125
3126                 if ( in_array( $author_obj->ID, $author ) )
3127                         return true;
3128                 elseif ( in_array( $author_obj->nickname, $author ) )
3129                         return true;
3130                 elseif ( in_array( $author_obj->user_nicename, $author ) )
3131                         return true;
3132
3133                 return false;
3134         }
3135
3136         /**
3137          * Is the query for an existing category archive page?
3138          *
3139          * If the $category parameter is specified, this function will additionally
3140          * check if the query is for one of the categories specified.
3141          *
3142          * @since 3.1.0
3143          *
3144          * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
3145          * @return bool
3146          */
3147         function is_category( $category = '' ) {
3148                 if ( !$this->is_category )
3149                         return false;
3150
3151                 if ( empty($category) )
3152                         return true;
3153
3154                 $cat_obj = $this->get_queried_object();
3155
3156                 $category = (array) $category;
3157
3158                 if ( in_array( $cat_obj->term_id, $category ) )
3159                         return true;
3160                 elseif ( in_array( $cat_obj->name, $category ) )
3161                         return true;
3162                 elseif ( in_array( $cat_obj->slug, $category ) )
3163                         return true;
3164
3165                 return false;
3166         }
3167
3168         /**
3169          * Is the query for an existing tag archive page?
3170          *
3171          * If the $tag parameter is specified, this function will additionally
3172          * check if the query is for one of the tags specified.
3173          *
3174          * @since 3.1.0
3175          *
3176          * @param mixed $slug Optional. Tag slug or array of slugs.
3177          * @return bool
3178          */
3179         function is_tag( $slug = '' ) {
3180                 if ( !$this->is_tag )
3181                         return false;
3182
3183                 if ( empty( $slug ) )
3184                         return true;
3185
3186                 $tag_obj = $this->get_queried_object();
3187
3188                 $slug = (array) $slug;
3189
3190                 if ( in_array( $tag_obj->slug, $slug ) )
3191                         return true;
3192
3193                 return false;
3194         }
3195
3196         /**
3197          * Is the query for an existing taxonomy archive page?
3198          *
3199          * If the $taxonomy parameter is specified, this function will additionally
3200          * check if the query is for that specific $taxonomy.
3201          *
3202          * If the $term parameter is specified in addition to the $taxonomy parameter,
3203          * this function will additionally check if the query is for one of the terms
3204          * specified.
3205          *
3206          * @since 3.1.0
3207          *
3208          * @param mixed $taxonomy Optional. Taxonomy slug or slugs.
3209          * @param mixed $term. Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
3210          * @return bool
3211          */
3212         function is_tax( $taxonomy = '', $term = '' ) {
3213                 global $wp_taxonomies;
3214
3215                 if ( !$this->is_tax )
3216                         return false;
3217
3218                 if ( empty( $taxonomy ) )
3219                         return true;
3220
3221                 $queried_object = $this->get_queried_object();
3222                 $tax_array = array_intersect( array_keys( $wp_taxonomies ), (array) $taxonomy );
3223                 $term_array = (array) $term;
3224
3225                 // Check that the taxonomy matches.
3226                 if ( ! ( isset( $queried_object->taxonomy ) && count( $tax_array ) && in_array( $queried_object->taxonomy, $tax_array ) ) )
3227                         return false;
3228
3229                 // Only a Taxonomy provided.
3230                 if ( empty( $term ) )
3231                         return true;
3232
3233                 return isset( $queried_object->term_id ) &&
3234                         count( array_intersect(
3235                                 array( $queried_object->term_id, $queried_object->name, $queried_object->slug ),
3236                                 $term_array
3237                         ) );
3238         }
3239
3240         /**
3241          * Whether the current URL is within the comments popup window.
3242          *
3243          * @since 3.1.0
3244          *
3245          * @return bool
3246          */
3247         function is_comments_popup() {
3248                 return (bool) $this->is_comments_popup;
3249         }
3250
3251         /**
3252          * Is the query for an existing date archive?
3253          *
3254          * @since 3.1.0
3255          *
3256          * @return bool
3257          */
3258         function is_date() {
3259                 return (bool) $this->is_date;
3260         }
3261
3262         /**
3263          * Is the query for an existing day archive?
3264          *
3265          * @since 3.1.0
3266          *
3267          * @return bool
3268          */
3269         function is_day() {
3270                 return (bool) $this->is_day;
3271         }
3272
3273         /**
3274          * Is the query for a feed?
3275          *
3276          * @since 3.1.0
3277          *
3278          * @param string|array $feeds Optional feed types to check.
3279          * @return bool
3280          */
3281         function is_feed( $feeds = '' ) {
3282                 if ( empty( $feeds ) || ! $this->is_feed )
3283                         return (bool) $this->is_feed;
3284                 $qv = $this->get( 'feed' );
3285                 if ( 'feed' == $qv )
3286                         $qv = get_default_feed();
3287                 return in_array( $qv, (array) $feeds );
3288         }
3289
3290         /**
3291          * Is the query for a comments feed?
3292          *
3293          * @since 3.1.0
3294          *
3295          * @return bool
3296          */
3297         function is_comment_feed() {
3298                 return (bool) $this->is_comment_feed;
3299         }
3300
3301         /**
3302          * Is the query for the front page of the site?
3303          *
3304          * This is for what is displayed at your site's main URL.
3305          *
3306          * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
3307          *
3308          * If you set a static page for the front page of your site, this function will return
3309          * true when viewing that page.
3310          *
3311          * Otherwise the same as @see WP_Query::is_home()
3312          *
3313          * @since 3.1.0
3314          * @uses is_home()
3315          * @uses get_option()
3316          *
3317          * @return bool True, if front of site.
3318          */
3319         function is_front_page() {
3320                 // most likely case
3321                 if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
3322                         return true;
3323                 elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
3324                         return true;
3325                 else
3326                         return false;
3327         }
3328
3329         /**
3330          * Is the query for the blog homepage?
3331          *
3332          * This is the page which shows the time based blog content of your site.
3333          *
3334          * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
3335          *
3336          * If you set a static page for the front page of your site, this function will return
3337          * true only on the page you set as the "Posts page".
3338          *
3339          * @see WP_Query::is_front_page()
3340          *
3341          * @since 3.1.0
3342          *
3343          * @return bool True if blog view homepage.
3344          */
3345         function is_home() {
3346                 return (bool) $this->is_home;
3347         }
3348
3349         /**
3350          * Is the query for an existing month archive?
3351          *
3352          * @since 3.1.0
3353          *
3354          * @return bool
3355          */
3356         function is_month() {
3357                 return (bool) $this->is_month;
3358         }
3359
3360         /**
3361          * Is the query for an existing single page?
3362          *
3363          * If the $page parameter is specified, this function will additionally
3364          * check if the query is for one of the pages specified.
3365          *
3366          * @see WP_Query::is_single()
3367          * @see WP_Query::is_singular()
3368          *
3369          * @since 3.1.0
3370          *
3371          * @param mixed $page Page ID, title, slug, or array of such.
3372          * @return bool
3373          */
3374         function is_page( $page = '' ) {
3375                 if ( !$this->is_page )
3376                         return false;
3377
3378                 if ( empty( $page ) )
3379                         return true;
3380
3381                 $page_obj = $this->get_queried_object();
3382
3383                 $page = (array) $page;
3384
3385                 if ( in_array( $page_obj->ID, $page ) )
3386                         return true;
3387                 elseif ( in_array( $page_obj->post_title, $page ) )
3388                         return true;
3389                 else if ( in_array( $page_obj->post_name, $page ) )
3390                         return true;
3391
3392                 return false;
3393         }
3394
3395         /**
3396          * Is the query for paged result and not for the first page?
3397          *
3398          * @since 3.1.0
3399          *
3400          * @return bool
3401          */
3402         function is_paged() {
3403                 return (bool) $this->is_paged;
3404         }
3405
3406         /**
3407          * Is the query for a post or page preview?
3408          *
3409          * @since 3.1.0
3410          *
3411          * @return bool
3412          */
3413         function is_preview() {
3414                 return (bool) $this->is_preview;
3415         }
3416
3417         /**
3418          * Is the query for the robots file?
3419          *
3420          * @since 3.1.0
3421          *
3422          * @return bool
3423          */
3424         function is_robots() {
3425                 return (bool) $this->is_robots;
3426         }
3427
3428         /**
3429          * Is the query for a search?
3430          *
3431          * @since 3.1.0
3432          *
3433          * @return bool
3434          */
3435         function is_search() {
3436                 return (bool) $this->is_search;
3437         }
3438
3439         /**
3440          * Is the query for an existing single post?
3441          *
3442          * Works for any post type, except attachments and pages
3443          *
3444          * If the $post parameter is specified, this function will additionally
3445          * check if the query is for one of the Posts specified.
3446          *
3447          * @see WP_Query::is_page()
3448          * @see WP_Query::is_singular()
3449          *
3450          * @since 3.1.0
3451          *
3452          * @param mixed $post Post ID, title, slug, or array of such.
3453          * @return bool
3454          */
3455         function is_single( $post = '' ) {
3456                 if ( !$this->is_single )
3457                         return false;
3458
3459                 if ( empty($post) )
3460                         return true;
3461
3462                 $post_obj = $this->get_queried_object();
3463
3464                 $post = (array) $post;
3465
3466                 if ( in_array( $post_obj->ID, $post ) )
3467                         return true;
3468                 elseif ( in_array( $post_obj->post_title, $post ) )
3469                         return true;
3470                 elseif ( in_array( $post_obj->post_name, $post ) )
3471                         return true;
3472
3473                 return false;
3474         }
3475
3476         /**
3477          * Is the query for an existing single post of any post type (post, attachment, page, ... )?
3478          *
3479          * If the $post_types parameter is specified, this function will additionally
3480          * check if the query is for one of the Posts Types specified.
3481          *
3482          * @see WP_Query::is_page()
3483          * @see WP_Query::is_single()
3484          *
3485          * @since 3.1.0
3486          *
3487          * @param mixed $post_types Optional. Post Type or array of Post Types
3488          * @return bool
3489          */
3490         function is_singular( $post_types = '' ) {
3491                 if ( empty( $post_types ) || !$this->is_singular )
3492                         return (bool) $this->is_singular;
3493
3494                 $post_obj = $this->get_queried_object();
3495
3496                 return in_array( $post_obj->post_type, (array) $post_types );
3497         }
3498
3499         /**
3500          * Is the query for a specific time?
3501          *
3502          * @since 3.1.0
3503          *
3504          * @return bool
3505          */
3506         function is_time() {
3507                 return (bool) $this->is_time;
3508         }
3509
3510         /**
3511          * Is the query for a trackback endpoint call?
3512          *
3513          * @since 3.1.0
3514          *
3515          * @return bool
3516          */
3517         function is_trackback() {
3518                 return (bool) $this->is_trackback;
3519         }
3520
3521         /**
3522          * Is the query for an existing year archive?
3523          *
3524          * @since 3.1.0
3525          *
3526          * @return bool
3527          */
3528         function is_year() {
3529                 return (bool) $this->is_year;
3530         }
3531
3532         /**
3533          * Is the query a 404 (returns no results)?
3534          *