Tighter and leaner WordPress templates with get_template_part()

Update: This article is a little dated now. As of a few months ago, I’ve stopped using Victoria Park and now use a fork of Underscores from Automattic. I’d recommend starting there. That said, everything else in the article still applies!

I use Victoria Park, a very slightly modified fork of Automattic’s Toolbox, for all of my projects. But every now and then when starting something new, I’ll go shopping around for a theme that’s custom-built for the task at hand. If I’m making a portfolio site, or a knowledge base, for example, I’ll often look to see if there’s a ready-made solution out there, rather than starting from scratch.

A lot of the themes I find out there seem like they’re ready to just drop into place, but so far, at least for me, they’ve always been fool’s gold.

Using something other than your tried-and-tested base theme is a bit like cooking in someone else’s kitchen. Sure, things will get cooked, and the meal will most likely turn out just fine, but it won’t be the same. You won’t find the same frying pans you’re used to, the stove will be different, the cutting board too small, the knives not sharp, etc. Cooking in someone else’s kitchen just won’t feel natural to you, and neither will using someone else’s WordPress theme.

Pots, pans and knifes, all your own

I’ve directed lots of people to Toolbox and its successor _s. I’m still using Toolbox at the moment, but plan to take _s for a spin on my next project. The two are very similar and _s looks on the surface to add nice, minimal enhancements to an already good theme.

Even if you don’t fully adopt these themes as your own starting point, I will recommend (encourage? implore?) that you follow Automattic’s lead in these few important ways:

1. No more loop.php

For too long, loop.php was a melting-pot for a huge pile of logic and conditionals that made modifying it a chore. Ten lines of code that say, “if the user is logged in, and not in the admin area, and not looking at a blog post, and not didn’t have a sandwich for lunch, then show them this content”, make things hard to read and modify. There’s a better way to naturally abstract that logic away. WordPress already knows about and expects files like single.php, page.php, front-page.php, etc, so references to them don’t need to be coded into a loop.php file. There’s no need for conditionals like is_single(), or is_front(), for example, because these already have their own template files. Any code you put in front-page.php or single.php will be picked up automatically, no need for conditionals.

2. Start with a good index.php file.

index.php is usually your first port of call. This is where you want your loop. Like so:

<?php /* Start the Loop */ ?>
<?php while ( have_posts() ) : the_post(); ?>

		get_template_part( 'content', get_post_format() );

<?php endwhile; ?>

Looks simple enough, but there’s a small bit of magic in there. For a good description of this magic, please see item 3, below.

3. get_template_part()—the heart of your theme.

Though not a huge, or terribly powerful function, get_template_part() has become a core part of all of my themes. get_template_part() is more than a function, it’s a way of thinking about structuring your themes. Instead of including the markup for your blog posts, asides, or galleries directly inside index.php (or formerly loop.php), leading to huge, unreadable files, you include their contents in a separate file: content-{post-type}.php. An example will clear things up.

Imagine trying to have different markup in a standard blog post and an aside, where you remove the title, tags, and category:

To achieve this, an old loop file might look like this (I’ll write this in English instead of PHP, for understandability):

while ( have_posts() ) : the_post();

if post-type = 'aside'
	<footer> The date, the tags, etc </footer>

if post-type = 'blog post'
		<h2>Post title</h2>
	<footer> The date, the tags, etc </footer>

if post-type = 'gallery'
		<h2>Post title</h2>
		.....the gallery.....
	<footer> The date, the tags, etc </footer>

While your shiny, new index file will be much simplified. Containing just this tiny loop:

while ( have_posts() ) : the_post();

get_template_part( 'content', get_post_format() );

Using this example, WordPress will still loop through all of your posts, but it will examine each one to see what post format it has (aside, image, article, gallery, link, etc). Each time, it will go looking for a corresponding content file:


Now, all of your template code is neatly abstracted into individual files. You know, for example, that you don’t want to have titles on aside posts, so to get rid of them, just delete the post title from content-aside.php.

The obvious next question you might have is, what if I don’t have a template file for each post type I have? The beauty of this method, is that you don’t need one. If you want asides to look just like blog posts, then don’t have a content-aside.php file. WordPress will simply look for it, not find it, and serve the plain content.php instead. The only file you need is content.php—you’ll only need the others if/when you want that post type to look different.

This all probably sounds a bit like we’re splitting hairs. What’s the difference between having one really long file and having a bunch of really small files? It might not make much difference to you at all, but it makes a big difference to me. As I keep adding more and more post types, including more and more custom post types (outside the standard ones: aside, gallery, links, etc), using this get_template_part() pattern becomes really useful. Instead of scrolling through potentially hundreds of lines of template code, you now just need determine the post type and find its corresponding content-{post-type}.php file.

To sum up

Have a look at _s to see how this is done, or have a look at Victoria Park to see how I do it. My rule of thumb is, whenever I’m doing something like adding/removing a post tile, or post tags/categories, or the date, or otherwise changing a post’s markup in any way, I make sure I’m doing it in a content-{post-format}.php file instead of in index.php or loop.php. Note, of course, that this works just as well for custom post types as for the different post formats. Just put your custom post type content in: content-{my-custom-post-type}.php

This is an excellent habit to get into and will lead to much more readable, maintainable and sharable themes.