Why, When, and How to Make Your Own Template Tags

One of the great things about WordPress is that there are a lot of things that work the way you’d expect. You might not have the foggiest idea what WordPress does under the hood — that it’s pulling data from a database, that it’s written in PHP, that plugins work via hooks, etc — but when you open a WordPress template you can probably pretty accurately guess what the_date(), the_title(), and the_content() do.

These template tags are built into WordPress, and they’re great. But what a lot of people who’ve used them don’t realize is that you can pretty easily make your own, and they’re super useful.

Why You Should Make Template Tags

So we’ve covered what we’re doing: making our own functions like the_excerpt(), the obvious next question is “Why?”

Basically, a good set of template tags for your project at the surest way to make sure that you theme’s files don’t become a tangle of data-fetching logic. If you’ve seen it before, you know what I mean: rather than a member of the template hierarchy (think single.php) being a few dozen line longs, for complex data-display you’ll frequently find hundreds.

What do I mean by data-fetching logic? Well, imagine that we’re building a minor directory-type view for some new content type in WordPress. If our content is a movie review, we’ll likely have attached a star rating to each review, probably some genre taxonomies, and maybe we’ll also list out other things like the movie’s tagline, the reviewer’s “Three Second Summary” and more. To get this stuff, you can quickly find yourself making lots of calls like:

<?php echo get_post_meta( get_the_ID(), '_movrev_star_rating', true ); ?>

<?php the_terms( get_the_ID(), 'genre' ); ?>

These, on their own, aren’t the end of the world. But string a lot of them together, especially with some logic around them, and it’ll get big quick. Complex and over-long data-fetching logic inside of templates is so common in WordPress because it’s so easy: just put some more PHP in the file (we talked about this more recently in “The Four Types of Templates…“), but that doesn’t make it a good idea. Our theme pages should be as clear and simple as they can be, and making our own template tags is a great first step.

When Should I Make My Own?

Creating more lines of code before you know them to be necessary is a great way to waste time.

When you do this is partly up to you. You can either make template tags as you find yourself making ugliness in your template, as a periodic cleanup phase. You could also do it all up front. Perhaps as we create our taxonomy for a genre, we’d like to make the matching template tag to fetch it. It’s up to you.

My only word of caution: remember YAGNI. YAGNI stands for “You Ain’t Gonna Need It” and is a good thing to keep in mind if you front load the creation of these sorts of template tags “just in case.” Creating more lines of code before you know them to be necessary is a great way to waste time. If you’re thinking of going the up-front route, just be careful you don’t waste hours building functions that you’ll literally never find yourself calling.

How to Make Your Template Tags

If you’ve done a lot of PHP function writing, you’ll find this all rather boring. If you’ve not, you may be a bit scared by the whole idea. But basically, you just need to realize that WordPress’s own template tags are simply PHP functions. So how do you make your own? Just write some functions.

The one important thing to keep in mind is that our template tags, like WordPress’s own, are going to be loop dependent. In our examples above, get_the_ID() refers to the current loop-primed post (i.e. by the_post()). That means WordPress will need to have set a specific global $post that we’ll refer to in our functions.

A Generic Custom-Field Getting

Don’t get discouraged if I lost you a bit in the last paragraph. We’ll explain below. Our goal in this example is to transform the kind-of crufty fetching of the star rating into a generic getter for all our custom field. In code, I want to:

// Make
<?php echo get_post_meta( get_the_ID(), '_movrev_star_rating', true ); ?>
// into 
<?php movrev_field( 'star_rating' ); ?>

How? Well just a simple function like this, put into our theme’s functions.php file:

function movrev_field( $field_name ) {
    echo get_post_meta( 
        get_the_ID(),
        '_movrev_'.$field_name,
        true
    )
}

What’s that doing. Well it’s a function which is taking one string, our shortened name for the field, and just putting that into our function call in the right place. Because all our post meta field’s have been “namespaced” with the _movrev_ prefix, we’re tacking that on so we don’t have to remember it everywhere.

Quick Note on global $post

Because some people prefer to be clear about the global state that their functions are accessing (I prefer to hide it from myself and live in the comforting illusion that WordPress has no global state…) I’ll also note that you could write the above function as:

function movrev_field( $field_name ) {
    global $post;
    echo get_post_meta( 
        $post->ID,
        '_movrev_'.$field_name,
        true
    )
}

I’m noting this because you’ll see this a lot. Effectively, the call to global $post accesses the global state that WordPress sets up in the loop, and then we’re getting the ID off that $post object ourself. Under the hood, this is precisely what get_the_ID() does, but it can be confusing for new programmers to not realize these two are equivalent.

Specific Custom-Field Getting

Let’s say that we’d rather go all the way. Rather than this function with a parameters, we want a bona fide argument-less template tag in the WordPress style. If we want our display of the rating to be done with some code like:

<div>Rating: <?php the_star_rating(); ?></div>

The code to do this would be:

function the_star_rating() {
    echo get_post_meta( get_the_ID(), '_movrev_star_rating', true );
}

A Note on “Namespacing”

The code is hopefully clear enough we need not explain it. Instead lets talk a bit about the fact that I just wrote my own function that doesn’t start with what I call a “poor person’s namespace” (to differentiate them from real PHP namespaces). In general, it’s best practice when you write functions in a WordPress ecosystem to always have a “namespace” at the front of your functions to avoid naming collision that’ll trigger terrible complaints from PHP. (We covered a lot more about namespaces recently, so check it out if you’re not completely following this paragraph.)

This is good advice. But sometimes, for either the beauty of your templates or some other reason, it’s worth taking a calculated risk. In naming my function the_star_rating(), I’m making a wager that this WordPress site will never install a different plugin (or theme) with that function name, and that WordPress core will never introduce such a template tag. I’m okay with that bet, on this theoretical site. But if you’re not you can easily tack your “namespace” to front:

function movrev_the_star_rating() {
    echo get_post_meta( get_the_ID(), '_movrev_star_rating', true );
}

Making Your Template Tag Really Pay Off: Custom Value Rendering

One of the really nice things — and the reasons star ratings are a great example — is that template tags really pay off for you when you don’t want to just return the value, but instead return it in a specific format. Let’s say our integer between one and five of the star rating is to be rendered with HTML entities of a filled star (?, &#10029;) and an empty star (?, &#10025;). (Aesthetically, these two don’t feel quite like a match for our task, but it keeps the code quite simple.) Then we can just use a simple for loop to always show five stars, putting out the correct number of filled and empties:

function movrev_the_star_rating() {
    $rating = get_post_meta( get_the_ID(), '_movrev_star_rating', true );
    for ($i = 1; $i <= 5; $i++) {
        if ($rating >= $i) {
            echo '&#10029;';
        } else {
            echo '&#10025;';
        }
    }
}

Now everwhere you’ve used that template tag, you’ll get the rendered stars rather than the mere number. Nice!

Getting Taxonomy Values as Strings

Last example, this time with a taxonomy rather than a field. Doing a basic “show the linked taxonomy terms associated with this item” is a pretty simple template tag.

function mevrev_genre() {
    the_terms( get_the_ID(), 'genre' );
}

The function inside our template tag is almost so short that we don’t need to make our own template tage at all. But let’s assume — for reasons of client specification, SEO, whatever, that you can’t let those terms be linked. Well here’s another advantage of making your own template tags: if you always use them, and had used them before you got the “never link to genre archives” requirement, you can quickly change the behavior in all of your page templates with simple change to your template tag.

The link-less version is easiest to do as something like:

function mevrev_genre() {
    echo strip_tags(
        get_the_terms( get_the_ID(), 'genre' );
    );
}

If you’re not familiar, strip_tags is just a PHP function that takes marked up HTML and pulls out all the HTML tags. In this case, it’ll be removing the <a href="…">, etc for us.

Pretty Cool, Right?

The case for making your own template tags increases pretty quickly as the complexity of your logic for rendering a value from a post increases. If you have one custom field value, or one set of taxonomy terms rendered in the default way, this is all a bit silly. But as your complexity increases — as we started to get into in the final star example, or the genre one, the benefits start to increase.

Fundamentally template tags are about containment and repeating yourself. We could always manually access values on raw post objects and display them, but it’s nice that the_title() exists. It’s also nice to keep in mind that you can make your own just like it very easily. Happy hacking!

Image credit: Gratisography


2 Responses

Pingbacks