[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> template.php (source)

   1  <?php
   2  /**
   3   * Template loading functions.
   4   *
   5   * @package WordPress
   6   * @subpackage Template
   7   */
   8  
   9  /**
  10   * Retrieves path to a template.
  11   *
  12   * Used to quickly retrieve the path of a template without including the file
  13   * extension. It will also check the parent theme, if the file exists, with
  14   * the use of locate_template(). Allows for more generic template location
  15   * without the use of the other get_*_template() functions.
  16   *
  17   * @since 1.5.0
  18   *
  19   * @param string   $type      Filename without extension.
  20   * @param string[] $templates An optional list of template candidates.
  21   * @return string Full path to template file.
  22   */
  23  function get_query_template( $type, $templates = array() ) {
  24      $type = preg_replace( '|[^a-z0-9-]+|', '', $type );
  25  
  26      if ( empty( $templates ) ) {
  27          $templates = array( "{$type}.php" );
  28      }
  29  
  30      /**
  31       * Filters the list of template filenames that are searched for when retrieving a template to use.
  32       *
  33       * The dynamic portion of the hook name, `$type`, refers to the filename -- minus the file
  34       * extension and any non-alphanumeric characters delimiting words -- of the file to load.
  35       * The last element in the array should always be the fallback template for this query type.
  36       *
  37       * Possible hook names include:
  38       *
  39       *  - `404_template_hierarchy`
  40       *  - `archive_template_hierarchy`
  41       *  - `attachment_template_hierarchy`
  42       *  - `author_template_hierarchy`
  43       *  - `category_template_hierarchy`
  44       *  - `date_template_hierarchy`
  45       *  - `embed_template_hierarchy`
  46       *  - `frontpage_template_hierarchy`
  47       *  - `home_template_hierarchy`
  48       *  - `index_template_hierarchy`
  49       *  - `page_template_hierarchy`
  50       *  - `paged_template_hierarchy`
  51       *  - `privacypolicy_template_hierarchy`
  52       *  - `search_template_hierarchy`
  53       *  - `single_template_hierarchy`
  54       *  - `singular_template_hierarchy`
  55       *  - `tag_template_hierarchy`
  56       *  - `taxonomy_template_hierarchy`
  57       *
  58       * @since 4.7.0
  59       *
  60       * @param string[] $templates A list of template candidates, in descending order of priority.
  61       */
  62      $templates = apply_filters( "{$type}_template_hierarchy", $templates );
  63  
  64      $template = locate_template( $templates );
  65  
  66      $template = locate_block_template( $template, $type, $templates );
  67  
  68      /**
  69       * Filters the path of the queried template by type.
  70       *
  71       * The dynamic portion of the hook name, `$type`, refers to the filename -- minus the file
  72       * extension and any non-alphanumeric characters delimiting words -- of the file to load.
  73       * This hook also applies to various types of files loaded as part of the Template Hierarchy.
  74       *
  75       * Possible hook names include:
  76       *
  77       *  - `404_template`
  78       *  - `archive_template`
  79       *  - `attachment_template`
  80       *  - `author_template`
  81       *  - `category_template`
  82       *  - `date_template`
  83       *  - `embed_template`
  84       *  - `frontpage_template`
  85       *  - `home_template`
  86       *  - `index_template`
  87       *  - `page_template`
  88       *  - `paged_template`
  89       *  - `privacypolicy_template`
  90       *  - `search_template`
  91       *  - `single_template`
  92       *  - `singular_template`
  93       *  - `tag_template`
  94       *  - `taxonomy_template`
  95       *
  96       * @since 1.5.0
  97       * @since 4.8.0 The `$type` and `$templates` parameters were added.
  98       *
  99       * @param string   $template  Path to the template. See locate_template().
 100       * @param string   $type      Sanitized filename without extension.
 101       * @param string[] $templates A list of template candidates, in descending order of priority.
 102       */
 103      return apply_filters( "{$type}_template", $template, $type, $templates );
 104  }
 105  
 106  /**
 107   * Retrieves path of index template in current or parent template.
 108   *
 109   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 110   * and {@see '$type_template'} dynamic hooks, where `$type` is 'index'.
 111   *
 112   * @since 3.0.0
 113   *
 114   * @see get_query_template()
 115   *
 116   * @return string Full path to index template file.
 117   */
 118  function get_index_template() {
 119      return get_query_template( 'index' );
 120  }
 121  
 122  /**
 123   * Retrieves path of 404 template in current or parent template.
 124   *
 125   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 126   * and {@see '$type_template'} dynamic hooks, where `$type` is '404'.
 127   *
 128   * @since 1.5.0
 129   *
 130   * @see get_query_template()
 131   *
 132   * @return string Full path to 404 template file.
 133   */
 134  function get_404_template() {
 135      return get_query_template( '404' );
 136  }
 137  
 138  /**
 139   * Retrieves path of archive template in current or parent template.
 140   *
 141   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 142   * and {@see '$type_template'} dynamic hooks, where `$type` is 'archive'.
 143   *
 144   * @since 1.5.0
 145   *
 146   * @see get_query_template()
 147   *
 148   * @return string Full path to archive template file.
 149   */
 150  function get_archive_template() {
 151      $post_types = array_filter( (array) get_query_var( 'post_type' ) );
 152  
 153      $templates = array();
 154  
 155      if ( count( $post_types ) === 1 ) {
 156          $post_type   = reset( $post_types );
 157          $templates[] = "archive-{$post_type}.php";
 158      }
 159      $templates[] = 'archive.php';
 160  
 161      return get_query_template( 'archive', $templates );
 162  }
 163  
 164  /**
 165   * Retrieves path of post type archive template in current or parent template.
 166   *
 167   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 168   * and {@see '$type_template'} dynamic hooks, where `$type` is 'archive'.
 169   *
 170   * @since 3.7.0
 171   *
 172   * @see get_archive_template()
 173   *
 174   * @return string Full path to archive template file.
 175   */
 176  function get_post_type_archive_template() {
 177      $post_type = get_query_var( 'post_type' );
 178      if ( is_array( $post_type ) ) {
 179          $post_type = reset( $post_type );
 180      }
 181  
 182      $obj = get_post_type_object( $post_type );
 183      if ( ! ( $obj instanceof WP_Post_Type ) || ! $obj->has_archive ) {
 184          return '';
 185      }
 186  
 187      return get_archive_template();
 188  }
 189  
 190  /**
 191   * Retrieves path of author template in current or parent template.
 192   *
 193   * The hierarchy for this template looks like:
 194   *
 195   * 1. author-{nicename}.php
 196   * 2. author-{id}.php
 197   * 3. author.php
 198   *
 199   * An example of this is:
 200   *
 201   * 1. author-john.php
 202   * 2. author-1.php
 203   * 3. author.php
 204   *
 205   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 206   * and {@see '$type_template'} dynamic hooks, where `$type` is 'author'.
 207   *
 208   * @since 1.5.0
 209   *
 210   * @see get_query_template()
 211   *
 212   * @return string Full path to author template file.
 213   */
 214  function get_author_template() {
 215      $author = get_queried_object();
 216  
 217      $templates = array();
 218  
 219      if ( $author instanceof WP_User ) {
 220          $templates[] = "author-{$author->user_nicename}.php";
 221          $templates[] = "author-{$author->ID}.php";
 222      }
 223      $templates[] = 'author.php';
 224  
 225      return get_query_template( 'author', $templates );
 226  }
 227  
 228  /**
 229   * Retrieves path of category template in current or parent template.
 230   *
 231   * The hierarchy for this template looks like:
 232   *
 233   * 1. category-{slug}.php
 234   * 2. category-{id}.php
 235   * 3. category.php
 236   *
 237   * An example of this is:
 238   *
 239   * 1. category-news.php
 240   * 2. category-2.php
 241   * 3. category.php
 242   *
 243   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 244   * and {@see '$type_template'} dynamic hooks, where `$type` is 'category'.
 245   *
 246   * @since 1.5.0
 247   * @since 4.7.0 The decoded form of `category-{slug}.php` was added to the top of the
 248   *              template hierarchy when the category slug contains multibyte characters.
 249   *
 250   * @see get_query_template()
 251   *
 252   * @return string Full path to category template file.
 253   */
 254  function get_category_template() {
 255      $category = get_queried_object();
 256  
 257      $templates = array();
 258  
 259      if ( ! empty( $category->slug ) ) {
 260  
 261          $slug_decoded = urldecode( $category->slug );
 262          if ( $slug_decoded !== $category->slug ) {
 263              $templates[] = "category-{$slug_decoded}.php";
 264          }
 265  
 266          $templates[] = "category-{$category->slug}.php";
 267          $templates[] = "category-{$category->term_id}.php";
 268      }
 269      $templates[] = 'category.php';
 270  
 271      return get_query_template( 'category', $templates );
 272  }
 273  
 274  /**
 275   * Retrieves path of tag template in current or parent template.
 276   *
 277   * The hierarchy for this template looks like:
 278   *
 279   * 1. tag-{slug}.php
 280   * 2. tag-{id}.php
 281   * 3. tag.php
 282   *
 283   * An example of this is:
 284   *
 285   * 1. tag-wordpress.php
 286   * 2. tag-3.php
 287   * 3. tag.php
 288   *
 289   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 290   * and {@see '$type_template'} dynamic hooks, where `$type` is 'tag'.
 291   *
 292   * @since 2.3.0
 293   * @since 4.7.0 The decoded form of `tag-{slug}.php` was added to the top of the
 294   *              template hierarchy when the tag slug contains multibyte characters.
 295   *
 296   * @see get_query_template()
 297   *
 298   * @return string Full path to tag template file.
 299   */
 300  function get_tag_template() {
 301      $tag = get_queried_object();
 302  
 303      $templates = array();
 304  
 305      if ( ! empty( $tag->slug ) ) {
 306  
 307          $slug_decoded = urldecode( $tag->slug );
 308          if ( $slug_decoded !== $tag->slug ) {
 309              $templates[] = "tag-{$slug_decoded}.php";
 310          }
 311  
 312          $templates[] = "tag-{$tag->slug}.php";
 313          $templates[] = "tag-{$tag->term_id}.php";
 314      }
 315      $templates[] = 'tag.php';
 316  
 317      return get_query_template( 'tag', $templates );
 318  }
 319  
 320  /**
 321   * Retrieves path of custom taxonomy term template in current or parent template.
 322   *
 323   * The hierarchy for this template looks like:
 324   *
 325   * 1. taxonomy-{taxonomy_slug}-{term_slug}.php
 326   * 2. taxonomy-{taxonomy_slug}-{term_id}.php
 327   * 3. taxonomy-{taxonomy_slug}.php
 328   * 4. taxonomy.php
 329   *
 330   * An example of this is:
 331   *
 332   * 1. taxonomy-location-texas.php
 333   * 2. taxonomy-location-67.php
 334   * 3. taxonomy-location.php
 335   * 4. taxonomy.php
 336   *
 337   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 338   * and {@see '$type_template'} dynamic hooks, where `$type` is 'taxonomy'.
 339   *
 340   * @since 2.5.0
 341   * @since 4.7.0 The decoded form of `taxonomy-{taxonomy_slug}-{term_slug}.php` was added to the top of the
 342   *              template hierarchy when the term slug contains multibyte characters.
 343   * @since 6.9.0 Added `taxonomy-{taxonomy_slug}-{term_id}.php` to the hierarchy.
 344   *
 345   * @see get_query_template()
 346   *
 347   * @return string Full path to custom taxonomy term template file.
 348   */
 349  function get_taxonomy_template() {
 350      $term = get_queried_object();
 351  
 352      $templates = array();
 353  
 354      if ( ! empty( $term->slug ) ) {
 355          $taxonomy = $term->taxonomy;
 356  
 357          $slug_decoded = urldecode( $term->slug );
 358          if ( $slug_decoded !== $term->slug ) {
 359              $templates[] = "taxonomy-$taxonomy-{$slug_decoded}.php";
 360          }
 361  
 362          $templates[] = "taxonomy-$taxonomy-{$term->slug}.php";
 363          $templates[] = "taxonomy-$taxonomy-{$term->term_id}.php";
 364          $templates[] = "taxonomy-$taxonomy.php";
 365      }
 366      $templates[] = 'taxonomy.php';
 367  
 368      return get_query_template( 'taxonomy', $templates );
 369  }
 370  
 371  /**
 372   * Retrieves path of date template in current or parent template.
 373   *
 374   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 375   * and {@see '$type_template'} dynamic hooks, where `$type` is 'date'.
 376   *
 377   * @since 1.5.0
 378   *
 379   * @see get_query_template()
 380   *
 381   * @return string Full path to date template file.
 382   */
 383  function get_date_template() {
 384      return get_query_template( 'date' );
 385  }
 386  
 387  /**
 388   * Retrieves path of home template in current or parent template.
 389   *
 390   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 391   * and {@see '$type_template'} dynamic hooks, where `$type` is 'home'.
 392   *
 393   * @since 1.5.0
 394   *
 395   * @see get_query_template()
 396   *
 397   * @return string Full path to home template file.
 398   */
 399  function get_home_template() {
 400      $templates = array( 'home.php', 'index.php' );
 401  
 402      return get_query_template( 'home', $templates );
 403  }
 404  
 405  /**
 406   * Retrieves path of front page template in current or parent template.
 407   *
 408   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 409   * and {@see '$type_template'} dynamic hooks, where `$type` is 'frontpage'.
 410   *
 411   * @since 3.0.0
 412   *
 413   * @see get_query_template()
 414   *
 415   * @return string Full path to front page template file.
 416   */
 417  function get_front_page_template() {
 418      $templates = array( 'front-page.php' );
 419  
 420      return get_query_template( 'frontpage', $templates );
 421  }
 422  
 423  /**
 424   * Retrieves path of Privacy Policy page template in current or parent template.
 425   *
 426   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 427   * and {@see '$type_template'} dynamic hooks, where `$type` is 'privacypolicy'.
 428   *
 429   * @since 5.2.0
 430   *
 431   * @see get_query_template()
 432   *
 433   * @return string Full path to privacy policy template file.
 434   */
 435  function get_privacy_policy_template() {
 436      $templates = array( 'privacy-policy.php' );
 437  
 438      return get_query_template( 'privacypolicy', $templates );
 439  }
 440  
 441  /**
 442   * Retrieves path of page template in current or parent template.
 443   *
 444   * Note: For block themes, use locate_block_template() function instead.
 445   *
 446   * The hierarchy for this template looks like:
 447   *
 448   * 1. {Page Template}.php
 449   * 2. page-{page_name}.php
 450   * 3. page-{id}.php
 451   * 4. page.php
 452   *
 453   * An example of this is:
 454   *
 455   * 1. page-templates/full-width.php
 456   * 2. page-about.php
 457   * 3. page-4.php
 458   * 4. page.php
 459   *
 460   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 461   * and {@see '$type_template'} dynamic hooks, where `$type` is 'page'.
 462   *
 463   * @since 1.5.0
 464   * @since 4.7.0 The decoded form of `page-{page_name}.php` was added to the top of the
 465   *              template hierarchy when the page name contains multibyte characters.
 466   *
 467   * @see get_query_template()
 468   *
 469   * @return string Full path to page template file.
 470   */
 471  function get_page_template() {
 472      $id       = get_queried_object_id();
 473      $template = get_page_template_slug();
 474      $pagename = get_query_var( 'pagename' );
 475  
 476      if ( ! $pagename && $id ) {
 477          /*
 478           * If a static page is set as the front page, $pagename will not be set.
 479           * Retrieve it from the queried object.
 480           */
 481          $post = get_queried_object();
 482          if ( $post ) {
 483              $pagename = $post->post_name;
 484          }
 485      }
 486  
 487      $templates = array();
 488      if ( $template && 0 === validate_file( $template ) ) {
 489          $templates[] = $template;
 490      }
 491      if ( $pagename ) {
 492          $pagename_decoded = urldecode( $pagename );
 493          if ( $pagename_decoded !== $pagename ) {
 494              $templates[] = "page-{$pagename_decoded}.php";
 495          }
 496          $templates[] = "page-{$pagename}.php";
 497      }
 498      if ( $id ) {
 499          $templates[] = "page-{$id}.php";
 500      }
 501      $templates[] = 'page.php';
 502  
 503      return get_query_template( 'page', $templates );
 504  }
 505  
 506  /**
 507   * Retrieves path of search template in current or parent template.
 508   *
 509   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 510   * and {@see '$type_template'} dynamic hooks, where `$type` is 'search'.
 511   *
 512   * @since 1.5.0
 513   *
 514   * @see get_query_template()
 515   *
 516   * @return string Full path to search template file.
 517   */
 518  function get_search_template() {
 519      return get_query_template( 'search' );
 520  }
 521  
 522  /**
 523   * Retrieves path of single template in current or parent template. Applies to single Posts,
 524   * single Attachments, and single custom post types.
 525   *
 526   * The hierarchy for this template looks like:
 527   *
 528   * 1. {Post Type Template}.php
 529   * 2. single-{post_type}-{post_name}.php
 530   * 3. single-{post_type}.php
 531   * 4. single.php
 532   *
 533   * An example of this is:
 534   *
 535   * 1. templates/full-width.php
 536   * 2. single-post-hello-world.php
 537   * 3. single-post.php
 538   * 4. single.php
 539   *
 540   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 541   * and {@see '$type_template'} dynamic hooks, where `$type` is 'single'.
 542   *
 543   * @since 1.5.0
 544   * @since 4.4.0 `single-{post_type}-{post_name}.php` was added to the top of the template hierarchy.
 545   * @since 4.7.0 The decoded form of `single-{post_type}-{post_name}.php` was added to the top of the
 546   *              template hierarchy when the post name contains multibyte characters.
 547   * @since 4.7.0 `{Post Type Template}.php` was added to the top of the template hierarchy.
 548   *
 549   * @see get_query_template()
 550   *
 551   * @return string Full path to single template file.
 552   */
 553  function get_single_template() {
 554      $object = get_queried_object();
 555  
 556      $templates = array();
 557  
 558      if ( ! empty( $object->post_type ) ) {
 559          $template = get_page_template_slug( $object );
 560          if ( $template && 0 === validate_file( $template ) ) {
 561              $templates[] = $template;
 562          }
 563  
 564          $name_decoded = urldecode( $object->post_name );
 565          if ( $name_decoded !== $object->post_name ) {
 566              $templates[] = "single-{$object->post_type}-{$name_decoded}.php";
 567          }
 568  
 569          $templates[] = "single-{$object->post_type}-{$object->post_name}.php";
 570          $templates[] = "single-{$object->post_type}.php";
 571      }
 572  
 573      $templates[] = 'single.php';
 574  
 575      return get_query_template( 'single', $templates );
 576  }
 577  
 578  /**
 579   * Retrieves an embed template path in the current or parent template.
 580   *
 581   * The hierarchy for this template looks like:
 582   *
 583   * 1. embed-{post_type}-{post_format}.php
 584   * 2. embed-{post_type}.php
 585   * 3. embed.php
 586   *
 587   * An example of this is:
 588   *
 589   * 1. embed-post-audio.php
 590   * 2. embed-post.php
 591   * 3. embed.php
 592   *
 593   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 594   * and {@see '$type_template'} dynamic hooks, where `$type` is 'embed'.
 595   *
 596   * @since 4.5.0
 597   *
 598   * @see get_query_template()
 599   *
 600   * @return string Full path to embed template file.
 601   */
 602  function get_embed_template() {
 603      $object = get_queried_object();
 604  
 605      $templates = array();
 606  
 607      if ( ! empty( $object->post_type ) ) {
 608          $post_format = get_post_format( $object );
 609          if ( $post_format ) {
 610              $templates[] = "embed-{$object->post_type}-{$post_format}.php";
 611          }
 612          $templates[] = "embed-{$object->post_type}.php";
 613      }
 614  
 615      $templates[] = 'embed.php';
 616  
 617      return get_query_template( 'embed', $templates );
 618  }
 619  
 620  /**
 621   * Retrieves the path of the singular template in current or parent template.
 622   *
 623   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 624   * and {@see '$type_template'} dynamic hooks, where `$type` is 'singular'.
 625   *
 626   * @since 4.3.0
 627   *
 628   * @see get_query_template()
 629   *
 630   * @return string Full path to singular template file
 631   */
 632  function get_singular_template() {
 633      return get_query_template( 'singular' );
 634  }
 635  
 636  /**
 637   * Retrieves path of attachment template in current or parent template.
 638   *
 639   * The hierarchy for this template looks like:
 640   *
 641   * 1. {mime_type}-{sub_type}.php
 642   * 2. {sub_type}.php
 643   * 3. {mime_type}.php
 644   * 4. attachment.php
 645   *
 646   * An example of this is:
 647   *
 648   * 1. image-jpeg.php
 649   * 2. jpeg.php
 650   * 3. image.php
 651   * 4. attachment.php
 652   *
 653   * The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
 654   * and {@see '$type_template'} dynamic hooks, where `$type` is 'attachment'.
 655   *
 656   * @since 2.0.0
 657   * @since 4.3.0 The order of the mime type logic was reversed so the hierarchy is more logical.
 658   *
 659   * @see get_query_template()
 660   *
 661   * @return string Full path to attachment template file.
 662   */
 663  function get_attachment_template() {
 664      $attachment = get_queried_object();
 665  
 666      $templates = array();
 667  
 668      if ( $attachment ) {
 669          if ( str_contains( $attachment->post_mime_type, '/' ) ) {
 670              list( $type, $subtype ) = explode( '/', $attachment->post_mime_type );
 671          } else {
 672              list( $type, $subtype ) = array( $attachment->post_mime_type, '' );
 673          }
 674  
 675          if ( ! empty( $subtype ) ) {
 676              $templates[] = "{$type}-{$subtype}.php";
 677              $templates[] = "{$subtype}.php";
 678          }
 679          $templates[] = "{$type}.php";
 680      }
 681      $templates[] = 'attachment.php';
 682  
 683      return get_query_template( 'attachment', $templates );
 684  }
 685  
 686  /**
 687   * Set up the globals used for template loading.
 688   *
 689   * @since 6.5.0
 690   *
 691   * @global string $wp_stylesheet_path Path to current theme's stylesheet directory.
 692   * @global string $wp_template_path   Path to current theme's template directory.
 693   */
 694  function wp_set_template_globals() {
 695      global $wp_stylesheet_path, $wp_template_path;
 696  
 697      $wp_stylesheet_path = get_stylesheet_directory();
 698      $wp_template_path   = get_template_directory();
 699  }
 700  
 701  /**
 702   * Retrieves the name of the highest priority template file that exists.
 703   *
 704   * Searches in the stylesheet directory before the template directory and
 705   * wp-includes/theme-compat so that themes which inherit from a parent theme
 706   * can just overload one file.
 707   *
 708   * @since 2.7.0
 709   * @since 5.5.0 The `$args` parameter was added.
 710   *
 711   * @global string $wp_stylesheet_path Path to current theme's stylesheet directory.
 712   * @global string $wp_template_path   Path to current theme's template directory.
 713   *
 714   * @param string|array $template_names Template file(s) to search for, in order.
 715   * @param bool         $load           If true the template file will be loaded if it is found.
 716   * @param bool         $load_once      Whether to require_once or require. Has no effect if `$load` is false.
 717   *                                     Default true.
 718   * @param array        $args           Optional. Additional arguments passed to the template.
 719   *                                     Default empty array.
 720   * @return string The template filename if one is located.
 721   */
 722  function locate_template( $template_names, $load = false, $load_once = true, $args = array() ) {
 723      global $wp_stylesheet_path, $wp_template_path;
 724  
 725      if ( ! isset( $wp_stylesheet_path ) || ! isset( $wp_template_path ) ) {
 726          wp_set_template_globals();
 727      }
 728  
 729      $is_child_theme = is_child_theme();
 730  
 731      $located = '';
 732      foreach ( (array) $template_names as $template_name ) {
 733          if ( ! $template_name ) {
 734              continue;
 735          }
 736          if ( file_exists( $wp_stylesheet_path . '/' . $template_name ) ) {
 737              $located = $wp_stylesheet_path . '/' . $template_name;
 738              break;
 739          } elseif ( $is_child_theme && file_exists( $wp_template_path . '/' . $template_name ) ) {
 740              $located = $wp_template_path . '/' . $template_name;
 741              break;
 742          } elseif ( file_exists( ABSPATH . WPINC . '/theme-compat/' . $template_name ) ) {
 743              $located = ABSPATH . WPINC . '/theme-compat/' . $template_name;
 744              break;
 745          }
 746      }
 747  
 748      if ( $load && '' !== $located ) {
 749          load_template( $located, $load_once, $args );
 750      }
 751  
 752      return $located;
 753  }
 754  
 755  /**
 756   * Requires the template file with WordPress environment.
 757   *
 758   * The globals are set up for the template file to ensure that the WordPress
 759   * environment is available from within the function. The query variables are
 760   * also available.
 761   *
 762   * @since 1.5.0
 763   * @since 5.5.0 The `$args` parameter was added.
 764   *
 765   * @global array      $posts
 766   * @global WP_Post    $post          Global post object.
 767   * @global bool       $wp_did_header
 768   * @global WP_Query   $wp_query      WordPress Query object.
 769   * @global WP_Rewrite $wp_rewrite    WordPress rewrite component.
 770   * @global wpdb       $wpdb          WordPress database abstraction object.
 771   * @global string     $wp_version
 772   * @global WP         $wp            Current WordPress environment instance.
 773   * @global int        $id
 774   * @global WP_Comment $comment       Global comment object.
 775   * @global int        $user_ID
 776   *
 777   * @param string $_template_file Path to template file.
 778   * @param bool   $load_once      Whether to require_once or require. Default true.
 779   * @param array  $args           Optional. Additional arguments passed to the template.
 780   *                               Default empty array.
 781   */
 782  function load_template( $_template_file, $load_once = true, $args = array() ) {
 783      global $posts, $post, $wp_did_header, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID;
 784  
 785      if ( is_array( $wp_query->query_vars ) ) {
 786          /*
 787           * This use of extract() cannot be removed. There are many possible ways that
 788           * templates could depend on variables that it creates existing, and no way to
 789           * detect and deprecate it.
 790           *
 791           * Passing the EXTR_SKIP flag is the safest option, ensuring globals and
 792           * function variables cannot be overwritten.
 793           */
 794          // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
 795          extract( $wp_query->query_vars, EXTR_SKIP );
 796      }
 797  
 798      if ( isset( $s ) ) {
 799          $s = esc_attr( $s );
 800      }
 801  
 802      /**
 803       * Fires before a template file is loaded.
 804       *
 805       * @since 6.1.0
 806       *
 807       * @param string $_template_file The full path to the template file.
 808       * @param bool   $load_once      Whether to require_once or require.
 809       * @param array  $args           Additional arguments passed to the template.
 810       */
 811      do_action( 'wp_before_load_template', $_template_file, $load_once, $args );
 812  
 813      if ( $load_once ) {
 814          require_once $_template_file;
 815      } else {
 816          require $_template_file;
 817      }
 818  
 819      /**
 820       * Fires after a template file is loaded.
 821       *
 822       * @since 6.1.0
 823       *
 824       * @param string $_template_file The full path to the template file.
 825       * @param bool   $load_once      Whether to require_once or require.
 826       * @param array  $args           Additional arguments passed to the template.
 827       */
 828      do_action( 'wp_after_load_template', $_template_file, $load_once, $args );
 829  }
 830  
 831  /**
 832   * Checks whether the template should be output buffered for enhancement.
 833   *
 834   * By default, an output buffer is only started if a {@see 'wp_template_enhancement_output_buffer'} filter has been
 835   * added by the time a template is included at the {@see 'wp_before_include_template'} action. This allows template
 836   * responses to be streamed as much as possible when no template enhancements are registered to apply.
 837   *
 838   * @since 6.9.0
 839   *
 840   * @return bool Whether the template should be output-buffered for enhancement.
 841   */
 842  function wp_should_output_buffer_template_for_enhancement(): bool {
 843      /**
 844       * Filters whether the template should be output-buffered for enhancement.
 845       *
 846       * By default, an output buffer is only started if a {@see 'wp_template_enhancement_output_buffer'} filter has been
 847       * added. For this default to apply, a filter must be added by the time the template is included at the
 848       * {@see 'wp_before_include_template'} action. This allows template responses to be streamed as much as possible
 849       * when no template enhancements are registered to apply. This filter allows a site to opt in to adding such
 850       * template enhancement filters during the rendering of the template.
 851       *
 852       * @since 6.9.0
 853       *
 854       * @param bool $use_output_buffer Whether an output buffer is started.
 855       */
 856      return (bool) apply_filters( 'wp_should_output_buffer_template_for_enhancement', has_filter( 'wp_template_enhancement_output_buffer' ) );
 857  }
 858  
 859  /**
 860   * Starts the template enhancement output buffer.
 861   *
 862   * This function is called immediately before the template is included.
 863   *
 864   * @since 6.9.0
 865   *
 866   * @return bool Whether the output buffer successfully started.
 867   */
 868  function wp_start_template_enhancement_output_buffer(): bool {
 869      if ( ! wp_should_output_buffer_template_for_enhancement() ) {
 870          return false;
 871      }
 872  
 873      $started = ob_start(
 874          'wp_finalize_template_enhancement_output_buffer',
 875          0, // Unlimited buffer size so that entire output is passed to the filter.
 876          /*
 877           * Instead of the default PHP_OUTPUT_HANDLER_STDFLAGS (cleanable, flushable, and removable) being used for
 878           * flags, the PHP_OUTPUT_HANDLER_FLUSHABLE flag must be omitted. If the buffer were flushable, then each time
 879           * that ob_flush() is called, a fragment of the output would be sent into the output buffer callback. This
 880           * output buffer is intended to capture the entire response for processing, as indicated by the chunk size of 0.
 881           * So the buffer does not allow flushing to ensure the entire buffer can be processed, such as for optimizing an
 882           * entire HTML document, where markup in the HEAD may need to be adjusted based on markup that appears late in
 883           * the BODY.
 884           *
 885           * If this ends up being problematic, then PHP_OUTPUT_HANDLER_FLUSHABLE could be added to the $flags and the
 886           * output buffer callback could check if the phase is PHP_OUTPUT_HANDLER_FLUSH and abort any subsequent
 887           * processing while also emitting a _doing_it_wrong().
 888           *
 889           * The output buffer needs to be removable because WordPress calls wp_ob_end_flush_all() and then calls
 890           * wp_cache_close(). If the buffers are not all flushed before wp_cache_close() is closed, then some output buffer
 891           * handlers (e.g. for caching plugins) may fail to be able to store the page output in the object cache.
 892           * See <https://github.com/WordPress/performance/pull/1317#issuecomment-2271955356>.
 893           */
 894          PHP_OUTPUT_HANDLER_STDFLAGS ^ PHP_OUTPUT_HANDLER_FLUSHABLE
 895      );
 896  
 897      if ( $started ) {
 898          /**
 899           * Fires when the template enhancement output buffer has started.
 900           *
 901           * @since 6.9.0
 902           */
 903          do_action( 'wp_template_enhancement_output_buffer_started' );
 904      }
 905  
 906      return $started;
 907  }
 908  
 909  /**
 910   * Finalizes the template enhancement output buffer.
 911   *
 912   * Checks to see if the output buffer is complete and contains HTML. If so, runs the content through
 913   * the `wp_template_enhancement_output_buffer` filter.  If not, the original content is returned.
 914   *
 915   * @since 6.9.0
 916   *
 917   * @see wp_start_template_enhancement_output_buffer()
 918   *
 919   * @param string $output Output buffer.
 920   * @param int    $phase  Phase.
 921   * @return string Finalized output buffer.
 922   */
 923  function wp_finalize_template_enhancement_output_buffer( string $output, int $phase ): string {
 924      // When the output is being cleaned (e.g. pending template is replaced with error page), do not send it through the filter.
 925      if ( ( $phase & PHP_OUTPUT_HANDLER_CLEAN ) !== 0 ) {
 926          return $output;
 927      }
 928  
 929      // Detect if the response is an HTML content type.
 930      $is_html_content_type = null;
 931      $html_content_types   = array( 'text/html', 'application/xhtml+xml' );
 932      foreach ( headers_list() as $header ) {
 933          $header_parts = explode( ':', strtolower( $header ), 2 );
 934          if (
 935              count( $header_parts ) === 2 &&
 936              'content-type' === $header_parts[0]
 937          ) {
 938              /*
 939               * This is looking for very specific content types, therefore it
 940               * doesn’t need to fully parse the header’s value. Instead, it needs
 941               * only assert that the content type is one of the static HTML types.
 942               *
 943               * Example:
 944               *
 945               *     Content-Type: text/html; charset=utf8
 946               *     Content-Type: text/html  ;charset=latin4
 947               *     Content-Type:application/xhtml+xml
 948               */
 949              $media_type           = trim( strtok( $header_parts[1], ';' ), " \t" );
 950              $is_html_content_type = in_array( $media_type, $html_content_types, true );
 951              break; // PHP only sends the first Content-Type header in the list.
 952          }
 953      }
 954      if ( null === $is_html_content_type ) {
 955          $is_html_content_type = in_array( ini_get( 'default_mimetype' ), $html_content_types, true );
 956      }
 957  
 958      // If the content type is not HTML, short-circuit since it is not relevant for enhancement.
 959      if ( ! $is_html_content_type ) {
 960          return $output;
 961      }
 962  
 963      $filtered_output = $output;
 964  
 965      /**
 966       * Filters the template enhancement output buffer prior to sending to the client.
 967       *
 968       * This filter only applies the HTML output of an included template. This filter is a progressive enhancement
 969       * intended for applications such as optimizing markup to improve frontend page load performance. Sites must not
 970       * depend on this filter applying since they may opt to stream the responses instead. Callbacks for this filter are
 971       * highly discouraged from using regular expressions to do any kind of replacement on the output. Use the HTML API
 972       * (either `WP_HTML_Tag_Processor` or `WP_HTML_Processor`), or else use {@see DOM\HtmlDocument} as of PHP 8.4 which
 973       * fully supports HTML5.
 974       *
 975       * @since 6.9.0
 976       *
 977       * @param string $filtered_output HTML template enhancement output buffer.
 978       * @param string $output          Original HTML template output buffer.
 979       */
 980      return (string) apply_filters( 'wp_template_enhancement_output_buffer', $filtered_output, $output );
 981  }


Generated : Thu Oct 23 08:20:05 2025 Cross-referenced by PHPXref