Tying a React SPA to WordPress as a Backend [w/ WP REST API]

Even the biggest companies in a given space need to adapt to survive. Apple with the iPod. Google with AdWords. You get the idea.

Another tech big fish, WordPress, has been keeping up with a recent trend—headless CMS—showing a will to stay relevant and evolve:

wordpress-rest-api

Every developer and their dog have something to say about WordPress, and it’s not always flattering. Far from it. However, even its most avid detractors are forced to take notice of this feature, because it has already transformed the way we use the popular CMS.

WordPress Rest API is a huge step forward for frontend developers looking to combine the power of JavaScript tools like React.js with WordPress.

This is exactly what I want to do today with this demo of the WordPress REST API in the work. I’ll try to find out if this is really a game-changer and to deconstruct the hype surrounding it.

I’ll use WordPress as a backend, and WordPress REST API to feed data into a neat React.js SPA:

  • Creating models with the WP Advanced Custom Fields plugin.
  • Generating a custom endpoint.
  • Setting up a React single-page application.
  • Consuming the JSON REST API with React.

Before we start, let’s see what is the REST API for WordPress and why you should care about it.

Disclaimer: This is an updated version of an earlier post. We were curious about revisiting the WP REST API with a whole new use case, so here it is! 😉

What is WordPress REST API?

WordPress itself doesn’t need any introduction, but let’s take a closer look at the recent WP REST API. Before we start sliding down the road of its evolution, let’s get some definitions out of the way:

An API (Application Program Interface) is a set of protocols for building software applications. It defines the way information is shared between programs and structures the way different components of an application will interact with each other. A good API makes for easier program development by providing all the necessary pieces. You can learn more about APIs here.

REST (Representational State Transfer) is an architectural style defining constraints on the way programs are made. When this architecture is met by web services we called them RESTful APIs or, simply, REST APIs.

JSON (JavaScript Object Notation) is a format for structuring data so that a large number of applications can read it. It makes interactions between something like, say, WordPress, and any kind of app convenient.

As of WordPress 4.7, these concepts have been applied to create the WordPress JSON REST API. It allows for a decoupled approach, effectively separating data (back) from views (front).

What does it mean for users?

From now on, WordPress can be used as a headless CMS.

This offers a whole new world of possibilities for developers, as the frontend of WordPress doesn’t need to be “WordPress”—PHP-generated views. The ever-growing numbers of frontend frameworks can now be hooked up to a WordPress backend to develop websites and applications.

wordpress-as-headless-cms
Monolothic CMS vs Headless CMS [source]

When it comes to WP REST API, benefits abound.

Don’t only take my word for it, developers already using it are thrilled of this paradigm shift:

“I’ve been able to forget about some of the weaker aspects of WordPress and take advantage of some of its better features — such as revisions, a simple editing interface, and familiarity. I can then use any frontend framework to consume the REST API, and display the content in the form I choose, taking advantage of the great features of those JavaScript frameworks, without the hassle of WordPress theming.”

Working alone on a small demo means that I still have to deal with it to get WordPress running. On a larger project with a bigger team though, frontend developers could work in the language of their choice (without ever touching PHP) even if all the data is managed with WordPress on the backend. JSON magic at work right here.

Looking for alternatives? We’ve listed a load of headless solutions that we’ve put to the test in other technical tutorials.

Easier applications & using React on a headless WordPress

WordPress REST API makes it easier to connect to apps. A custom looking mobile or single-page app can now more easily than ever not only read WordPress data, but also create, edit and delete that data.

Many have started to use WordPress in “weird places”, as in applications where it would have been a pain to work with a few years ago.

As for us? We chose React for this demo because, well, we’ve been talking too much about Vue recently. Jokes aside, we do want to keep our content diversified, and React still is one of the best frameworks out there: flexible & reusable component system, Facebook-backed open source project, efficient workflow with JSX, etc.

Also, using WP REST API with a React frontend you can put together a full JAMstack, the which I’m always more than willing.

For another way to connect React to a Headless CMS, check out this tutorial about the static site generator Gatsby and GraphQL.

Enough talking; time to get practical.

WordPress & React Tutorial: JSON REST API example

react-wordpress-rest-api

In this demo, I’ll show you how to craft a responsive React SPA. The final result will be a dynamic pictures gallery including descriptions and link credits to Unsplash authors.

Prerequisites

  • A running WordPress instance.
  • Basic React knowledge.

1. Creating models with custom fields in WordPress

Let’s jump right into the WordPress admin.

I’ll use the ACF (Advanced Custom Fields) plugin to start building the demo.

This plugin allows you to add custom fields to native WordPress entities such as posts. It’s thoroughly tested, stable, and gives us a kick-start to add custom data to pages.

You can easily install it using the plugins tab inside the WordPress dashboard. Here’s what you need to choose:

wordpress-acf-plugin

Declare these custom fields by clicking on the new custom fields section in the left panel. You’ll need an URL, a description, and an image all wrapped under the fields group name “section”. For the description, you won’t actually create a new field but use the post body instead.

wordpress-custom-fields

Now that you can add custom data to your WordPress posts, let’s use them to create images to showcase in the React app. Here’s the list of newly created posts:

wordpress-posts

2. Generating a custom endpoint

At the moment, your custom data is registered but wouldn’t show up if you were to poke the JSON REST API. To do so, you need to create a custom endpoint. Hop back in your WordPress folder and open the functions.php file. That’s where you’ll register your new endpoint.

Add these lines add the end of the file:

function  sections_endpoint( $request_data ) {
    $args = array(
        'post_type' => 'post',```
        'posts_per_page'=>-1, 
        'numberposts'=>-1
    );
    $posts = get_posts($args);
    foreach ($posts as $key => $post) {
        $posts[$key]->acf = get_fields($post->ID);
    }
    return  $posts;
}
add_action( 'rest_api_init', function () {
    register_rest_route( 'sections/v1', '/post/', array(
        'methods' => 'GET',
        'callback' => 'sections_endpoint'
    ));
});

This creates a custom endpoint with the add_action method by registering it through the rest_api_init hook. Once you call the endpoint, the callback will be executed, which adds the custom fields under the acf key.

Now that the mapping works appropriately, feel free to hit your new REST endpoint at: /wordpress/wp-json/sections/v1/post.

3. Setting up the React SPA

Want to test everything right now? Hit your server for a test at: /wp-json/wp/v2/posts.

You should see all your posts with the proper custom fields mapped.

Time to add that React SPA to the mix!

I’ll be using the create-react-app module to scaffold it. Go ahead and create a project, then fire up your favorite editor with the following lines: create-react-app unsplash-demo.

Then, change your project folder and run npm install --save bulma. This is going to make your web app responsive; it’s elegant and easy to use.

The plan is to showcase each picture on the home page with a possibility to click on it to provide an individual view.

While you’re at it, install react-image-lightbox, a neat little component to show the pictures in a lightbox.

4. Consuming the WordPress JSON API with React

You can now open the project in your favorite text editor and directly open the App.js file.

That’s where the majority of logic will go. I’ll paste the whole component into a single code section so it’s easier to visualize and provide an explanation after:

import  React, { Component } from  'react';
import  Header  from  './components/Header';
import {
    PopupboxManager,
    PopupboxContainer
} from  'react-popupbox';
import  '../node_modules/react-popupbox/dist/react-popupbox.css'
import  '../node_modules/bulma/css/bulma.css';
import  './App.css';
class  App  extends  Component {
    constructor(){
        super();
        this.state  = {
            isOpen:  false,
            sections: [],
            current:  null,
            dataRoute:  "http://localhost/wordpress/wp-json/sections/v1/post"
        }
    }
    get  scaledSections(){
        var  nbr  = (this.state.sections.length/3)
            .toString()
            .split('.');
        var  sections  = [];
        for(var  i  =  0; i  <  nbr[0]; i++){
            sections[i] = [];
                for(var  j  =  1; j  <=  3; j++ ){
                    sections[i].push(this.state.sections[i*3  +  j  -  1]);
            }
        }
        if(nbr[1]){
            var  missing  =  nbr[1].startsWith('3')
                ?  1
                :  2;
            sections.push([]);
            for(var  k  =  0; k  <  missing; k++){
                sections[sections.length  -  1].push(this.state.sections[nbr[0]*  3 +  k]);
            }
        }
        return  sections;
    }
    componentDidMount(){
        fetch(this.state.dataRoute)
            .then(res  =>  res.json())
            .then(sections  =>  this.setState((prevState, props) => {
                return { sections:  sections.map(this.mapSection)};
            }));
    }  
    mapSection(section){
        return {
            img:  section.acf.image,
            src:  section.acf.image.url,
            title:  section.post_title,
            key:  section.post_title,
            description:  section.post_content,
            author: {
                name:  section.acf.author_name,
                link:  section.acf.author_link
            }
        }
    }
    openPopupbox(section){
        const  content  = (
            <div>
                <img  src={section.src}  width={section.img.sizes["large-width"]}  alt=""/>
                <p>{section.title} - {section.description}</p>
                <p><a  href={section.author.link}>{section.author.name}</a></p>
            </div>)
        
        PopupboxManager.open({ content })
    }
    render() {
        return (
        <div  className="App">
            <header  className="App-header">
                <Header></Header>
            </header>           
            <div>
                {this.scaledSections.map((level, i) =>
                <div  className="columns"  key={i}>
                    {level.map((section, j) =>
                    <div  className="column"  key={j}>
                        <img
                            className="image"
                            alt=""
                            src={section.src}
                            height={section.img["small-height"]}
                            onClick={() => this.openPopupbox(this.state.sections[i*3+j])}/>
                    </div>
                    )}
                </div>
                )} 
            </div>    
            <PopupboxContainer  />
        </div>);
    }
}
export  default  App;

This looks like a lot, but a good chunk of the logic is only present so the images are arranged automatically in rows of three pictures or less. The function doing this is the scaledSections getter. I won’t explain it since it’s not significant in the scope of this tutorial.

  • The constructor doesn’t do much, but it’s still important to note that it’s where the dataRoute is specified—it’s the route you defined earlier to fetch images containing custom fields.
  • The componentDidMount function is pretty self-explanatory; that’s where you fetch the data from the endpoint. The function is part of React’s lifecycle; it’s executed once the component is mounted and ready to fire.
  • The mapSection function only maps the endpoint response to a friendlier frontend format so you can access your image’s properties easily.
  • The openPopupbox function takes a section which is an image with added information showed using the small lightbox component I installed earlier.
  • The good ol’ render function at the end, of course, defines the whole component HTML output. There, you iterate over the scaledSections defined earlier to render all your desired images. It’s also important to see the use of bulma classes, more specifically the columns and column classes. That’s what makes your whole app responsive.
  • Finally, without going into details, I also created a small Header component to style the page a little more.

Here you have it! You can fire up a local server with npm start directly in your project root folder, and you should have a small photo gallery running!

It’s important to keep in mind that this isn’t SEO friendly out-of-the-box as search engines won’t crawl the content. You could use the same process shown here with Vue or use Next.js.

Live Demo & GitHub repo

See the live demo here

See WP + React GitHub repo here

Here’s how it should look like (if you also copied the CSS from the demo):

wordpress-react-demo

And the mobile view:

wordpress-react-mobile-app

Closing Thoughts

The WordPress portion was more fun than the first time around. Playing around with the WP REST API already felt more natural. On the frontend, well, building React apps is always a lot of fun! I had a blast taking the time to work on making the code clean and smoothing the look & feel of the app.

I spent around 3 to 4 hours building the whole thing. The fact that I’d work with WordPress this way before paved the way a little and I’m sure more seasoned WP developers will find it even easier. I still had some hurdles on the frontend side and pushing the app into “production”.

Thinking out loud here; you could have some fun pushing the React app further feature-wise. At the moment it’s really just an auto-scaling gallery but creating new components with a router for individual views instead of a lightbox, or auto-scaling with a metro-like look could be your next challenges if you want to go on with this demo!

To learn more about WP REST API you can find the documentation here, or a thorough white paper by Human Made, here.

Leave a Reply