Blog

Automation in WordPress: A Practical Guide

In this new post in the series I’ll go through practical about Automation in WordPress the concepts of automation are explained, as well as actionable instructions on how to start automating ASAP!

 

So… Why Should I Learn Automation?

In the previous article in this series, Automation: The Future of WordPress Development, I explained how you can leverage automation in WordPress (with Gulp) to help you cut down development time.

Due to the good feedback and support I got from you guys, I decided to write up a detailed guide of how I use Gulp in my development process. I’m sure many of you will find the practical concepts described here super useful.

Your aim should be to leverage Gulp to do a bunch of automated tasks for us while you’re busy developing, so that you don’t have to constantly stop for menial, annoying tasks and instead have deep focus on the product you’re developing, be it a theme or a plugin. I’m going to introduce a bunch of areas where Gulp is going to save your ass, for real. Hold it tight!

 

Setting Up Prerequisites

As mentioned in the previous part, there are a handful of good automation tools, but for the sake of simplicity, and for a better delivery of these automation concepts, I’ve selected Gulp as the most appropriate one. If you’re already familiar and experienced with automation, then feel free to read on, then apply on top of a different tool than Gulp if you prefer so.

Note: If you have Node.js, Gulp and Bower already installed — skip to the next section.

Before we dive into the setup of Gulp, you should know that Gulp runs on Node.js (a hard dependency). So first, make sure you have Node.js installed on your operating system before continuing.

Next up, move on to installing Gulp through npm, which is the package manager that comes bundled with Node.js.

Pop open the terminal, and type in this line. It will install Gulp’s command line tool.

$ npm install -g gulp-cli

Next step is to install Bower. This is a front-end package manager we’ll be using to grab third-party libraries such as Twitter Bootstrap, Font Awesome and similar ones.

$ npm install -g bower

Now that both Gulp and Bower are installed, let’s start off with an initial setup.

 

Setting up our Automation Tool

This guide will work both for parent and child themes, as well as plugin, so feel free to create a blank new theme/plugin if you prefer. Under your active project directory, create a file named package.json and paste in the following:

{
  "name": "automation",
  "version": "0.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "gulp-eslint": "^3.0.1"
  },
  "devDependencies": {
    "gulp-wp-pot": "^1.3.1",
    "gulp-sort": "^2.0.0",
    "gulp-bower": "^0.0.13",
    "browser-sync": "~2.14.3",
    "del": "~2.2.0",
    "es6-promise": "~3.2.1",
    "gulp": "~3.9.1",
    "gulp-autoprefixer": "~3.1.0",
    "gulp-concat": "~2.6.0",
    "gulp-cssnano": "~2.1.2",
    "gulp-eslint": "^3.0.1",
    "gulp-imagemin": "~3.0.1",
    "gulp-jshint": "^2.0.1",
    "gulp-notify": "~2.2.0",
    "gulp-phpcs": "^1.1.1",
    "gulp-rename": "~1.2.2",
    "gulp-sass": "~2.3.2",
    "gulp-scss-lint": "~0.4.0",
    "gulp-sourcemaps": "~1.6.0",
    "gulp-uglify": "~2.0.0",
    "jshint": "^2.9.2",
    "jshint-stylish": "^2.2.0"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

This is the manifest file for NPM, which dictates which packages should be installed. The ones we have here are directly related to the functioning of Gulp, most of which are Gulp plugins.

Upgrade to GenerateWP Premium Enjoy better WordPress generators  Upgrade Now

The full list of packages and their version is under the devDependencies and dependencies array (The difference between them is that devDependencies are to be used for development environments only, but in this scenario we don’t run Gulp on production anyway, so it doesn’t matter.) These dependencies are going to be used by Gulp, as you’ll see throughout this guide.

After saving the file, run the following line in the terminal (make sure you are cd’d into your current theme directory beforehand):

npm install

Let’s go ahead and configure Bower with some basic libraries.

Create a file named bower.json, and paste in the following:

{
  "name": "automated-theme",
  "description": "Automated WordPress theme for the GenerateWP automation series.",
  "main": "index.js",
  "authors": [
    "Your Name <[email protected]>"
  ],
  "license": "ISC",
  "homepage": "",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "bootstrap-sass": "bootstrap-sass-official#^3.3.6",
    "font-awesome": "fontawesome#^4.6.3",
    "jquery": "jquery#2.0"
  }
}

Then run:

bower install

This will cause the dependencies mentioned in the dependencies array to be installed to a directory named bower_components under your theme’s root. If it doesn’t exist there, it will be created by Bower automatically. That’s it for our dependencies. Let’s move on to the good stuff: setting up our first automated task.

 

The File Structure

Before we dive in, let me quickly explain how your theme directory will look once integrated with our automation tool. There are two main folders you will be dealing with.

Folder structure in a sample theme implementing Gulp
Folder structure in a sample theme implementing Gulp

The first is the assets folder. This folder is for storing raw development files. Within this folder are 4 subfolders: fonts, images, scripts and styles. For each of these, any files saved within will stay intact. And that’s the whole idea and purpose of the assets folder, that it always holds the original files.

Next up is the dist folder. Within, it has the same 4 directories as in assets. The main difference is that the files that go here are the ones that went through the automation process, and are optimized to the state the automation process runs in: either development or production.

In “development” state, which is the one you’ll be working under the most, the files undergo basic optimization. SCSS/LESS files get compiled and put together, while JavaScript files only get merged.

Once you decide your code is ready for production, all you need to do is run a single command, gulp production, and a production-ready distribution will be saved under the dist directory. Wait till you finish reading this guide before you run this command though.

If you’re using Git for deployments, then I recommend you work with two different branches. One for development (dev) and the other for production (master/prod). When you’re ready to deploy, commit your changes in the development branch, then switch to the production branch (git checkout master/prod), merge the commits you just made (git merge dev), and run gulp production, which will generate and place the production-ready files at /dist/.

 

Automating Stylesheet Generation

So you have written your own CSS. Even better, you’ve used a CSS-extension like SCSS/Sass or LESS. I know, they’re awesome. But there’s one thing that stops you from using these files right away: a compilation process must take place before they can be used in the browser (generally speaking).

Given so, how can we automate the compilation, so that every time a source file is changed, the “ready CSS” will be updated on-the-spot? Let’s examine some code.

var config = {
     sassPath: './assets/sass',
     bowerDir: './bower_components'
}

gulp.task('css', function() {
    return gulp.src(config.sassPath + '/style.scss')
        .pipe(sourcemaps.init())
         .pipe(sass({
                 // outputStyle: 'compressed',
                 sourceMap: true,
                 includePaths: [
                     './assets/sass',
                     config.bowerDir + '/bootstrap-sass/assets/stylesheets',
                     config.bowerDir + '/font-awesome/scss',
                 ],
             }).on('error', sass.logError))
         .pipe(sourcemaps.write())
         .pipe(gulp.dest('./dist/css'))
         .pipe(browserSync.stream())
         .pipe(notify('SCSS compilation done'));
});

You first feed Gulp in the folder where the main source files are stored on line 2 (in this example I’m using Sass). We then push the compiled CSS down the flow and create source maps (more details on this later).

Another cool automated process we can drop here is auto prefixing. This process will automatically assign vendor prefixes to your CSS rules, based on the service Can I Use. It’s recommended by Google and used in Twitter, so be sure that it’s a good practice.

Last but not least, we want to sync up our browser tab with the new changes (live reload) and send over a notification to your operating system, so you know when the automation process has been completed.

Upgrade to GenerateWP Premium Enjoy better WordPress generators  Upgrade Now

The production version also includes a minification task, but now we’ll only review the development version.

 

Automating JavaScript Linting & Minification

Focusing on having perfectly-written or optimized JavaScript code is not enough, and you probably know it already. Nowadays, with mobile devices usage growing more common than ever before, you must be taking your mobile users into consideration. How can you make it easier on them? Partially, by making sure bandwidth usage is kept down to the absolute minimum necessary. One of the ways to reach this goal is by minifying your textual-based static assets — like CSS, JS and SVG files.

This can be easily achieved with Gulp. Similar to handling stylesheets with Gulp, you feed in the source JS files, then various Gulp plugins do the extra work needed to concatenate the files, minify (compress) them and optionally add source maps.

The goal is to merge all the JavaScript files in your theme to a single one, so it’s retrieved much faster on both desktop and mobile devices.

// List all your JS files HERE
var js_files = [
    'bower_components/jquery/jquery.js',
    'bower_components/bootstrap-sass/assets/javascripts/bootstrap.js',
    'assets/js/**/*.js'
];

gulp.task('scripts', function() {
    return gulp.src(js_files)
        .pipe(sourcemaps.init())
        .pipe(concat('main.js'))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest('./dist/scripts'))
        .pipe(browserSync.stream())
        .pipe(notify( 'JS compiled' )); // Output to notification
});

Explanation: In the first part (lines 3-4), we mention all the files we want included in the final JavaScript file, by order. The first file mentioned here will end up the first in the final file, and so on.

On line #11, the file merging happens.

If you intend on adding a Bower package, then remember to add its main file’s relative path to this array. If the library you’re adding has a CSS file that needs to be included, then keep reading, since I’m going to touch on this in a bit.

Note that when working in development mode, a minification process doesn’t take place so you can debug your JS file with ease.

 

Automating Image Optimization

Image optimization is often an aspect that gets overlooked when developers deal with tailor-fitted WordPress themes. I’m not talking about images you upload to WordPress through the media uploader. I am talking about images you might include in your theme, such as a logo, different background images, icons, etc. In some scenarios, whoever provided you the images might have optimized them already. But this automated task ensures no stone is left unturned and that all images are optimized.

Automating such task is especially important in our day and age where mobile usage grows from day to day. This will improve page-load speed, plus give your website some extra points courtesy of the big brother, Google.

var img_files = [
    'assets/images/**/*'
];

gulp.task( 'images', function() {
    return gulp.src(img_files)
        .pipe(gulp.dest( 'dist/images' ))
        .pipe(browserSync.stream());
});

gulp.task( 'images-min', function() {
    return gulp.src( img_files )
    .pipe( imagemin( { 
        optimizationLevel: 3,
        progressive: true,
        interlaced: true 
    } ) )
    .pipe( gulp.dest( 'dist/images' ) );
});

If you’d like, you can change the settings that are passed to ImageMin, which is the library that takes care of the image optimization.

 

Live Browser Refresh for Development Automation

Many developers work in a way where they alter something in their project, save a file or two, return to the browser and manually hit the refresh button to see their changes take effect. Since we’re dealing with automation here — wouldn’t it be cool to simplify and automate this process? Well, you bet. Instead of having to manually refresh the page each time changes are made, the page will refresh itself automatically when a change is made either in a PHP, CSS or JavaScript file.

Upgrade to GenerateWP Premium Enjoy better WordPress generators  Upgrade Now

This can be done with BrowserSync. We integrate BrowserSync into our automation flow and after the task at hand is done, we run a command that submits a signal to the active tab in your browser to refresh itself.

We can also use the same technique for when image and fonts are being added.

gulp.task('watch', function() {
    gulp.start( 'css' );

    browserSync.init({
        files: ['{lib,directives}/**/*.php', '*.php'],
        proxy: 'http://local.wordpress.dev/',
        snippetOptions: {
            whitelist: ['/wp-admin/admin-ajax.php'],
            blacklist: ['/wp-admin/**']
        }
    });

    gulp.watch( ['assets/sass/**/*'], ['css'] );
    gulp.watch( ['assets/js/**/*'], ['scripts'] );
    gulp.watch( ['assets/js/**/*'], ['custom-scripts'] );
    gulp.watch( ['assets/fonts/**/*'], ['fonts'] );
    gulp.watch( ['assets/images/**/*'], ['images'] );
    gulp.watch( ['languages/**/*'], ['pot'] );
    gulp.watch( ['{lib,directives}/**/*.php', '*.php'], ['php'] );
});

In the first highlighted area, we set up BrowserSync. Note that you’re going to have to change your configuration, notably the proxy property, to the root URL of your development WP installation. The rest is pretty generic configuration.

In the second block (lines 13 to 19) we define the different kinds of files, and define what task shall run once any of these files change. You can see for example that on line 17, we define that each time an image is being added (or changed) to the assets/images folder, the task images will run.

 

Automating a Release-ready Copy

Running Gulp production command

As I mentioned before, it’s crucial to optimize static files and resources to maximize the user experience. It only makes sense to optimize the files that will later be copied to your production server. Though, for the development environment it doesn’t mean much.

We can leverage Gulp to creating a copy of all your resources in a production-ready format. What does that mean?

  • Textual files (CSS+JS) undergo concatenation and are minified (compressed)
  • Images undergo optimization for smallest file size while keeping quality as high as possible
  • Fonts are being copied as-is

The process will be as such: whenever the changes you’re working on are ready, we’ll copy all static files to the “dist” directory under the theme’s root. In the filename for JS and CSS files, just before the file extension, we’ll add the .min suffix, which indicates that the file has underwent a minification process.

Let’s see how this can be done with Gulp:

gulp.task( 'production', ['clean'], function() {
    gulp.start( 'css-min', 'scripts-min', 'images-min', 'fonts-min' );
});

This little piece of code will run all of the tasks that end with -min, not before running the clean task which empties the dist directory.

 

Automating Localization (l10n)

As you know, it’s a best practice to have localization support in your project, especially when working on a product that is planned to be released or sold online. Being honest, in such case it’s an obligation on your part.

So, if you’re actively localizing your product, you may know by now that every time you want to translate a string in your theme, you have to run a special command, as described in the theme handbook. Let’s be honest. It’s a tiring process. Who do you think enjoys running terminal lines manually every now and then, and wasting time when forgetting to do so and having it suck your time? Nobody, that’s right.

This is how we’re going to automate it.

gulp.task( 'pot', function() {
    return gulp.src('*.php')
        .pipe(sort())
        .pipe(wpPot( {
            domain: 'yourtextdomain',
            destFile:'yourtextdomain.pot',
            package: 'themename',
            bugReport: 'http://example.com',
            lastTranslator: 'John Doe <[email protected]>',
            team: 'Team Team <[email protected]>'
        } ))
        .pipe(gulp.dest('languages'));
} );

Now every time you save any of your PHP files, this process will run in the background. Note that if you’re working on a translation while writing PHP code, you might need to update your PO file from the catalog, POT file. This is the only file that’s being affected in this process.

You can run this specific task in the terminal:

$ gulp pot

 

In Conclusion (And What’s Next?)

Automation is already being utilized by many projects, and is, at times, leveraged to high extents. I have already proved to myself (and hopefully to you too) that this is the way to go when developing for WordPress and any other platform or framework.

It pays to learn the inner working of automation a little deeper. I thought to recommend some resources and links for you to maximize the value that Gulp has to offer you.

Check these out, and last but not least — please share with us your automation stories. We’d love to hear how you’re getting it to work in your projects!

Maor Chasen

A proud WordPress Developer and contributor. Maor focuses on plugin development and occasionally contributes to WordPress core.

3 Comments:

  • Yuriy Gerasimov (@ygerasimov)

    thank you very much for the article! Very useful!

    Maor, what do you use for automating testing of the WP sites?

    Reply

    • Maor Chasen

      Hi Yuriy! This depends on how you want your sites to be tested. Also, what is there to test? Let me know 🙂

      Generally speaking, there are some great in-browser automated testing (open-source) solutions such as SauceLabs, PhantomJS as well as DalekJS that have amazing testing capabilities. Even though this topic leans a little more towards Unit Testing, this can totally be automated and it’s actually a good idea for the next post in this series.

      Reply

Leave a Reply