| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * WordPress Query API 4 * 5 * The query API attempts to get which part of WordPress the user is on. It 6 * also provides functionality for getting URL query information. 7 * 8 * @link https://developer.wordpress.org/themes/basics/the-loop/ More information on The Loop. 9 * 10 * @package WordPress 11 * @subpackage Query 12 */ 13 14 /** 15 * Retrieves the value of a query variable in the WP_Query class. 16 * 17 * @since 1.5.0 18 * @since 3.9.0 The `$default_value` argument was introduced. 19 * 20 * @global WP_Query $wp_query WordPress Query object. 21 * 22 * @param string $query_var The variable key to retrieve. 23 * @param mixed $default_value Optional. Value to return if the query variable is not set. 24 * Default empty string. 25 * @return mixed Contents of the query variable. 26 */ 27 function get_query_var( $query_var, $default_value = '' ) { 28 global $wp_query; 29 return $wp_query->get( $query_var, $default_value ); 30 } 31 32 /** 33 * Retrieves the currently queried object. 34 * 35 * Wrapper for WP_Query::get_queried_object(). 36 * 37 * @since 3.1.0 38 * 39 * @global WP_Query $wp_query WordPress Query object. 40 * 41 * @return WP_Term|WP_Post_Type|WP_Post|WP_User|null The queried object. 42 */ 43 function get_queried_object() { 44 global $wp_query; 45 return $wp_query->get_queried_object(); 46 } 47 48 /** 49 * Retrieves the ID of the currently queried object. 50 * 51 * Wrapper for WP_Query::get_queried_object_id(). 52 * 53 * @since 3.1.0 54 * 55 * @global WP_Query $wp_query WordPress Query object. 56 * 57 * @return int ID of the queried object. 58 */ 59 function get_queried_object_id() { 60 global $wp_query; 61 return $wp_query->get_queried_object_id(); 62 } 63 64 /** 65 * Sets the value of a query variable in the WP_Query class. 66 * 67 * @since 2.2.0 68 * 69 * @global WP_Query $wp_query WordPress Query object. 70 * 71 * @param string $query_var Query variable key. 72 * @param mixed $value Query variable value. 73 */ 74 function set_query_var( $query_var, $value ) { 75 global $wp_query; 76 $wp_query->set( $query_var, $value ); 77 } 78 79 /** 80 * Sets up The Loop with query parameters. 81 * 82 * Note: This function will completely override the main query and isn't intended for use 83 * by plugins or themes. Its overly-simplistic approach to modifying the main query can be 84 * problematic and should be avoided wherever possible. In most cases, there are better, 85 * more performant options for modifying the main query such as via the {@see 'pre_get_posts'} 86 * action within WP_Query. 87 * 88 * This must not be used within the WordPress Loop. 89 * 90 * @since 1.5.0 91 * 92 * @global WP_Query $wp_query WordPress Query object. 93 * 94 * @param array|string $query Array or string of WP_Query arguments. 95 * @return WP_Post[]|int[] Array of post objects or post IDs. 96 */ 97 function query_posts( $query ) { 98 $GLOBALS['wp_query'] = new WP_Query(); 99 return $GLOBALS['wp_query']->query( $query ); 100 } 101 102 /** 103 * Destroys the previous query and sets up a new query. 104 * 105 * This should be used after query_posts() and before another query_posts(). 106 * This will remove obscure bugs that occur when the previous WP_Query object 107 * is not destroyed properly before another is set up. 108 * 109 * @since 2.3.0 110 * 111 * @global WP_Query $wp_query WordPress Query object. 112 * @global WP_Query $wp_the_query Copy of the global WP_Query instance created during wp_reset_query(). 113 */ 114 function wp_reset_query() { 115 $GLOBALS['wp_query'] = $GLOBALS['wp_the_query']; 116 wp_reset_postdata(); 117 } 118 119 /** 120 * After looping through a separate query, this function restores 121 * the $post global to the current post in the main query. 122 * 123 * @since 3.0.0 124 * 125 * @global WP_Query $wp_query WordPress Query object. 126 */ 127 function wp_reset_postdata() { 128 global $wp_query; 129 130 if ( isset( $wp_query ) ) { 131 $wp_query->reset_postdata(); 132 } 133 } 134 135 /* 136 * Query type checks. 137 */ 138 139 /** 140 * Determines whether the query is for an existing archive page. 141 * 142 * Archive pages include category, tag, author, date, custom post type, 143 * and custom taxonomy based archives. 144 * 145 * For more information on this and similar theme functions, check out 146 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 147 * Conditional Tags} article in the Theme Developer Handbook. 148 * 149 * @since 1.5.0 150 * 151 * @see is_category() 152 * @see is_tag() 153 * @see is_author() 154 * @see is_date() 155 * @see is_post_type_archive() 156 * @see is_tax() 157 * @global WP_Query $wp_query WordPress Query object. 158 * 159 * @return bool Whether the query is for an existing archive page. 160 */ 161 function is_archive() { 162 global $wp_query; 163 164 if ( ! isset( $wp_query ) ) { 165 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 166 return false; 167 } 168 169 return $wp_query->is_archive(); 170 } 171 172 /** 173 * Determines whether the query is for an existing post type archive page. 174 * 175 * For more information on this and similar theme functions, check out 176 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 177 * Conditional Tags} article in the Theme Developer Handbook. 178 * 179 * @since 3.1.0 180 * 181 * @global WP_Query $wp_query WordPress Query object. 182 * 183 * @param string|string[] $post_types Optional. Post type or array of posts types 184 * to check against. Default empty. 185 * @return bool Whether the query is for an existing post type archive page. 186 */ 187 function is_post_type_archive( $post_types = '' ) { 188 global $wp_query; 189 190 if ( ! isset( $wp_query ) ) { 191 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 192 return false; 193 } 194 195 return $wp_query->is_post_type_archive( $post_types ); 196 } 197 198 /** 199 * Determines whether the query is for an existing attachment page. 200 * 201 * For more information on this and similar theme functions, check out 202 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 203 * Conditional Tags} article in the Theme Developer Handbook. 204 * 205 * @since 2.0.0 206 * 207 * @global WP_Query $wp_query WordPress Query object. 208 * 209 * @param int|string|int[]|string[] $attachment Optional. Attachment ID, title, slug, or array of such 210 * to check against. Default empty. 211 * @return bool Whether the query is for an existing attachment page. 212 */ 213 function is_attachment( $attachment = '' ) { 214 global $wp_query; 215 216 if ( ! isset( $wp_query ) ) { 217 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 218 return false; 219 } 220 221 return $wp_query->is_attachment( $attachment ); 222 } 223 224 /** 225 * Determines whether the query is for an existing author archive page. 226 * 227 * If the $author parameter is specified, this function will additionally 228 * check if the query is for one of the authors specified. 229 * 230 * For more information on this and similar theme functions, check out 231 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 232 * Conditional Tags} article in the Theme Developer Handbook. 233 * 234 * @since 1.5.0 235 * 236 * @global WP_Query $wp_query WordPress Query object. 237 * 238 * @param int|string|int[]|string[] $author Optional. User ID, nickname, nicename, or array of such 239 * to check against. Default empty. 240 * @return bool Whether the query is for an existing author archive page. 241 */ 242 function is_author( $author = '' ) { 243 global $wp_query; 244 245 if ( ! isset( $wp_query ) ) { 246 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 247 return false; 248 } 249 250 return $wp_query->is_author( $author ); 251 } 252 253 /** 254 * Determines whether the query is for an existing category archive page. 255 * 256 * If the $category parameter is specified, this function will additionally 257 * check if the query is for one of the categories specified. 258 * 259 * For more information on this and similar theme functions, check out 260 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 261 * Conditional Tags} article in the Theme Developer Handbook. 262 * 263 * @since 1.5.0 264 * 265 * @global WP_Query $wp_query WordPress Query object. 266 * 267 * @param int|string|int[]|string[] $category Optional. Category ID, name, slug, or array of such 268 * to check against. Default empty. 269 * @return bool Whether the query is for an existing category archive page. 270 */ 271 function is_category( $category = '' ) { 272 global $wp_query; 273 274 if ( ! isset( $wp_query ) ) { 275 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 276 return false; 277 } 278 279 return $wp_query->is_category( $category ); 280 } 281 282 /** 283 * Determines whether the query is for an existing tag archive page. 284 * 285 * If the $tag parameter is specified, this function will additionally 286 * check if the query is for one of the tags specified. 287 * 288 * For more information on this and similar theme functions, check out 289 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 290 * Conditional Tags} article in the Theme Developer Handbook. 291 * 292 * @since 2.3.0 293 * 294 * @global WP_Query $wp_query WordPress Query object. 295 * 296 * @param int|string|int[]|string[] $tag Optional. Tag ID, name, slug, or array of such 297 * to check against. Default empty. 298 * @return bool Whether the query is for an existing tag archive page. 299 */ 300 function is_tag( $tag = '' ) { 301 global $wp_query; 302 303 if ( ! isset( $wp_query ) ) { 304 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 305 return false; 306 } 307 308 return $wp_query->is_tag( $tag ); 309 } 310 311 /** 312 * Determines whether the query is for an existing custom taxonomy archive page. 313 * 314 * If the $taxonomy parameter is specified, this function will additionally 315 * check if the query is for that specific $taxonomy. 316 * 317 * If the $term parameter is specified in addition to the $taxonomy parameter, 318 * this function will additionally check if the query is for one of the terms 319 * specified. 320 * 321 * For more information on this and similar theme functions, check out 322 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 323 * Conditional Tags} article in the Theme Developer Handbook. 324 * 325 * @since 2.5.0 326 * 327 * @global WP_Query $wp_query WordPress Query object. 328 * 329 * @param string|string[] $taxonomy Optional. Taxonomy slug or slugs to check against. 330 * Default empty. 331 * @param int|string|int[]|string[] $term Optional. Term ID, name, slug, or array of such 332 * to check against. Default empty. 333 * @return bool Whether the query is for an existing custom taxonomy archive page. 334 * True for custom taxonomy archive pages, false for built-in taxonomies 335 * (category and tag archives). 336 */ 337 function is_tax( $taxonomy = '', $term = '' ) { 338 global $wp_query; 339 340 if ( ! isset( $wp_query ) ) { 341 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 342 return false; 343 } 344 345 return $wp_query->is_tax( $taxonomy, $term ); 346 } 347 348 /** 349 * Determines whether the query is for an existing date archive. 350 * 351 * For more information on this and similar theme functions, check out 352 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 353 * Conditional Tags} article in the Theme Developer Handbook. 354 * 355 * @since 1.5.0 356 * 357 * @global WP_Query $wp_query WordPress Query object. 358 * 359 * @return bool Whether the query is for an existing date archive. 360 */ 361 function is_date() { 362 global $wp_query; 363 364 if ( ! isset( $wp_query ) ) { 365 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 366 return false; 367 } 368 369 return $wp_query->is_date(); 370 } 371 372 /** 373 * Determines whether the query is for an existing day archive. 374 * 375 * A conditional check to test whether the page is a date-based archive page displaying posts for the current day. 376 * 377 * For more information on this and similar theme functions, check out 378 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 379 * Conditional Tags} article in the Theme Developer Handbook. 380 * 381 * @since 1.5.0 382 * 383 * @global WP_Query $wp_query WordPress Query object. 384 * 385 * @return bool Whether the query is for an existing day archive. 386 */ 387 function is_day() { 388 global $wp_query; 389 390 if ( ! isset( $wp_query ) ) { 391 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 392 return false; 393 } 394 395 return $wp_query->is_day(); 396 } 397 398 /** 399 * Determines whether the query is for a feed. 400 * 401 * For more information on this and similar theme functions, check out 402 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 403 * Conditional Tags} article in the Theme Developer Handbook. 404 * 405 * @since 1.5.0 406 * 407 * @global WP_Query $wp_query WordPress Query object. 408 * 409 * @param string|string[] $feeds Optional. Feed type or array of feed types 410 * to check against. Default empty. 411 * @return bool Whether the query is for a feed. 412 */ 413 function is_feed( $feeds = '' ) { 414 global $wp_query; 415 416 if ( ! isset( $wp_query ) ) { 417 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 418 return false; 419 } 420 421 return $wp_query->is_feed( $feeds ); 422 } 423 424 /** 425 * Is the query for a comments feed? 426 * 427 * @since 3.0.0 428 * 429 * @global WP_Query $wp_query WordPress Query object. 430 * 431 * @return bool Whether the query is for a comments feed. 432 */ 433 function is_comment_feed() { 434 global $wp_query; 435 436 if ( ! isset( $wp_query ) ) { 437 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 438 return false; 439 } 440 441 return $wp_query->is_comment_feed(); 442 } 443 444 /** 445 * Determines whether the query is for the front page of the site. 446 * 447 * This is for what is displayed at your site's main URL. 448 * 449 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'. 450 * 451 * If you set a static page for the front page of your site, this function will return 452 * true when viewing that page. 453 * 454 * Otherwise the same as {@see is_home()}. 455 * 456 * For more information on this and similar theme functions, check out 457 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 458 * Conditional Tags} article in the Theme Developer Handbook. 459 * 460 * @since 2.5.0 461 * 462 * @global WP_Query $wp_query WordPress Query object. 463 * 464 * @return bool Whether the query is for the front page of the site. 465 */ 466 function is_front_page() { 467 global $wp_query; 468 469 if ( ! isset( $wp_query ) ) { 470 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 471 return false; 472 } 473 474 return $wp_query->is_front_page(); 475 } 476 477 /** 478 * Determines whether the query is for the blog homepage. 479 * 480 * The blog homepage is the page that shows the time-based blog content of the site. 481 * 482 * is_home() is dependent on the site's "Front page displays" Reading Settings 'show_on_front' 483 * and 'page_for_posts'. 484 * 485 * If a static page is set for the front page of the site, this function will return true only 486 * on the page you set as the "Posts page". 487 * 488 * For more information on this and similar theme functions, check out 489 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 490 * Conditional Tags} article in the Theme Developer Handbook. 491 * 492 * @since 1.5.0 493 * 494 * @see is_front_page() 495 * @global WP_Query $wp_query WordPress Query object. 496 * 497 * @return bool Whether the query is for the blog homepage. 498 */ 499 function is_home() { 500 global $wp_query; 501 502 if ( ! isset( $wp_query ) ) { 503 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 504 return false; 505 } 506 507 return $wp_query->is_home(); 508 } 509 510 /** 511 * Determines whether the query is for the Privacy Policy page. 512 * 513 * The Privacy Policy page is the page that shows the Privacy Policy content of the site. 514 * 515 * is_privacy_policy() is dependent on the site's "Change your Privacy Policy page" Privacy Settings 'wp_page_for_privacy_policy'. 516 * 517 * This function will return true only on the page you set as the "Privacy Policy page". 518 * 519 * For more information on this and similar theme functions, check out 520 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 521 * Conditional Tags} article in the Theme Developer Handbook. 522 * 523 * @since 5.2.0 524 * 525 * @global WP_Query $wp_query WordPress Query object. 526 * 527 * @return bool Whether the query is for the Privacy Policy page. 528 */ 529 function is_privacy_policy() { 530 global $wp_query; 531 532 if ( ! isset( $wp_query ) ) { 533 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 534 return false; 535 } 536 537 return $wp_query->is_privacy_policy(); 538 } 539 540 /** 541 * Determines whether the query is for an existing month archive. 542 * 543 * For more information on this and similar theme functions, check out 544 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 545 * Conditional Tags} article in the Theme Developer Handbook. 546 * 547 * @since 1.5.0 548 * 549 * @global WP_Query $wp_query WordPress Query object. 550 * 551 * @return bool Whether the query is for an existing month archive. 552 */ 553 function is_month() { 554 global $wp_query; 555 556 if ( ! isset( $wp_query ) ) { 557 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 558 return false; 559 } 560 561 return $wp_query->is_month(); 562 } 563 564 /** 565 * Determines whether the query is for an existing single page. 566 * 567 * If the $page parameter is specified, this function will additionally 568 * check if the query is for one of the pages specified. 569 * 570 * For more information on this and similar theme functions, check out 571 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 572 * Conditional Tags} article in the Theme Developer Handbook. 573 * 574 * @since 1.5.0 575 * 576 * @see is_single() 577 * @see is_singular() 578 * @global WP_Query $wp_query WordPress Query object. 579 * 580 * @param int|string|int[]|string[] $page Optional. Page ID, title, slug, or array of such 581 * to check against. Default empty. 582 * @return bool Whether the query is for an existing single page. 583 */ 584 function is_page( $page = '' ) { 585 global $wp_query; 586 587 if ( ! isset( $wp_query ) ) { 588 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 589 return false; 590 } 591 592 return $wp_query->is_page( $page ); 593 } 594 595 /** 596 * Determines whether the query is for a paged result and not for the first page. 597 * 598 * For more information on this and similar theme functions, check out 599 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 600 * Conditional Tags} article in the Theme Developer Handbook. 601 * 602 * @since 1.5.0 603 * 604 * @global WP_Query $wp_query WordPress Query object. 605 * 606 * @return bool Whether the query is for a paged result. 607 */ 608 function is_paged() { 609 global $wp_query; 610 611 if ( ! isset( $wp_query ) ) { 612 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 613 return false; 614 } 615 616 return $wp_query->is_paged(); 617 } 618 619 /** 620 * Determines whether the query is for a post or page preview. 621 * 622 * For more information on this and similar theme functions, check out 623 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 624 * Conditional Tags} article in the Theme Developer Handbook. 625 * 626 * @since 2.0.0 627 * 628 * @global WP_Query $wp_query WordPress Query object. 629 * 630 * @return bool Whether the query is for a post or page preview. 631 */ 632 function is_preview() { 633 global $wp_query; 634 635 if ( ! isset( $wp_query ) ) { 636 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 637 return false; 638 } 639 640 return $wp_query->is_preview(); 641 } 642 643 /** 644 * Is the query for the robots.txt file? 645 * 646 * @since 2.1.0 647 * 648 * @global WP_Query $wp_query WordPress Query object. 649 * 650 * @return bool Whether the query is for the robots.txt file. 651 */ 652 function is_robots() { 653 global $wp_query; 654 655 if ( ! isset( $wp_query ) ) { 656 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 657 return false; 658 } 659 660 return $wp_query->is_robots(); 661 } 662 663 /** 664 * Is the query for the favicon.ico file? 665 * 666 * @since 5.4.0 667 * 668 * @global WP_Query $wp_query WordPress Query object. 669 * 670 * @return bool Whether the query is for the favicon.ico file. 671 */ 672 function is_favicon() { 673 global $wp_query; 674 675 if ( ! isset( $wp_query ) ) { 676 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 677 return false; 678 } 679 680 return $wp_query->is_favicon(); 681 } 682 683 /** 684 * Is the query for a sitemap? 685 * 686 * @since 7.1.0 687 * 688 * @global WP_Query $wp_query WordPress Query object. 689 * 690 * @return bool Whether the query is for a sitemap. 691 */ 692 function is_sitemap(): bool { 693 global $wp_query; 694 695 if ( ! isset( $wp_query ) ) { 696 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '7.1.0' ); 697 return false; 698 } 699 700 return $wp_query->is_sitemap(); 701 } 702 703 /** 704 * Determines whether the query is for random content. 705 * 706 * True for a blog home, archive or search request that includes the `random` query 707 * variable, for example `example.com/random/` or `example.com/random/category/news/`. 708 * 709 * @since 7.2.0 710 * 711 * @see wp_is_random_content_query() 712 * @global WP_Query $wp_query WordPress Query object. 713 * 714 * @return bool Whether the query is for random content. 715 */ 716 function is_random(): bool { 717 global $wp_query; 718 719 if ( ! isset( $wp_query ) ) { 720 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '7.2.0' ); 721 return false; 722 } 723 724 return $wp_query->is_random(); 725 } 726 727 /** 728 * Determines whether the query is for a search. 729 * 730 * For more information on this and similar theme functions, check out 731 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 732 * Conditional Tags} article in the Theme Developer Handbook. 733 * 734 * @since 1.5.0 735 * 736 * @global WP_Query $wp_query WordPress Query object. 737 * 738 * @return bool Whether the query is for a search. 739 */ 740 function is_search() { 741 global $wp_query; 742 743 if ( ! isset( $wp_query ) ) { 744 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 745 return false; 746 } 747 748 return $wp_query->is_search(); 749 } 750 751 /** 752 * Determines whether the query is for an existing single post. 753 * 754 * Works for any post type, except attachments and pages 755 * 756 * If the $post parameter is specified, this function will additionally 757 * check if the query is for one of the Posts specified. 758 * 759 * For more information on this and similar theme functions, check out 760 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 761 * Conditional Tags} article in the Theme Developer Handbook. 762 * 763 * @since 1.5.0 764 * 765 * @see is_page() 766 * @see is_singular() 767 * @global WP_Query $wp_query WordPress Query object. 768 * 769 * @param int|string|int[]|string[] $post Optional. Post ID, title, slug, or array of such 770 * to check against. Default empty. 771 * @return bool Whether the query is for an existing single post. 772 */ 773 function is_single( $post = '' ) { 774 global $wp_query; 775 776 if ( ! isset( $wp_query ) ) { 777 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 778 return false; 779 } 780 781 return $wp_query->is_single( $post ); 782 } 783 784 /** 785 * Determines whether the query is for an existing single post of any post type 786 * (post, attachment, page, custom post types). 787 * 788 * If the $post_types parameter is specified, this function will additionally 789 * check if the query is for one of the Posts Types specified. 790 * 791 * For more information on this and similar theme functions, check out 792 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 793 * Conditional Tags} article in the Theme Developer Handbook. 794 * 795 * @since 1.5.0 796 * 797 * @see is_page() 798 * @see is_single() 799 * @global WP_Query $wp_query WordPress Query object. 800 * 801 * @param string|string[] $post_types Optional. Post type or array of post types 802 * to check against. Default empty. 803 * @return bool Whether the query is for an existing single post 804 * or any of the given post types. 805 */ 806 function is_singular( $post_types = '' ) { 807 global $wp_query; 808 809 if ( ! isset( $wp_query ) ) { 810 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 811 return false; 812 } 813 814 return $wp_query->is_singular( $post_types ); 815 } 816 817 /** 818 * Determines whether the query is for a specific time. 819 * 820 * For more information on this and similar theme functions, check out 821 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 822 * Conditional Tags} article in the Theme Developer Handbook. 823 * 824 * @since 1.5.0 825 * 826 * @global WP_Query $wp_query WordPress Query object. 827 * 828 * @return bool Whether the query is for a specific time. 829 */ 830 function is_time() { 831 global $wp_query; 832 833 if ( ! isset( $wp_query ) ) { 834 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 835 return false; 836 } 837 838 return $wp_query->is_time(); 839 } 840 841 /** 842 * Determines whether the query is for a trackback endpoint call. 843 * 844 * For more information on this and similar theme functions, check out 845 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 846 * Conditional Tags} article in the Theme Developer Handbook. 847 * 848 * @since 1.5.0 849 * 850 * @global WP_Query $wp_query WordPress Query object. 851 * 852 * @return bool Whether the query is for a trackback endpoint call. 853 */ 854 function is_trackback() { 855 global $wp_query; 856 857 if ( ! isset( $wp_query ) ) { 858 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 859 return false; 860 } 861 862 return $wp_query->is_trackback(); 863 } 864 865 /** 866 * Determines whether the query is for an existing year archive. 867 * 868 * For more information on this and similar theme functions, check out 869 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 870 * Conditional Tags} article in the Theme Developer Handbook. 871 * 872 * @since 1.5.0 873 * 874 * @global WP_Query $wp_query WordPress Query object. 875 * 876 * @return bool Whether the query is for an existing year archive. 877 */ 878 function is_year() { 879 global $wp_query; 880 881 if ( ! isset( $wp_query ) ) { 882 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 883 return false; 884 } 885 886 return $wp_query->is_year(); 887 } 888 889 /** 890 * Determines whether the query has resulted in a 404 (returns no results). 891 * 892 * For more information on this and similar theme functions, check out 893 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 894 * Conditional Tags} article in the Theme Developer Handbook. 895 * 896 * @since 1.5.0 897 * 898 * @global WP_Query $wp_query WordPress Query object. 899 * 900 * @return bool Whether the query is a 404 error. 901 */ 902 function is_404() { 903 global $wp_query; 904 905 if ( ! isset( $wp_query ) ) { 906 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 907 return false; 908 } 909 910 return $wp_query->is_404(); 911 } 912 913 /** 914 * Is the query for an embedded post? 915 * 916 * @since 4.4.0 917 * 918 * @global WP_Query $wp_query WordPress Query object. 919 * 920 * @return bool Whether the query is for an embedded post. 921 */ 922 function is_embed() { 923 global $wp_query; 924 925 if ( ! isset( $wp_query ) ) { 926 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); 927 return false; 928 } 929 930 return $wp_query->is_embed(); 931 } 932 933 /** 934 * Determines whether the query is the main query. 935 * 936 * For more information on this and similar theme functions, check out 937 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 938 * Conditional Tags} article in the Theme Developer Handbook. 939 * 940 * @since 3.3.0 941 * 942 * @global WP_Query $wp_query WordPress Query object. 943 * 944 * @return bool Whether the query is the main query. 945 */ 946 function is_main_query() { 947 global $wp_query; 948 949 if ( ! isset( $wp_query ) ) { 950 _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '6.1.0' ); 951 return false; 952 } 953 954 if ( 'pre_get_posts' === current_filter() ) { 955 _doing_it_wrong( 956 __FUNCTION__, 957 sprintf( 958 /* translators: 1: pre_get_posts, 2: WP_Query->is_main_query(), 3: is_main_query(), 4: Documentation URL. */ 959 __( 'In %1$s, use the %2$s method, not the %3$s function. See %4$s.' ), 960 '<code>pre_get_posts</code>', 961 '<code>WP_Query->is_main_query()</code>', 962 '<code>is_main_query()</code>', 963 __( 'https://developer.wordpress.org/reference/functions/is_main_query/' ) 964 ), 965 '3.7.0' 966 ); 967 } 968 969 return $wp_query->is_main_query(); 970 } 971 972 /* 973 * The Loop. Post loop control. 974 */ 975 976 /** 977 * Determines whether current WordPress query has posts to loop over. 978 * 979 * @since 1.5.0 980 * 981 * @global WP_Query $wp_query WordPress Query object. 982 * 983 * @phpstan-impure 984 * 985 * @return bool True if posts are available, false if end of the loop. 986 */ 987 function have_posts() { 988 global $wp_query; 989 990 if ( ! isset( $wp_query ) ) { 991 return false; 992 } 993 994 return $wp_query->have_posts(); 995 } 996 997 /** 998 * Determines whether the caller is in the Loop. 999 * 1000 * For more information on this and similar theme functions, check out 1001 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 1002 * Conditional Tags} article in the Theme Developer Handbook. 1003 * 1004 * @since 2.0.0 1005 * 1006 * @global WP_Query $wp_query WordPress Query object. 1007 * 1008 * @return bool True if caller is within loop, false if loop hasn't started or ended. 1009 */ 1010 function in_the_loop() { 1011 global $wp_query; 1012 1013 if ( ! isset( $wp_query ) ) { 1014 return false; 1015 } 1016 1017 return $wp_query->in_the_loop; 1018 } 1019 1020 /** 1021 * Rewind the loop posts. 1022 * 1023 * @since 1.5.0 1024 * 1025 * @global WP_Query $wp_query WordPress Query object. 1026 */ 1027 function rewind_posts() { 1028 global $wp_query; 1029 1030 if ( ! isset( $wp_query ) ) { 1031 return; 1032 } 1033 1034 $wp_query->rewind_posts(); 1035 } 1036 1037 /** 1038 * Iterate the post index in the loop. 1039 * 1040 * @since 1.5.0 1041 * 1042 * @global WP_Query $wp_query WordPress Query object. 1043 */ 1044 function the_post() { 1045 global $wp_query; 1046 1047 if ( ! isset( $wp_query ) ) { 1048 return; 1049 } 1050 1051 $wp_query->the_post(); 1052 } 1053 1054 /* 1055 * Comments loop. 1056 */ 1057 1058 /** 1059 * Determines whether current WordPress query has comments to loop over. 1060 * 1061 * @since 2.2.0 1062 * 1063 * @global WP_Query $wp_query WordPress Query object. 1064 * 1065 * @phpstan-impure 1066 * 1067 * @return bool True if comments are available, false if no more comments. 1068 */ 1069 function have_comments() { 1070 global $wp_query; 1071 1072 if ( ! isset( $wp_query ) ) { 1073 return false; 1074 } 1075 1076 return $wp_query->have_comments(); 1077 } 1078 1079 /** 1080 * Iterate comment index in the comment loop. 1081 * 1082 * @since 2.2.0 1083 * 1084 * @global WP_Query $wp_query WordPress Query object. 1085 */ 1086 function the_comment() { 1087 global $wp_query; 1088 1089 if ( ! isset( $wp_query ) ) { 1090 return; 1091 } 1092 1093 $wp_query->the_comment(); 1094 } 1095 1096 /** 1097 * Redirect old slugs to the correct permalink. 1098 * 1099 * Attempts to find the current slug from the past slugs. 1100 * 1101 * @since 2.1.0 1102 */ 1103 function wp_old_slug_redirect() { 1104 if ( is_404() && '' !== get_query_var( 'name' ) ) { 1105 // Guess the current post type based on the query vars. 1106 if ( get_query_var( 'post_type' ) ) { 1107 $post_type = get_query_var( 'post_type' ); 1108 } elseif ( get_query_var( 'attachment' ) ) { 1109 $post_type = 'attachment'; 1110 } elseif ( get_query_var( 'pagename' ) ) { 1111 $post_type = 'page'; 1112 } else { 1113 $post_type = 'post'; 1114 } 1115 1116 if ( is_array( $post_type ) ) { 1117 if ( count( $post_type ) > 1 ) { 1118 return; 1119 } 1120 $post_type = reset( $post_type ); 1121 } 1122 1123 // Do not attempt redirect for hierarchical post types. 1124 if ( is_post_type_hierarchical( $post_type ) ) { 1125 return; 1126 } 1127 1128 $id = _find_post_by_old_slug( $post_type ); 1129 1130 if ( ! $id ) { 1131 $id = _find_post_by_old_date( $post_type ); 1132 } 1133 1134 /** 1135 * Filters the old slug redirect post ID. 1136 * 1137 * @since 4.9.3 1138 * 1139 * @param int $id The redirect post ID. 1140 */ 1141 $id = apply_filters( 'old_slug_redirect_post_id', $id ); 1142 1143 if ( ! $id ) { 1144 return; 1145 } 1146 1147 $link = get_permalink( $id ); 1148 1149 if ( get_query_var( 'paged' ) > 1 ) { 1150 $link = user_trailingslashit( trailingslashit( $link ) . 'page/' . get_query_var( 'paged' ) ); 1151 } elseif ( is_embed() ) { 1152 $link = user_trailingslashit( trailingslashit( $link ) . 'embed' ); 1153 } 1154 1155 /** 1156 * Filters the old slug redirect URL. 1157 * 1158 * @since 4.4.0 1159 * 1160 * @param string $link The redirect URL. 1161 */ 1162 $link = apply_filters( 'old_slug_redirect_url', $link ); 1163 1164 if ( ! $link ) { 1165 return; 1166 } 1167 1168 wp_redirect( $link, 301 ); // Permanent redirect. 1169 exit; 1170 } 1171 } 1172 1173 /** 1174 * Find the post ID for redirecting an old slug. 1175 * 1176 * @since 4.9.3 1177 * @access private 1178 * 1179 * @see wp_old_slug_redirect() 1180 * @global wpdb $wpdb WordPress database abstraction object. 1181 * 1182 * @param string $post_type The current post type based on the query vars. 1183 * @return int The Post ID. 1184 */ 1185 function _find_post_by_old_slug( $post_type ) { 1186 global $wpdb; 1187 1188 $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_slug' AND meta_value = %s", $post_type, get_query_var( 'name' ) ); 1189 1190 /* 1191 * If year, monthnum, or day have been specified, make our query more precise 1192 * just in case there are multiple identical _wp_old_slug values. 1193 */ 1194 if ( get_query_var( 'year' ) ) { 1195 $query .= $wpdb->prepare( ' AND YEAR(post_date) = %d', get_query_var( 'year' ) ); 1196 } 1197 if ( get_query_var( 'monthnum' ) ) { 1198 $query .= $wpdb->prepare( ' AND MONTH(post_date) = %d', get_query_var( 'monthnum' ) ); 1199 } 1200 if ( get_query_var( 'day' ) ) { 1201 $query .= $wpdb->prepare( ' AND DAYOFMONTH(post_date) = %d', get_query_var( 'day' ) ); 1202 } 1203 1204 $key = md5( $query ); 1205 $last_changed = wp_cache_get_last_changed( 'posts' ); 1206 $cache_key = "find_post_by_old_slug:$key"; 1207 $cache = wp_cache_get_salted( $cache_key, 'post-queries', $last_changed ); 1208 if ( false !== $cache ) { 1209 $id = $cache; 1210 } else { 1211 $id = (int) $wpdb->get_var( $query ); 1212 wp_cache_set_salted( $cache_key, $id, 'post-queries', $last_changed ); 1213 } 1214 1215 return $id; 1216 } 1217 1218 /** 1219 * Find the post ID for redirecting an old date. 1220 * 1221 * @since 4.9.3 1222 * @access private 1223 * 1224 * @see wp_old_slug_redirect() 1225 * @global wpdb $wpdb WordPress database abstraction object. 1226 * 1227 * @param string $post_type The current post type based on the query vars. 1228 * @return int The Post ID. 1229 */ 1230 function _find_post_by_old_date( $post_type ) { 1231 global $wpdb; 1232 1233 $date_query = ''; 1234 if ( get_query_var( 'year' ) ) { 1235 $date_query .= $wpdb->prepare( ' AND YEAR(pm_date.meta_value) = %d', get_query_var( 'year' ) ); 1236 } 1237 if ( get_query_var( 'monthnum' ) ) { 1238 $date_query .= $wpdb->prepare( ' AND MONTH(pm_date.meta_value) = %d', get_query_var( 'monthnum' ) ); 1239 } 1240 if ( get_query_var( 'day' ) ) { 1241 $date_query .= $wpdb->prepare( ' AND DAYOFMONTH(pm_date.meta_value) = %d', get_query_var( 'day' ) ); 1242 } 1243 1244 $id = 0; 1245 if ( $date_query ) { 1246 $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta AS pm_date, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_date' AND post_name = %s" . $date_query, $post_type, get_query_var( 'name' ) ); 1247 $key = md5( $query ); 1248 $last_changed = wp_cache_get_last_changed( 'posts' ); 1249 $cache_key = "find_post_by_old_date:$key"; 1250 $cache = wp_cache_get_salted( $cache_key, 'post-queries', $last_changed ); 1251 if ( false !== $cache ) { 1252 $id = $cache; 1253 } else { 1254 $id = (int) $wpdb->get_var( $query ); 1255 if ( ! $id ) { 1256 // Check to see if an old slug matches the old date. 1257 $id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts, $wpdb->postmeta AS pm_slug, $wpdb->postmeta AS pm_date WHERE ID = pm_slug.post_id AND ID = pm_date.post_id AND post_type = %s AND pm_slug.meta_key = '_wp_old_slug' AND pm_slug.meta_value = %s AND pm_date.meta_key = '_wp_old_date'" . $date_query, $post_type, get_query_var( 'name' ) ) ); 1258 } 1259 wp_cache_set_salted( $cache_key, $id, 'post-queries', $last_changed ); 1260 } 1261 } 1262 1263 return $id; 1264 } 1265 1266 /** 1267 * Determines whether random content redirects are enabled. 1268 * 1269 * @since 7.2.0 1270 * 1271 * @return bool True if random content redirects are enabled, false otherwise. 1272 */ 1273 function wp_is_random_content_redirect_enabled(): bool { 1274 /** 1275 * Filters whether random content redirects are enabled. 1276 * 1277 * Random content redirects add rewrite rules for URLs such as `/random/`, so the 1278 * rewrite rules need to be flushed after changing the value returned by this filter. 1279 * 1280 * @since 7.2.0 1281 * 1282 * @param bool $enabled Whether random content redirects are enabled. Default true. 1283 */ 1284 return (bool) apply_filters( 'wp_enable_random_content_redirect', true ); 1285 } 1286 1287 /** 1288 * Determines whether a query is a request for random content. 1289 * 1290 * A random content request is a front end, main query for the blog home, an archive, 1291 * or search results that includes the `random` query variable and at least one 1292 * `randomable` post type. For example 1293 * `example.com/random/`, `example.com/random/category/news/` or `example.com/?s=foo&random`. 1294 * 1295 * Singular (including embeds) and feed requests are never random content requests, 1296 * nor are requests using an HTTP method other than GET or HEAD. 1297 * 1298 * @since 7.2.0 1299 * 1300 * @param WP_Query $query The query to check. 1301 * @return bool True if the query is a request for random content, false otherwise. 1302 */ 1303 function wp_is_random_content_query( WP_Query $query ): bool { 1304 if ( 1305 ! $query->is_random() 1306 || ! $query->is_main_query() 1307 || is_admin() 1308 || ! wp_is_random_content_redirect_enabled() 1309 ) { 1310 return false; 1311 } 1312 1313 $request_method = isset( $_SERVER['REQUEST_METHOD'] ) && is_string( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( $_SERVER['REQUEST_METHOD'] ) : ''; 1314 if ( 'GET' !== $request_method && 'HEAD' !== $request_method ) { 1315 return false; 1316 } 1317 1318 return array() !== wp_get_random_content_post_types( $query ); 1319 } 1320 1321 /** 1322 * Retrieves the post types eligible for selection by a random content request. 1323 * 1324 * These are the post types the query would otherwise return, limited to those 1325 * registered as `randomable`. 1326 * 1327 * @since 7.2.0 1328 * 1329 * @see register_post_type() 1330 * 1331 * @param WP_Query $query The query to retrieve the post types for. 1332 * @return string[] Post type names eligible for random selection. 1333 * 1334 * @phpstan-return list<string> 1335 */ 1336 function wp_get_random_content_post_types( WP_Query $query ): array { 1337 $post_types = $query->get( 'post_type' ); 1338 1339 if ( empty( $post_types ) && $query->is_tax() && $query->tax_query instanceof WP_Tax_Query ) { 1340 // Match WP_Query::get_posts(): searchable post types using any of the queried taxonomies. 1341 $taxonomies = array_keys( $query->tax_query->queried_terms ); 1342 $post_types = array(); 1343 1344 foreach ( get_post_types( array( 'exclude_from_search' => false ) ) as $post_type ) { 1345 $object_taxonomies = 'attachment' === $post_type ? get_taxonomies_for_attachments() : get_object_taxonomies( $post_type ); 1346 if ( array_intersect( $taxonomies, $object_taxonomies ) ) { 1347 $post_types[] = $post_type; 1348 } 1349 } 1350 } elseif ( empty( $post_types ) && ! $query->is_search() ) { 1351 $post_types = array( 'post' ); 1352 } 1353 1354 if ( empty( $post_types ) || 'any' === $post_types ) { 1355 $post_types = get_post_types( array( 'exclude_from_search' => false ) ); 1356 } 1357 1358 $random_post_types = array(); 1359 1360 foreach ( (array) $post_types as $post_type ) { 1361 // Plugins may set invalid values on the `post_type` query variable. 1362 if ( ! is_string( $post_type ) ) { 1363 continue; 1364 } 1365 1366 $post_type_object = get_post_type_object( $post_type ); 1367 1368 if ( $post_type_object && $post_type_object->randomable ) { 1369 $random_post_types[] = $post_type_object->name; 1370 } 1371 } 1372 1373 return $random_post_types; 1374 } 1375 1376 /** 1377 * Limits the main query to posts eligible for random content requests. 1378 * 1379 * The main query is used to select the random post so the request runs the same 1380 * query, and the same filters, as the archive it is randomizing. As such, callbacks 1381 * on the {@see 'pre_get_posts'} action may modify the posts eligible for selection, 1382 * for example to limit the post types or exclude a category: 1383 * 1384 * add_action( 1385 * 'pre_get_posts', 1386 * static function ( WP_Query $query ) { 1387 * if ( wp_is_random_content_query( $query ) ) { 1388 * $query->set( 'category__not_in', array( 1 ) ); 1389 * } 1390 * } 1391 * ); 1392 * 1393 * Only randomable post types and published posts without a password are eligible. 1394 * The number and order of posts are enforced by {@see wp_random_content_post_limits()} and 1395 * {@see wp_random_content_posts_orderby()}, so callbacks modifying them on archives do not 1396 * affect the selection. 1397 * 1398 * Added to the {@see 'pre_get_posts'} action by {@see WP::handle_random()} while the 1399 * random content query runs, so it runs after other callbacks. 1400 * 1401 * @since 7.2.0 1402 * 1403 * @param WP_Query $query The WP_Query instance (passed by reference). 1404 */ 1405 function wp_random_content_pre_get_posts( $query ): void { 1406 if ( ! wp_is_random_content_query( $query ) ) { 1407 return; 1408 } 1409 1410 $query->set( 'post_type', wp_get_random_content_post_types( $query ) ); 1411 $query->set( 'post_status', 'publish' ); 1412 $query->set( 'has_password', false ); 1413 $query->set( 'ignore_sticky_posts', true ); 1414 $query->set( 'no_found_rows', true ); 1415 $query->set( 'update_post_meta_cache', false ); 1416 $query->set( 'update_post_term_cache', false ); 1417 // The order and number of posts are enforced by filters, which a suppressed query skips. 1418 $query->set( 'suppress_filters', false ); 1419 } 1420 1421 /** 1422 * Orders the random content query randomly. 1423 * 1424 * Added to the {@see 'posts_orderby'} filter by {@see WP::handle_random()} while the random 1425 * content query runs. Enforcing the order in SQL prevents {@see 'pre_get_posts'} 1426 * callbacks setting the order of posts on archives from affecting the selection. 1427 * 1428 * @since 7.2.0 1429 * 1430 * @param string $orderby The ORDER BY clause of the query. 1431 * @param WP_Query $query The WP_Query instance. 1432 * @return string The ORDER BY clause of the query. 1433 */ 1434 function wp_random_content_posts_orderby( $orderby, WP_Query $query ): string { 1435 if ( wp_is_random_content_query( $query ) ) { 1436 return 'RAND()'; 1437 } 1438 1439 return (string) $orderby; 1440 } 1441 1442 /** 1443 * Limits the random content query to a single post. 1444 * 1445 * Added to the {@see 'post_limits'} filter by {@see WP::handle_random()} while the random 1446 * content query runs. Enforcing the limit in SQL prevents {@see 'pre_get_posts'} 1447 * callbacks setting the number of posts, offset or page on archives from affecting 1448 * the selection. 1449 * 1450 * @since 7.2.0 1451 * 1452 * @param string $limits The LIMIT clause of the query. 1453 * @param WP_Query $query The WP_Query instance. 1454 * @return string The LIMIT clause of the query. 1455 */ 1456 function wp_random_content_post_limits( $limits, WP_Query $query ): string { 1457 if ( wp_is_random_content_query( $query ) ) { 1458 return 'LIMIT 0, 1'; 1459 } 1460 1461 return (string) $limits; 1462 } 1463 1464 /** 1465 * Prevents the random content query from being split into multiple database queries. 1466 * 1467 * Randomly ordered queries are not cached, so there is no benefit to querying the post 1468 * IDs separately to the post objects. Disabling the split allows the random post to be 1469 * retrieved in a single database query. 1470 * 1471 * @since 7.2.0 1472 * 1473 * @param bool $split_the_query Whether or not to split the query. 1474 * @param WP_Query $query The WP_Query instance. 1475 * @return bool Whether or not to split the query. 1476 */ 1477 function wp_random_content_split_the_query( $split_the_query, WP_Query $query ): bool { 1478 if ( wp_is_random_content_query( $query ) ) { 1479 return false; 1480 } 1481 1482 return (bool) $split_the_query; 1483 } 1484 1485 /** 1486 * Redirects random content requests to the randomly selected post. 1487 * 1488 * Called by {@see WP::handle_random()} immediately after the main query selects the 1489 * random post, to avoid unnecessary processing before the redirect. As the redirect 1490 * is sent before {@see WP::send_headers()}, the headers preventing the redirect being 1491 * cached or indexed are sent with it. 1492 * 1493 * If no post is selected, for example on an empty archive, {@see WP::handle_random()} 1494 * handles the request as a 404. If the post's permalink is on another site, the 1495 * request is handled as a regular archive request. 1496 * 1497 * @since 7.2.0 1498 * 1499 * @global WP_Query $wp_query WordPress Query object. 1500 */ 1501 function wp_random_content_redirect(): void { 1502 global $wp_query; 1503 1504 if ( ! wp_is_random_content_query( $wp_query ) || ! $wp_query->post instanceof WP_Post ) { 1505 return; 1506 } 1507 1508 $location = get_permalink( $wp_query->post ); 1509 1510 // Only consider redirecting permitted locations so wp_safe_redirect doesn't redirect to the fallback. 1511 if ( ! $location || ! wp_validate_redirect( $location, '' ) ) { 1512 return; 1513 } 1514 1515 nocache_headers(); 1516 1517 if ( ! headers_sent() ) { 1518 header( 'X-Robots-Tag: noindex, follow' ); 1519 } 1520 1521 if ( wp_safe_redirect( $location, 302 ) ) { 1522 exit; 1523 } 1524 } 1525 1526 /** 1527 * Flushes the rewrite rules when a page or post at the random content base changes. 1528 * 1529 * A published page at the random base, for example `example.com/random/`, takes 1530 * precedence over random content redirects. So does a published post when the 1531 * permalink structure places posts at the same URL, for example `/%postname%/`, 1532 * see {@see WP_Rewrite::post_permalinks_share_random_base()}. As the rewrite rules account 1533 * for the page or post, they need to be regenerated when it is published, 1534 * unpublished, renamed, moved or deleted. 1535 * 1536 * Runs on the {@see 'wp_after_insert_post'} and {@see 'after_delete_post'} actions. 1537 * 1538 * @since 7.2.0 1539 * 1540 * @see WP_Rewrite::random_rewrite_rules() 1541 * @global WP_Rewrite $wp_rewrite WordPress rewrite component. 1542 * 1543 * @param int $post_id Post ID. 1544 * @param WP_Post $post Post object. 1545 * @param bool $update Optional. Whether this is an existing post being updated. Default false. 1546 * @param WP_Post|null $post_before Optional. Post object before the update, null for new posts. Default null. 1547 */ 1548 function wp_random_content_flush_rewrite_rules_for_post( int $post_id, WP_Post $post, bool $update = false, ?WP_Post $post_before = null ): void { 1549 global $wp_rewrite; 1550 1551 if ( ! $wp_rewrite->using_permalinks() || ! wp_is_random_content_redirect_enabled() ) { 1552 return; 1553 } 1554 1555 foreach ( array( $post, $post_before ) as $page ) { 1556 if ( 1557 $page instanceof WP_Post 1558 && $wp_rewrite->get_random_base() === $page->post_name 1559 && ( 1560 ( 'page' === $page->post_type && 0 === (int) $page->post_parent ) 1561 || ( 'post' === $page->post_type && $wp_rewrite->post_permalinks_share_random_base() ) 1562 ) 1563 ) { 1564 flush_rewrite_rules( false ); 1565 return; 1566 } 1567 } 1568 } 1569 1570 /** 1571 * Set up global post data. 1572 * 1573 * @since 1.5.0 1574 * @since 4.4.0 Added the ability to pass a post ID to `$post`. 1575 * 1576 * @global WP_Query $wp_query WordPress Query object. 1577 * 1578 * @param WP_Post|object|int $post WP_Post instance or Post ID/object. 1579 * @return bool True when finished. 1580 */ 1581 function setup_postdata( $post ) { 1582 global $wp_query; 1583 1584 if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) { 1585 return $wp_query->setup_postdata( $post ); 1586 } 1587 1588 return false; 1589 } 1590 1591 /** 1592 * Generates post data. 1593 * 1594 * @since 5.2.0 1595 * 1596 * @global WP_Query $wp_query WordPress Query object. 1597 * 1598 * @param WP_Post|object|int $post WP_Post instance or Post ID/object. 1599 * @return array|false Elements of post, or false on failure. 1600 */ 1601 function generate_postdata( $post ) { 1602 global $wp_query; 1603 1604 if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) { 1605 return $wp_query->generate_postdata( $post ); 1606 } 1607 1608 return false; 1609 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Oct 25 08:20:35 2026 | Cross-referenced by PHPXref |