Monday, June 27, 2016

Single Page Apps Using AngularJS and the WordPress REST API

Automattic is working on integrating the WordPress REST API plugin into the WP core, which means that the API will be available without the actual plugin, and we could see more of WordPress integration with front-end JavaScript frameworks.

This would allow a faster time to market for applications, since some basic functionality that is often implemented from scratch in JavaScript apps is already implemented; we could use WordPress' user management, WooCommerce for product handling, static pages, and the list goes on! It is also possible to add custom endpoints to the API.

One way to use this API would be to include a front-end JS framework as part of a WordPress theme. This can be inconvenient, though, as it enforces a non-standard directory structure and is generally not a best-practice use of either the framework or the WordPress theme.

A better solution is to use a REST API to expose WP data and make two apps that are completely structurally separated, but connected with a "session sharing" technique, in order to use the best from both.

In this tutorial, I will show you how to do this "session sharing", where WordPress is used for user management and login, and on the client-side, an Angular app that allows easy, SPA-like (Single Page Application) post editing for authorized users.

You can find the code for the WordPress child theme and the Angular client app on GitHub:

Requirements

Before starting this tutorial, it is recommended that you already have some experience with the following:

Additionally, we will be using:

  • Vagrant (two virtual machines, one for WP and the other for running the Angular app on a grunt server)
  • Yeoman (to scaffold our Angular app)
  • Grunt

as development tools, but you should be also fine if you use some other way to run your local WP site and other or no scaffolding tool.

A WordPress REST API

In order to achieve our goal architecture, we have to install the WordPress REST API plugin, which is currently in it's beta phase and there are things to consider, see here.

The official recommendation is not to use version 2 in production, as the latest stable version is version 1. Also, the rumor is that the plugin will never get a stable version, but instead when the plugin is ready to move out of beta, it will be released as part of the WordPress core. In this tutorial we will use the version 2 plugin nonetheless.

Authentication

There are several authentication methods that can be used to secure the REST API (see here for details), but let's take a brief look at the pros and cons of each:

Basic Authentication

This is the most basic authentication type, where we would send the username and password in the header with every request. It requires SSL, as otherwise we would open the username and password to attack. Also, we are giving the Client ID and secret to the client.

Cookie Authentication

The standard, built-in wordpress login system also works. The trouble with this approach is that in order to avoid CSRF issues, we have to use it on the inside of WP. Since we need to access the API from outside, from another app, this approach is not for us.

OAuth Authentication

We are going to be using a non-standard way of implementing OAuth here. We will not let the user authorize an application explicitly, but instead we will seamlessly hook into the WordPress login function, authorize our Angular app for the user and retrieve an access token, which we forward to the JS app in order to authorize the API requests.

It's very important to mention that, even with this approach, we need SSL. Since this is an educational tutorial we will not be introducing the complexity of SSL even though, regarding the code itself, there would be no difference with or without SSL.

This approach should be preferred over basic auth, since we do not have to store the username and password of the user in the browser or give the Client ID and Secret to the user. The OAuth approach is only possible with a plugin, and for this reason we are going to use WP OAuth Server.

Sharing the Token

After we generate the token upon logging in to WP, we need to somehow share it with our JS app. There are multiple ways to do this, depending on your needs and personal preferences. In this tutorial we will describe two of these approaches. It's worth mentioning that both of these approaches might be constrained by browser version.

Setting Wildcard Domain Cookie

The first option, which is possible only if both apps are on same subdomain, is to set a wildcard cookie and then use that cookie on Angular side. If using this approach, it's important to take care of your local hosts file, in order to have the same subdomain.

I personally use Vagrant and Vagrant host manager, and then set the hostname of the WordPress VM to sitepoint.local and the other Vagrant VM's hostname to app.sitepoint.local. This will automatically edit your hosts file like this:

192.168.33.16  app.sitepoint.local  # VAGRANT: 297067a67f66f631aa1962e3b49ab73c (default) / cc52bb5a-3972-4b55-8e0c-0c805b9c6f1c
192.168.33.15  sitepoint.local  # VAGRANT: 6a5b8c757547fe9f0a32a0c747a91a79 (default) / b08c3e7d-cba8-4130-a11b-b26494574280

This is the approach we will use in this tutorial, but if you feel that this is an additional complication for you, consider the iframe option.

Posting to localStorage via iframe

This approach is better for someone who wants to avoid handling cookies and/or does not have the WP app and Angular app on same sub-domains. We expose an iframe from the SPA to WP and then we post a message to the iframe, inside which there is a listener waiting for incoming messages to take the access token and store it in the JS app's localStorage, for later use. I will explain the modifications needed in a separate section at the end of the article. See here for browser compatibility.

The Server

First we are going to create a template for the login screen containing the code to generate the access token. Then, we will hook into some login/logout functions in order to handle the cookie (or iframe, if you go with that option).

Create the server VM

Time to grease some elbows! I like starting out a WordPress project by cloning the Scotchbox Vagrantfile .

Open your favorite terminal application and navigate to the folder where you wish to keep the project. In my case this is /boxes. Then, clone the Scotchbox repo and navigate inside.

cd /boxes
git clone http://ift.tt/1uFOPMK sitepoint-wp-rest-api
cd sitepoint-wp-rest-api

# remove .git folder in order not to get confused if you later initialise your own repository
rm -rf .git

# Initialise a vagrant machine
vagrant up

At this point, you may want to open the sitepoint-wp-rest-api folder in your favorite IDE or text editor, since we need to edit the Vagrantfile.

This is how the Vagrantfile looks by default when cloned:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|

    config.vm.box = "scotch/box"
    config.vm.network "private_network", ip: "192.168.33.10"
    config.vm.hostname = "scotchbox"
    config.vm.synced_folder ".", "/var/www", :mount_options => ["dmode=777", "fmode=666"]

    # Optional NFS. Make sure to remove other synced_folder line too
    #config.vm.synced_folder ".", "/var/www", :nfs => { :mount_options => ["dmode=777","fmode=666"] }

end

There are two thing to take care of here:

  1. Change the IP
  2. Change the hostname

In case you already have a network device or another VM running on 192.168.33.10, make sure to change that. You can choose any IP address as long as it's in the private address space.

If you want to use the approach with sub-domain cookie, it is also important to change the hostname to a FQDN.

Optional: You can also increase the RAM/CPU of the VM. This can be especially handy later for the second VM ,when we will need to run bash npm install - it will take less time if we increase the performance of the VM. Check the commented-out part at the end of the code snippet for how to achieve this. Although it's sometimes good to see how the system runs on 512MB RAM and 1 CPU (Vagrant's default), for development purposes we want it to be fast. Later when testing/optimizing speed of the WP site, you can tune this down again.

The final Vagrantfile looks like this

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|

    config.vm.box = "scotch/box"
    config.vm.network "private_network", ip: "172.31.255.254"
    config.vm.hostname = "sitepoint-wp-rest-api.test"
    config.vm.synced_folder ".", "/var/www", :mount_options => ["dmode=777", "fmode=666"]

    # Optional NFS. Make sure to remove other synced_folder line too
    #config.vm.synced_folder ".", "/var/www", :nfs => { :mount_options => ["dmode=777","fmode=666"] }

    # Optional performance tweaking
    #config.vm.provider "virtualbox" do |v|
    #   v.memory = 2048
    #   v.cpus = 2
    #end
end

One last step before we turn on the VM: the vagrant-hostupdater plugin install. What this plugin does is, when you run vagrant up, it updates your local hosts file with the IP and hostname given in the Vagrantfile, you will see what that means in a few moments.

# Install Vagrant host udpater plugin
vagrant plugin install vagrant-hostsupdater

Now it's time to boot up the machine:

vagrant up

You may get asked for the sudo password since vagrant-hostupdater will be editing the /etc/hosts file, which requires admin permissions.

This will take a minute (or a few minutes!) depending on whether you already have the scotch/box image locally - it has to be downloaded first if you do not.

Now, visit http://172.31.255.254/ and you should see the Scotchbox information page (what you actually see is the index.php located in the public folder of the cloned Scotchbox repository).

The result of what the hostupdater plugin did can be seen if you visit http://ift.tt/28YusYP - it's still the same page. Sitepoint-wp-rest-api.test resolves to 172.31.255.254 via your local hosts file. From now on we will use this FQDN to access our REST API.

Install WordPress

Now that we have a server running, it's time to install WordPress. Go into your local user's folder and download WordPress. Unpack it, create a configuration file and then copy raw files to the public folder inside of sitepoint-wp-rest-api.

cd ~
curl -OL http://ift.tt/zUVk1t
tar xzvf latest.tar.gz
cd ~/wordpress
cp wp-config-sample.php wp-config.php

# Do not forget to change /boxes to the actual folder onb *your* system
sudo rsync -avP ~/wordpress/ /boxes/sitepoint-wp-rest-api/public

Now, head back to your IDE and open wp-config.php. Fill in the DB credentials as found here. Additionally, it is a good practice to add WP_HOME and WP_SITEURL variables in the configuration files. They will override the values from the database, making it easier for versioning and changing between environments/hosts.

// wp-config.php

/** The name of the database for WordPress */
define('DB_NAME', 'scotchbox');

/** MySQL database username */
define('DB_USER', 'root');

/** MySQL database password */
define('DB_PASSWORD', 'root');

/** This is new, WP SiteURL and Home globals override */
define('WP_SITEURL', 'http://ift.tt/28YusYP');
define('WP_HOME', WP_SITEURL);

Change these values, and save the file.

Visit http://ift.tt/28YusYP again, and this time you should see a WordPress install wizard.

WordPress install - step 2

Click next a few times and finally you should see a default WP site with the twentysixteen theme running.

Install the REST API plugin

Head to the WordPress REST API plugin page and download the plugin. Unzip the downloaded file and copy it to wp-content/plugins/. Go to http://ift.tt/28YuEXW, click Plugins on the left menu, find WordPress REST API and activate it. No additional configuration or setup is needed for the API - it just works!

Now, if you visit http://ift.tt/28ZaXeK you should get a JSON array containing all the posts:

Continue reading %Single Page Apps Using AngularJS and the WordPress REST API%


by Almir Bijedic via SitePoint

No comments:

Post a Comment