| [ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
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 unset($GLOBALS['wp_query']); 91 $GLOBALS['wp_query'] = new WP_Query(); 92 return $GLOBALS['wp_query']->query($query); 93 } 94 95 /** 96 * Destroy the previous query and set up a new query. 97 * 98 * This should be used after {@link query_posts()} and before another {@link 99 * query_posts()}. This will remove obscure bugs that occur when the previous 100 * wp_query object is not destroyed properly before another is set up. 101 * 102 * @since 2.3.0 103 * @uses $wp_query 104 */ 105 function wp_reset_query() { 106 unset($GLOBALS['wp_query']); 107 $GLOBALS['wp_query'] = $GLOBALS['wp_the_query']; 108 wp_reset_postdata(); 109 } 110 111 /** 112 * After looping through a separate query, this function restores 113 * the $post global to the current post in the main query 114 * 115 * @since 3.0.0 116 * @uses $wp_query 117 */ 118 function wp_reset_postdata() { 119 global $wp_query; 120 if ( !empty($wp_query->post) ) { 121 $GLOBALS['post'] = $wp_query->post; 122 setup_postdata($wp_query->post); 123 } 124 } 125 126 /* 127 * Query type checks. 128 */ 129 130 /** 131 * Is the query for an archive page? 132 * 133 * Month, Year, Category, Author, Post Type archive... 134 * 135 * @see WP_Query::is_archive() 136 * @since 1.5.0 137 * @uses $wp_query 138 * 139 * @return bool 140 */ 141 function is_archive() { 142 global $wp_query; 143 144 if ( ! isset( $wp_query ) ) { 145 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 146 return false; 147 } 148 149 return $wp_query->is_archive(); 150 } 151 152 /** 153 * Is the query for a post type archive page? 154 * 155 * @see WP_Query::is_post_type_archive() 156 * @since 3.1.0 157 * @uses $wp_query 158 * 159 * @param mixed $post_types Optional. Post type or array of posts types to check against. 160 * @return bool 161 */ 162 function is_post_type_archive( $post_types = '' ) { 163 global $wp_query; 164 165 if ( ! isset( $wp_query ) ) { 166 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 167 return false; 168 } 169 170 return $wp_query->is_post_type_archive( $post_types ); 171 } 172 173 /** 174 * Is the query for an attachment page? 175 * 176 * @see WP_Query::is_attachment() 177 * @since 2.0.0 178 * @uses $wp_query 179 * 180 * @return bool 181 */ 182 function is_attachment() { 183 global $wp_query; 184 185 if ( ! isset( $wp_query ) ) { 186 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 187 return false; 188 } 189 190 return $wp_query->is_attachment(); 191 } 192 193 /** 194 * Is the query for an author archive page? 195 * 196 * If the $author parameter is specified, this function will additionally 197 * check if the query is for one of the authors specified. 198 * 199 * @see WP_Query::is_author() 200 * @since 1.5.0 201 * @uses $wp_query 202 * 203 * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames 204 * @return bool 205 */ 206 function is_author( $author = '' ) { 207 global $wp_query; 208 209 if ( ! isset( $wp_query ) ) { 210 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 211 return false; 212 } 213 214 return $wp_query->is_author( $author ); 215 } 216 217 /** 218 * Is the query for a category archive page? 219 * 220 * If the $category parameter is specified, this function will additionally 221 * check if the query is for one of the categories specified. 222 * 223 * @see WP_Query::is_category() 224 * @since 1.5.0 225 * @uses $wp_query 226 * 227 * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs. 228 * @return bool 229 */ 230 function is_category( $category = '' ) { 231 global $wp_query; 232 233 if ( ! isset( $wp_query ) ) { 234 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 235 return false; 236 } 237 238 return $wp_query->is_category( $category ); 239 } 240 241 /** 242 * Is the query for a tag archive page? 243 * 244 * If the $tag parameter is specified, this function will additionally 245 * check if the query is for one of the tags specified. 246 * 247 * @see WP_Query::is_tag() 248 * @since 2.3.0 249 * @uses $wp_query 250 * 251 * @param mixed $slug Optional. Tag slug or array of slugs. 252 * @return bool 253 */ 254 function is_tag( $slug = '' ) { 255 global $wp_query; 256 257 if ( ! isset( $wp_query ) ) { 258 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 259 return false; 260 } 261 262 return $wp_query->is_tag( $slug ); 263 } 264 265 /** 266 * Is the query for a taxonomy archive page? 267 * 268 * If the $taxonomy parameter is specified, this function will additionally 269 * check if the query is for that specific $taxonomy. 270 * 271 * If the $term parameter is specified in addition to the $taxonomy parameter, 272 * this function will additionally check if the query is for one of the terms 273 * specified. 274 * 275 * @see WP_Query::is_tax() 276 * @since 2.5.0 277 * @uses $wp_query 278 * 279 * @param mixed $taxonomy Optional. Taxonomy slug or slugs. 280 * @param mixed $term Optional. Term ID, name, slug or array of Term IDs, names, and slugs. 281 * @return bool 282 */ 283 function is_tax( $taxonomy = '', $term = '' ) { 284 global $wp_query; 285 286 if ( ! isset( $wp_query ) ) { 287 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 288 return false; 289 } 290 291 return $wp_query->is_tax( $taxonomy, $term ); 292 } 293 294 /** 295 * Whether the current URL is within the comments popup window. 296 * 297 * @see WP_Query::is_comments_popup() 298 * @since 1.5.0 299 * @uses $wp_query 300 * 301 * @return bool 302 */ 303 function is_comments_popup() { 304 global $wp_query; 305 306 if ( ! isset( $wp_query ) ) { 307 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 308 return false; 309 } 310 311 return $wp_query->is_comments_popup(); 312 } 313 314 /** 315 * Is the query for a date archive? 316 * 317 * @see WP_Query::is_date() 318 * @since 1.5.0 319 * @uses $wp_query 320 * 321 * @return bool 322 */ 323 function is_date() { 324 global $wp_query; 325 326 if ( ! isset( $wp_query ) ) { 327 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 328 return false; 329 } 330 331 return $wp_query->is_date(); 332 } 333 334 /** 335 * Is the query for a day archive? 336 * 337 * @see WP_Query::is_day() 338 * @since 1.5.0 339 * @uses $wp_query 340 * 341 * @return bool 342 */ 343 function is_day() { 344 global $wp_query; 345 346 if ( ! isset( $wp_query ) ) { 347 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 348 return false; 349 } 350 351 return $wp_query->is_day(); 352 } 353 354 /** 355 * Is the query for a feed? 356 * 357 * @see WP_Query::is_feed() 358 * @since 1.5.0 359 * @uses $wp_query 360 * 361 * @param string|array $feeds Optional feed types to check. 362 * @return bool 363 */ 364 function is_feed( $feeds = '' ) { 365 global $wp_query; 366 367 if ( ! isset( $wp_query ) ) { 368 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 369 return false; 370 } 371 372 return $wp_query->is_feed( $feeds ); 373 } 374 375 /** 376 * Is the query for a comments feed? 377 * 378 * @see WP_Query::is_comments_feed() 379 * @since 3.0.0 380 * @uses $wp_query 381 * 382 * @return bool 383 */ 384 function is_comment_feed() { 385 global $wp_query; 386 387 if ( ! isset( $wp_query ) ) { 388 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 389 return false; 390 } 391 392 return $wp_query->is_comment_feed(); 393 } 394 395 /** 396 * Is the query for the front page of the site? 397 * 398 * This is for what is displayed at your site's main URL. 399 * 400 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'. 401 * 402 * If you set a static page for the front page of your site, this function will return 403 * true when viewing that page. 404 * 405 * Otherwise the same as @see is_home() 406 * 407 * @see WP_Query::is_front_page() 408 * @since 2.5.0 409 * @uses is_home() 410 * @uses get_option() 411 * 412 * @return bool True, if front of site. 413 */ 414 function is_front_page() { 415 global $wp_query; 416 417 if ( ! isset( $wp_query ) ) { 418 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 419 return false; 420 } 421 422 return $wp_query->is_front_page(); 423 } 424 425 /** 426 * Is the query for the blog homepage? 427 * 428 * This is the page which shows the time based blog content of your site. 429 * 430 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'. 431 * 432 * If you set a static page for the front page of your site, this function will return 433 * true only on the page you set as the "Posts page". 434 * 435 * @see is_front_page() 436 * 437 * @see WP_Query::is_home() 438 * @since 1.5.0 439 * @uses $wp_query 440 * 441 * @return bool True if blog view homepage. 442 */ 443 function is_home() { 444 global $wp_query; 445 446 if ( ! isset( $wp_query ) ) { 447 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 448 return false; 449 } 450 451 return $wp_query->is_home(); 452 } 453 454 /** 455 * Is the query for a month archive? 456 * 457 * @see WP_Query::is_month() 458 * @since 1.5.0 459 * @uses $wp_query 460 * 461 * @return bool 462 */ 463 function is_month() { 464 global $wp_query; 465 466 if ( ! isset( $wp_query ) ) { 467 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 468 return false; 469 } 470 471 return $wp_query->is_month(); 472 } 473 474 /** 475 * Is the query for a single page? 476 * 477 * If the $page parameter is specified, this function will additionally 478 * check if the query is for one of the pages specified. 479 * 480 * @see is_single() 481 * @see is_singular() 482 * 483 * @see WP_Query::is_page() 484 * @since 1.5.0 485 * @uses $wp_query 486 * 487 * @param mixed $page Page ID, title, slug, or array of such. 488 * @return bool 489 */ 490 function is_page( $page = '' ) { 491 global $wp_query; 492 493 if ( ! isset( $wp_query ) ) { 494 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 495 return false; 496 } 497 498 return $wp_query->is_page( $page ); 499 } 500 501 /** 502 * Is the query for paged result and not for the first page? 503 * 504 * @see WP_Query::is_paged() 505 * @since 1.5.0 506 * @uses $wp_query 507 * 508 * @return bool 509 */ 510 function is_paged() { 511 global $wp_query; 512 513 if ( ! isset( $wp_query ) ) { 514 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 515 return false; 516 } 517 518 return $wp_query->is_paged(); 519 } 520 521 /** 522 * Is the query for a post or page preview? 523 * 524 * @see WP_Query::is_preview() 525 * @since 2.0.0 526 * @uses $wp_query 527 * 528 * @return bool 529 */ 530 function is_preview() { 531 global $wp_query; 532 533 if ( ! isset( $wp_query ) ) { 534 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 535 return false; 536 } 537 538 return $wp_query->is_preview(); 539 } 540 541 /** 542 * Is the query for the robots file? 543 * 544 * @see WP_Query::is_robots() 545 * @since 2.1.0 546 * @uses $wp_query 547 * 548 * @return bool 549 */ 550 function is_robots() { 551 global $wp_query; 552 553 if ( ! isset( $wp_query ) ) { 554 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 555 return false; 556 } 557 558 return $wp_query->is_robots(); 559 } 560 561 /** 562 * Is the query for a search? 563 * 564 * @see WP_Query::is_search() 565 * @since 1.5.0 566 * @uses $wp_query 567 * 568 * @return bool 569 */ 570 function is_search() { 571 global $wp_query; 572 573 if ( ! isset( $wp_query ) ) { 574 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 575 return false; 576 } 577 578 return $wp_query->is_search(); 579 } 580 581 /** 582 * Is the query for a single post? 583 * 584 * Works for any post type, except attachments and pages 585 * 586 * If the $post parameter is specified, this function will additionally 587 * check if the query is for one of the Posts specified. 588 * 589 * @see is_page() 590 * @see is_singular() 591 * 592 * @see WP_Query::is_single() 593 * @since 1.5.0 594 * @uses $wp_query 595 * 596 * @param mixed $post Post ID, title, slug, or array of such. 597 * @return bool 598 */ 599 function is_single( $post = '' ) { 600 global $wp_query; 601 602 if ( ! isset( $wp_query ) ) { 603 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 604 return false; 605 } 606 607 return $wp_query->is_single( $post ); 608 } 609 610 /** 611 * Is the query for a single post of any post type (post, attachment, page, ... )? 612 * 613 * If the $post_types parameter is specified, this function will additionally 614 * check if the query is for one of the Posts Types specified. 615 * 616 * @see is_page() 617 * @see is_single() 618 * 619 * @see WP_Query::is_singular() 620 * @since 1.5.0 621 * @uses $wp_query 622 * 623 * @param mixed $post_types Optional. Post Type or array of Post Types 624 * @return bool 625 */ 626 function is_singular( $post_types = '' ) { 627 global $wp_query; 628 629 if ( ! isset( $wp_query ) ) { 630 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 631 return false; 632 } 633 634 return $wp_query->is_singular( $post_types ); 635 } 636 637 /** 638 * Is the query for a specific time? 639 * 640 * @see WP_Query::is_time() 641 * @since 1.5.0 642 * @uses $wp_query 643 * 644 * @return bool 645 */ 646 function is_time() { 647 global $wp_query; 648 649 if ( ! isset( $wp_query ) ) { 650 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 651 return false; 652 } 653 654 return $wp_query->is_time(); 655 } 656 657 /** 658 * Is the query for a trackback endpoint call? 659 * 660 * @see WP_Query::is_trackback() 661 * @since 1.5.0 662 * @uses $wp_query 663 * 664 * @return bool 665 */ 666 function is_trackback() { 667 global $wp_query; 668 669 if ( ! isset( $wp_query ) ) { 670 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 671 return false; 672 } 673 674 return $wp_query->is_trackback(); 675 } 676 677 /** 678 * Is the query for a specific year? 679 * 680 * @see WP_Query::is_year() 681 * @since 1.5.0 682 * @uses $wp_query 683 * 684 * @return bool 685 */ 686 function is_year() { 687 global $wp_query; 688 689 if ( ! isset( $wp_query ) ) { 690 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 691 return false; 692 } 693 694 return $wp_query->is_year(); 695 } 696 697 /** 698 * Is the query a 404 (returns no results)? 699 * 700 * @see WP_Query::is_404() 701 * @since 1.5.0 702 * @uses $wp_query 703 * 704 * @return bool 705 */ 706 function is_404() { 707 global $wp_query; 708 709 if ( ! isset( $wp_query ) ) { 710 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' ); 711 return false; 712 } 713 714 return $wp_query->is_404(); 715 } 716 717 /** 718 * Is the query the main query? 719 * 720 * @since 3.3.0 721 * 722 * @return bool 723 */ 724 function is_main_query() { 725 global $wp_query; 726 return $wp_query->is_main_query(); 727 } 728 729 /* 730 * The Loop. Post loop control. 731 */ 732 733 /** 734 * Whether current WordPress query has results to loop over. 735 * 736 * @see WP_Query::have_posts() 737 * @since 1.5.0 738 * @uses $wp_query 739 * 740 * @return bool 741 */ 742 function have_posts() { 743 global $wp_query; 744 745 return $wp_query->have_posts(); 746 } 747 748 /** 749 * Whether the caller is in the Loop. 750 * 751 * @since 2.0.0 752 * @uses $wp_query 753 * 754 * @return bool True if caller is within loop, false if loop hasn't started or ended. 755 */ 756 function in_the_loop() { 757 global $wp_query; 758 759 return $wp_query->in_the_loop; 760 } 761 762 /** 763 * Rewind the loop posts. 764 * 765 * @see WP_Query::rewind_posts() 766 * @since 1.5.0 767 * @uses $wp_query 768 * 769 * @return null 770 */ 771 function rewind_posts() { 772 global $wp_query; 773 774 return $wp_query->rewind_posts(); 775 } 776 777 /** 778 * Iterate the post index in the loop. 779 * 780 * @see WP_Query::the_post() 781 * @since 1.5.0 782 * @uses $wp_query 783 */ 784 function the_post() { 785 global $wp_query; 786 787 $wp_query->the_post(); 788 } 789 790 /* 791 * Comments loop. 792 */ 793 794 /** 795 * Whether there are comments to loop over. 796 * 797 * @see WP_Query::have_comments() 798 * @since 2.2.0 799 * @uses $wp_query 800 * 801 * @return bool 802 */ 803 function have_comments() { 804 global $wp_query; 805 return $wp_query->have_comments(); 806 } 807 808 /** 809 * Iterate comment index in the comment loop. 810 * 811 * @see WP_Query::the_comment() 812 * @since 2.2.0 813 * @uses $wp_query 814 * 815 * @return object 816 */ 817 function the_comment() { 818 global $wp_query; 819 return $wp_query->the_comment(); 820 } 821 822 /* 823 * WP_Query 824 */ 825 826 /** 827 * The WordPress Query class. 828 * 829 * @link http://codex.wordpress.org/Function_Reference/WP_Query Codex page. 830 * 831 * @since 1.5.0 832 */ 833 class WP_Query { 834 835 /** 836 * Query vars set by the user 837 * 838 * @since 1.5.0 839 * @access public 840 * @var array 841 */ 842 var $query; 843 844 /** 845 * Query vars, after parsing 846 * 847 * @since 1.5.0 848 * @access public 849 * @var array 850 */ 851 var $query_vars = array(); 852 853 /** 854 * Taxonomy query, as passed to get_tax_sql() 855 * 856 * @since 3.1.0 857 * @access public 858 * @var object WP_Tax_Query 859 */ 860 var $tax_query; 861 862 /** 863 * Metadata query container 864 * 865 * @since 3.2.0 866 * @access public 867 * @var object WP_Meta_Query 868 */ 869 var $meta_query = false; 870 871 /** 872 * Holds the data for a single object that is queried. 873 * 874 * Holds the contents of a post, page, category, attachment. 875 * 876 * @since 1.5.0 877 * @access public 878 * @var object|array 879 */ 880 var $queried_object; 881 882 /** 883 * The ID of the queried object. 884 * 885 * @since 1.5.0 886 * @access public 887 * @var int 888 */ 889 var $queried_object_id; 890 891 /** 892 * Get post database query. 893 * 894 * @since 2.0.1 895 * @access public 896 * @var string 897 */ 898 var $request; 899 900 /** 901 * List of posts. 902 * 903 * @since 1.5.0 904 * @access public 905 * @var array 906 */ 907 var $posts; 908 909 /** 910 * The amount of posts for the current query. 911 * 912 * @since 1.5.0 913 * @access public 914 * @var int 915 */ 916 var $post_count = 0; 917 918 /** 919 * Index of the current item in the loop. 920 * 921 * @since 1.5.0 922 * @access public 923 * @var int 924 */ 925 var $current_post = -1; 926 927 /** 928 * Whether the loop has started and the caller is in the loop. 929 * 930 * @since 2.0.0 931 * @access public 932 * @var bool 933 */ 934 var $in_the_loop = false; 935 936 /** 937 * The current post ID. 938 * 939 * @since 1.5.0 940 * @access public 941 * @var object 942 */ 943 var $post; 944 945 /** 946 * The list of comments for current post. 947 * 948 * @since 2.2.0 949 * @access public 950 * @var array 951 */ 952 var $comments; 953 954 /** 955 * The amount of comments for the posts. 956 * 957 * @since 2.2.0 958 * @access public 959 * @var int 960 */ 961 var $comment_count = 0; 962 963 /** 964 * The index of the comment in the comment loop. 965 * 966 * @since 2.2.0 967 * @access public 968 * @var int 969 */ 970 var $current_comment = -1; 971 972 /** 973 * Current comment ID. 974 * 975 * @since 2.2.0 976 * @access public 977 * @var int 978 */ 979 var $comment; 980 981 /** 982 * Amount of posts if limit clause was not used. 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 ); 1402 1403 foreach ( $keys as $key ) { 1404 if ( !isset($array[$key]) ) 1405 $array[$key] = ''; 1406 } 1407 1408 $array_keys = array('category__in', 'category__not_in', 'category__and', 'post__in', 'post__not_in', 1409 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and'); 1410 1411 foreach ( $array_keys as $key ) { 1412 if ( !isset($array[$key]) ) 1413 $array[$key] = array(); 1414 } 1415 return $array; 1416 } 1417 1418 /** 1419 * Parse a query string and set query type booleans. 1420 * 1421 * @since 1.5.0 1422 * @access public 1423 * 1424 * @param string|array $query Optional query. 1425 */ 1426 function parse_query( $query = '' ) { 1427 if ( ! empty( $query ) ) { 1428 $this->init(); 1429 $this->query = $this->query_vars = wp_parse_args( $query ); 1430 } elseif ( ! isset( $this->query ) ) { 1431 $this->query = $this->query_vars; 1432 } 1433 1434 $this->query_vars = $this->fill_query_vars($this->query_vars); 1435 $qv = &$this->query_vars; 1436 $this->query_vars_changed = true; 1437 1438 if ( ! empty($qv['robots']) ) 1439 $this->is_robots = true; 1440 1441 $qv['p'] = absint($qv['p']); 1442 $qv['page_id'] = absint($qv['page_id']); 1443 $qv['year'] = absint($qv['year']); 1444 $qv['monthnum'] = absint($qv['monthnum']); 1445 $qv['day'] = absint($qv['day']); 1446 $qv['w'] = absint($qv['w']); 1447 $qv['m'] = absint($qv['m']); 1448 $qv['paged'] = absint($qv['paged']); 1449 $qv['cat'] = preg_replace( '|[^0-9,-]|', '', $qv['cat'] ); // comma separated list of positive or negative integers 1450 $qv['pagename'] = trim( $qv['pagename'] ); 1451 $qv['name'] = trim( $qv['name'] ); 1452 if ( '' !== $qv['hour'] ) $qv['hour'] = absint($qv['hour']); 1453 if ( '' !== $qv['minute'] ) $qv['minute'] = absint($qv['minute']); 1454 if ( '' !== $qv['second'] ) $qv['second'] = absint($qv['second']); 1455 1456 // Compat. Map subpost to attachment. 1457 if ( '' != $qv['subpost'] ) 1458 $qv['attachment'] = $qv['subpost']; 1459 if ( '' != $qv['subpost_id'] ) 1460 $qv['attachment_id'] = $qv['subpost_id']; 1461 1462 $qv['attachment_id'] = absint($qv['attachment_id']); 1463 1464 if ( ('' != $qv['attachment']) || !empty($qv['attachment_id']) ) { 1465 $this->is_single = true; 1466 $this->is_attachment = true; 1467 } elseif ( '' != $qv['name'] ) { 1468 $this->is_single = true; 1469 } elseif ( $qv['p'] ) { 1470 $this->is_single = true; 1471 } elseif ( ('' !== $qv['hour']) && ('' !== $qv['minute']) &&('' !== $qv['second']) && ('' != $qv['year']) && ('' != $qv['monthnum']) && ('' != $qv['day']) ) { 1472 // If year, month, day, hour, minute, and second are set, a single 1473 // post is being queried. 1474 $this->is_single = true; 1475 } elseif ( '' != $qv['static'] || '' != $qv['pagename'] || !empty($qv['page_id']) ) { 1476 $this->is_page = true; 1477 $this->is_single = false; 1478 } else { 1479 // Look for archive queries. Dates, categories, authors, search, post type archives. 1480 1481 if ( !empty($qv['s']) ) { 1482 $this->is_search = true; 1483 } 1484 1485 if ( '' !== $qv['second'] ) { 1486 $this->is_time = true; 1487 $this->is_date = true; 1488 } 1489 1490 if ( '' !== $qv['minute'] ) { 1491 $this->is_time = true; 1492 $this->is_date = true; 1493 } 1494 1495 if ( '' !== $qv['hour'] ) { 1496 $this->is_time = true; 1497 $this->is_date = true; 1498 } 1499 1500 if ( $qv['day'] ) { 1501 if ( ! $this->is_date ) { 1502 $this->is_day = true; 1503 $this->is_date = true; 1504 } 1505 } 1506 1507 if ( $qv['monthnum'] ) { 1508 if ( ! $this->is_date ) { 1509 $this->is_month = true; 1510 $this->is_date = true; 1511 } 1512 } 1513 1514 if ( $qv['year'] ) { 1515 if ( ! $this->is_date ) { 1516 $this->is_year = true; 1517 $this->is_date = true; 1518 } 1519 } 1520 1521 if ( $qv['m'] ) { 1522 $this->is_date = true; 1523 if ( strlen($qv['m']) > 9 ) { 1524 $this->is_time = true; 1525 } else if ( strlen($qv['m']) > 7 ) { 1526 $this->is_day = true; 1527 } else if ( strlen($qv['m']) > 5 ) { 1528 $this->is_month = true; 1529 } else { 1530 $this->is_year = true; 1531 } 1532 } 1533 1534 if ( '' != $qv['w'] ) { 1535 $this->is_date = true; 1536 } 1537 1538 $this->query_vars_hash = false; 1539 $this->parse_tax_query( $qv ); 1540 1541 foreach ( $this->tax_query->queries as $tax_query ) { 1542 if ( 'NOT IN' != $tax_query['operator'] ) { 1543 switch ( $tax_query['taxonomy'] ) { 1544 case 'category': 1545 $this->is_category = true; 1546 break; 1547 case 'post_tag': 1548 $this->is_tag = true; 1549 break; 1550 default: 1551 $this->is_tax = true; 1552 } 1553 } 1554 } 1555 unset( $tax_query ); 1556 1557 if ( empty($qv['author']) || ($qv['author'] == '0') ) { 1558 $this->is_author = false; 1559 } else { 1560 $this->is_author = true; 1561 } 1562 1563 if ( '' != $qv['author_name'] ) 1564 $this->is_author = true; 1565 1566 if ( !empty( $qv['post_type'] ) && ! is_array( $qv['post_type'] ) ) { 1567 $post_type_obj = get_post_type_object( $qv['post_type'] ); 1568 if ( ! empty( $post_type_obj->has_archive ) ) 1569 $this->is_post_type_archive = true; 1570 } 1571 1572 if ( $this->is_post_type_archive || $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax ) 1573 $this->is_archive = true; 1574 } 1575 1576 if ( '' != $qv['feed'] ) 1577 $this->is_feed = true; 1578 1579 if ( '' != $qv['tb'] ) 1580 $this->is_trackback = true; 1581 1582 if ( '' != $qv['paged'] && ( intval($qv['paged']) > 1 ) ) 1583 $this->is_paged = true; 1584 1585 if ( '' != $qv['comments_popup'] ) 1586 $this->is_comments_popup = true; 1587 1588 // if we're previewing inside the write screen 1589 if ( '' != $qv['preview'] ) 1590 $this->is_preview = true; 1591 1592 if ( is_admin() ) 1593 $this->is_admin = true; 1594 1595 if ( false !== strpos($qv['feed'], 'comments-') ) { 1596 $qv['feed'] = str_replace('comments-', '', $qv['feed']); 1597 $qv['withcomments'] = 1; 1598 } 1599 1600 $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment; 1601 1602 if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) ) 1603 $this->is_comment_feed = true; 1604 1605 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 ) ) 1606 $this->is_home = true; 1607 1608 // Correct is_* for page_on_front and page_for_posts 1609 if ( $this->is_home && 'page' == get_option('show_on_front') && get_option('page_on_front') ) { 1610 $_query = wp_parse_args($this->query); 1611 // pagename can be set and empty depending on matched rewrite rules. Ignore an empty pagename. 1612 if ( isset($_query['pagename']) && '' == $_query['pagename'] ) 1613 unset($_query['pagename']); 1614 if ( empty($_query) || !array_diff( array_keys($_query), array('preview', 'page', 'paged', 'cpage') ) ) { 1615 $this->is_page = true; 1616 $this->is_home = false; 1617 $qv['page_id'] = get_option('page_on_front'); 1618 // Correct <!--nextpage--> for page_on_front 1619 if ( !empty($qv['paged']) ) { 1620 $qv['page'] = $qv['paged']; 1621 unset($qv['paged']); 1622 } 1623 } 1624 } 1625 1626 if ( '' != $qv['pagename'] ) { 1627 $this->queried_object =& get_page_by_path($qv['pagename']); 1628 if ( !empty($this->queried_object) ) 1629 $this->queried_object_id = (int) $this->queried_object->ID; 1630 else 1631 unset($this->queried_object); 1632 1633 if ( 'page' == get_option('show_on_front') && isset($this->queried_object_id) && $this->queried_object_id == get_option('page_for_posts') ) { 1634 $this->is_page = false; 1635 $this->is_home = true; 1636 $this->is_posts_page = true; 1637 } 1638 } 1639 1640 if ( $qv['page_id'] ) { 1641 if ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) { 1642 $this->is_page = false; 1643 $this->is_home = true; 1644 $this->is_posts_page = true; 1645 } 1646 } 1647 1648 if ( !empty($qv['post_type']) ) { 1649 if ( is_array($qv['post_type']) ) 1650 $qv['post_type'] = array_map('sanitize_key', $qv['post_type']); 1651 else 1652 $qv['post_type'] = sanitize_key($qv['post_type']); 1653 } 1654 1655 if ( ! empty( $qv['post_status'] ) ) { 1656 if ( is_array( $qv['post_status'] ) ) 1657 $qv['post_status'] = array_map('sanitize_key', $qv['post_status']); 1658 else 1659 $qv['post_status'] = preg_replace('|[^a-z0-9_,-]|', '', $qv['post_status']); 1660 } 1661 1662 if ( $this->is_posts_page && ( ! isset($qv['withcomments']) || ! $qv['withcomments'] ) ) 1663 $this->is_comment_feed = false; 1664 1665 $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment; 1666 // Done correcting is_* for page_on_front and page_for_posts 1667 1668 if ( '404' == $qv['error'] ) 1669 $this->set_404(); 1670 1671 $this->query_vars_hash = md5( serialize( $this->query_vars ) ); 1672 $this->query_vars_changed = false; 1673 1674 do_action_ref_array('parse_query', array(&$this)); 1675 } 1676 1677 /* 1678 * Parses various taxonomy related query vars. 1679 * 1680 * @access protected 1681 * @since 3.1.0 1682 * 1683 * @param array &$q The query variables 1684 */ 1685 function parse_tax_query( &$q ) { 1686 if ( ! empty( $q['tax_query'] ) && is_array( $q['tax_query'] ) ) { 1687 $tax_query = $q['tax_query']; 1688 } else { 1689 $tax_query = array(); 1690 } 1691 1692 if ( !empty($q['taxonomy']) && !empty($q['term']) ) { 1693 $tax_query[] = array( 1694 'taxonomy' => $q['taxonomy'], 1695 'terms' => array( $q['term'] ), 1696 'field' => 'slug', 1697 ); 1698 } 1699 1700 foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t ) { 1701 if ( 'post_tag' == $taxonomy ) 1702 continue; // Handled further down in the $q['tag'] block 1703 1704 if ( $t->query_var && !empty( $q[$t->query_var] ) ) { 1705 $tax_query_defaults = array( 1706 'taxonomy' => $taxonomy, 1707 'field' => 'slug', 1708 ); 1709 1710 if ( isset( $t->rewrite['hierarchical'] ) && $t->rewrite['hierarchical'] ) { 1711 $q[$t->query_var] = wp_basename( $q[$t->query_var] ); 1712 } 1713 1714 $term = $q[$t->query_var]; 1715 1716 if ( strpos($term, '+') !== false ) { 1717 $terms = preg_split( '/[+]+/', $term ); 1718 foreach ( $terms as $term ) { 1719 $tax_query[] = array_merge( $tax_query_defaults, array( 1720 'terms' => array( $term ) 1721 ) ); 1722 } 1723 } else { 1724 $tax_query[] = array_merge( $tax_query_defaults, array( 1725 'terms' => preg_split( '/[,]+/', $term ) 1726 ) ); 1727 } 1728 } 1729 } 1730 1731 // Category stuff 1732 if ( !empty($q['cat']) && '0' != $q['cat'] && !$this->is_singular && $this->query_vars_changed ) { 1733 $q['cat'] = ''.urldecode($q['cat']).''; 1734 $q['cat'] = addslashes_gpc($q['cat']); 1735 $cat_array = preg_split('/[,\s]+/', $q['cat']); 1736 $q['cat'] = ''; 1737 $req_cats = array(); 1738 foreach ( (array) $cat_array as $cat ) { 1739 $cat = intval($cat); 1740 $req_cats[] = $cat; 1741 $in = ($cat > 0); 1742 $cat = abs($cat); 1743 if ( $in ) { 1744 $q['category__in'][] = $cat; 1745 $q['category__in'] = array_merge( $q['category__in'], get_term_children($cat, 'category') ); 1746 } else { 1747 $q['category__not_in'][] = $cat; 1748 $q['category__not_in'] = array_merge( $q['category__not_in'], get_term_children($cat, 'category') ); 1749 } 1750 } 1751 $q['cat'] = implode(',', $req_cats); 1752 } 1753 1754 if ( !empty($q['category__in']) ) { 1755 $q['category__in'] = array_map('absint', array_unique( (array) $q['category__in'] ) ); 1756 $tax_query[] = array( 1757 'taxonomy' => 'category', 1758 'terms' => $q['category__in'], 1759 'field' => 'term_id', 1760 'include_children' => false 1761 ); 1762 } 1763 1764 if ( !empty($q['category__not_in']) ) { 1765 $q['category__not_in'] = array_map('absint', array_unique( (array) $q['category__not_in'] ) ); 1766 $tax_query[] = array( 1767 'taxonomy' => 'category', 1768 'terms' => $q['category__not_in'], 1769 'operator' => 'NOT IN', 1770 'include_children' => false 1771 ); 1772 } 1773 1774 if ( !empty($q['category__and']) ) { 1775 $q['category__and'] = array_map('absint', array_unique( (array) $q['category__and'] ) ); 1776 $tax_query[] = array( 1777 'taxonomy' => 'category', 1778 'terms' => $q['category__and'], 1779 'field' => 'term_id', 1780 'operator' => 'AND', 1781 'include_children' => false 1782 ); 1783 } 1784 1785 // Tag stuff 1786 if ( '' != $q['tag'] && !$this->is_singular && $this->query_vars_changed ) { 1787 if ( strpos($q['tag'], ',') !== false ) { 1788 $tags = preg_split('/[,\s]+/', $q['tag']); 1789 foreach ( (array) $tags as $tag ) { 1790 $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db'); 1791 $q['tag_slug__in'][] = $tag; 1792 } 1793 } else if ( preg_match('/[+\s]+/', $q['tag']) || !empty($q['cat']) ) { 1794 $tags = preg_split('/[+\s]+/', $q['tag']); 1795 foreach ( (array) $tags as $tag ) { 1796 $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db'); 1797 $q['tag_slug__and'][] = $tag; 1798 } 1799 } else { 1800 $q['tag'] = sanitize_term_field('slug', $q['tag'], 0, 'post_tag', 'db'); 1801 $q['tag_slug__in'][] = $q['tag']; 1802 } 1803 } 1804 1805 if ( !empty($q['tag_id']) ) { 1806 $q['tag_id'] = absint( $q['tag_id'] ); 1807 $tax_query[] = array( 1808 'taxonomy' => 'post_tag', 1809 'terms' => $q['tag_id'] 1810 ); 1811 } 1812 1813 if ( !empty($q['tag__in']) ) { 1814 $q['tag__in'] = array_map('absint', array_unique( (array) $q['tag__in'] ) ); 1815 $tax_query[] = array( 1816 'taxonomy' => 'post_tag', 1817 'terms' => $q['tag__in'] 1818 ); 1819 } 1820 1821 if ( !empty($q['tag__not_in']) ) { 1822 $q['tag__not_in'] = array_map('absint', array_unique( (array) $q['tag__not_in'] ) ); 1823 $tax_query[] = array( 1824 'taxonomy' => 'post_tag', 1825 'terms' => $q['tag__not_in'], 1826 'operator' => 'NOT IN' 1827 ); 1828 } 1829 1830 if ( !empty($q['tag__and']) ) { 1831 $q['tag__and'] = array_map('absint', array_unique( (array) $q['tag__and'] ) ); 1832 $tax_query[] = array( 1833 'taxonomy' => 'post_tag', 1834 'terms' => $q['tag__and'], 1835 'operator' => 'AND' 1836 ); 1837 } 1838 1839 if ( !empty($q['tag_slug__in']) ) { 1840 $q['tag_slug__in'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__in'] ) ); 1841 $tax_query[] = array( 1842 'taxonomy' => 'post_tag', 1843 'terms' => $q['tag_slug__in'], 1844 'field' => 'slug' 1845 ); 1846 } 1847 1848 if ( !empty($q['tag_slug__and']) ) { 1849 $q['tag_slug__and'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__and'] ) ); 1850 $tax_query[] = array( 1851 'taxonomy' => 'post_tag', 1852 'terms' => $q['tag_slug__and'], 1853 'field' => 'slug', 1854 'operator' => 'AND' 1855 ); 1856 } 1857 1858 $this->tax_query = new WP_Tax_Query( $tax_query ); 1859 } 1860 1861 /** 1862 * Sets the 404 property and saves whether query is feed. 1863 * 1864 * @since 2.0.0 1865 * @access public 1866 */ 1867 function set_404() { 1868 $is_feed = $this->is_feed; 1869 1870 $this->init_query_flags(); 1871 $this->is_404 = true; 1872 1873 $this->is_feed = $is_feed; 1874 } 1875 1876 /** 1877 * Retrieve query variable. 1878 * 1879 * @since 1.5.0 1880 * @access public 1881 * 1882 * @param string $query_var Query variable key. 1883 * @return mixed 1884 */ 1885 function get($query_var) { 1886 if ( isset($this->query_vars[$query_var]) ) 1887 return $this->query_vars[$query_var]; 1888 1889 return ''; 1890 } 1891 1892 /** 1893 * Set query variable. 1894 * 1895 * @since 1.5.0 1896 * @access public 1897 * 1898 * @param string $query_var Query variable key. 1899 * @param mixed $value Query variable value. 1900 */ 1901 function set($query_var, $value) { 1902 $this->query_vars[$query_var] = $value; 1903 } 1904 1905 /** 1906 * Retrieve the posts based on query variables. 1907 * 1908 * There are a few filters and actions that can be used to modify the post 1909 * database query. 1910 * 1911 * @since 1.5.0 1912 * @access public 1913 * @uses do_action_ref_array() Calls 'pre_get_posts' hook before retrieving posts. 1914 * 1915 * @return array List of posts. 1916 */ 1917 function &get_posts() { 1918 global $wpdb, $user_ID, $_wp_using_ext_object_cache; 1919 1920 $this->parse_query(); 1921 1922 do_action_ref_array('pre_get_posts', array(&$this)); 1923 1924 // Shorthand. 1925 $q = &$this->query_vars; 1926 1927 // Fill again in case pre_get_posts unset some vars. 1928 $q = $this->fill_query_vars($q); 1929 1930 // Parse meta query 1931 $this->meta_query = new WP_Meta_Query(); 1932 $this->meta_query->parse_query_vars( $q ); 1933 1934 // Set a flag if a pre_get_posts hook changed the query vars. 1935 $hash = md5( serialize( $this->query_vars ) ); 1936 if ( $hash != $this->query_vars_hash ) { 1937 $this->query_vars_changed = true; 1938 $this->query_vars_hash = $hash; 1939 } 1940 unset($hash); 1941 1942 // First let's clear some variables 1943 $distinct = ''; 1944 $whichauthor = ''; 1945 $whichmimetype = ''; 1946 $where = ''; 1947 $limits = ''; 1948 $join = ''; 1949 $search = ''; 1950 $groupby = ''; 1951 $fields = ''; 1952 $post_status_join = false; 1953 $page = 1; 1954 1955 if ( isset( $q['caller_get_posts'] ) ) { 1956 _deprecated_argument( 'WP_Query', '3.1', __( '"caller_get_posts" is deprecated. Use "ignore_sticky_posts" instead.' ) ); 1957 if ( !isset( $q['ignore_sticky_posts'] ) ) 1958 $q['ignore_sticky_posts'] = $q['caller_get_posts']; 1959 } 1960 1961 if ( !isset( $q['ignore_sticky_posts'] ) ) 1962 $q['ignore_sticky_posts'] = false; 1963 1964 if ( !isset($q['suppress_filters']) ) 1965 $q['suppress_filters'] = false; 1966 1967 if ( !isset($q['cache_results']) ) { 1968 if ( $_wp_using_ext_object_cache ) 1969 $q['cache_results'] = false; 1970 else 1971 $q['cache_results'] = true; 1972 } 1973 1974 if ( !isset($q['update_post_term_cache']) ) 1975 $q['update_post_term_cache'] = true; 1976 1977 if ( !isset($q['update_post_meta_cache']) ) 1978 $q['update_post_meta_cache'] = true; 1979 1980 if ( !isset($q['post_type']) ) { 1981 if ( $this->is_search ) 1982 $q['post_type'] = 'any'; 1983 else 1984 $q['post_type'] = ''; 1985 } 1986 $post_type = $q['post_type']; 1987 if ( !isset($q['posts_per_page']) || $q['posts_per_page'] == 0 ) 1988 $q['posts_per_page'] = get_option('posts_per_page'); 1989 if ( isset($q['showposts']) && $q['showposts'] ) { 1990 $q['showposts'] = (int) $q['showposts']; 1991 $q['posts_per_page'] = $q['showposts']; 1992 } 1993 if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) ) 1994 $q['posts_per_page'] = $q['posts_per_archive_page']; 1995 if ( !isset($q['nopaging']) ) { 1996 if ( $q['posts_per_page'] == -1 ) { 1997 $q['nopaging'] = true; 1998 } else { 1999 $q['nopaging'] = false; 2000 } 2001 } 2002 if ( $this->is_feed ) { 2003 $q['posts_per_page'] = get_option('posts_per_rss'); 2004 $q['nopaging'] = false; 2005 } 2006 $q['posts_per_page'] = (int) $q['posts_per_page']; 2007 if ( $q['posts_per_page'] < -1 ) 2008 $q['posts_per_page'] = abs($q['posts_per_page']); 2009 else if ( $q['posts_per_page'] == 0 ) 2010 $q['posts_per_page'] = 1; 2011 2012 if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 ) 2013 $q['comments_per_page'] = get_option('comments_per_page'); 2014 2015 if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) { 2016 $this->is_page = true; 2017 $this->is_home = false; 2018 $q['page_id'] = get_option('page_on_front'); 2019 } 2020 2021 if ( isset($q['page']) ) { 2022 $q['page'] = trim($q['page'], '/'); 2023 $q['page'] = absint($q['page']); 2024 } 2025 2026 // If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present. 2027 if ( isset($q['no_found_rows']) ) 2028 $q['no_found_rows'] = (bool) $q['no_found_rows']; 2029 else 2030 $q['no_found_rows'] = false; 2031 2032 switch ( $q['fields'] ) { 2033 case 'ids': 2034 $fields = "$wpdb->posts.ID"; 2035 break; 2036 case 'id=>parent': 2037 $fields = "$wpdb->posts.ID, $wpdb->posts.post_parent"; 2038 break; 2039 default: 2040 $fields = "$wpdb->posts.*"; 2041 } 2042 2043 // If a month is specified in the querystring, load that month 2044 if ( $q['m'] ) { 2045 $q['m'] = '' . preg_replace('|[^0-9]|', '', $q['m']); 2046 $where .= " AND YEAR($wpdb->posts.post_date)=" . substr($q['m'], 0, 4); 2047 if ( strlen($q['m']) > 5 ) 2048 $where .= " AND MONTH($wpdb->posts.post_date)=" . substr($q['m'], 4, 2); 2049 if ( strlen($q['m']) > 7 ) 2050 $where .= " AND DAYOFMONTH($wpdb->posts.post_date)=" . substr($q['m'], 6, 2); 2051 if ( strlen($q['m']) > 9 ) 2052 $where .= " AND HOUR($wpdb->posts.post_date)=" . substr($q['m'], 8, 2); 2053 if ( strlen($q['m']) > 11 ) 2054 $where .= " AND MINUTE($wpdb->posts.post_date)=" . substr($q['m'], 10, 2); 2055 if ( strlen($q['m']) > 13 ) 2056 $where .= " AND SECOND($wpdb->posts.post_date)=" . substr($q['m'], 12, 2); 2057 } 2058 2059 if ( '' !== $q['hour'] ) 2060 $where .= " AND HOUR($wpdb->posts.post_date)='" . $q['hour'] . "'"; 2061 2062 if ( '' !== $q['minute'] ) 2063 $where .= " AND MINUTE($wpdb->posts.post_date)='" . $q['minute'] . "'"; 2064 2065 if ( '' !== $q['second'] ) 2066 $where .= " AND SECOND($wpdb->posts.post_date)='" . $q['second'] . "'"; 2067 2068 if ( $q['year'] ) 2069 $where .= " AND YEAR($wpdb->posts.post_date)='" . $q['year'] . "'"; 2070 2071 if ( $q['monthnum'] ) 2072 $where .= " AND MONTH($wpdb->posts.post_date)='" . $q['monthnum'] . "'"; 2073 2074 if ( $q['day'] ) 2075 $where .= " AND DAYOFMONTH($wpdb->posts.post_date)='" . $q['day'] . "'"; 2076 2077 // If we've got a post_type AND its not "any" post_type. 2078 if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) { 2079 foreach ( (array)$q['post_type'] as $_post_type ) { 2080 $ptype_obj = get_post_type_object($_post_type); 2081 if ( !$ptype_obj || !$ptype_obj->query_var || empty($q[ $ptype_obj->query_var ]) ) 2082 continue; 2083 2084 if ( ! $ptype_obj->hierarchical || strpos($q[ $ptype_obj->query_var ], '/') === false ) { 2085 // Non-hierarchical post_types & parent-level-hierarchical post_types can directly use 'name' 2086 $q['name'] = $q[ $ptype_obj->query_var ]; 2087 } else { 2088 // Hierarchical post_types will operate through the 2089 $q['pagename'] = $q[ $ptype_obj->query_var ]; 2090 $q['name'] = ''; 2091 } 2092 2093 // Only one request for a slug is possible, this is why name & pagename are overwritten above. 2094 break; 2095 } //end foreach 2096 unset($ptype_obj); 2097 } 2098 2099 if ( '' != $q['name'] ) { 2100 $q['name'] = sanitize_title_for_query( $q['name'] ); 2101 $where .= " AND $wpdb->posts.post_name = '" . $q['name'] . "'"; 2102 } elseif ( '' != $q['pagename'] ) { 2103 if ( isset($this->queried_object_id) ) { 2104 $reqpage = $this->queried_object_id; 2105 } else { 2106 if ( 'page' != $q['post_type'] ) { 2107 foreach ( (array)$q['post_type'] as $_post_type ) { 2108 $ptype_obj = get_post_type_object($_post_type); 2109 if ( !$ptype_obj || !$ptype_obj->hierarchical ) 2110 continue; 2111 2112 $reqpage = get_page_by_path($q['pagename'], OBJECT, $_post_type); 2113 if ( $reqpage ) 2114 break; 2115 } 2116 unset($ptype_obj); 2117 } else { 2118 $reqpage = get_page_by_path($q['pagename']); 2119 } 2120 if ( !empty($reqpage) ) 2121 $reqpage = $reqpage->ID; 2122 else 2123 $reqpage = 0; 2124 } 2125 2126 $page_for_posts = get_option('page_for_posts'); 2127 if ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) { 2128 $q['pagename'] = sanitize_title_for_query( wp_basename( $q['pagename'] ) ); 2129 $q['name'] = $q['pagename']; 2130 $where .= " AND ($wpdb->posts.ID = '$reqpage')"; 2131 $reqpage_obj = get_page($reqpage); 2132 if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) { 2133 $this->is_attachment = true; 2134 $post_type = $q['post_type'] = 'attachment'; 2135 $this->is_page = true; 2136 $q['attachment_id'] = $reqpage; 2137 } 2138 } 2139 } elseif ( '' != $q['attachment'] ) { 2140 $q['attachment'] = sanitize_title_for_query( wp_basename( $q['attachment'] ) ); 2141 $q['name'] = $q['attachment']; 2142 $where .= " AND $wpdb->posts.post_name = '" . $q['attachment'] . "'"; 2143 } 2144 2145 if ( $q['w'] ) 2146 $where .= ' AND ' . _wp_mysql_week( "`$wpdb->posts`.`post_date`" ) . " = '" . $q['w'] . "'"; 2147 2148 if ( intval($q['comments_popup']) ) 2149 $q['p'] = absint($q['comments_popup']); 2150 2151 // If an attachment is requested by number, let it supersede any post number. 2152 if ( $q['attachment_id'] ) 2153 $q['p'] = absint($q['attachment_id']); 2154 2155 // If a post number is specified, load that post 2156 if ( $q['p'] ) { 2157 $where .= " AND {$wpdb->posts}.ID = " . $q['p']; 2158 } elseif ( $q['post__in'] ) { 2159 $post__in = implode(',', array_map( 'absint', $q['post__in'] )); 2160 $where .= " AND {$wpdb->posts}.ID IN ($post__in)"; 2161 } elseif ( $q['post__not_in'] ) { 2162 $post__not_in = implode(',', array_map( 'absint', $q['post__not_in'] )); 2163 $where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)"; 2164 } 2165 2166 if ( is_numeric($q['post_parent']) ) 2167 $where .= $wpdb->prepare( " AND $wpdb->posts.post_parent = %d ", $q['post_parent'] ); 2168 2169 if ( $q['page_id'] ) { 2170 if ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) { 2171 $q['p'] = $q['page_id']; 2172 $where = " AND {$wpdb->posts}.ID = " . $q['page_id']; 2173 } 2174 } 2175 2176 // If a search pattern is specified, load the posts that match 2177 if ( !empty($q['s']) ) { 2178 // added slashes screw with quote grouping when done early, so done later 2179 $q['s'] = stripslashes($q['s']); 2180 if ( !empty($q['sentence']) ) { 2181 $q['search_terms'] = array($q['s']); 2182 } else { 2183 preg_match_all('/".*?("|$)|((?<=[\\s",+])|^)[^\\s",+]+/', $q['s'], $matches); 2184 $q['search_terms'] = array_map('_search_terms_tidy', $matches[0]); 2185 } 2186 $n = !empty($q['exact']) ? '' : '%'; 2187 $searchand = ''; 2188 foreach( (array) $q['search_terms'] as $term ) { 2189 $term = esc_sql( like_escape( $term ) ); 2190 $search .= "{$searchand}(($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}'))"; 2191 $searchand = ' AND '; 2192 } 2193 2194 if ( !empty($search) ) { 2195 $search = " AND ({$search}) "; 2196 if ( !is_user_logged_in() ) 2197 $search .= " AND ($wpdb->posts.post_password = '') "; 2198 } 2199 } 2200 2201 // Allow plugins to contextually add/remove/modify the search section of the database query 2202 $search = apply_filters_ref_array('posts_search', array( $search, &$this ) ); 2203 2204 // Taxonomies 2205 if ( !$this->is_singular ) { 2206 $this->parse_tax_query( $q ); 2207 2208 $clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' ); 2209 2210 $join .= $clauses['join']; 2211 $where .= $clauses['where']; 2212 } 2213 2214 if ( $this->is_tax ) { 2215 if ( empty($post_type) ) { 2216 $post_type = 'any'; 2217 $post_status_join = true; 2218 } elseif ( in_array('attachment', (array) $post_type) ) { 2219 $post_status_join = true; 2220 } 2221 } 2222 2223 // Back-compat 2224 if ( !empty($this->tax_query->queries) ) { 2225 $tax_query_in_and = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'NOT IN' ), 'NOT' ); 2226 if ( !empty( $tax_query_in_and ) ) { 2227 if ( !isset( $q['taxonomy'] ) ) { 2228 foreach ( $tax_query_in_and as $a_tax_query ) { 2229 if ( !in_array( $a_tax_query['taxonomy'], array( 'category', 'post_tag' ) ) ) { 2230 $q['taxonomy'] = $a_tax_query['taxonomy']; 2231 if ( 'slug' == $a_tax_query['field'] ) 2232 $q['term'] = $a_tax_query['terms'][0]; 2233 else 2234 $q['term_id'] = $a_tax_query['terms'][0]; 2235 2236 break; 2237 } 2238 } 2239 } 2240 2241 $cat_query = wp_list_filter( $tax_query_in_and, array( 'taxonomy' => 'category' ) ); 2242 if ( !empty( $cat_query ) ) { 2243 $cat_query = reset( $cat_query ); 2244 $the_cat = get_term_by( $cat_query['field'], $cat_query['terms'][0], 'category' ); 2245 if ( $the_cat ) { 2246 $this->set( 'cat', $the_cat->term_id ); 2247 $this->set( 'category_name', $the_cat->slug ); 2248 } 2249 unset( $the_cat ); 2250 } 2251 unset( $cat_query ); 2252 2253 $tag_query = wp_list_filter( $tax_query_in_and, array( 'taxonomy' => 'post_tag' ) ); 2254 if ( !empty( $tag_query ) ) { 2255 $tag_query = reset( $tag_query ); 2256 $the_tag = get_term_by( $tag_query['field'], $tag_query['terms'][0], 'post_tag' ); 2257 if ( $the_tag ) { 2258 $this->set( 'tag_id', $the_tag->term_id ); 2259 } 2260 unset( $the_tag ); 2261 } 2262 unset( $tag_query ); 2263 } 2264 } 2265 2266 if ( !empty( $this->tax_query->queries ) || !empty( $this->meta_query->queries ) ) { 2267 $groupby = "{$wpdb->posts}.ID"; 2268 } 2269 2270 // Author/user stuff 2271 2272 if ( empty($q['author']) || ($q['author'] == '0') ) { 2273 $whichauthor = ''; 2274 } else { 2275 $q['author'] = (string)urldecode($q['author']); 2276 $q['author'] = addslashes_gpc($q['author']); 2277 if ( strpos($q['author'], '-') !== false ) { 2278 $eq = '!='; 2279 $andor = 'AND'; 2280 $q['author'] = explode('-', $q['author']); 2281 $q['author'] = (string)absint($q['author'][1]); 2282 } else { 2283 $eq = '='; 2284 $andor = 'OR'; 2285 } 2286 $author_array = preg_split('/[,\s]+/', $q['author']); 2287 $_author_array = array(); 2288 foreach ( $author_array as $key => $_author ) 2289 $_author_array[] = "$wpdb->posts.post_author " . $eq . ' ' . absint($_author); 2290 $whichauthor .= ' AND (' . implode(" $andor ", $_author_array) . ')'; 2291 unset($author_array, $_author_array); 2292 } 2293 2294 // Author stuff for nice URLs 2295 2296 if ( '' != $q['author_name'] ) { 2297 if ( strpos($q['author_name'], '/') !== false ) { 2298 $q['author_name'] = explode('/', $q['author_name']); 2299 if ( $q['author_name'][ count($q['author_name'])-1 ] ) { 2300 $q['author_name'] = $q['author_name'][count($q['author_name'])-1]; // no trailing slash 2301 } else { 2302 $q['author_name'] = $q['author_name'][count($q['author_name'])-2]; // there was a trailing slash 2303 } 2304 } 2305 $q['author_name'] = sanitize_title_for_query( $q['author_name'] ); 2306 $q['author'] = get_user_by('slug', $q['author_name']); 2307 if ( $q['author'] ) 2308 $q['author'] = $q['author']->ID; 2309 $whichauthor .= " AND ($wpdb->posts.post_author = " . absint($q['author']) . ')'; 2310 } 2311 2312 // MIME-Type stuff for attachment browsing 2313 2314 if ( isset($q['post_mime_type']) && '' != $q['post_mime_type'] ) { 2315 $table_alias = $post_status_join ? $wpdb->posts : ''; 2316 $whichmimetype = wp_post_mime_type_where($q['post_mime_type'], $table_alias); 2317 } 2318 2319 $where .= $search . $whichauthor . $whichmimetype; 2320 2321 if ( empty($q['order']) || ((strtoupper($q['order']) != 'ASC') && (strtoupper($q['order']) != 'DESC')) ) 2322 $q['order'] = 'DESC'; 2323 2324 // Order by 2325 if ( empty($q['orderby']) ) { 2326 $orderby = "$wpdb->posts.post_date " . $q['order']; 2327 } elseif ( 'none' == $q['orderby'] ) { 2328 $orderby = ''; 2329 } else { 2330 // Used to filter values 2331 $allowed_keys = array('name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count'); 2332 if ( !empty($q['meta_key']) ) { 2333 $allowed_keys[] = $q['meta_key']; 2334 $allowed_keys[] = 'meta_value'; 2335 $allowed_keys[] = 'meta_value_num'; 2336 } 2337 $q['orderby'] = urldecode($q['orderby']); 2338 $q['orderby'] = addslashes_gpc($q['orderby']); 2339 2340 $orderby_array = array(); 2341 foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) { 2342 // Only allow certain values for safety 2343 if ( ! in_array($orderby, $allowed_keys) ) 2344 continue; 2345 2346 switch ( $orderby ) { 2347 case 'menu_order': 2348 break; 2349 case 'ID': 2350 $orderby = "$wpdb->posts.ID"; 2351 break; 2352 case 'rand': 2353 $orderby = 'RAND()'; 2354 break; 2355 case $q['meta_key']: 2356 case 'meta_value': 2357 $orderby = "$wpdb->postmeta.meta_value"; 2358 break; 2359 case 'meta_value_num': 2360 $orderby = "$wpdb->postmeta.meta_value+0"; 2361 break; 2362 case 'comment_count': 2363 $orderby = "$wpdb->posts.comment_count"; 2364 break; 2365 default: 2366 $orderby = "$wpdb->posts.post_" . $orderby; 2367 } 2368 2369 $orderby_array[] = $orderby; 2370 } 2371 $orderby = implode( ',', $orderby_array ); 2372 2373 if ( empty( $orderby ) ) 2374 $orderby = "$wpdb->posts.post_date ".$q['order']; 2375 else 2376 $orderby .= " {$q['order']}"; 2377 } 2378 2379 if ( is_array( $post_type ) ) { 2380 $post_type_cap = 'multiple_post_type'; 2381 } else { 2382 $post_type_object = get_post_type_object( $post_type ); 2383 if ( empty( $post_type_object ) ) 2384 $post_type_cap = $post_type; 2385 } 2386 2387 if ( 'any' == $post_type ) { 2388 $in_search_post_types = get_post_types( array('exclude_from_search' => false) ); 2389 if ( ! empty( $in_search_post_types ) ) 2390 $where .= $wpdb->prepare(" AND $wpdb->posts.post_type IN ('" . join("', '", $in_search_post_types ) . "')"); 2391 } elseif ( !empty( $post_type ) && is_array( $post_type ) ) { 2392 $where .= " AND $wpdb->posts.post_type IN ('" . join("', '", $post_type) . "')"; 2393 } elseif ( ! empty( $post_type ) ) { 2394 $where .= " AND $wpdb->posts.post_type = '$post_type'"; 2395 $post_type_object = get_post_type_object ( $post_type ); 2396 } elseif ( $this->is_attachment ) { 2397 $where .= " AND $wpdb->posts.post_type = 'attachment'"; 2398 $post_type_object = get_post_type_object ( 'attachment' ); 2399 } elseif ( $this->is_page ) { 2400 $where .= " AND $wpdb->posts.post_type = 'page'"; 2401 $post_type_object = get_post_type_object ( 'page' ); 2402 } else { 2403 $where .= " AND $wpdb->posts.post_type = 'post'"; 2404 $post_type_object = get_post_type_object ( 'post' ); 2405 } 2406 2407 if ( ! empty( $post_type_object ) ) { 2408 $edit_cap = $post_type_object->cap->edit_post; 2409 $read_cap = $post_type_object->cap->read_post; 2410 $edit_others_cap = $post_type_object->cap->edit_others_posts; 2411 $read_private_cap = $post_type_object->cap->read_private_posts; 2412 } else { 2413 $edit_cap = 'edit_' . $post_type_cap; 2414 $read_cap = 'read_' . $post_type_cap; 2415 $edit_others_cap = 'edit_others_' . $post_type_cap . 's'; 2416 $read_private_cap = 'read_private_' . $post_type_cap . 's'; 2417 } 2418 2419 if ( ! empty( $q['post_status'] ) ) { 2420 $statuswheres = array(); 2421 $q_status = $q['post_status']; 2422 if ( ! is_array( $q_status ) ) 2423 $q_status = explode(',', $q_status); 2424 $r_status = array(); 2425 $p_status = array(); 2426 $e_status = array(); 2427 if ( in_array('any', $q_status) ) { 2428 foreach ( get_post_stati( array('exclude_from_search' => true) ) as $status ) 2429 $e_status[] = "$wpdb->posts.post_status <> '$status'"; 2430 } else { 2431 foreach ( get_post_stati() as $status ) { 2432 if ( in_array( $status, $q_status ) ) { 2433 if ( 'private' == $status ) 2434 $p_status[] = "$wpdb->posts.post_status = '$status'"; 2435 else 2436 $r_status[] = "$wpdb->posts.post_status = '$status'"; 2437 } 2438 } 2439 } 2440 2441 if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) { 2442 $r_status = array_merge($r_status, $p_status); 2443 unset($p_status); 2444 } 2445 2446 if ( !empty($e_status) ) { 2447 $statuswheres[] = "(" . join( ' AND ', $e_status ) . ")"; 2448 } 2449 if ( !empty($r_status) ) { 2450 if ( !empty($q['perm'] ) && 'editable' == $q['perm'] && !current_user_can($edit_others_cap) ) 2451 $statuswheres[] = "($wpdb->posts.post_author = $user_ID " . "AND (" . join( ' OR ', $r_status ) . "))"; 2452 else 2453 $statuswheres[] = "(" . join( ' OR ', $r_status ) . ")"; 2454 } 2455 if ( !empty($p_status) ) { 2456 if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can($read_private_cap) ) 2457 $statuswheres[] = "($wpdb->posts.post_author = $user_ID " . "AND (" . join( ' OR ', $p_status ) . "))"; 2458 else 2459 $statuswheres[] = "(" . join( ' OR ', $p_status ) . ")"; 2460 } 2461 if ( $post_status_join ) { 2462 $join .= " LEFT JOIN $wpdb->posts AS p2 ON ($wpdb->posts.post_parent = p2.ID) "; 2463 foreach ( $statuswheres as $index => $statuswhere ) 2464 $statuswheres[$index] = "($statuswhere OR ($wpdb->posts.post_status = 'inherit' AND " . str_replace($wpdb->posts, 'p2', $statuswhere) . "))"; 2465 } 2466 foreach ( $statuswheres as $statuswhere ) 2467 $where .= " AND $statuswhere"; 2468 } elseif ( !$this->is_singular ) { 2469 $where .= " AND ($wpdb->posts.post_status = 'publish'"; 2470 2471 // Add public states. 2472 $public_states = get_post_stati( array('public' => true) ); 2473 foreach ( (array) $public_states as $state ) { 2474 if ( 'publish' == $state ) // Publish is hard-coded above. 2475 continue; 2476 $where .= " OR $wpdb->posts.post_status = '$state'"; 2477 } 2478 2479 if ( is_admin() ) { 2480 // Add protected states that should show in the admin all list. 2481 $admin_all_states = get_post_stati( array('protected' => true, 'show_in_admin_all_list' => true) ); 2482 foreach ( (array) $admin_all_states as $state ) 2483 $where .= " OR $wpdb->posts.post_status = '$state'"; 2484 } 2485 2486 if ( is_user_logged_in() ) { 2487 // Add private states that are limited to viewing by the author of a post or someone who has caps to read private states. 2488 $private_states = get_post_stati( array('private' => true) ); 2489 foreach ( (array) $private_states as $state ) 2490 $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'"; 2491 } 2492 2493 $where .= ')'; 2494 } 2495 2496 if ( !empty( $this->meta_query->queries ) ) { 2497 $clauses = $this->meta_query->get_sql( 'post', $wpdb->