Creating a Website with Nuxt.js and WordPress REST API


Update:
You can now use my boilerplate from the public repo:
https://github.com/bovas85/nuxt-headless 
(please start it if you appreciate it, feel free to contribute).

Often times we find ourselves in the position where our clients want a Content Management System (CMS onwards) that will allow them to edit their pages without having to know HTML code to do so.

It’s then usually a choice between a bespoke CMS and WordPress (recently though we are seeing more and more “Headless” CMS coming up, as well as the very valid alternative of markdown or static CMS options).

In our case, we opted for WordPress for a few reasons:
- It’s a solid CMS with years and years of experience on the field
- Security issues are now almost gone, considering the automatic security updates from version 4.7 onwards (I might be mistaken on the version, don’t quote me on that).
- WordPress REST API gives us access to several fields (and custom ones) without the need of serving the whole front-end with WordPress.

Our Backend Developer was also more familiar with PHP, Laravel and WordPress than other technologies, so luckily we opted for WordPress in the end.

Regarding the Frontend, I was in charge of choosing the stack and as I love Vue.js (Vue 2) so much, I definitely pushed that forward, using Nuxt.js for Server Side Rendering (SSR from now on).

Part 1, What’s Nuxt.js ?

Nuxt.js PROs:
1) automatically generated routing with middlewares, validators and more 
2) full SSR support out of the box with vuex support 
3) pages system with async data hooks, transitions, loading indicator etc 
4) layouts system out of the box 
5) metadata handling out of the box with SSR support 
6) all the fancy nuxt modules providing stuff like PWA, authentication, offline support and more 
7) convention over configuration approach which i prefer 
8) A community of Vue devs that all work with the same opinionated approach.
Point 8 is particularly huge because Vue community is extremely divided, due to Vue being a progressive framework. 
People use Vue in so many different ways that having a large part of the Vue community that actually does use Vue the same way is great.
That’s excluding SSR…

— @gustojs#2934 from VueLand Discord channel

As you can tell, these features are a huge advantage for a small agency that can’t spend too much time on designing an enterprise architecture for their stack.
WordPress recently bundled the REST api inside the core package (4.6.0) and so I decided to try it for our first website.

It was a migration from an AngularJS frontend…


Part 2, Initial Setup

The first required point was for the websites to be as much SEO friendly as possible, coming from Angular 1/1.5 where the only easy solution was prerender.io (which wasn’t implemented).

I had tried Nuxt previously for a side project, but things never click unless you are hard at work on it.

I was familiar with VueJS but the initial setup for Nuxt left me a bit dubious of the capabilities. It looked too simple to be true, and without any config from the initial CLI.

You can start by installing the vue cli if you haven’t done so yet:

npm install -g vue-cli

(watch out for vue-cli 3 that’s soon coming out as that might change this following command)

Then using vue-cli you can init a new Nuxt project typing:

vue init nuxt-community/starter-template <project-name>

Where <project-name> is your folder and project name.
You’ll scaffold a directory containing several others and a nuxt.config.js file:

initial nuxt.config.js file for my vue-meetup talk

The first thing to understand about Nuxt is that it’s an hassle-free framework around VueJS and SSR.

It only uses modules and libraries already available in VueJS, but organises them into a really neat, opinionated folder structure.

folder structure for a nuxt project

Part 3, Going Deeper

The main problem initially was how to integrate sass and use sass variables in my project.
I had to do this sorcery here to have variables available in each Single File Component (SFC) or page

This then became much easier thanks to a Nuxt Module which can be simply added to nuxt.config in an array with a list of sass variables to load globally.

The next step was figuring out how to manage the state.

For some reason I though a global mixin was a good idea

The reality is that when you have a couple of components, maybe a navigation bar or some modals, it’s already time to load Vuex.

To do that in Nuxt is as easy as:

index.js inside /store folder with some example mutations and nuxtServerInit

Nuxt also gives a way to load every meaningful state beforehand by using NuxtServerInit action in the store.
This allows you to prefetch everything you need without the need of using mounted to load it (and losing on SSR that way).

There are other methods that can be used outside the store, which are asyncData (that loads data in the component) and fetch (that commits mutations or dispatches actions).

These can be used if you need something only locally within a component or page.

asyncData returns a new data property in the local .vue page
we can commit new data from an API to the store with fetch

One thing to realise here is that we are dealing with two instances.
One on the server, virtual and not visible, and one on the client-side.

This means there are some gotchas when developing with Nuxt and any server side app but Nuxt makes these gotchas very limited and simple to overcome.

Nuxt has bundled in a <no-ssr> component, which can wrap anything else, including other components, as long as you have a single root element inside it.

no-ssr runs the enclosed code only client-side (no SSR)

This plugin allows what’s inside to live only on the client side, and is particularly useful when dealing with 3rd party plugins that might contain references to window or DOM elements and are not needed on server side.

If you don’t do this or something else I’ll show now, you might encounter a different tree structure, which Nuxt will notify you of:

The other gotcha is how libraries and components are loaded into Nuxt.
We load them by creating plugins in the plugin folder and attaching using either Vue.use, Vue.component or Vue.directive with it.

The second step here is to add that plugin into nuxt.config, and here we can specify whether that’s an ssr ready plugin (just by typing the path to the plugin), or not, by specifying ssr: false there.


Part 4: dealing with WordPress CMS and API calls

Once the main project is setup and you start dealing with each page, the quickest and best approach in my opinion is to add a plugin called:
Advanced Custom Fields (ACF)
to WordPress backend.

This adds custom field functionality to pages and posts in WordPress.
To extend this to the REST API you will also need a plugin called
ACF to REST API
REST API Enabler

Some useful addons:
WP REST API filter fields
filter fields Enables you to filter the fields returned by the api.

WP REST API Pure Taxonomies
This plugin include all available taxonomy attributes into the WordPress REST API (v2) without additional API requests.

WP REST API Cache
Enable caching for WordPress REST API and increase speed of your application.
Caveat here:
If you are doing post requests (example contact-form-7 plugin), make sure you don’t use this plugin, or if you do, filter the string ‘contact-forms’ in functions.php like below:

add_filter( 'rest_cache_skip', function( $skip, $request_uri ) {
if ( ! $skip && false !== stripos( $request_uri, 'contact-form-7' )) {
return true;
}
return $skip;
}, 10, 2 );

WP REST API Menus
Extends WP API with WordPress menu routes.

The next step then was to configure the API endpoints.
I personally used a config.js file that I can import like so:

import Config from ‘~/assets/config’;

This will allow me to have a clear and configured endpoint location for all my pages.

The above is partially taken from a luxury travel operator, Antilophia.
The site isn’t live yet, but I will update here once it is. Stay tuned ;)

Once you have the above config, you can configure the app to retrieve data either on nuxtServerInit or with fetch / asyncData.

With that, you can then populate each section of the website using the advanced custom fields plus the rest of the WordPress API fields available (anything really).

The server will update the content every time it loads a session for a user.

You can create dynamic pages using the folder structure :<dynamic-param>
Where <dynamic-param> is the name of the parameter you want (eg. :destination)

This gives you access to the parameter using:

this.$route.params.<dynamic-param>

For example, /pages/:mexico/index.vue would return

this.$route.params.destination === ‘mexico’

Remember in asyncData or fetch, you don’t have access to ‘this’ as it runs before mounting the page, but you can access the ‘context’.

async fetch ({app, store, params}) {
// this gives you acess to route params with the shorthand params
// but also to the store and the other app values
// check all fields at
https://nuxtjs.org/api/context/
}

If you have a lot of API calls, I can suggest two options:
- Use a WP REST API Cache plugin like WP REST API Cache
-
Cache nuxtServerInit calls

For the latter, it’s a bit tricky and requires you to use lre-cache mechanisms and axios-extensions package.
A gist with all the files is linked below.

Link: https://gist.github.com/bovas85/8b5610ac94dd036628f53f702b300a64

vuex store
add this extension to axios and add the axios.js plugin to nuxt.config.js

This is particularly useful if you are generating a static site (nuxt generate) as nuxtServerInit will run once per page generated (imagine if you have 20 dynamic pages, then it will run 20*number of api calls).

Part 5: How about deploying the app?

We tried two routes with this.
1) We used a nuxt generated static site served with a regular server (old school way). Fast but the downside is if you have lots of dynamic pages, rendering the dynamic routes is a bit tricky and slow (check here for how to do that);
2) We used a nodeJS hosted service like Now (there are several, or even just use your hosting if it supports NodeJS, our didn’t).

I wrote an article on a particular gotcha when migrating a domain to Now from GoDaddy, you can read it here:

“Deploying your SSR app to Zeit Now from GoDaddy” @MoustacheDsign https://medium.com/@moustachedesign/deploying-your-ssr-app-to-zeit-now-from-godaddy-41b51302375f

With now, after installing the cli you just type now and it will deploy your SSR site in seconds (literally, depending on your connection and how big the site is ;) )

The result is a very small, optimised, and async bundle. There’s automatic chunk splitting for pages out of the box, so you don’t need to worry about those tricky chunks no more.

not bad

Part 6: What’s Next for Vue and Nuxt?

Vue and Nuxt are not newcomers anymore, there is a big ecosystem of plugins, modules and libraries that are available and will get bigger and bigger.

Some of those I used include plugins for sliders, carousels, lazy image loading, and most of the time can be included even if not native to Nuxt or even Vuejs.

Nuxt.js is an OpenCollective and self funded.
If you love this as I do, consider donating at https://opencollective.com/nuxtjs

Send issues for Nuxt here (it integrates with Github issues, quite neat!):
https://nuxtjs.cmty.io

It’s a wrap

Do you have any questions?
If so feel free to comment down below, or tweet me @moustacheDsign

Some sites I’ve made following this approach:


If you have any questions, reply here or tweet me @moustacheDsign

Thanks from the cat