Guide to Understanding WordPress Theme File Structure

WordPress works on a template system with defaults when one doesn’t exist. Each template type serves a purpose by letting users display different formats and styles based on content type. For example, your front page may show a different layout and content from your actual post page.

Each page type has its own name. When a page type doesn’t have an associated template, WordPress will fall back and use the closest parent template in its place. The root default fall back is your index.php – a file that is required in every theme, regardless of everything.

In fact, there are only two files that WordPress requires, at minimum, to be recognized as a valid theme and it is your index.php and style.css .

You can also add a functions.php that contains all your additional classes, php hooks and whatever else – but the finer details of its contents are for a different post. For this post, we’ll be going over the theme file structure, what each file does and where they sit in the WordPress hierarchy for rendering.

Presenting the template tree

The diagram above is basically the decision tree that WordPress goes through in order to figure out which template to render based on the page type. If a template doesn’t exist, it continues down the flow, until ultimately we land on index.php if nothing else matches.

This makes index.php the catch-all template and hence why it is one of the minimally required file in a WordPress theme.

You can click on the diagram above to go to the source image and it will let you view the entire flow chart in full size.

The content below is going to go through the individual pathways and what each template file means, beginning from left to right, in accordance with the flow chart above.

Search Results Page

As a user, you find yourself hitting the search bar on a WordPress website. This leads you to a search results page – or according to WordPress, it’s the search.php template page.

If a search.php template doesn’t exist, WordPress defaults to your index.php

There isn’t much to the search results page and the display hierarchy structure is pretty flat.

search page ------> search.php  ------> index.php

Error 404 page

Like the search results page, the error 404 page’s hierarchy is also very flat and straight forward. When a page doesn’t exist or something went wrong, WordPress will show a 404 page.

If a 404.php exists, WordPress will display that. If not, it will default to whatever logic has been coded into the index.php template page.

404 page  ------> 404.php  ------> index.php

Blog Posts Page

Your blog posts page is the page that displays a list of all your blog posts. At first, WordPress will search for the home.php template. If that doesn’t exist, then it will hit the default index.php

blog posts page  ------> home.php  ------> index.php

Site Front Page

Everything so far has been rather simple and flat. The site’s front page gets a little bit more interesting because there is a choice available, forking the displayed template based on the selected item.

This is because the site owner can select if a specific static page is shown or the blog posts list page. They can do this via the customization option that’s available by default.

When Your latest posts is selected, WordPress will put you on the blog posts page flow, showing home.php first if it exists, then defaults to index.php if it doesn’t.

If A static page is selected, the user gets the option to choose which page they want to display as the front landing page for the website. Flow wise, WordPress will put you onto the singular page flow, which is discussed below.

site front page  ------>  if Your latest posts  ------> Blog Posts Page flow
                 ------>  if A static page      ------> Singular Page flow

Singular Page

This is where the complexity of potential templates begin. A singular page is split into two types – static page and single post. Each type has its own separate flow that merges on the file singular.php and ultimately the default fall-back of index.php

Static page flow

A static page is the single pages that you’d use for things like about and contact pages. They are one-off instances that aren’t expected to change often or be part of a larger categorical collection.

When you have a static page, you have the option to use the default or a custom template that is available under the Page Settings section of a page.

For example, in the screenshot below, the specific page has two other templates – an Authors template and a Contacts template – associated with it.

When a custom template is selected, WordPress will render that custom template. If none exists, WordPress will render page.php. If that doesn’t exist, then WordPress will default to singular.php then index.php

If default is selected, WordPress looks for a page-$slug.php template. If that doesn’t exist, then it goes for page-$id.php. It does this to give more granularity to your theme’s customization and doesn’t expect the slug or id to change, hence why it hones in a very specific value that’s associated to that particular page. If none these things exists, then WordPress will default to page.php before going to singular.php and then, finally, index.php

So the static page flow looks something like this:

site static page  ---> if custom template  ---> $custom.php  -----------------
                                                                              |  ---> page.php  ---> singular.php  ---> index.php 
                  ---> if default ---> page-$slug.php ---> page-$id.php ------

Single post page flow

A single post has three potential forks you can go down – attachment, custom and blog post type.

An attachment type is simply a page that’s dedicated to the attachments such as images. A blog post is the default post type that comes with WordPress. Finally, a custom post type is where WordPress’ flexibility is – in its ability for developers to create custom post types.

Let’s look at the first flow – the attachment flow.

In the attachment flow, WordPress looks for a combination of custom mime and subtype combination. A mime type is your file extension such as .wav, .mp3 and .jpg

If this file doesn’t exist, it will hunt down a corresponding subtype file. If that doesn’t exist, WordPress will go to the next thing in the tree, which is the mime type template. If that also doesn’t exist, then WordPress will hunt down the attachment.php. Finally, if that also doesn’t exist, then single.php is used, before it hits singular.php and then the default of index.php

So the flow for the attachment option looks something like this:

single post page  ---> attachment type --> $mimetype-$subtype.php ---> $subtype.php ---> $mimetype.php ---> attachment.php ---> single.php --> singular.php --> index.php

Next on the potential options list is…custom type

When it comes to custom types, this is one of the most powerful features available to WordPress. This is because you can set your custom post type to be anything you want. For example, you could have a custom portfolio post type or a series of FAQ items post type.

When a custom post type single page is selected, WordPress goes through a flow of matching the custom post type template first. If that doesn’t exist, then it hunts down a single-$posttype-$slug.php file. If there is no match, next in the hierarchy is single-$posttype.php

If nothing matches at all, WordPress defaults to single.php then singular.php and finally, the fallback default for everything – index.php

Here is what the flow looks like:

single post page  ---> custom post type ---> $custom.php ---> single-$posttype-$slug.php ---> single.php ---> singular.php ---> index.php

And finally, the blog type

The blog type is the default post type that comes out of the box with WordPress. You can also have a $custom.php template for blog types, followed by single.php, then singular.php and finally the default of index.php

For this flow, it looks something like this:

single post page  ---> blog post type ---> $custom.php ---> single-post.php ---> single.php ---> singular.php ---> index.php

Putting it all together

So, now if we were to put it all together, this branch of options and hierarchy looks something like this:

                  |---> attachment type --> $mimetype-$subtype.php ---> $subtype.php ---> $mimetype.php ---> attachment.php ---| 
 single post page |---> custom post type ---> $custom.php ---> single-$posttype-$slug.php -------------------------------------| ---->  single.php ---> singular.php ---> index.php 
                  |---> blog post type ---> $custom.php ---> single-post.php --------------------------------------------------|  

Archive Page

The archive page is potentially the most complicated one out of all the landing pages a user can land on. Most of the time, theme developers spend very little time on this but the granularity that WordPress provides can be used to your advantage when coding your theme.

There are six potential forks and they are as follows:

Author Archives Page

The author archives page deals specifically with a list of previous posts made by a particular author. It first looks for the author-$nicename.php file. A WordPress $nicename is basically a sanitized version of a username, where spaces are replaced with dashes instead. If that doesn’t exist, then WordPress looks for an author-$id.php file, followed by author.php, then archive.php and finally the index.php as the default if everything else fails.

Here’s what the flow looks like:

archive page  ---> author archives page ---> author-$nicename.php ---> author-$id.php ---> author.php ---> archive.php ---> index.php

Category Archives Page

The category archives page shows a list of previously posted items based on a specific category. The flow starts off with WordPress looking for a category-$slug.php file, followed by category-$id.php. If none of these exists, it looks for a category.php, before defaulting to archive.php and ultimately index.php.

This flow is illustrated below:

 archive page  ---> category archives page ---> category-$slug.php ---> category-$id.php ---> category.php ---> archive.php ---> index.php

Custom Post Type Archives Page

Like a normal post type, custom post type also comes with its own archives page. WordPress sorts this via archive-$posttype.php. If that doesn’t exist then it looks for archive.php and then defaults to index.php

archive page --->  custom post type archieves page ---> archive-$posttype.php ---> archive.php --> index.php

Custom Taxonomy Archives Page

A taxonomy is a way of grouping posts together. By default, WordPress comes with tags and categories. You can create your own taxonomies to group your posts by, based on your content type and nature of your WordPress theme.

When a custom taxonomy exists, WordPress looks for a taxonomy-$taxonomy-$term.php file. If that doesn’t exist, the next one in the hierarchy is taxonomy-$taxonomy.php. If all else fails to exist, taxonomy.php is chosen next, followed by archive.php and finally the default index.php

 archive page  ---> custom taxonomy archieves page ---> taxonomy-$taxonomy-$term.php ---> taxonomy-$taxonomy.php ---> taxonomy.php ---> archive.php ---> index.php

Date Archives Page

The date archives collate the returned result based on dates. This is often granulated down to week, month and year options. WordPress first looks for a date.php file to deal with date-related archive content, followed by archive.php and then index.php

                                   | ---> Week -------|
 archive page ---> date archive ---| ---> Month ------| ----> date.php ---> archive.php ---> index.php
                                   | ---> Year -------|

and finally, Tag Archives Page

The tag archives page works in a similar fashion as the category archives page, with the only difference being that it uses tags as the basis for evaluation. WordPress starts off looking for a tag-$slug.php file, followed by a specific tag-$id.php template. If none of these exists, it looks for a less granular template that deals specifically with tags – tag.php.

If none of these files exists, it falls back on the default archive.php and then index.php

archive page ---> tag archives page ---> tag-$slug.php ---> tag-$id.php ---> tag.php ---> archive.php ---> index.php

And that’s it!

When it’s in a giant diagram, things can seem daunting and large. However, when we break it down to its different flows, WordPress page hierarchy isn’t that bad. We are able to see that there’s more to it than just an index.php and single.php template page, and that the seemingly complex is actually very linear.

I hope this article has helped you understand how it all fits together and that it will provide you with good reference material in the future.

Thank you for reading!

I am currently embarking on a Prototype Year to experiment my way into a life I want. This space is for documenting that journey.

Leave a Reply

Your email address will not be published. Required fields are marked *