How To Build A Skin For Your Web App With React And WordPress

This is an article written by me for Smashing Magazine five days ago. It’s about building a WordPress theme and store using React.

So you’ve trained yourself as a web engineer, and now want to build a blazing fast online shop for your customers. The product list should appear in an instant, and searching should waste no more than a split second either. Is that the stuff of daydreams?

Not anymore. Well, at least it’s nothing that can’t be achieved with the combination of WordPress’ REST API and React, a modern JavaScript library.

Wait, What? WordPress REST API?Link

Yes, the WordPress REST API will help you build the back-end foundation for your web application. This is a good choice for your web application’s back-end technology if you are building a content-driven solution. WordPress will interoperate smoothly with other technologies as well; you could use Node.js as the focus of your application to connect to other RESTful services.

The WordPress REST API is a game-changer for WordPress, which can now safely be called a web application framework — not just a CMS. Now that the front- and back-end are completely decoupled, WordPress can be used as a mobile app back-end or as a back-end for any system focusing on content.

But why WordPress? The reason: You will be amazed at the functionalities that emerge out of the box with WordPress. You will get extensive user management, media management, and an incredibly developer-friendly set of APIs to extend your work.

In this article, I will walk you through building an SPA (Single Page Application) WordPress theme using the JavaScript library called React, connecting to the WP REST API.

Let’s Jump Into Building The Theme

This article assumes you are already familiar with the various existing WordPress APIs, particularly the ones that drive the development of themes for your site’s aesthetics, and functionalities for your site’s plugins. I also assume you have set up your development platform for WordPress, such as the LAMP stack in a Linux or MacOS environment.

For simplicity, though, I will refer only to absolute paths as visible with the XAMPP platform that is used with Windows.

Now, let’s create an instance of WordPress in our localhost, naming it ‘Celestial.’ That is the name of the WordPress theme we are going to use to help us set the direction for building future themes ready for use with web applications powered by the WordPress REST API. You may already be familiar with WordPress’ much-loved template hierarchy, but with the REST API, you have an opportunity to discover something different!

We then need to create a folder for the theme within the wp-content\themes folder. Navigate to C:\xampp\htdocs\celestial\wp-content\themes\ (or equivalent) and create a folder celestial. Add these files inside the celestial theme folder:

  1. index.php
    The catch-all file for the theme.
  2. style.css
    This contains information about the theme (and not actual CSS).
  3. functions.php
    To write the functionality and the importing of CSS and JS files.

Add an image file named screenshot.jpg if you want a picture for your theme showing inside the dashboard.

NoteThe code for each file is a few lines long and can be found on GitHub.

Next, log in to your WordPress Dashboard, head over to Appearance→ Themes and select ‘Celestial’ as the theme. Now that the foundation is in place, let’s get onto creating the theme.

WordPress theme selector
You can select the ‘Celestial’ theme you created from the Themes panel in the dashboard.

Getting Started With React And Webpack For The Theme

React is a very popular UI library supported and maintained by Facebook. According to Stack Overflow’s Developer Survey 2017results, “React is the most loved among developers.”

ReactJS
React: A JavaScript library for building user interfaces.

For starting the project, you need to initialize the project as an NPM (Node Package Manager) project. This is done with the command npm init in the terminal (after having installed Node.js and NPM on your computer). Initializing the project will prompt you for certain configuration information. After successful initialization, NPM will create a package.json file in the theme’s root directory. This file will include the project details and all dependencies of the project.

React is now under MIT license, so we will be using version 16 of React as the JavaScript library for this project. React has some cool features under the hood, such as the Virtual DOM (a representation of the document within memory) and has a host of tools surrounding it such as the React Router. React is also used in the WordPress’ Project Calypso — the dashboard for WordPress.com.

We will now install the required NPM packages to the project:

  1. Type npm install --save react react-dom in the terminal and press enter to install the packages.
    Installing React via CLI
    Using npm to install react and react-dom.

    Since we are building the theme as a Single Page Application (SPA), we need the help of a tool such as Webpack. We will be writing code as different components, and Webpack will help us package them all together and output them as a single .js or .css file. In short, it’s a module bundler.

    Webpack has first to be installed globally on your computer. To do that, we again can utilize NPM.

  2. Type in the command npm install -g webpack to get the latest stable version of Webpack installed globally in your system.Next, we will install NPM packages supporting Webpack in our app.
  3. Go to the package.json file in my git repo and copy the rest of the dependencies from there into your package.json’s dependencies section. Then run npm install again to install all the packages within package.json.
    {
     "name": "celestial",
     "version": "1.0.0",
     "description": "A basic theme using the WordPress REST API and React",
     "main": "index.js",
     "dependencies": {
       "babel-core": "^6.26.0",
       "babel-loader": "^7.1.2",
       "babel-preset-es2015": "^6.24.1",
       "babel-preset-react": "^6.24.1",
       "css-loader": "^0.28.7",
       "extract-text-webpack-plugin": "^3.0.1",
       "file-loader": "^1.1.5",
       "image-webpack-loader": "^3.4.2",
       "node-sass": "^4.5.3",
       "path": "^0.12.7",
       "react": "^16.0.0",
       "react-dom": "^16.0.0",
       "react-router-dom": "^4.2.2",
       "sass-loader": "^6.0.6",
       "style-loader": "^0.19.0",
       "url-loader": "^0.6.2",
       "webpack": "^3.6.0"
     },
     "devDependencies": {},
     "scripts": {
       "build": "webpack",   
       "watch": "webpack --watch"
     },
     "keywords": [
       "blog",
       "decoupled",
       "react",
       "rest-api"
     ],
     "author": "Muhammad Muhsin",
     "license": "GPL-3.0"
    }
    

    The above is a list of all required packages in the package.json file for this project.

  4. Copy the configurations from GitHub and paste it into your theme folder’s webpack.config.js file.
    var ExtractTextPlugin = require("extract-text-webpack-plugin");
    var path = require('path');
    
    module.exports = {
       entry: {
           app: './src/index.jsx'
       },
       output: {
           path: path.resolve(__dirname, 'dist'),
           filename: '[name].js'
       },
       module: {
           rules: [
               {
                   test: /\.scss$/,
                   use: ExtractTextPlugin.extract({
                       fallback: 'style-loader',
                       use: ['css-loader','sass-loader'],
                       publicPath: 'dist'
                   })
               },
               {
                   test: /\.jsx?$/,
                   exclude: /node_modules/,
                   use: 'babel-loader'
               },
               {
                   test: /\.(jpe?g|png|gif|svg)$/i,
                   use: [
                       'file-loader?name=[name].[ext]&outputPath=images/&publicPath=http://localhost/celestial/wp-content/themes/celestial/dist/images',
                       'image-webpack-loader'
                   ]
               },
               { test:
                   /\.(woff2?|svg)$/,
                   loader: 'url-loader?limit=10000&name=fonts/[name].[ext]'
               },
               {
                   test: /\.(ttf|eot)$/,
                   loader: 'file-loader?name=fonts/[name].[ext]'
               }
           ]
       },
       resolve: {
           extensions: ['.js', '.jsx']
       },
       plugins: [
           new ExtractTextPlugin({
               filename: "style.css",
               allChunks: true
           })
       ]
    }
    

    Important: Please note that module.exports → module → rules[3] → use → publicPath can change according to where your project’s dist images are situated in localhost. If this is wrong, images may not display correctly in the web app.

  5. Afterwards, these commands can be used to compile the project:
    • webpack or npm run build to compile the project, or
    • webpack --watch or npm run watch to compile the project and watch for changes.

NoteTo get a better understanding of Webpack, read this article by Joseph Zimmerman on Smashing Magazine.

Extending The WordPress REST APILink

The WordPress REST API comes with many different endpoints for fetching posts, pages, media and so on. However, they may not always have all the details in their response. For instance, the posts method does not give the URL of the featured image or the author’s name. Therefore, we have to make separate calls to each of these elements.

Wordpress REST API
Access your WordPress site’s data through an easy-to-use HTTP REST API.

But what if you wanted to have your own data appear within the posts response? That’s where the magic of extending the REST API comes in. The following code will add two additional variables in the response to the posts request, namely author_name and featured_image_src. The code is within the functions.php file:

// Add various fields to the JSON output
function celestial_register_fields() {
    // Add Author Name
    register_rest_field( 'post',
        'author_name',
        array(
            'get_callback'      => 'celestial_get_author_name',
            'update_callback'   => null,
            'schema'            => null
        )
    );
    // Add Featured Image
    register_rest_field( 'post',
        'featured_image_src',
        array(
            'get_callback'      => 'celestial_get_image_src',
            'update_callback'   => null,
            'schema'            => null
        )
   );
   // Add Published Date
    register_rest_field( 'post',
       'published_date',
       array(
           'get_callback'      => 'celestial_published_date',
           'update_callback'   => null,
           'schema'            => null
       )
    );
}
add_action( 'rest_api_init', 'celestial_register_fields' );

function celestial_get_author_name( $object, $field_name, $request ) {
    return get_the_author_meta( 'display_name' );
}
function celestial_get_image_src( $object, $field_name, $request ) {
   if($object[ 'featured_media' ] == 0) {
       return $object[ 'featured_media' ];
   }
    $feat_img_array = wp_get_attachment_image_src( $object[ 'featured_media' ], 'thumbnail', true );
   return $feat_img_array[0];
}
function celestial_published_date( $object, $field_name, $request ) {
    return get_the_time('F j, Y');
}
Extending the REST API with additional variables in the functions.php file.

A Global JavaScript Variable

There are certain WordPress constants (or known as ‘variables’) that we will be using throughout the React app. This will be information about the various routes of the application (and later on be WooCommerce specific ones).

This variable is defined within the functions.php file. It will be called ‘CelestialSettings’ and be appended to celestial-scripts, the handle for the enqueued app.js file:

wp_enqueue_script( 'celestial-script', get_stylesheet_directory_uri() . '/dist/app.js' , array(), '1.0', true );

    $url = trailingslashit( home_url() );
    $path = trailingslashit( parse_url( $url, PHP_URL_PATH ) );

    wp_scripts()->add_data( 'celestial-script', 'data', sprintf( 'var CelestialSettings = %s;', wp_json_encode( array(
        'title' => get_bloginfo( 'name', 'display' ),
        'path' => $path,
        'URL' => array(
            'api' => esc_url_raw( get_rest_url( null, '/wp/v2' ) ),
            'root' => esc_url_raw( $url ),
        ),
        'woo' => array(
            'url' => esc_url_raw( 'https://localhost/celestial/wp-json/wc/v2/' ),
            'consumer_key' => 'ck_803bcdcaa73d3a406a0f107041b07ef6217e05b9',
            'consumer_secret' => 'cs_c50ba3a77cc88c3bf46ebac49bbc96de3a543f03'
        ),
    ) ) ) );

Passing WordPress (PHP) variables to the front-end.

The above code shows an example of getting WordPress (PHP) variables to the front-end, an important and very useful technique when building a decoupled theme. This object variable holds the site title, path, the URL for the API and root and three variables relating to WooCommerce (explained later).

React And JSXLink

React is different from the rest of the major JavaScript libraries. What I mean by that is, we generally write JavaScript within our HTML. However, when it comes to React, we write HTML inside our JavaScript code. To be more accurate, we write JSX inside JS. JSX is very similar to HTML but has a few differences. The class attribute is written as className for instance. This is then converted to plain JavaScript through Webpack and Babel and saved within app.js.

There are, however, a few restrictions with writing JSX. For instance, we can have only one child within our render() method, which will serve as the root element for a Component. However, the advantage is that it is easier to debug. We can know exactly where we have made a mistake, whereas in normal HTML our error will generally not be shown explicitly. We will be writing JSX for this project, and therefore, the JavaScript files will have an extension of .jsx. However, it could also be .js if you prefer so.

Create the following files within the src folder:

  1. index.jsx (the main file and the one which contains the React Router configurations)
  2. header.jsx (the header component)
  3. footer.jsx (the footer component)
  4. posts.jsx (for the archive of posts)
  5. post-list.jsx (component for an individual post within posts.jsx)
  6. post.jsx (for a single post)
  7. products.jsx (contains all the products from WooCommerce)
  8. product.jsx (displays a single product from WooCommerce)
  9. style.scss (to contain all CSS code in SASS format)
Folder structure of src folder
Folder structure of the src folder in the Celestial project.

ReactDOM.render()Link

The index.jsx file is the root of the project. What I mean by that is, the index.jsx contains the component App which is rendered to the DOM.

import { render } from 'react-dom'; // importing render from ReactDOM

const App = () => ( // defining the routes

   <div id="page-inner">

       <Header />

       <div id="content">

           <Switch>

               <Route exact path={CelestialSettings.path} component={Posts} /> // the root path

           </Switch>

       </div>

       <Footer />

   </div>

);

// React Router

const routes = (

   <Router>

       <Route path="/" component={App} />

   </Router>

);

render( // rendering to the DOM by replacing #page with the root React component

   (routes), document.getElementById('page') // rendering the route

);

The other components are specified within React Router and will be loaded upon visiting the different routes.

This is how we write modular components where all the different components ultimately end at index.jsx.

Stateful vs. Stateless ComponentsLink

You would have noticed components being written in either of the following two ways:

  1. const App = () => (
  2. class Post extends React.Component {

The first way is how we write Stateless Components and the second is an example of Stateful Components. Stateless means that component does not have ‘state’ in it. ‘state’ is essentially a variable that has information within the component, and every time the variable changes, the component is re-rendered. Stateful Components are also known as ‘Smart Components.’ The state variables are thus used for inner communication within that component.

The second type, Stateless Components do not have the state variable in them and sometimes called ‘Dumb Components.’ However, like Stateful Components, they have ‘props,’ which are properties passed down to them from their parent components.

Stateful components have the React lifecycle methods whereas the Stateless one has only the render() method which is the default method for it.

React Lifecycle MethodsLink

These are methods called at different stages in the component’s lifecycle, which we can override to run our own code at those instances. We are utilizing the following methods in our application:

  • constructor()
    Called before a component is mounted.
  • componentDidMount()
    Invoked immediately after a component is mounted.
  • render()
    The method which is called to render the JSX (HTML) content.
  • componentDidUpdate()
    Called when the component is updated.
  • componentWillUnmount()
    Invoked when a component is to be removed.

NoteTo learn more about Components and their lifecycle, read the documentation here.

Leave a Reply

Your email address will not be published. Required fields are marked *