In my last two articles I have discussed how to prepare your WordPress site to act as the backend for a JSON REST-API powered app using a separate, non-WordPress front-end, and I have illustrated how to use Node.js and Express to power that front-end.
This article will show you how to get content in and out of the basic HTML layout, and how to use the HTML5 history API to update URLs.
As I emphasized in the last article: using a node.js front-end provides a faster front-end experience, which is easier for non-WordPress developers to work with and provides complete separation of concerns for front-end templating.
While my example code, a starter project for a hybrid web and mobile app called Josie — named after one of my dogs — is totally functional (you can see it in action here), it is designed as a starting point if you want to run with this sort of implementation. For a more advanced implementation of Express and Node with the WordPress REST API, check out K. Adam White’s ExpressPress.
I chose to use Handlebars as the templating engine for this project, but you could substitute this for any templating system you want without too much modification.
A few gotchas
There are a few practical issues to keep in mind when moving your site’s front-end outside of WordPress. There are also some SEO concerns that some people might have, which I will discuss later when I talk about URLs. First, however, I want to discuss the actual issues that can prevent proper functionality.
It is important that you have set cross domain origin headers (CORS) properly, as I described in the first article in this series, or this will not work in most browsers. If you get no content, the first thing to check for is a CORS error in your console.
The next issue is any CSS or JavaScript added by a plugin to the WordPress front-end will not be loaded. This is going to be a problem for any front-end social sharing plugins or for any page builders. This is an especially big deal for form plugins that use AJAX to submit data, as the JavaScript they rely on will not be there. AJAX interactions in general will be an issue if they check HTTP referer (which they should).
For now you’ll have to forgo these types of plugins and write new solutions in your front-end code. Hopefully, over time, as the REST API becomes more widely used, plugin developers will start to work around these issues. I know it is something I will be looking at.
The foundation
The example code I’m showing you in this article uses Foundation. The first thing you’ll need to do is include the Foundation CSS and JavaScript, as well as the app’s main JS file in your site using standard script and style tags. You can, of course, substitute Bootstrap or some other framework or roll your own.
Also, as I explained last week, I’m trying to keep things simple, and for now I have eschewed proper dependency management to keep things simple. In order to keep your project manageable you will want to use Bower, Gulp, or some other dependency manager, but that’s a topic for another day.
Also, in the last article, I showed the basic HTML layout for the body page. This week we will be adding a JavaScript file called josie.js to house the actual app’s code. We will need to add tags for that, and for a few other scripts — including Handlebars for templating, Fastclick for improving mobile interactions, and of course, jQuery.
You can find all of the files from here.
Here’s my full page layout, minus the templates, and plus one extra bit of code we will look at next:
Soon we will start creating the app’s JavaScript, and it’s going to expect a few parameters be set. The app’s code uses an object-oriented approach that allows it to be modified externally, which is great as that adds a lot of flexibility. Also, it allows us to add some site-specific options outside of the main script file, so we do not have to edit it.
This requires a separate script, which I drop into the end of index.html before the end of the body. In it we need to set the URL for both the site and for its JSON API. We also need to provide the selectors for the menu content area and the main content area.
Since we will be working with the menu endpoint that I showed in the first article, all we need to do to choose a menu set in the WordPress menu editor is to set the name of the menu in params.mainMenuName.
Once we’ve built the params object, we just add it to the Josie object that is in the window scope already. Here’s what it looks with the values I used for testing using one of the default VVV sites as the back-end:
Laying out the app script
The app is written almost entirely inside one object. I need to credit Phil Lewis — one of the Pods developers — for showing me the virtues of it, which I chose mainly because it’s extensible. If you want to start a project by forking my GitHub repo, and do not want to lose the ability to get improvements to the code I add in the future by pulling the origin, you can still customize it from another script.
This is possible beacuse the whole object is in the window scope. For example, if you want to change the click handler for your own custom code, simply add this:
I posted a gist of the script with just the object’s layout and how it’s initialized with no code in the functions. This allows you to see it in its entirety, and if you want you can even write your own logic into that layout.
Please notice at the end there is a separate section that’s outside of the main object, which runs on document ready. That is where we tell the script’s main router to run when the document is ready and when the URL changes. We can also set up other libraries there. For example, that’s where I activate foundation. And later, when we need to register handlebars helpers, that’s where we will do it.
Getting posts
Constructing a URL string for fetching posts is something that I’ve covered in many of my earlier articles on the REST API. Here’s a basic pattern to use AJAX to fetch a post, given the correct URL stored in the variable postsURL:
In our apps object, we can construct a function called getPosts using this basic pattern. We will want it to accept a parameter called offset to enable it with pagination. Based on the value of that parameter and the global posts_per_page parameter, we can construct a URL string that has the correct posts_per_page and offset filter values, like this:
Once we have the posts, we need to render them using the Handlebars template #posts.
This is very simple: In our success callback function, we loop through each post using jQuery’s each method. Once inside the loop, we select the template by ID, then we render the template with the current post in the loop and then add it to variable HTML. After that, we append HTML to the container we stored in the app’s global parameter mainContainer. It looks like this:
And here is the whole function put together with the pagination and the functions to fade out and fade in the main container:
Fetching a single post
Getting a single post is very similar to the function above. The callback function to render the Handlebars template is simpler, however, since we don’t need the each loop.
The url string creation is a little different, as we will need to query for a single post and in order for the app’s main router to work properly, we want to be able to query by ID or by slug.
For this reason, the function will need to accept two parameters: ID and slug. They are technically both optional, however one must be provided for it to work. The way I configured the logic is that if slug is set, then the URL is built using the “name” filter, if not the URL is built using the post’s ID. Here is that logic:
As I said, this function is very similar to the one used for getting all of the posts. Here is what the whole thing looks like:
Pagination
The function for getting multiple posts (as illustrated above) is called a pagination function to output pagination after the posts. The function below adds previous and subsequent links to the end of the blog index. It’s designed to work with Foundation’s pagination component, but you can modify the markup to suit your needs.
The important part is that it links to page/<page-number>. The internal router will then detect the page number and construct the correct URL string inside of the getPosts function.
Creating handlebars templates and helpers
I can’t write a full tutorial of Handlebars.js into the next few paragraphs, but luckily Handlebars is really easy to use. In a Handlebars template, we can output any part of the JavaScript object passed to it, such as a the JSON we receive in response from a RESTful API, simply by placing the object’s index in two brackets. For example, to output the post’s title, we do this: {{title}}
We can also use three brackets to allow any HTML markup to render. That way we can do {{{content}}} and have the content render with all of the markup we added in the WordPress post editor.
Handlebars templates also support traversing into an object. So, for example, the JSON for a WordPress post contains an object called “author,” which contains an index called “name” with the author’s displayed name. As a result, we can output the author’s name, with {{author.name}}.
Handlebars templates are actually scripts with the mime type “text/x-handlebars-template,” where each one must have a unique ID. In this app we will have three templates, which we write directly into the index.html. They will have the ID’s “post” for displaying posts when an archive is being shown, and “terms” for showing posts in a taxonomy archive.
Let’s start the single post template with the surrounding script tag and the basic HTML markup:
This is the basic markup for a WordPress post. We can now fill this in with any part of the JSON object, as I explained above.
You can see my three templates here, but first take a look at the single post template:
Here you’ll find that Handlebars gives us a few cool things. The first is the ability to traverse into the JSON. For example, it makes use of the traversals I mentioned above. Since featured_image returns an object full of data, “{{featured_image}}” would not give us the URL for the featured image. However we can traverse into the object by adding a dot and the sub field, which allows us to use “{{featured_image.guid}} to get the image’s URL and {{featured_image.title}} to get its title to use in the alt tag.
Also, this template uses multiple Handlebars helpers. Helpers are special functions we can use to reduce redundant code in templates. There are three of them in use in my templates, which you can see here. They help format dates, show categories for a post, and create consistent markup for links in order to work with click handler and router. The link helper is important as it is designed to work with the click handler.
In app routing and permalinks
One of the goals of this project was to have the same URL structure as WordPress’ pretty permalinks. To do so, I added a Handlebars Helper for creating internal links in the app. These links trigger a specific click event that prevents the browser from refreshing the page. Instead, new content is loaded using the app’s internal functionality and the browser’s URL is updated using the HTML5 history API.
I know some people are going to lose their minds here because some search engines — not including Google — will not index a site using push states properly. Personally, I don’t care, I’m more interested in end-user, non-end-bot experience. Also, this is not a unique issue and there are lots of solutions for handling the SEO concerns it might encounter.
Thanks to the helper for links, all internal links have an attribute added called “josie,” whose value is internal. These will be caught by this event registration code in the main app’s init() function:
This allows for links to external sites to work as usual, but internal links trigger the internal routing logic. Here is the click handler function:
This function can be broken into three sections: The first reads the title and ID of the post. The second constructs a new URL to set in the browser using the history API’s replaceState (this method updates the browser’s URL and title to that of the new post being shown). The last section loads the new content using the functions we already created.
This link handler works in concert with the routing function in the events object. Here’s the full events object:
The way this script is written is that you can easily replace parts of it. If you need to modify the logic in all (or one) of these events, just define Josie.events or Josie.events.clickHandler in a separate script. As I said, in the beginning, this is a totally functional starting point, so use as much as you want.
It’s all new territory
I’ve walked you through how I created a single page web app using about a thousand lines of heavily commented, generously spaced code. This new RESTful API in WordPress is opening exciting new options for WordPress developers that we can choose to use and I hope the separated front-end style site will be one of them. I hope that you will be able to use and improve upon the starter app.
As I use this in more projects, I intend to add form handling, Pods integration, and other tools to make it more interactive and powerful.
It’s so exciting that we’re able to use this tool in new and exciting ways, which makes it even more important to share what works for you with the rest of the community. If you come up with something better than what I have, please feel free to share a link to your Github repository in the comments, I’d love to see it.
Josh Pollock started learning WordPress development when he was supposed to be working on his masters thesis, which ended up being about open source solutions for sustainable design and was presented in a WordPress site. You can learn more about him at JoshPress.net or follow him on twitter @Josh412
The post Building the Front-End for the JSON REST API-Powered Single Page Web App appeared first on Torque.