WordPress Theme Files Hierarchy

This post is about the names of the WordPress theme files. And it also reviews which file to include for showing the content of a specific page. This is very important, necessary, and at the same time very simple, for understanding, knowledge. Everyone who works with WordPress must have them. Below you will find fully covered WordPress theme files structure and the order of how these files are connected (their hierarchy).

An example of how a hierarchy works

For example, we go to the "My-Category" page http://example.com/category/my-category. Here my-category is the slug of this category. And the ID is 25.

The slug and ID you can find on the edit-category admin page.

Then one of the files below will be responsible for the template of this WordPress page (files are checked one by one, the first existing file in the theme will be the template for this page):

  1. category-my-category.php
  2. category-25.php
  3. category.php
  4. archive.php
  5. index.php

Hierarchy, in this case, is a consistent check for the existence of a template file. For the content of one page on the site, there may be several files. Checking which file will be used one by one. I.e., WordPress has a list of suitable file names, and each of the names is checked in turn for the physical existence of such a file, as soon as WordPress sees that the file exists, the search for a suitable file stops, and the found file is used as a template.

Other theme files

Also, WordPress has common connectable files. They do not participate in the hierarchy but need to be plugged in manually where necessary. For example, the sidebar.php file is included in the theme template file using the function get_sidebar().

A whole list of such 'includable' files:

Page types and file names

Now when we understand how the hierarchy works, let's look at all the file names that WordPress tries to find when you visit a particular page on the site.

The complete diagram for all kinds of pages and their files looks like this:

The same diagram in interactive form.

Now, I will describe this picture, make from it a list of site pages and the corresponding php files for them.

The files from the list below should be located in the theme directory.

Posts

Static page

  • {any_name}.php (when the page template is used)
  • page-{post_slug}.php
  • page-{post_id}.php
  • page.php
  • singular.php
  • index.php

    Post

  • single-post-{post_slug}.php
  • single-post.php
  • single.php
  • singular.php
  • index.php

    Custom post type

  • {any_name}.php (for heirarchical posts with templates support. From WP 4.7)
  • single-{post_type}-{post_slug}.php
  • single-{post_type}.php
  • single.php
  • singular.php
  • index.php

    Attachment

  • {MIME_type_start}.php
  • {MIME_type_end}.php
  • {MIME_type_start}-{MIME_type_end}.php
  • attachment.php
  • single-attachment-{attachment_slug}.php (allows you to specify a template for a single attachment)
  • single-attachment.php (same as attachment.php)
  • single.php
  • singular.php
  • index.php

    By the 'start' and 'end' of the MIME type, I mean the first and last part of the MIME which is separated by /. For example, if it is a text file with MIME type 'text/plain', then the existence of the following files will be checked: first text.php, then plain.php, and then text-plain.php.

    See the code of wp_get_mime_types() function for a complete list of MIME types.

Archives

Category

  • category-{slug}.php
  • category-{id}.php
  • category.php
  • archive.php
  • paged.php (if a pagination page)
  • index.php

    Tag

  • tag-{slug}.php
  • tag-{id}.php
  • tag.php
  • archive.php
  • paged.php (if a pagination page)
  • index.php

    Taxonomy

  • taxonomy-{taxonomy_name}-{slug}.php
  • taxonomy-{taxonomy_name}.php
  • taxonomy.php
  • archive.php
  • paged.php (if a pagination page)
  • index.php

    Post type archive page

  • archive-{post_type_slug}.php
  • archive.php
  • paged.php (if a pagination page)
  • index.php

    Author page

  • author-{nickname}.php
  • author-{id}.php
  • author.php
  • archive.php
  • paged.php (if pagination page)
  • index.php

    Archive page of date (day, month, year)

  • date.php
  • archive.php
  • paged.php (if a pagination page)
  • index.php

404 page

  • 404.php
  • index.php

Search page

  • search.php
  • index.php

Main page

  • front-page.php
  • ('page' post type logic if a page is selected as a front page)
  • home.php
  • index.php

Blog page

The blog page appears when the 'page' is selected as a front page.

  • home.php
  • index.php

Embeds

The embed template file is used to render a post which is being embedded with REST API. Embedding appeared in WP 4.5 and allows you to embed your posts in other sites. See get_post_embed_url().

  • embed-{post-type}-{post_format}.php
  • embed-{post-type}.php
  • embed.php

To change the embedding content only, you can create a embed-content.php file in your theme and describe embed HTML in it. The original embed HTML is in the core file /wp-includes/theme-compat/embed-content.php.

Non-ASCII characters handling

Since WordPress 4.7, any dynamic part of a template name which includes non-ASCII characters in its name actually supports both the un-encoded and the encoded form, in that order. You can choose which to use.

Let's look at the page template hierarchy for a page named Hello World 😀 with the ID of 6:

  • page-hello-world-😀.php
  • page-hello-world-%f0%9f%98%80.php
  • page-6.php
  • page.php
  • singular.php

The same behavior applies to post slugs, term names, and author nicenames.

How it works in WP core

For the logic of order in which the files are connected is responsible the core file wp-includes/template-loader.php. If you study it, the file explains everything. But such a study is not so interesting, so I will explain it here in details.

First of all. template-loader.php file is connected after the whole WordPress environment is loaded. After the wp-load.php file is run and the main query is inited (see wp()). I.e. template-loader.php file is connected at the very end of the PHP script.

First runs the hook template_redirect. You can do some kind of checks in this hook and if you need redirect the user to another URL, you must use die() in it. I.e. if the hook changes something, then the work of template-loader.php file ends and the user is redirected.

Next triggers not interesting hook exit_on_http_head. It allows you to make something appear on the screen when there is HTTP HEAD request...

Next there are checks on all Conditional Tags. During these checks, WordPress detects which template file is more suitable for the current request. The conditional tag is checked, then another and another... As soon as one of the conditional tags is triggered, the corresponding function is called, which finds the appropriate template file and returns the path to it. All such functions are described in get_query_template().

Next - path to the theme file is defined! Now it runs through the template_include filter which allows us to modify the template file for the current request.

Next, the file connects to PHP and starts the visual part of the page generation.

Filters

You can change the file hierarchy through dynamic filters:

  • (type)_template_hierarchy - filters the array of filenames in the hierarchy by which to search for the desired file. From WP 4.7.

  • (type)_template - filters the path to the template file that has already been defined.

All variants of type parameter can be found in the $type parameter of get_query_template() function. Here they are:

  • index
  • 404
  • archive
  • post_type_archive
  • author
  • category
  • tag
  • taxonomy
  • date
  • home
  • front_page
  • page
  • paged
  • search
  • single
  • singular
  • attachment
  • comments_popup

Example of using such filter see in the answer to this question (rus).