Having a RESTful API in WordPress opens up options for WordPress developers and non-developers alike.
Most of my articles on the REST API focus on using it to improve WordPress sites. But one equally exciting thing about having a RESTful API, which we haven’t discussed yet, is that it makes it easier than ever for developers who are not WordPress specialists to create the front-end for a site or app. And all can be done without disrupting the use of WordPress for content management.
This should excite developers because, though WordPress shines as a content management system, PHP leaves much to be desired as a templating language and therefore requires a lot of work to create proper separation of concerns in the front-end. Having the ability to transfer the process of rendering front-end content entirely into JavaScript, or some other more front-end friendly language, is definitely worth your time. It’s not only easier to work with, but it also creates opportunities to increase interactivity and overall performance.
This is the first part of a three-part series on creating single page web and mobile apps, which are powered by the WordPress REST API, but have a front-end separated entirely from WordPress. In fact, the front-end will be running on a node.js server.
The node.js server can, and probably should be running on an entirely different server than the server (Apache, nginx, etc) that is powering the WordPress site.
In this article, I will lay out my approach for the series. I will also discuss optimizing your site to act as a back-end for a non-WordPress front-end. In the succeeding articles I will focus on the non-WordPress side of the site. In addition, I will provide some useful information about using node.js.
My approach
If you’re a WordPress developer, this approach is probably fairly new, so I am going to stick in my example code using basic JavaScript, and using jQuery’s AJAX library for most of the heavy lifting.
A developer who is more familiar with Node and Express (the middleware I am using) will probably look at this and think “he’s not doing it right!”
The truth is that I’m only using Express so I can have WordPress-style permalinks without 404s when the browser is refreshed. I’m also using Express to show basic concepts, with as few complications as possible.
So, if you’re a Node and/or Express user and want to stick to the normal workflow, I would recommend that you read this article about preparing the WordPress site and then take a look at K. Adam White’s ExpressPress project on GitHub. He prepared it for his talk at this year’s WordCamp SF.
That said, the example code I will be showing is totally functional. I hope that you will either use it as a starting point for your own projects or become inspired to create something better and more interesting to share with the community.
When I spoke with White he indicated that he too feels that his code is a good starter, but not up to production level. This is an exciting new territory and pushing the envelope of what we can do requires that we share our code.
Preparing your WordPress site
Technically, all you need to do to allow a WordPress site to act as the back-end for a non-WordPress front-end is install the REST API plugin. That said, there are several issues that you will most likely need to address for your project to succeed. I will be tackling several of them in this article, so that when we start working on the front-end side, everything will be ready to go. Fortunately the REST API plugin has hooks that we can use for solving all of these issues.
Cross origin issues
The most common issue that you can run into when working with a separate front-end, which also applies to making your site’s API available for use by other sites, is the restrictions placed by cross-origin restrictions. For security reasons, most browsers by default won’t allow you to load content from one site to another if they are served from two separate domains. This will prevent AJAX requests from succeeding when requesting data from a separate domain. That is, unless the correct Cross Resource Origin Sharing (CORS) headers are set.
CORS headers can be used to selectively allow certain domains, or alternatively any site, to access your site. While CORS headers can be set globally for a WordPress site, or only for wp-login, in our case we want to set the header to apply only to the REST API’s output. All headers, including CORS headers, must be output before any HTML content. The REST API provides the “json_serve_request” filter that we can use to do this.
One option is to allow requests to originate from any origin. We can accomplish that like this:
While this is the easiest option, it may not be preferable in most situations. You can replace the asterisk in the above code with a specific URL to allow that site to access the REST API remotely. What you can’t do is add more than one CORS header. As a result, if you want more than one site to have access, you will need to detect the referring site before setting the header. By doing it this way, you can set the header if the referring site is one you want to allow requests to originate from.
We can do this by defining an array of acceptable domains and then checking if the origin domain — i.e. the value of the $_SERVER['HTTP_ORIGIN']; — is in that array. If so we can set that as the allowed domain. Here’s how that works:
This checks if the super global $_SERVER has the key ‘HTTP_ORIGIN,’ which should contain the domain of the site making the request. If it does, it then checks if the URL request that originates is in the array of allowed domains. If it is, it then checks if that domain is used for the CORS header. If not, no CORS headers are set.
Protecting against requests for too many posts at once
On the post endpoint the “posts_per_page” filter can be used without authentication. This is a potential security issue if you have lots of content on your site, as requesting too many posts at once could be used as part of a DDOS attack. This is especially true if you set a CORS header to allow any domain to access the REST API remotely. Even if you do not, this is still an issue as origin headers can be faked.
All of the parameters for making post queries via the REST API have a filter. They are created dynamically using the pattern “json_query_var-<name-of-filter>.” This means that we can override any value set for the ‘posts_per_page’ filter by hooking “json_query_var-posts_per_page.” I recommend limiting to the maximum amount you intend to use in your app.
For example, if you intend to use ten posts per page, you would use this:
This filter only takes effect if the number of posts per page exceeds ten, and if so the value is changed to ten. As a result a request to “/posts?filter[post_per_page]=5″ would return five posts, while a request to “/posts?filter[post_per_page]=50000″ would return 10 posts.
Preparing for pagination
By default, offset is not a publicly queryable variable. This makes pagination in your app impossible. Later this week, I will show you how to build simple pagination using the posts_per_page and offset filter. For example, if ten posts were being used per page, the second page of posts will be retrieved with a GET request to “/posts?filter[posts_per_page]=10&offset=[10].” By default, this would actually return posts 1-10, not 11-20 as we would expect, since offset is not a publicly queryable variable.
Luckily this is a very easy fix as we can add “offset” to the domain of public vars using the ‘json_query_vars’ filter. This filter exposes an array of filters we can use for non-authenticated queries. We can add or remove queryable variables using it. Here’s how to add offset:
Optimization
The REST API does not reinvent how posts or other information are queried from the database. It uses WP_Query for posts, WP_User_Query for users, and so forth. As a result, most of the same methods we use to optimize our sites apply here. For example, WP_Query leverages object caching, so using a persistent object cache — such as Memcached or Redis — will improve its performance no matter how it is used, including when making requests via the REST API.
The one common WordPress optimization strategy that has no effect here is page caching, as it acts to serve static HTML files to visitors to the front-end of your site, and these requests are not generating front-end HTML. Again, the REST API came through with a filter that allows us to intercept requests and serve a response directly.
Using this, I was able to create a very simple cache for REST API request using the WP-TLC-Transients library, which I wrote about recently, to handle the caching. This simple caching system checks if it has already served a request for the same URL and, if so, returns that response. If not, it allows the REST API to build the response and then caches it before serving the response.
This is all made possible via the “json_pre_dispatch” filter. This filter exposes two variables — $result and $server — to the filter. $result by default is false. If this filter does not return false, its value is used as the response and most of the rest of the plugin is skipped. The other variable, $server, is the JSON server itself, which allows us to properly format our results.
Here is a slightly simplified version of my REST API cache library, which we can use to cache results like this:
If you are familiar with the TLC-Transient-Library you will notice that this looks for an existing transient name for the hashed value of the URL that was requested. If not, it calls the function “jp_rest_cache_rebuild” to generate the cached value, and passe the $server variable to it.
That function is actually quite simple: it just used the dispatch method of the server’s class to set in motion the REST API’s default behavior for building a response:
Adding custom routes and endpoints
Like WordPress or any good plugin, the REST API is very extensible. One of the reasons is that the REST API makes very easy to add custom endpoints. This is great, as there is no way that it can be all things to all sites. Working with custom endpoints is very simple. I am not going to cover this subject exhaustively here, as that really deserves an article of its own, but I will show you how I created a menu endpoint for the example app that I’ll be going over in my next two articles.
This endpoint was created after an early version of my code required manually building a JavaScript array for generating the menus from. That seemed like a silly thing to do when WordPress has a great menu editor already. It also seemed like a way that too easily allowed for human error to break things on the resulting site.
To solve this, I wrote a custom route and endpoint to serve the result of wp_get_nav_menu_items as a JSON array. It’s actually a perfect example of how easy this sort of thing is.
To create a custom route, you must hook into “json_endpoints” filter, and then add your route and endpoint to the array exposed by that filter. In the filter function you can then specify a callback function to use. Here is a slightly simplified version of the library I created for adding menu routes:
The function before the class instantiates the class and calls its method “register_routes,” which is where the route and endpoint are set by adding them to the $routes array exposed by this filter.
In the first class method, we add a key to the routes array with the URL for making requests. You will notice that I add a leading element to the URL. This is like prefixing a function to make sure that it doesn’t clash with other plugins. Just going directly to “/menus” is irresponsible, as it will create a conflict if a menu route is added by another plugin or by the core REST API in the future. The last part of the key “(?P<menu>[w-_]+” allows for the last part of the request URL to be the name of a menu and for that to be passed to the first parameter of our callback.
The value of this key tells the JSON server what callback function to use for this endpoint and what type of request to route to it. In this case, we are routing GET requests by using “WP_JSON_Server::READABLE,” and allowing it to accept JSON in the requests body by using WP_JSON_Server::ACCEPT_JSON. The body of the request is passed to our callback function as its second argument.
The callback function sends the menu name and the array of parameters from the body of the request, which the REST API plugin already converted to a PHP array for us.
The whole thing is actually quite simple. If you need a fully-featured API for your site or plugin, I recommend what we did at Pods for our API — forking the BuddyPress API add-on plugin and matching it to your needs.
Now we’re ready to rock
I know that was a lot to take in, and not all of it applies to every single site, but these are some of the things that you need to keep in mind in order to make your WordPress site perform as well as possible when used as the back-end for a web app. What I’ve discussed here applies equally to the example code I’ll be showing you in the next two articles, and any site using the REST API to power another site or integrate with one or more other sites or services.
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 Preparing Your WordPress Site to Power a Single Page Web App appeared first on Torque.