Get pro WordPress tips or your money back!

An Alternative to WordPress Plugin Templates

If this post seems a bit out-of-place with the rest of the content on our blog, that’s because right now it is. That’s changing today.

This is the first in a series of posts we’re calling the WP Site Care Workbench. Before today, we haven’t talked about it much but we actually write quite a lot of code here at WP Site Care. We do custom site builds, rebuild our customer’s sites, write custom plugins, rewrite broken plugins, and we’re even working on our own line of custom WordPress products.

Lately I’ve been thinking that we should start talking about how we work and what exactly we do every day more openly. Talking about some this stuff will help educate our existing customers and hopefully let newcomers know that we actually are the WordPress experts that we claim to be.

If you have any questions about how we work or would like to request code-related topics for us to cover in the future, just hit us up in the comments. Now, let’s dive into some code!

WordPress plugin templates are kinda broken

It’s no secret that the WordPress template system leaves a lot to be desired. Developers hate working with it so much that there entire libraries built to enhance or completely circumvent it within plugins and themes. The less-than-awesome template system is even part of the reason why people are so excited about the REST API being integrated into WordPress core.

I get it. Templating in WordPress is painful. You have to learn weird template tags, WordPress quirks, and conform to odd data structures. The thing is, It’s even worse when you try to do it in a plugin. Oddly enough, WordPress core doesn’t provide any way for a plugin to register a front-end display which can be modified from within a theme.

rage-quit-wordpress

Woah, easy there champ. Before you full on rage quit front-end WP dev and sail off into a JavaScript framework-colored sunset, there have been quite a few clever attempts at fixing this problem. Most of the current solutions are re-implementations of the WordPress core locate_template and get_template_part functions. They’re better than the default of not doing anything and they work well in some situations.

Basically, the idea is that the “default” version of the template will live in the plugin, but a theme builder or user can copy it into their theme and modify it to suit their needs. If the plugin gets updated, the modified template in the theme will stay the way it is and the modifications will be preserved.

Sounds pretty cool, right?

It is…. or at least it is in theory. Unfortunately, In practice it kind of turns into a nightmare. Because WordPress doesn’t really have a robust template system, templates tend to contain a mix of markup and logic. Purists will dismiss this as a horrible train-wreck, and it kind of is, but that’s just the way things work in the WordPress world. This is where the problems start.

Because WordPress templates are usually a bit of a mess, when a plugin needs to update functionality they also need to make changes to their templates. When they do this, they fall out of sync with any changes which have been made in a theme or child theme. The end result is usually a partially broken website.

One place where you’ll run into this pretty often is the popular eCommerce platform WooCommerce. It’s such an issue for Woo that they’ve implemented a rudimentary template versioning system to let people know when their templates are out of date and might need to be updated.

woocommerce-wordpress-plugin-templates

If this is starting to sound pretty annoying, that’s because it is. You end up having to watch plugin updates like a hawk and patch things as they break. Sometimes it’s a quick fix, but other times it could require rewriting large blocks of code in multiple template files.

Managing this is a pain in the neck on a single site, so you can imagine how much of a problem it is for our support team. We have 100s and 100s of sites that need update babysitting, many due to this exact problem with plugin templates.

So… that sucks.

Maybe sucks is a little strong. It is better than not being able to modify output from plugins at all. I suppose I should be happy about that, but as per usual; I’m just annoyed. There has to be a better way.

After a lot of thought and quite a bit of trial and error, I’ve come up with something. I’m not sure if it’s “better” but I do think that it’sĀ a more modular, future-proof alternative to what’s being done in most plugins today. It’s already part of WordPress core and it’s already something you’re extremely familiar with if you’re writing WordPress plugins. So, what exactly am I suggesting?

Use the WordPress Hook & Filter API for front-end markup & display

This honestly isn’t a revolutionary idea. The Genesis framework has been doing it for years. We even have our own starter theme with a modern implementation of the idea. Basically, the entire theme is made up of hooked callback functions and template parts which can be unhooked and/or filtered before they output to the browser.

This kind of a markup system requires a lot more planning and thought in order for it to work the way it’s supposed to, but that also means you’ll have a more robust front-end API for users to interact with. If you set up your plugin using small, modular chunks of markup, users will be able to safely add, remove, and modify any piece of the front end display that isn’t working for their specific design or use-case.

Let’s look at some code

Recently I’ve been working on a fairly simple Testimonials plugin called Nice Testimonials. We’ll probably be releasing it to WordPress.org sometime next month, but for now I’ll just share a couple snippets. The plugin has some basic front-end displays and the entire thing has been written in a way which allows it to be modified one tiny building-block at a time. Here’s what the main “template” looks like:

<?php
/**
* Template action hooks used to display a loop of testimonials.
*
* @package NiceTestimonials\Templates
* @author Robert Neu
* @copyright Copyright (c) 2016, WP Site Care
* @license GPL-2.0+
* @since 1.0.0
*/
do_action( 'nice_testimonials_loop_before', $data );
if ( ! empty( $data['testimonials'] ) ) {
do_action( 'nice_testimonials_loop_start', $data );
foreach ( $data['testimonials'] as $post ) {
setup_postdata( $post );
do_action( 'nice_testimonials_loop_top', $data, $post );
do_action( 'nice_testimonials_loop_content', $data, $post );
do_action( 'nice_testimonials_loop_bottom', $data, $post );
}
do_action( 'nice_testimonials_loop_end', $data );
wp_reset_postdata();
}
do_action( 'nice_testimonials_loop_after', $data );
view raw loop.php hosted with ❤ by GitHub

As you can see, there’s really no markup in the template file at all. It can’t be overridden in the theme, so that structure will always reliably exist. What can be overridden is the actual markup itself.

If a user doesn’t like any part of your default markup, or wants to add something to it, it should be very straightforward. They only need to remove one of core plugin actions and/or add a custom one of their own. Here’s an example:

<?php
add_action( 'nice_testimonials_loop_top', 'nice_testimonials_entry_header_open', 14 );
/**
* Output the opening markup for a testimonial entry header.
*
* @since 0.1.0
* @access public
* @param array $data All template data associated with the current widget.
* @return void
*/
function nice_testimonials_entry_header_open() {
echo '<header class="testimonial-header">';
}
add_action( 'nice_testimonials_loop_top', 'nice_testimonials_entry_avatar', 18 );
/**
* Output a testimonial author's avatar.
*
* @since 0.1.0
* @access public
* @param array $data All template data associated with the current widget.
* @return void
*/
function nice_testimonials_entry_avatar( $data ) {
echo nice_testimonials_get_entry_avatar( $data );
}
add_action( 'nice_testimonials_loop_top', 'nice_testimonials_entry_header_close', 22 );
/**
* Output the closing markup for a testimonial entry header.
*
* @since 0.1.0
* @access public
* @param array $data All template data associated with the current widget.
* @return void
*/
function nice_testimonials_entry_header_close() {
echo '</header>';
}

This is an extremely basic example for a very simple plugin, but the possibilities are huge. You can create pre-formatted template tags with filters to output complex markup chunks. If you want, you could even create a HTML attribute system like the one in our CareLib theme framework. It really just depends on how much flexibility you think you need to bake into your front-end code.

I don’t want to harp on WooCommerce too much, but it’s the perfect example of a plugin where a system like this could have worked wonders compared to the template override method. Imagine if they had elected to use a completely hook and filter based front-end API rather than the complex, fragile template structure they’re stuck with now. The underlying API code would be much easier to update and maintain, and developers could add, remove, or modify anything they like. What’s more, they could have done it without having to override and maintain entire template files forever.

Welp, that’s my idea

Is this the best way to create front-end templates in WordPress? No, probably not. It requires an understanding of WordPress core APIs, solid HTML and PHP skills, the ability to plan and think ahead, and a decent amount of patience. That said, I do think this is probably the most flexible option available using the tools WordPress provides.

Without implementing or building a full-blown template engine, I don’t think you’ll find a more bulletproof method for implementing flexible, future-friendly plugin templates.

What do you think? Would you consider implementing something like this in your own plugins? If you’re a theme developer or user, would you rather work with something like this or do you prefer a template system like the one used in WooCommerce? Do you think I’m out of my mind? Let’s talk it out.

Enjoy this post? Never miss another one.

11 Comments

  1. Andrew

    Awesome post, thanks for sharing.

    I’m developing a plugin right now and trying to figure out the best way to give end-developer’s the most flexibility to customize. I think the hook / filter solution will work the best. and this will probably do it.

    I haven’t looked too much into the PHP templating world, but wouldn’t splitting the logic from the view fix this issue? For example let’s say we have a “widget” component in our plugin. Inside the widget folder we create two files, “controller” and “view”. The controller does all the logic work and constructs the variables for us. Then the view simply outputs those variables? Sure if the end-developer doesn’t know what variables he has access to there might be confusion, but I think that’s something clean documentation would fix.

    What am I missing here?

    Thanks again

    1. Rob Neu

      Hey Andrew,

      Thanks! Splitting the logic from the view is really only half the issue with PHP/WordPress templates. Doing that does make it easier for an end-user to manipulate the markup as they see fit, but it’s still kind of limited. Let me give you an example.

      Plugin A registers a template and allows it to be overridden by a theme

      An end user installs Plugin A and overrides the template in their theme and everything is great.

      Now that same end user installs Plugin B which adds a chunk of markup to the template in Plugin A by overriding it and injecting it.

      Which template is the correct one at this point? If the answer is the one in the plugin, the end user loses their customizations and is probably pretty confused. If the answer is the one in the theme, then plugin B’s customizations are never implemented and the end user is still pretty confused.

      If Plugin A had used the method outlined in this post, plugin B could have simply hooked in their markup block without making any overrides or changes to the template. Then the changes in the end user’s theme would (probably) be compatible with both plugins.

      That’s the idea anyway. It’s not perfect and still could run into issues similar to the ones that template overrides incur, but in general I think it’s more modular and “safer” without adding a bunch of extra overhead like a full-blown template engine.

  2. Ben Furfie

    Thanks for this Rob. It’s become an increasingly painful pain point after working with Drupal and building modules for it. It’s approach to template injection is definitely miles ahead of WordPress’ but it’s far from perfect. On the other hand, WordPress’ menu approach is mile ahead of Drupal’s, which when it comes to modules is as painful as plugin templates are in WordPress.

    I’ve long been a fan of Genesis’ use of hooks and filters and have increasingly been implementing them in my own projects – even if I’ve stopped using Genesis because it doesn’t play nicely with Foundation (at least not without a ton of code rewrites).

    I’ve recently been banging my head against the wall when it comes to template injection for WordPress. I’ve been using a combination of TGPMA and get_template_part but as you’ve said, it’s far from a neat solution.

    The API approach is – like you said – likely to put off beginners, but then I think it’ll probably be much less of a head-f*** than they’ll have with the increasingly common move toward OOPPHP and OOPJS. However, I think it’s definitely a step in the right direction.

    I’ll definitely be spending some time looking at this approach more closely when I have a spare hour or two.

  3. Manuel Vicedo

    I agree with this approach. We actually transitioned our themes and plugins to a hook-based layout, which makes everything so much better from a programming perspective. If you need to add something, all you need to do is hook to the appropriate action.

    Taking it one step further, I actually took the time to code a free plugin that builds on this. It’s a small tool meant to make hooking a lot easier for non coders and embed content without having to mess with mini-plugins and the like. Best of all, it works with anything that uses hooks:
    http://wordpress.org/plugins/infuse

    1. Rob Neu

      Hey Manuel,

      Infuse looks pretty cool! Do you have any plans to add support for Theme Hook Alliance hooks?

      We standardized all of our themes on THA in hopes that more developers would start adopting it, but so far there hasn’t been a ton of movement on that front. šŸ™

  4. Mike Hemberger

    Great stuff Rob!

    I’ve been struggling to find a solution to this for an internal SAAS-esque plugin we’re building. This seems like a great solution, given what we’re stuck with in WP core. I’ve been trying to deal with loading CPT archive/single templates in a plugin but allowing them to be overridden in the theme. Still not sure of a great solution there.

    I wonder if a mix of your method and Gamajo Template Loader would be something helpful. Each hook, instead of echoing markup, would load small template in the plugin. Each of those templates could be overridable in the theme (or possibly another helper function?). This way, you could remove the entire hook to build something new, or just override a small template file to just slightly alter some code.

    Curious of your thoughts on mixing the two…

    1. Rob Neu

      Thanks Mike!

      Hmm… I definitely have hooked small template parts in themes in some cases, so I could see it being useful to have both a template loader and a hooked template part. I’d probably try to save it as a last resort though just because it opens the door to having really unpredictable markup.

      It’s tough to say what the best approach would be for your situation without seeing exactly what you’re trying to do. If possible, I’d try to write some modular template tags which can be filtered and used in different ways before going back to the template override method.

  5. Wes Cole

    I love this approach. So much better than how a lot of plugins like Woo handle templates. The issue in why I think people don’t implement or like utilizing templates like this is due to the knowledge curve. I think its easy to forget that a lot of people who are starting or are mainly HTML/CSS developers have a hard time comprehending hooks and filters.

    I know personally, it has taken working in Genesis to really get a grasp on hooks. Before, it confused me not seeing plain ol’ template files.

    That isn’t to say that we shouldn’t use the approach that you outlined above, but it takes more educational efforts for developers to be able to utilize and fully understand.

    Posts like this are a great start in educating people on this approach.

    1. Rob Neu

      Hey Wes,

      I agree, all of this can be pretty difficult to wrap your head around at first, especially if you’re primarily a front-end developer. Actions and filters are a pretty weird concept if you’re used to writing straight template code.

      Honestly, I wish doing this wasn’t necessary and that something more like the Woo system would allow for the same levels of flexibility. Unfortunately, after working with WordPress themes for years I’ve never come across anything that is even close without going down the rabbit hole that is PHP template engines.

      Using a method like this does require more documentation and generally creates more overhead on the education side of things, so that’s definitely something to keep in mind if you decide to implement a similar system. Thanks for the feedback!

  6. darrinb

    I was just going to write a post about this for a widget I’m releasing soon! One of the things I’ve started doing is building widget plugins with fellow developers in mind; adding hooks/filters throughout that allow extension by 3rd parties. I do it a little different than you outlined. I basically build out the markup, but have almost every aspect filterable; similar to how the comment_form() functions.

    But I definitely like this idea better! It seems cleaner to me. Nice job!

    1. Rob Neu

      Thanks Darrin!

      I know this is a pain point for a lot of developers. It’s been one of mine for as long as I’ve been working with plugins and so far this has been the best solution I’ve managed to come up with.

      Basically, my real hope in publishing this is that someone sees it and thinks of an even better way to do things that I can steal. šŸ˜‰

Leave a Reply

You have to agree to the comment policy.

This site uses Akismet to reduce spam. Learn how your comment data is processed.