Make Your Themes Better by Getting to Know get_template_part()
One of the easiest mistakes to make when you first start to make WordPress themes is duplication. It’s one of the simplest and most complicated lesson of making good software anywhere, really. Duplicating code with a quick copy and paste is super easy, and in the short term you feel really efficient — look at all these things I’ve accomplished quickly.
Why Duplication is the Enemy of Maintainability
As time passes, you start to find that the code you quickly copied needs to change. And then you’re faced with a dichotomy rotten on both ends…
But as time passes, you start to find that the code you quickly copied needs to change. And then you’re faced with a dichotomy rotten on both ends: you either have to manually find all the places you’ve copied the code that needs changing and change each instance, or sacrifice the consistency and accuracy for the quick expediency of only changing the ones you notice.
I learned how to do things in PHP and WordPress with themes, and I started — as almost everyone does and arguably should — by duplicating and then modifying an existing theme. I was hugely efficient at first — I had a working theme almost instantly. But then I’d decide that I wanted to change things about how the metadata on posts looked and I’d have to go modify it in every file in the template hierarchy which used the loop and had the order of its calls to
the_date() different than I’d like.
A quick aside: If you’re not crystal clear on either of those concepts — the loop and the template hierarchy — reading the posts I linked there, this summary of how they interrelate, or something else about them, is a quick way to really up your game when it comes to WordPress themes. I went far too long with a dim understanding of those concepts, and everything I did was unnecessarily complicated by it.
Anyway, I was doing this in the bad old days before WordPress had child themes, or cool tools like
get_template_part(), and so I suffered through the downsides of duplication. Let my hard won lesson be your gain, and use
get_template_part() for any code you’re thinking of copying and pasting in your theme. How do you do that? I’m glad you asked.
Put quite simply,
get_template_part() is a WordPress function that includes template “partials” wherever you need them. The canonical example is, as I mentioned above, when you have a way you want your posts displayed across many files —
archive.php are obvious places where you might be looking to use an “abbreviated” post format which you want to look consistent, for example.
What you should do, then, is put your abbreviated post layout in a file —
abbreviated.php is what we’ll use in this case — and then use
get_template_part() to pull it in anywhere you want to use it. For clarity’s sake, here’s an example bit of the loop in an
index.php file that would use
if ( have_posts() ) : while ( have_posts() ) : the_post(); get_template_part( 'abbreviated' ); endwhile; endif;
And here’s the actual content of our theoretical
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <?php the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' ); ?> <?php the_excerpt(); ?> </article>
Now the clever among you may have an interesting but dangerous thought: “Why not just use PHP’s
require functions?” Well, you can, and it’ll work. But if you ever want to make a child theme that inherits from your theme, or want to use a better bit of
get_template_part() we’ll cover below, you may have issues.
get_template_part() makes it easy for a child theme to just replace your
abbreviated.php file, but if you
include it, the child theme will be forced to replace every file in which you used the
include. So while it works, I’d recommend against it.
Another Perk of using
What I’ve kept concealed so far is that you can use a second parameter on
get_template_part, which makes it even more powerful. The child theme stuff is useful, and honestly more important to me, but if you care at all about post formats, this feature is for you. The Codex actually explains this bit really well, so I may as well just quote it:
Assuming the theme folder is
wp-content/themes, that the parent theme is
twentyten, and the child theme is
twentytenchild, then the following code —
<?php get_template_part( 'loop', 'index' ); ?>
will do a PHP
require()for the first file that exists among these, in this priority:
What does that have to do with post formats? Well, if your second parameter is your post’s format, you can find it when your theme has built a special post rendering for that format, and if not it’ll fall back to the default you’ve set. In most of the default WordPress themes, and many others, you’ll see this come out like this:
while ( have_posts() ) : the_post(); get_template_part( 'content', get_post_format() ); endwhile;
At first glance, this may just look confusing. But all it’s doing is safely handling any post format anyone ever dreams up. Most of the default themes have robust and specific support for all the post formats, but if you’re just dipping your toe in you can create the ones you know you want and skip the rest. The magic of
get_template_part() will make sure you setup always works.
The Out Shout
get_template_part is a powerful and valuable part of WordPress. You’ll see it in most good themes you try to edit, and now I hope you know what it’s doing and why it’s valuable.
To close, there is one issue I’ve hit my head against I want to call out the solution to: because of the way
get_template_part works, your local variables in the parent file aren’t accessible in the included file. (Examples: a rudimentary counter in your loop, a more complex determiner of some state you want to add to your post class.) You could make them global, redesign the concept that requires it, do a different weird dance, or you could just take advantage of the
locate_template() function that
get_template_part() uses under the hood and run a quick
include(locate_template('your-template-name.php'));, as Keith Devin explains. Happy theming!