Building a React-powered starter theme

As I near the final stretch in my Bov Academy studies, it’s time for me to choose a final project. For my final project, I have decided to capitalize on my love of JavaScript + WordPress. So, in this post, I want to introduce Aurora Theme–a React-powered starter theme for WordPress. (If you click the link shortly after this is posted, the joke’s on you. I haven’t deployed anything yet, and that is, indeed, the current default theme.)

So maybe you’re thinking, “why is she sharing something she hasn’t even started?” That’s a great question. I thought it’d be pretty neat to document the entire journey of building this thing. To many of us in the WordPress community, this whole REST API thing is still a foreign concept. Breaking our traditional PHP theme paradigm is going to take time. It’s going to take research. And it may not be pretty. I already have questions about implementation of things in the back of my mind, and I’m hoping to answer these questions as I go, and share them with the community. Of course, if you’re reading one of these posts, and you have questions, speak up and ask in the post comments, or @me on Twitter. Let’s help each other. With that, let’s get this thing started. Read on below for a detailed project plan.

Aurora Theme Project Plan

Business Justification

The WordPress REST API was merged into WordPress Core in December 2015. The REST API gives developers a modern way of interacting with WordPress using modern JavaScript techniques and technologies. By default, WordPress ships with endpoints to interact with standard post types (posts and pages), but it can be extended to create custom endpoints which may include post meta, or anything else one might need from the database.

Implementation of the REST API gives WordPress users and developers several advantages. WordPress can continue to operate as a familiar and robust backend for data storage and delivery, while making the data itself more accessible to other platforms. Decoupling data delivery from the content management system (CMS) makes WordPress more accessible to a broader audience. For example, building a frontend to consume WordPress data no longer requires knowledge of the WordPress theming system. It frees developers up to consume their data in whatever way is necessary from use in websites, to apps, and other third party services. Instead of WordPress being the solution for a website, it can be a building block in the foundation of a user’s larger application.

Even though the REST API has been part of WordPress for nearly two years, adoption of the API has been slow, and there are few themes utilizing the features of the REST API. There are even fewer “starter” themes built on the REST API. To date, most REST API-driven projects have been limited to the “high end” spectrum of client sites. But with the imminent integration of Gutenberg, JavaScript technologies are becoming an increasingly integral part of the WordPress experience.

Aurora will be a starter theme built to utilize the features of the standard endpoints in the WP REST API, and will use modern JavaScript technologies including ES Next and React. Aurora will finally make REST API-driven sites and technology more accessible to the everyday WordPress user and developer.

Requirements & Objectives

Any starter theme built for WordPress needs to give developers a leg up in the development process, but should not include so many features that it becomes burdensome to work with. To that end, it is incredibly important that Aurora remain relatively un-opinionated, yet provide the basic features one might expect of a functional WordPress theme (i.e. if you install and activate the theme, it shouldn’t look like a dumpster fire). Ideally, any opinionated elements (e.g. styling) could easily be blasted away, giving the next developer a clean slate.

To that end, Aurora will support modern JavaScript development techniques, and give developers a solid foundation for starting a REST API project. Including documentation support is especially integral to the success of Aurora. Since WordPress has long been in the PHP-based theme paradigm, it’s important to have a well-documented theme to help PHP developers transition to writing JavaScript-driven themes.

Aurora will be a clean, modern theme with the following features:

  • Sass
  • ES Next + React
  • Icon (SVG) management
  • Linting according the WordPress Coding Standards using PHPCS, ESLint, and Stylelint
  • Documentation support

Requirements

  • Support default post types (post, page, nav-menu, comments)
  • Well-documented
  • Easy to understand
  • Extensible
  • Performant
  • Accessible
  • Gutenberg-ready

Objectives

  • Adheres to WordPress Coding Standards for PHP, styling (CSS), and JavaScript.
  • Complies with Section 508 and WCAG 2.0AA accessibility standards.
  • Meets WordPress internationalization and localization guidelines.
  • Use techniques including Atomic Design to keep the theme files organized and easy to understand.

Project Scope / Deliverables

At this time, Aurora will only consist of the starter theme. Future implementations may include:

  • Extensibility via the command line–easily spin up reusable components via a command line integration (e.g. Yeoman), which will be hosted indepently from the theme (likely via a branch of Aurora Core).
  • Gutenberg components. Support for default Gutenberg components will exist, but new components are not in scope for the initial phase of the project.
  • A plugin for interacting with Custom Post Types / Custom Endpoints.

Aurora

Aurora will be a clean, elegant starter theme with simple styling, and basic components, to help developers get started on their WordPress REST API theme projects.

  • Use Aurora Core (the non-theme boilerplate) as the base setup for the theme
    • Tweak Aurora Core Webpack setup to work with WordPress (keeping in mind that hot module replacement doesn’t work in WordPress).
      • Browser Sync
  • Use Underscores for some of the base theme files
    • header.php (pulls in styles and head scripts)
    • footer.php (pulls in scripts)
    • index.php (a fall back if our JS fails)
    • 404.php?
    • functions.php
  • Theme components (React components)
    • Header
    • Navigation (this might be a challenge given that there is no clear way of interacting with menus via the default endpoints)
    • Footer
    • Archive (home, categories, tags, etc.)
    • Single post / page
    • Sidebar (I’m really curious about supporting widgets via the REST API)
    • 404
    • Search results (maybe this is the same as the archives?)
    • Social icons (menu)
    • Comments
  • How should the theme interact with the Customizer?
    • Custom logo
    • Site title
    • Site tagline
    • Site icon (favicon)
    • Sidebar (no sidebar, sidebar right, sidebar left)
    • Widget area(s) for the footer (see Alcatraz)
    • Footer copyright text
  • Testing (Mocha? Jest? other?)
  • Performance metrics
  • Type checking
    • Flow?
    • TypeScript?
  • Documentation
    • Sass documentation
    • Component documentation (KSS? Storybook?)

Resources

Getting started with task-running & Gulp

Front-end development typically consists of many stages, including scaffolding (setting up the project environment), development of the website or application, testing, optimization, and deployment. Setting up project environments and the rest of the project workflow from scratch project after project can become cumbersome. Task runners were introduced to solve this problem. Task runners help developers manage and automate all the tasks associated with the various stages of development. In this article, I will focus on the popular task runner Gulp, and show you how to set up Gulp with a basic tasks for compiling Sass.

Getting started with Gulp

First thing’s first–with any task runner, you will need to make sure you have Node installed on your computer. You can either visit the Node website and download the appropriate package and install from there, or use Homebrew (my preferred method) to install Node via the command line if you are using a Mac. To install Node via Homebrew, simply type brew install node in your terminal prompt.

Once you have Node installed, you’ll need to use NPM, the package manger that comes bundled with Node, to install Gulp. Several Node packages can be installed globally on your computer, and / or locally to your project. In this case, we’ll want to start by installing Gulp globally. Simply type the following into your terminal prompt:

npm install -g gulp-cli

In this command, the -g flag is what tells Node to install this as a global package.

Now that we have the Gulp CLI installed globally, we’re ready to get started configuring our project. If you already have a project for which you’d like to set up Sass, simply navigate to that project via your terminal. Something like this:

cd path/to/your/project

Otherwise, create a new directory and cd into the directory.

Setting up a Gulp project

Now we’re ready to start setting up our project to use Gulp. The first step in this process is to create a package.json file, which is a manifest that keeps track of all the packages we’re using for development of a specific project. This is particularly important when we’re working on a project across a team because it allows other team members to simply clone a Git repository and install the packages with a single command, rather than going through this entire setup process.

The first step is to ensure you’re in the correct directory for your project. Once you have ensured you’re in the correct directory, we’ll need to create our package.json file by typing the following in the terminal prompt:

npm init

This command will prompt you for information about the project. Follow the prompts and fill out the information as best as you can. If something doesn’t seem relevant at this point, simply hit Enter to accept the default. Once you have completed the steps of npm init, you will see a new package.json file at the root of your project.

Now we’re ready to start adding Node packages!

Adding packages

Earlier I mentioned that Node allows us to install packages globally on our computer, or locally to our project. At this stage, we’re going to install all the packages we need for this specific project locally.

The first package we’ll install is Gulp itself. We can do this by typing the following into the terminal window:

npm install --save-dev gulp

This command downloads Gulp into a node_modules directory in the root of your project. The --save-dev flag tells Node to save this package under the devDependencies object in our package.json file. This means that the next developer to come along can simply run npm install to grab the same dependency. If you were to only type --save in for the flag, it would save to a dependencies object, which is mean for development of Node applications; devDependencies are dependencies that are not required in the production environment.

This may be a good point to stop and add node_modules to your .gitignore file. node_modules tends to be a hefty folder with not just our packages, but their dependencies, and other developers involved in the project can just install these dependencies themselves by running npm install after they have cloned the project.

While we’re in the installation stage, let’s also install the Sass package we’ll need:

npm install --save-dev gulp-sass

Configuring Gulp tasks

Alright, now we have Gulp and our local packages installed, let’s go ahead and start configuring our Gulp tasks. The first thing you’ll need to do is create a Gulpfile.js in the root of your project.

Open the Gulpfile and add the following:

var gulp = require('gulp');

gulp.task('default', function() {
    // place code for your default task here
    console.log('Gulp is working!');
});

The var gulp = require('gulp'); line is telling Gulp to pull in the Gulp package from the node_modules folder.

The next few lines starting with gulp.task are configuring our first task, the default task, which simply prints Gulp is working! to the console. Go ahead and type gulp into the console to ensure everything is working, and that you see the Gulp is working! message.

Now that we’ve established the basic pattern for pulling in our packages and adding a task, let’s set up our Sass task.

Compiling Sass with Gulp

The first thing we need to do when adding a new package for usage with Gulp is load it into our Gulpfile:

var sass = require('gulp-sass');

Now that we have loaded sass to our file, let’s go ahead and set up the Sass task using gulp.task(), which takes two parameters: the name of the task, and a function which tells Gulp what to do to complete this task:

gulp.task('sass', function() {
    return gulp.src('./sass/*.scss')
    .pipe(sass.sync().on('error', sass.logError))
    .pipe(gulp.dest('./'));
});

gulp.src() tells Gulp which files to process during this task using a simple glob pattern–that is, look for anything within the sass directory that has a file extension of .scss.

That information is then piped (using .pipe(), which is similar to piping via the command line) to the sass.sync() function, which is set up to log any errors that may occur during the processing of that task.

Finally, that output, if it didn’t error, is piped to our destination folder, in this case the project root, where we should find our compiled CSS file.

The “guts” of a Gulp task is essentially a function that returns our output.

Now, if we have some Sass files in the Sass directory, we can run gulp sass from the command line, and we should see our compiled file in the root of the project.

Automating with Gulp

As you can imagine, running gulp sass every time you need to compile your stylesheets becomes cumbersome quickly. Let’s go ahead and add a task which will automatically compile our Sass every time we save a file, called watch:

gulp.task('watch', function() {
    gulp.watch('./sass/*.scss', ['sass']);
});

This task simply takes our initial glob pattern from gulp sass, and tells the watch method to watch for changes within files that match this pattern (you can also pass an array of several directories), and the second parameter tells the watch method which task(s) to run when a change is detected.

So now, when we want to work on our Sass, we can simply type gulp watch into the terminal, and anytime a file is saved, Gulp will automatically run our gulp sass task.

Wrapping up

This tutorial is just the tip of the Gulp iceberg. There are so many other helpful Gulp packages that can be added and configured to automate the development process. You can process stylesheets with PostCSS, concatenate and minify JavaScript, control versioning, and even deploy your sites or applications with Gulp. I encourage anyone looking to learn more to check out the Gulp website, read the Gulp docs, or search for Gulp plugins to further explore the possibilities.

In the meantime, if you’re looking for jump start, check out my Getting Started with Task Running & Gulp Gist for a package.json and Gulpfile.js that will get you started with Sass compilation, CSS & JS minification, and more. 😀

Using cat rivalry to understand the bind method

A few weeks ago, I used the rivalry between my girl cats, Whitney and Minnie, to solidify my understanding of JavaScript’s .bind method. I thought I’d share it because let’s be honest, the MDN explanation of .bind() is confusing:

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

What .bind() does–a plain English explanation

The JavaScript bind method allows developers to rebind or “rescope” the this keyword. When working with objects, and functions within objects, this refers to the object with which we are working. For example, in the the code below, this within the getKittyInfo method refers to the kitten object:

var nemesis = 'dog';
var kitten = {
    'name': 'Whitney',
    'age': 11,
    'color': 'orange',
    'markings': 'torbie',
    'nemesis': 'Minnie',
    getKittyInfo: function() {
        console.log( this.name + ' is an ' + this.age + ' year-old ' + this.color + ' ' + this.markings );
    }
}
kitten.getKittyInfo();

Output

"Whitney is an 11 year-old orange torbie"

Where things get confusing

However, whenever a function is inside another function, this is bound to the global object.

So, when we add the archNemesis() within within getKittyInfo(), our archNemesis()‘s this is instead bound to the global object (i.e. nemisis) instead of our kitten object:

var nemesis = 'dog';
var kitten = {
    'name': 'Whitney',
    'age': 11,
    'color': 'orange',
    'markings': 'torbie',
    'nemesis': 'Her younger sister, Minnie',
    getKittyInfo: function() {
        console.log( this.name + ' is an ' + this.age + ' year-old ' + this.color + ' ' + this.markings );
            function archNemesis() {
                console.log( 'Arch nemesis: ' + this.nemesis );
            }
        archNemesis();
    }
}
kitten.getKittyInfo();

Output

"Whitney is an 11 year-old orange torbie"
"Arch nemesis: dog"

When archNemesis() is called, the result of nemesis is dog because it is accessing the global object (i.e. our nemesis variable created right before our kitten object. In order to get archNemesis() to use the nemesis defined within our kitten object, we’ll need to bind the archNemesis function like so:

var boundNemesis = archNemesis.bind( this );

This tells our function that we’d prefer to use our kitten object’s this instead of the global this.

In the final example below, you can see how this was done within the kitten object’s archNemesis function:

var nemesis = 'dog';
var kitten = {
    'name': 'Whitney',
    'age': 11,
    'color': 'orange',
    'markings': 'torbie',
    'nemesis': 'Her younger sister, Minnie',
    getKittyInfo: function() {
        console.log( this.name + ' is an ' + this.age + ' year-old ' + this.color + ' ' + this.markings );
            function archNemesis() {
                console.log( 'Arch nemesis: ' + this.nemesis );
            }
        var boundNemesis = archNemesis.bind( this );
        boundNemesis();
    }
}
kitten.getKittyInfo();

Output

"Whitney is an 11 year-old orange torbie"
"Arch nemesis: Her younger sister, Minnie"

Hopefully this example has also helped you wrap your head around .bind(). If in your travels / experiments you come up with examples of your own, please feel free to share them in the comments!