Template Map makes my Client Work Easier

TL;DR: Built another WordPress plugin: Template Map (GitHub)

Very often my inspiration for building plugins is to make my life easier. Selfish as that may be, I’m a big fan of the idea behind using your own publicly released code as much as possible. When you’re actually in the trenches using the code you’re that much more open to the flaws it’s got. Further, I think it helps you to write better code by looking for better ways to generalize it. One of the most frustrating things I catch myself doing to this day is repeating code in my projects, right down to repeatable styles.

Inspiration for Template map, however, came from the WordPress community. And it all started with a piddly little tweet:


Obscureness clarified with:


Still obscure. But a tweet from Andrew Norcross really got me thinking:


Which turned into:

The snowball was rolling already.

Taking a step back; some foundation

The entire premise of this “problem” is directly related to the way I utilize WordPress for client work. It very well may not be the same way you utilize WordPress for client work, but that’s totally fine you might still find the solution useful. It builds upon my need to build Hierarchy, a plugin designed to make managing your content more contextual.

I feel the foundation of the public facing side of any WordPress site are it’s Pages. They dictate the skeleton of the entire URL structure. Sure there are cases where a Custom Post Type slug or taxonomy may be at the top level, but that’s quite rare with the sites I build. There are a couple of reasons for that, the primary reason being a repeating need to have client-editable content on what would be a Custom Post Type Archive field.

This is an important note to consider, reader. I see client oriented WordPress development being much different than the majority of user oriented WordPress development. With client sites there are more rules, you have to cover less of the entirety of WordPress’ landscape. Your clients are only going to use what you’ve built for them (for the most part, aside from those that get really into WordPress, stumble upon wordpress.org/plugins/ and go to town, but I digress). In fact I see client oriented development as so different than user oriented development that I wrote a book on it. Second edition in the works sign up for email updates.

Site structure

Back on track. Pages are the foundation to the URL structure of a WordPress site (for me). Therefore, Page Templates are very often highly utilized when building out pages of a site, especially top level Pages. As a result, the whole of the site navigation system is primarily constructed of Page permalinks.

I might be alone in this, but I do not use Menus in my client sites. As part of our process at Iron to Iron we put a lot of effort into streamlining and organizing navigation systems. We’ve found that relinquishing control over those navigation systems leads clients down a very tempting path to throw landing pages in the global nav because it’s not getting enough traffic, for example. No bueno. The Menus issue is complicated because more often than not the navigation markup itself usually ends up being complex. That’s not to say the WordPress Menus API isn’t capable of accommodating complexity, it’s just another reason I don’t typically utilize Menus for client work. This is one of the many things that are not even a discussion point when it comes to user oriented WordPress development. I don’t think a publicly released theme meant for general consumption would get very far at all without supporting WordPress Menus.

Since I don’t use Menus in client sites, my <nav>s are hard coded with links exactly the way I want. Trouble snuck in, though, when it came to the links in each anchor. The links are usually tied into these Pages that define the overall structure of the site, using WordPress’ get_permalink(). It usually ends up looking something like this (very slimmed down) example:

This method has worked fine… for the most part. Hard coding the Page IDs required for get_permalink() gets the job done when you’re doing the initial development and launch of a client site, but makes life painful when it comes to adding entirely new sections. Once a site is out in the wild the post IDs of that production environment, the staging environment, and your development environment will likely never be the same again (aside from the original core IDs used initially). Subsequent additions in this situation will need to use one ID when you’re developing locally, another when you’re staging, and yet another when in production. What to do?

Potential solutions

At first glance it might seem like get_permalink() has us covered by way of another function. Instead of using the post ID of these keystone pages, why not just use get_page_by_title() to snag the post ID dynamically?

get_permalink( get_page_by_title( 'About' ) );

That will only work so long as the title doesn’t change, but in this ever changing world of SEO, we can’t bank on that for very long. get_page_by_title() isn’t going to help us here, but what about the slug? get_page_by_path() would let us get the Page ID we’re looking for!

get_permalink( get_page_by_path( 'about' ) );

While the slug is less likely to change over time, it could, which leaves the option for a better solution. It also opens the necessity to now keep each environment’s database in sync so as to not lose any functionality. Also what would happen should the title/slug change in the production environment? Clients shouldn’t need to run every edit by you before they make it, right?

While WP Migrate DB Pro basically makes database migration as easy as it’s going to get, even it’s developers recommend not getting yourself into a situation where you need to keep two very dynamic databases in sync with one another. It’s a very difficult problem to solve, and one that when avoided can reduce a ton of stress from your workflow.

The opinionated ‘solution’

During that Twitter rambling and Norcross’ thought provoking tweet it occurred to me: Page Templates. WordPress stores information about Page Templates as post meta, so core is already doing what Norcross suggested. Brilliant; this allows for a solution to the problem using queried data regarding the Page Template metadata to help us build environment-agnostic permalinks at runtime! The only hanging point is the assumption that Page Template filenames (which is the value stored in the database) don’t change. Lucky for us, changing filenames is very unlikely to be done by the client and further: doing so will thereby ‘unlatch’ it from the Page to which it was originally attached, because WordPress can no longer find it until it’s redefined in the WordPress admin (or by manually editing the database records). This bodes very well for using the Page Template filename as a version controllable, deployable way to dynamically retrieve these link-building post IDs.

Introducing Template Map

As usual, a plugin that facilitates this functionality would make life much easier. Here is Template Map. Template Map is a utility class that facilitates a solution to the problem outlined above. The original, ID based gist from above can be replaced with:

As you can see, there isn’t an ID in sight. Its reference has been replaced with the appropriate Page Template, allowing for the same implementation without the headache of relying on hard coded post IDs to generate accurate permalinks.

You’ll also notice that Template Map makes it easier for you to determine whether the current page is within a ‘section’ of the site. Naturally sections are defined by the parent Page’s Page Template, so it uses that filename as well. It’s smarter than that though. Not only will it check Page ancestors, it also allows you to tell it which Custom Post Types are nested within that section.

Piggybacking off of the concept outlined in Hierarchy, I make a habit of nesting Custom Post Types within Pages for an optimal URL structure. This carries over to Template Map with the use of a simple hook that can be added to your theme’s functions.php:

// custom hook for Template Map
add_filter( 'template_map_post_types', function( $cpts, $section ) {
switch( $section ) {
case 'template-about.php':
$cpts = array( 'team' );
return $cpts;
}, 10, 2 );
view raw gistfile1.php hosted with ❤ by GitHub

With that hook, Template Map now knows that any single or archive page for the team Custom Post Type should be considered part of the About section (because the About page uses the template-about.php Page Template). Template Map also checks for all registered taxonomies for listed Custom Post Types and checks to see if any of those archive pages are being displayed as well.

Unfortunately this is also where some opinion comes in. The Page Templates system in WordPress was not designed under a one-to-one restriction, where only one Page Template can be used per Page. Template Map assumes this, however. I rarely (if ever) find myself recycling Page Templates when used in this manor, which is the only reason Template Map can even exist. I realize that’s not always the case (nor should it be) but it is something to note before making use of the plugin. Based on that, should I find myself in a situation where the same Page Template is used on more than one top level Page to be used in this way, I would likely create unique Page Templates that each utilize get_template_part() to reduce repeated code but allow for Template Map to do it’s thing.

What do you think? Have you found that you use hard coded IDs in your client work? Is this solution too far in left field? Should I just suck it up and start building (really customized) Menus? Thoughts are more than welcome, as are Pull Requests!

Plugin: http://wordpress.org/plugins/template-map/
GitHub: https://github.com/jchristopher/template-map