In the WordPress development world we are used to dealing with templates. WordPress themes for the most part are a grouping of a bunch of template files that make up the look and feed of a website. We use template tags in the form of short PHP function calls to insert data into the surrounding HTML so that many different pages, or parts of pages, can use the same markup.
While we are used to doing that in WordPress with PHP, I find moving that thought process to Javascript can be a bit of a stretch for some developers. The idea is almost the the same, a bunch of HTML with tokens in it to represent where data should go and how it should be organized.
There are various ways to go about templating in Javascript. There is a loose specification called Mustache which is implemented in many languages including Javascript. Extending that a bit is a library called Handlebars. The Underscore library has templating in it as well.
What you may not have realized, though, is that WordPress has shipped with a JS templating helper since WordPress 3.5. It is based on the Underscores templating engine, but it modifies the syntax of it to make it look and feel just a little more like the Mustache, but without dragging an entire extra library along for the ride.
Here’s a definition for the wp.template method.
wp.template( templateName )
File Location: //wp-includes/js/wp-utils.js:17-30
Registered Slug: wp-util
templateName
Type: String
The id of the template to grab out of the DOM without the ‘tmpl-‘ prefix.
Return
Type: Function
A function ready to accept an object containing data in accordance to the template.
Additional Notes
Templates are defined in script blocks with type=”text/html”. They need to be given an id of “tmpl-(template-name)”.
- Templates will be passed a
data
variable which can then be called upon to output values. - Escaped output goes in two curly braces
{{data.escaped}}
. - Unescaped data goes in three curly braces
{{{data.unescaped}}}
. - Arbitrary logic goes in carrot hash template tags
<# //logic #>
. - Anything not in one of the three token markers will be returned as is.
Example:
<script type="text/html" id="tmpl-my-template">
<p>I will simply be returned.</p>
<p>But I can also output an {{data.escapedValue}}.</p>
<p>If the data contains markup I can output it without escaping:</p>
{{{data.unescapedValue}}}
<p>And if I need to perform some conditional logic I can.</p>
<# if ( data.trueValue ) { #>
<p> I am only output if <code>data.trueValue</code> is true.
<# } #>
</script>
The Template Hack
For Javascript, since the majority of the time we’re processing data and inserting it after the page has finished loading, we need a way to make the teamplate accessible to our script without affecting the rendering of the current page. We don’t want a bunch of markup with {{data}}
tokens in it output for the world to see. It’s possible we could use CSS to hide it, but then we run into accessibility concerns, SEO concerns, it just starts becoming a mess.
For this reason, most javascript templating libraries make use of some form of <script></script>
tag to house the templates themselves. The reason for this is the behavior browsers have around script tags. If you place a script tag in your markup that has a type that the browser doesn’t actually understand, it will ignore it completely and continue merrily on it’s way. But, it will pause long enough to look at that script tag insert it into the DOM.
This is perfect for templating!
We’ve got a way to stick our markup into the DOM, but have the browser and screen readers ignore it without any CSS or extra work what so ever. In my examples I use the type “text/html” since this is semantically what the template actually contains.
This is a bit of a hack since the script tag was never meant to be used for this purpose, but the behavior is perfect for our needs until we have good support for the template element. It’s coming, but it’s not quite here yet.
Example
Let’s take a look at how we can actually use the wp.template method for JS templating in WordPress. This continues the example we started when looking at the wp.ajax helper to perform asynchronous requests. This is a common use case for templating.
After getting some new data from the server via Ajax, often times getting that data to display on the screen looks like a nasty mess of concatenating HTML strings together, but with templating, that doesn’t have to be the case.
In our example we are allowing the submission of comments via ajax, which means the page doesn’t get refreshed. However, once the comment is inserted we want display it for the user just as if it had always been there. This is going to be specific to our theme since comment templates can vary from theme to theme. Also for the purposes of simplicity we have disabled threaded comments.
Outputting the template
The first thing we need to do is get the template into the DOM so that our Ajax script can make use of it. To do that we’ll insert it in the footer using the wp_footer
action so that it doesn’t interrupt the initial rendering of the page.
function lw_comment_templates() {
include_once get_stylesheet_directory() . "/templates/comments-templates.php";
}
add_action( "wp_footer", "lw_comment_templates" );
We’ll house the template markup in a separate file to keep our PHP code nice and clean. Doing this makes the function to include the templates very simple. Note that in the finished example we add the action in the initialization function which allows us to only add these templates to the page if a comments form is actually present. There is no need to include templating markup if it’s not needed.
Next let’s take a look at a template in the /templates/comments-templates.php
file.
<?php /* Markup for a single comment when inserted into the DOM */ ?>
<script type="text/html" id="tmpl-comment-single">
<li class="{{data.comment_class}}" id="li-comment-{{data.comment_ID}}">
<div id="comment-{{data.comment_ID}}" class="comment">
<div class="comment-meta comment-author vcard">
{{{data.gravatar}}}
<div class="comment-meta-content">
<cite class="fn">
<# if ( data.comment_author_url ) { #>
<a href="{{data.comment_author_url}}" rel="nofollow" class="url">
<# } #>
{{data.comment_author}}
<# if ( data.comment_author_url ) { #>
</a>
<# } #>
</cite>
<p>
<a href="<?php the_permalink(); ?>#comment-{{data.comment_ID}}">
{{data.date_formatted}} at {{data.time_formatted}}
</a>
</p>
</div> <!-- /comment-meta-content -->
</div> <!-- /comment-meta -->
<div class="comment-content post-content">
<# if ( "1" !== data.comment_approved ) { #>
<p class="comment-awaiting-moderation"><?php _e( "Awaiting moderation", "wilson" ); ?></p>
<# } #>
{{{data.content_formatted}}}
</div><!-- /comment-content -->
</div><!-- /comment-## -->
</li>
<!-- #comment-## -->
</script>
That’s a lot of markup.
Imagine trying to generate that much markup by concatenating strings in Javascript. I seriously shudder at the thought. It’s not impossible, but it’s going to be ugly. I’m going to stick with templating.
We’ve given our template a name of “comment-single”, as can be seen by the id of the script tag, which is “tmpl-comment-single”. This name can be any valid HTML id string.
For any value that does not and should not contain markup we use the {{data.escaped}}
style template tags. If markup were to sneak in here it will get turned into html entities for display. This is true of the comment title, ID value, author name, date stamps, etc.
For values that do contain extra markup we’ve used the {{{data.unescaped}}}
style template tags, which allows the values to be inserted as is and parsed as HTML by the browser. We’re getting back the user’s gravatar as a full <img />
tag. Similarly, the comment content can contain some safe HTML. Both of these are output as unescaped values so the HTML inside the data will display correctly.
Finally, we’re making use of some light logic inside <# //logic #>
style tags. If the comment author doesn’t have a link, we don’t wrap their name in an <a />
tag. We conditionally show the author a note that their comment is awaiting moderation depending on if the comment is approved or not. Logic blocks should be kept small, but they can lend some extra power to the templates.
One other thing to note that is pretty fun. There is a PHP template tag in this template. Depending on the page that loads, this template will have the correct parmalink embedded into it using <?php the_permalink(); ?>
. With Javascript templates in WordPress you actually get two passes on the template. The first when outputting the template itself where you can use some PHP template tags to make the template more dynamic, and the second when actually processing the template with Javascript for display where you can fill in the rest of the blanks and create the final HTML string.
Using the template
Now that we have output the template we can make use of it in our Javascript file. Looking back at the definition of wp.template we can see that it is located in the wp-util
file, which we’ve already specified is a dependency of our ajax script. If we hadn’t, we’d need to either enqueue wp-util
or add it as a dependency for our script.
Before we can use our templates, we first have to get a reference to them. We’ll do this by declaring an additional variable where we will store the template function we create.
var singleTemplate = wp.template( "comment-single" );
That little line of Javascript is very powerful.
The wp.template helper is going out to the DOM and slurping up the contents of the template we defined, memorizing it, and creating a function that we can pass our data
to. Calling that function then returns a completed html string to us. We’ve assigned it to the singleTemplate
variable so now we can make use of our template by calling singleTemplate( data )
.
Let’s do that.
function commentSuccess( data ){
// Template the comment and unlock submissions.
$comment.before( singleTemplate( data ) );
$comment.remove();
$comment = false;
// Reset the form.
$commentForm.get(0).reset();
}
This short Javascript function is the entirety of our ajax success callback. Because we’ve used the wp.ajax
helper, we know a successful return is going to contain comment data, not an error. We’ve also left ourselves a bread crumb where we would like our comment to go and stored a reference to it in $comment
. So, turning the comment data into a comment is done entirely in the line $comment.before( singleTemplate( data ) );
. The rest of it removes our breadcrumb and resets our form so it’s ready for another comment.
One line to process Ajax data and insert it appropriately into the DOM. Sweet.
Basically we are making use of the jQuery .before
method to insert the template string. Any any of the DOM insertion functions in jQuery can be used, .html()
, .before()
, .after()
, .append()
, .prepend()
, and so on. If you need to insert a template string without jQuery, you can use a DOM element’s .innerHTML
property. With the wp-util
library, though, jQuery is a dependency so it will be there regardless.
Take a look at the finished product (video). It works well.
When to use this
Templating in Javascript is a powerful way to process data and turn it into displayable markup for the user. If you are processing a lot of data, use a template library of some kind. It will keep your Javascript free of long string concatenation blocks, which are hard to read and not fun to write. Which templating library you choose depends entirely on your situation.
If you are in the WordPress admin, specifically on the post edit screens, the wp-util
library is already present, so by all means grab hold of wp.template
and use it! If you are processing ajax requests on the front end of the site using the wp.ajax
methods, wp.template
comes along for the ride as well, use it!
I would not suggest, however, including the wp-util
library if templating is the only part you are making use of. At that point, I would suggest considering straight Underscores templating or something like Mustache.
If you have a good use case for wp.template or one of the other templating libraries I mentioned, drop it in the comments. I’m always interested in new ways to use this stuff.
April 20, 2014 at 1:25 pm
Thank you for this article! Great write up.
It was actually very strange I came across your article. I had been looking at WP core, the media uploader, and seeing where it outputs these templates, and was wondering what it all is. Literally a half hour later, I saw a tweet about this post when I was just perusing my Twitter feed.
Anyway, my dilemma was that I needed some dynamic form markup to feed to my javascript file every time the user does some action, but the markup doesn’t change on the user action, except for a few values within.
So, generating it initially on the page load would suffice, if I had a way to fill in the values. So, with this template system, I was able to have a solution where I didn’t have to do an AJAX call to the server every time the user takes action.
May 1, 2014 at 7:55 am
Thanks for the kind words, Jason, I’m glad you found it useful!
I’ve been a fan of your work ever since I ran into the Swagger theme at my last employer. It was a breath of fresh air after using a bunch of other Theme Forest themes. Keep up the great work with Theme Blvd.
May 1, 2014 at 12:33 am
I’ve been meaning to look into this for quite some time. Thank you for this great article! 🙂
May 1, 2014 at 12:35 am
BTW what do you think of reusing those template files on the server? I know some PHP libraries that offer Mustache-like template rendering, but was wondering if WP offers a solution.
May 1, 2014 at 7:50 am
You could do this with some regex work, which is basically what is happening under the hood. If you look at
wp-includes/js/wp-util.js:20-22
you can see the regexs that this is using to evaluate the template strings.As far as whether or not this is a good idea, I could go either way. If you are building an actual single page app, this could be really useful for getting pages to the screen before the JS loads, but as soon as you drag more PHP into the equation you have to start concerning yourself with how it interacts with caching plugins and state. I think I’ll have to reach for the cop out answer and say “it depends” 🙂
September 4, 2014 at 2:57 pm
I actually did that without doing any regex processing – instead, I just used some PHP logic to figure out whether I’m using the template to render output, or just rendering the template for use in JS.
It currently doesn’t support the if statements – I’m sure with some extra PHP these can be added as well, but I just don’t need them.
An example gist: https://gist.github.com/nikolov-tmw/8059ca8f1f5e0678be49
It’s a bit of extra work, but it’s worth it in case you need to render some HTML at load-time and you’d prefer to do it on the server side. This way you really only have to update one file when you’re changing your HTML.
August 8, 2014 at 5:59 am
WordPress really needs to document this a lot better, I’m going to try to knock up a template for people to download and dissect.
I Plan to augment all my shortcodes with this if for nothing else but a placeholder
February 20, 2015 at 12:14 pm
Thanks for this article. I was inspired to match the functionality in PHP so I created a wrapper class and function to emulate the same workflow using mustache.php
It wraps any data you give it in a data var, accessible with {{data.xxxxx}} to match functionality; that means that {{xxxxx}} won’t work.
https://gist.github.com/weskoop/2f69e69aefdadda7c94d
Any feedback is welcome.