A couple of weeks ago we were talking about the different types of themes we can find in WordPress. There we learned all about WordPress themes: what are basic themes, premium themes, and multipurpose themes; how to customize any theme using child themes; what are grandchild themes; and also how to create a theme using starter themes and framework themes.
Since some of you contacted me asking for more information on how to create a WordPress theme, I thought it’d be interesting to talk about the file hierarchy of a WordPress theme. In this post you’ll learn the basics of understanding what a WordPress theme looks like and hopefully have all the tools you need to create your first theme.
Before We Get Started…
Anyone can draw a house on paper, but not all of us are architects. If we’re lucky, we might be able to assemble an IKEA wardrobe. But that’s it. Why am I mentioning this? Because creating WordPress themes is no different! It’s very difficult and making something beautiful and user-friendly takes time and experience.
So, in this post I’m going to teach you “everything” you need to know to create a WordPress theme with two particularities:
- We will ignore absolutely everything related to the design of the theme itself and focus only on the technical part.
- We’re not going to start from scratch. Instead, we’ll use the Underscores starter theme. Why? Because it doesn’t make sense to start a theme from scratch when we have a quality skeleton that gives us some of the work done. And, besides, if that’s what you want to do, the WordPress documentation itself gives you the information you need.
Underscores, a Fantastic Starter Theme by Automattic
Underscores is a starter theme whose only goal is to provide the base skeleton on which one can develop their very own theme, offering well-documented HTML templates and some additional hacks. With it, we can greatly accelerate the creation of a new theme, since a large part of the tasks we have to do to get a theme underway are already in place.
Every theme must have a unique name. Mostly because all the themes you install in WordPress end up in the
wp-content/themes/ directory inside their own folder (something like
wp-content/themes/your-theme/, etc) and so different names are required to avoid collisions. So the first thing you have to do is decide the name of your theme and set it up.
If you go to the Underscores page, you’ll see a text field called Theme Name next to a Generate button. Simply enter the name of the theme you want (I, for example, used Nelio Software), click on the button, and a
.zip file will be downloaded with your settings, including prefixes for the functions you define so that they are unique (for example, instead of having a function called
setup that can conflict with the same function of another theme, ours is called
So, now that you have your starter theme ready… install it on WordPress, activate it, and let’s get to work!
If you open the directory of your theme and take a look inside, you will see that there are several files and directories inside it. I know it might seem a lot but, believe me, its easier than it seems.
The first file we are going to comment on is
style.css. As its name and type indicate, it contains the styles of our theme. But it’s also the file that contains some relevant meta information about our theme (hence it’s the first file we need to look at):
As you can see, this file starts with a fairly long comment that seems to follow a special format. Indeed, it follows a special format. From lines 2 to 11 we see a set of Attribute, Value pairs where different properties of the theme are defined: its name, its URL, its author, a description… By default these fields are filled with Underscores information, but you are free to change them to whatever you like.
If you are wondering what this information is for…. well, it’s the one shown on your WordPress dashboard, in the Appearance » Themes section:
Themes may also define a function file called, of course,
functions.php. Normally, in this file we define the typical hooks needed to enqueue stylesheets and scripts, as well as any additional helper functions that we might need. Basically it behaves like a plugin: if the theme is active, the file is automatically loaded and whatever is defined in it becomes available.
If you take a look at the
functions.php file that Underscores has created for you, you’ll see that a lot of things are already there. Let’s look at some examples of what it includes:
nelio_software_setup. This is a function that is invoked right after the theme has been loaded into WordPress through the hook
after_setup_theme. In it the theme defines several properties of our theme such as, for example, the support for featured images in blog posts, a navigation menu, the internationalization domain, etc. In my opinion, the most interesting thing about this function is that it is defined within a conditional block: this way, if someone creates a child theme to customize ours, they might be able to redefine this function to adapt it to their own needs.
nelio_software_widgets_init. Underscores also shows us how we can register sidebars, which are locations where one can add widgets. As you can see, it’s as easy as invoking the
register_sidebarfunction during the execution of the
nelio_software_scripts. This is one of the most important functions of the theme, as it’s in charge of enqueuing the scripts and styles required by our theme.
Nothing fancy, right?
An interesting point that deserves special mention is the
require statements that appear at the end of this file. Basically, these statements are loading some files from the
inc/ subdirectory, such as
inc/customizer.php, and they serve as a simple example on how to organize our code and keep it clean and tidy.
Obviously, nobody forces us to put absolutely all the functions and customizations we want in
functions.php. If we want to, we can organize ours in smaller files for more specific purposes and then require them as needed, keeping in mind that the entry point is this file.
Okay, so far we’ve seen the basics of a theme: how to set its metadata in
style.css and how to configure it and define any helper function we might need in
functions.php. But we’re supposed to be creating a theme so… Where do we define HTML templates? How do we make things look one way or another?
The answer to this question can be found in the other files that lie in the root directory of our theme. Just take a closer look and you’ll see most files are named so that you can easily guess what they do:
index.phpis the default template and it’s used to render any content from WordPress, unless there’s a more specific template for that content.
comments.phpis the template that renders the comments section in our blog posts.
single.phpis the template we use to render a blog post and, therefore, it overrides
index.phpfor blog posts.
page.phpis similar to
single.php, but in this case it applies to pages.
- and so on and so forth.
Nothing complicated, right? If you are curious about all the templates you can create and their names, I recommend that you look at the Codex page where they explain how to create a theme along with the page where they explain the template hierarchy in WordPress.
What’s inside a template in a WordPress theme? Well, they basically have what I’d say you’d expect: HTML to define the layout mixed with some PHP code to pull the actual data we want to render. For example, if we look at the
single.php file (which is used for rendering blog posts), we’ll see the following:
Let’s see what’s happening in each line:
- The first thing we see in line 10 is a call to the
get_headerfunction. This basically loads a template with some common HTML tags, such as
body… as well as any other common parts of our website, like a header or a navigation menu. We’ll talk about it later.
- Likewise, in line 37 we see a call to
get_footerwhich, as you can imagine, serves the opposite purpose. That is, it closes any tags we opened in the header and adds some footer info.
- Lines 13 to 33 do all the magic. On the one hand, we see that content will be surounded by two tags (
main) with some special classes and IDs, and then we have some PHP to load the actual content.
- Line 17 loads the WordPress loop.
- Line 20 loads the template in
template-parts/content.php, which contains the required HTML for rendering a post (that is, the title, the featured image, the content, and so on).
- Line 22 adds some navigation links.
- Line 25 loads the comments that this post might have via the function
comments_template, but only if comments are enabled, of course.
- Finally, line 36 adds the sidebar we defined in
Header and Footer
In the root of our theme we also find the files
footer.php. As I have already told you, they’re used to “open” and “close” the resulting HTML page we’ll send to our visitors’ browsers.
This is the header:
and this is the footer:
Again, there’s nothing fancy in here. Just some HTML code and a few PHP calls. But, anyway, let’s discuss the most relevant points of each file briefly:
- Any tags opened (but not closed) in
header.phpare closed in
- One of the most important aspects in
header.phpis the call to
wp_head, at line 20. This call must be done if we want plugins and the theme itself to be able to enqueue their own styles and scripts to the page.
- The rest of the code in
header.phpdefines the portion of our website that’s common to all pages, such as, for example, the heading image or the navigation menu.
footer.phpis similar to the header, but in this case it loads common code that appears at the end of all our pages.
- Just as with
footer.phpfile calls a special function named
wp_footer. It’s very important to have this function in our theme, or the plugins and the theme itself wouldn’t be able to add their own scripts at the end of the page.
Finally, let’s talk about some good practices you need to follow if you want to create a perfect theme.
- Enqueue styles and scripts. None of the templates included in Underscores adds a script or a style in the HTML code. Instead, they rely on the
wp_enqueue_stylefunctions. You should follow this approach too.
- Theme settings. Even if we create a simple theme, chances are we’ll want to add some customization properties that the user should be able to tweak. If you want to do that, don’t reinvent the wheel and implement you own settings screen, but use the Customizer’s API.
- Escape and Sanitize. That’s web design 101. It’s very, very important that all the data you print on screen is properly escaped and that any data you collect from the user is properly sanitized. If you don’t know what I’m talking about, read WordPress docs on this topic.
- Internationalization. If you want your theme to be used by anyone, you have to make sure it can be translated. So get used to WordPress internationalization functions and use them from the very beginning. If you do so, your theme will be translatable in no time!
- Theme Check. There’s a special plugin named Theme Check that checks the quality of your theme. Use it while developing a theme and make sure all the tests it runs pass. This is the plugin that the Theme Review Team in WordPress use so… why wouldn’t you want to use it too?
WordPress themes follow a fairly logical and user-friendly structure. Being PHP code, you can organize the code as you please, although there is a set of files that WordPress expects to be there for everything to work. I hope that today’s post has helped you to understand this structure a little more and, above all, to appreciate the usefulness of a starter theme like Underscores to create your first theme.