* @see get_query_template()
* @return string Full path to single template file.
function get_single_template() {
$object = get_queried_object();
if ( ! empty( $object->post_type ) ) {
$template = get_page_template_slug( $object );
if ( $template && 0 === validate_file( $template ) ) {
$templates[] = $template;
$name_decoded = urldecode( $object->post_name );
if ( $name_decoded !== $object->post_name ) {
$templates[] = "single-{$object->post_type}-{$name_decoded}.php";
$templates[] = "single-{$object->post_type}-{$object->post_name}.php";
$templates[] = "single-{$object->post_type}.php";
$templates[] = 'single.php';
return get_query_template( 'single', $templates );
* Retrieves an embed template path in the current or parent template.
* The hierarchy for this template looks like:
* 1. embed-{post_type}-{post_format}.php
* 2. embed-{post_type}.php
* 1. embed-post-audio.php
* The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
* and {@see '$type_template'} dynamic hooks, where `$type` is 'embed'.
* @see get_query_template()
* @return string Full path to embed template file.
function get_embed_template() {
$object = get_queried_object();
if ( ! empty( $object->post_type ) ) {
$post_format = get_post_format( $object );
$templates[] = "embed-{$object->post_type}-{$post_format}.php";
$templates[] = "embed-{$object->post_type}.php";
$templates[] = 'embed.php';
return get_query_template( 'embed', $templates );
* Retrieves the path of the singular template in current or parent template.
* The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
* and {@see '$type_template'} dynamic hooks, where `$type` is 'singular'.
* @see get_query_template()
* @return string Full path to singular template file
function get_singular_template() {
return get_query_template( 'singular' );
* Retrieve path of attachment template in current or parent template.
* The hierarchy for this template looks like:
* 1. {mime_type}-{sub_type}.php
* The template hierarchy and template path are filterable via the {@see '$type_template_hierarchy'}
* and {@see '$type_template'} dynamic hooks, where `$type` is 'attachment'.
* @since 4.3.0 The order of the mime type logic was reversed so the hierarchy is more logical.
* @see get_query_template()
* @return string Full path to attachment template file.
function get_attachment_template() {
$attachment = get_queried_object();
if ( false !== strpos( $attachment->post_mime_type, '/' ) ) {
list( $type, $subtype ) = explode( '/', $attachment->post_mime_type );
list( $type, $subtype ) = array( $attachment->post_mime_type, '' );
if ( ! empty( $subtype ) ) {
$templates[] = "{$type}-{$subtype}.php";
$templates[] = "{$subtype}.php";
$templates[] = "{$type}.php";
$templates[] = 'attachment.php';
return get_query_template( 'attachment', $templates );
* Retrieve the name of the highest priority template file that exists.
* Searches in the STYLESHEETPATH before TEMPLATEPATH and wp-includes/theme-compat
* so that themes which inherit from a parent theme can just overload one file.
* @since 5.5.0 The `$args` parameter was added.
* @param string|array $template_names Template file(s) to search for, in order.
* @param bool $load If true the template file will be loaded if it is found.
* @param bool $require_once Whether to require_once or require. Has no effect if `$load` is false.
* @param array $args Optional. Additional arguments passed to the template.
* @return string The template filename if one is located.
function locate_template( $template_names, $load = false, $require_once = true, $args = array() ) {
foreach ( (array) $template_names as $template_name ) {
if ( ! $template_name ) {
if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) {
$located = STYLESHEETPATH . '/' . $template_name;
} elseif ( file_exists( TEMPLATEPATH . '/' . $template_name ) ) {
$located = TEMPLATEPATH . '/' . $template_name;
} elseif ( file_exists( ABSPATH . WPINC . '/theme-compat/' . $template_name ) ) {
$located = ABSPATH . WPINC . '/theme-compat/' . $template_name;
if ( $load && '' !== $located ) {
load_template( $located, $require_once, $args );
* Require the template file with WordPress environment.
* The globals are set up for the template file to ensure that the WordPress
* environment is available from within the function. The query variables are
* @since 5.5.0 The `$args` parameter was added.
* @global WP_Post $post Global post object.
* @global bool $wp_did_header
* @global WP_Query $wp_query WordPress Query object.
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
* @global wpdb $wpdb WordPress database abstraction object.
* @global string $wp_version
* @global WP $wp Current WordPress environment instance.
* @global WP_Comment $comment Global comment object.
* @param string $_template_file Path to template file.
* @param bool $require_once Whether to require_once or require. Default true.
* @param array $args Optional. Additional arguments passed to the template.
function load_template( $_template_file, $require_once = true, $args = array() ) {
global $posts, $post, $wp_did_header, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID;
if ( is_array( $wp_query->query_vars ) ) {
* This use of extract() cannot be removed. There are many possible ways that
* templates could depend on variables that it creates existing, and no way to
* detect and deprecate it.
* Passing the EXTR_SKIP flag is the safest option, ensuring globals and
* function variables cannot be overwritten.
// phpcs:ignore WordPress.PHP.DontExtract.extract_extract
extract( $wp_query->query_vars, EXTR_SKIP );
require_once $_template_file;