Before we get started, let me ask you a question. What is the most common task you do when developing a WordPress theme (or any kind of website really)? What do you do so often that you don't even notice it - because it's in your muscle memory?

You refresh the browser. (Did not expect that one did you)

Well, what if I told you this can be automated and the browser can auto-refresh on its own whenever you make a change to a file? With Gulp, it's easy. And not only refreshing, you can automate sass compilation, file merging, syntax checks, deployment, you name it.

So, in this tutorial, I am going to show you how to set up Gulp and a few most common tasks that theme developers perform on a daily basis.


All the components that we are going to use in this tutorial rely on Node.js, which is the only requirement. It comes with a package manager called, unsurprisingly Node package manager, or NPM for short. Install Node then run $ npm -v to make sure it's running properly (it will give you version number).

Of course you should also have some kind of development environment for WordPress, be it VVV, HGV, MAMP or any other environment flavour of your choice. If it can run WordPress, you're good to go.

You'll also need a livereload extension for the browser you're developing in.

It's also advisable that you have at least hard of sass/scss (the difference is in the syntax, so I may choose either of the names going forward interchangeably)

Note: for the purpose of this tutorial I am going to set up a blank Underscores theme, but feel free to add the things you are about to learn to your existing one - you cannot do any harm.

What is Gulp

The official website says it's the streaming build system which are just fancy words for what is essentially a task manager. And by tasks I mean anything you need to do manually that could be automated (except for writing code that is, you can't avoid that). Some of the most common tasks you do when you're building a WordPress theme:

  • compile sass into CSS (if you use it)
  • compile Coffeescript into JavaScript (if you use it)
  • minify, concatenate, or lint (linting is a process of checking the code for poor coding practices) CSS and JavaScript
  • optimize images
  • create, delete, or zip files and folders
  • watch files for changes and…
  • refresh the browser if a file is changed - a task most commonly known as livereload. Bye-bye CMD + R.

From a more technical perspective, Gulp is a NPM package (that supports plugins), which means it needs Node.js to run.

What is Bower

Just like Gulp, Bower (initially developed at Twitter) is also an NPM package that manages frontend packages and their dependencies for you. What is a fronted package? jQuery is. Most of jQuery plugins are too - pretty much any JavaScript library that runs in the browser and usually comes with a CSS file (or more of them) is a frontend package. It's also my personal benchmark of quality; If a JavaScript library is also a NPM package it usually means the author follows modern practices and approaches. Not always, but often.

On our landing page for example, we use jQuery and a slider plugin (don't confuse it that with WordPress plugins) called Slick (for testimonials).

The problem Bower solves? Dependencies and outdatedness of those libraries/packages. You can easily run $ bower update and it'll automatically fetch the latest versions. Because I care about that. And you should too.

Install Gulp

Gulp requires two initial files in order to run: package.json and gulpfile.js so we're going to run the init script that creates the former (the latter you're going to have to create manually):

$ npm init .

It'll ask you a series of questions (just press enter if you don't know or are not sure) which will be transformed into a JSON configuration and saved into package.json. After some cleanup, my starting version looked like this:

  "name": "Kickstart",
  "version": "1.0.0",
  "description": "Underscores, enhanced with Gulp workflow",
  "main": "gulpfile.js",
  "author": "Tomaz Zaman <>"

Now, we need Gulp installed, so per it's documentation run $ npm install --save-dev gulp.

Now, that Gulp is installed, create a file in your theme root directory, named gulpfile.js and put the following in:

var gulp = require('gulp');

gulp.task('default', function() {


In order to test whether Gulp is installed properly, just run $ gulp - it'll run the default task (which does nothing for now), then exit.

Now, before we install any Gulp packages, we need to think about which tasks we'd like to automate:

  • I use sass, so we need a preprocessor which will make CSS out of it
  • I tend to separate JavaScript into multiple files (for clarity and organization) and I want to end up with one minified file
  • I'd like to know whether my JavaScript follows best practices
  • I like the browser to refresh automatically as I code.
  • I want Gulp to continue working when errors occur (by default it exits)

These are the basic requirements and some require more than one package, for example you need a watcher which will trigger the livereload when a file changes.

Let's install all of them in one go - run this command:

$ npm install —save-dev gulp-plumber gulp-watch gulp-livereload gulp-minify-css gulp-jshint jshint-stylish gulp-uglify gulp-rename gulp-notify gulp-include gulp-sass

(Don't worry if you've never heard of these packages, it'll become clear shortly)

Configure Gulp

Open gulpfile.js, which is where we'll spend the remainder of this tutorial. At the top, we need to require all the packages we installed in the previous step, so paste this in:

var gulp = require( 'gulp' ),
  plumber = require( 'gulp-plumber' ),
  watch = require( 'gulp-watch' ),
  livereload = require( 'gulp-livereload' ),
  minifycss = require( 'gulp-minify-css' ),
  jshint = require( 'gulp-jshint' ),
  stylish = require( 'jshint-stylish' ),
  uglify = require( 'gulp-uglify' ),
  rename = require( 'gulp-rename' ),
  notify = require( 'gulp-notify' ),
  include = require( 'gulp-include' ),
  sass = require( 'gulp-sass' );

Next, it's time to define the default error handler (gulp-plumber depends on it):

var onError = function( err ) {
  console.log( 'An error occurred:', err.message );
  this.emit( 'end' );

And now, finally, our first task which will compile sass into regular CSS (you're not still writing it by hand are you?):

gulp.task( 'scss', function() {
  return gulp.src( './scss/style.scss' )
    .pipe( plumber( { errorHandler: onError } ) )
    .pipe( sass() )
    .pipe( gulp.dest( '.' ) )
    .pipe( minifycss() )
    .pipe( rename( { suffix: '.min' } ) )
    .pipe( gulp.dest( '.' ) )
    .pipe( livereload() );
} );

Note: Don't worry if you don't know what pipe does, internally it's a function for streaming data (in our case files) while performing certain operations on that data in each step.

Let's look at this task we just defined; First, we tell it to take style.scss, register it with plumber (in case our sass has syntax errors) then compile it into regular CSS with sass() and finally writes it to the current directory. While we could stop there, I'm adding — for educational purposes — a few extra steps; After saving style.css it pipes it through a minificator, renames it to style.min.css, saves it, then finally reloads the browser.

Up until a couple of months ago, I used to use Compass for sass compilation, but it's really slow, which is why I switched to LibSass - an insanely fast, but slightly buggy option. You don't have to worry about it, since it's installed automatically with the gulp command above, so if you don't see any errors, it's working properly already.

Before we can test whether this task is working, we need the file /scss/style.scss, with the following example content:

$color: #36A9E1;

body {
  background: $color;

Now, the moment of truth. Run $ gulp scss and you should see your task creating two files in your root folder: style.css and style.min.css. Open the latter to see all the spaces and comments removed - which one you enqueue in WordPress depends whether you do minification on the server or not.

You probably don't want running this task every time you update a sass file, which is why we'll setup up the watch task:

gulp.task( 'watch', function() {
  livereload.listen(); './scss/**/*.scss', [ 'scss' ] ); './**/*.php' ).on( 'change', function( file ) {
    livereload.changed( file );
  } );
} );

As the last step, change the default task to look like this:

gulp.task( 'default', [ 'scss', 'watch' ], function() {

} );

Notice the two tasks in square brackets? Those are called dependant tasks and will run before the task which they are called in executes.

To test out whether everything is working properly run $ gulp (it'll keep running until you exit by pressing CTRL + C), open the WordPress site, and make sure to turn on Livereload extension on. Open the sample css file we created earlier, change the color to #78A30D and save the file. If your background changed from blue to green without the page refreshing, tap yourself on the back, job well done!

Note: In order to avoid this tutorial being any longer, I've deliberately left out JavaScript processing. But fear not, I created a gist with that included.

What about Bower?

Let's install the sass version of normalize.css via Bower. As with Gulp, you need to initialize the project by entering this command inside your theme root directory:

$ bower init .

Again, a couple of questions, you might as well just press enter through all of them and edit the created bower.json. Here's what mine looks like:

  "name": "Kickstart",
  "version": "1.0.0",
  "authors": [
    "Tomaž Zaman <>"
  "description": "Underscores + Gulp + Bower",
  "license": "MIT",
  "ignore": [

Then install Normalize:

$ bower install --save-dev normalize-scss

And import the newly installed file in your main sass stylesheet (scss/style.scss), so that it looks like this:

@import "../bower_components/normalize-scss/_normalize.scss";

$color: #36A9E1;

body {
  background: $color;

If you still have Gulp running, you should immediately see it in action, processing the new sass and creating new style.css. If not, run $ gulp and see the magic happen.


It may appear complicated at first but this kind of workflow is the future of not only WordPress theme development, but any kind of frontend development in general.

There are many theme authors out there who leverage the power of automation to significantly speed up their development workflow and this tutorial is all you need to get started. So no excuses - do it :)

New Call-to-actionQuality: The Codeable Differene

  • Gulp plumber is something new for me. Going to add it. Thanks for the tutorial.

    • You’re welcome! I had the same problem – sass errors would exit the process – and I had to do something about it and gulp-plumber seemed to be the most used utility plugin for Gulp

      • Yup! That is really hard to deal with. There are so many cool packages out there.

        Here is the list of packages I use

        “gulp” : “~3.8.10”,

        “gulp-autoprefixer”: “0.0.7”,

        “gulp-cache” : “~0.2.4”,

        “gulp-concat” : “~2.2.0”,

        “gulp-imagemin” : “~2.0.0”,

        “gulp-jshint” : “~1.6.2”,

        “gulp-livereload” : “~2.0.0”,

        “gulp-load-plugins”: “~0.5.1”,

        “gulp-minify-css” : “~0.3.4”,

        “gulp-notify” : “~1.3.1”,

        “gulp-rename” : “~1.2.0”,

        “gulp-ruby-sass” : “~0.5.0”,

        “gulp-uglify” : “~0.3.0”,

        “gulp-pixrem” : “0.1.1”,

        “gulp-uncss” : “1.0.0”,

        “tiny-lr” : “0.0.7”

        • What’s the use case for gulp-cache? – Never used it before.

          I see you’re using ruby-sass; Give gulp-sass a try. It’s based on Libsass which is a parser written in C and thus ridiculously fast. Up until a couple of months ago it had some bugs, but now they seem to be fixed, I’m using it on a daily basis – no problems.

          • Actually I process Images through a gulp task, where any new images are passed through Imagemin to compress JPG, GIF and PNG images down before triggering a LiveReload. The cache plugin makes sure that images aren’t processed multiple times, so you don’t need to worry about tasks bogging down every time you add a new image.

            // Images

            gulp.task(‘images’, function() {

            return gulp.src(‘assets/images/**/*’)

            .pipe(plugins.cache(plugins.imagemin({ optimizationLevel: 7, progressive: true, interlaced: true })))



            .pipe(plugins.notify({ message: ‘Images task complete’ }));


            That said, yes my Sass setup is a bit slow, that was why I was looking into vagrants to make it fast.
            For a big theme framework I am building for about 7 months now, it takes 5 secs
            to process the Sass. I will give gulp-sass a try, I hope through this very tutorial. If you say so about
            it being bug-free (since I heard other wise).

          • Primož Cigler

            Ruby SASS is now waiting for the LibSass to catch up on version 3.4 so very soon the 2 implementation will be identical features-wise.

  • Alexadark


    what are the advantages from gulp vs grunt vs codekit (which i use and very happy with it!) ?

    second thing, i think i have a problem with npm on my new computer (whici is really annoying as there is other extension which i really want to use:

    npm WARN package.json alexadark@1.0.0 No description

    npm WARN package.json alexadark@1.0.0 No repository field.

    npm WARN package.json alexadark@1.0.0 No README data

    npm WARN locking Error: EACCES, open ‘/Users/alexadark/.npm/_locks/gulp-6053d63b9c3ef9ba.lock’

    npm WARN locking at Error (native)

    npm WARN locking /Users/alexadark/.npm/_locks/gulp-6053d63b9c3ef9ba.lock failed { [Error: EACCES, open ‘/Users/alexadark/.npm/_locks/gulp-6053d63b9c3ef9ba.lock’]

    npm WARN locking errno: -13,

    npm WARN locking code: ‘EACCES’,

    npm WARN locking path: ‘/Users/alexadark/.npm/_locks/gulp-6053d63b9c3ef9ba.lock’ }

    npm ERR! Darwin 14.0.0

    npm ERR! argv “node” “/usr/local/bin/npm” “install” “–save-dev” “gulp”

    npm ERR! node v0.12.0

    npm ERR! npm v2.5.1

    npm ERR! Attempt to unlock /Users/alexadark/node_modules/gulp, which hasn’t been locked

    npm ERR!

    npm ERR! If you need help, you may report this error at:

    npm ERR!

    npm ERR! Please include the following file with any support request:

    npm ERR! /Users/alexadark/npm-debug.log

    well i suppose i have to post on github!

  • Why gulp and not grunt? I’m currently using grunt, because there is a lot more grunt packages available out there.

    • I used Grunt as well, but moved to Gulp because its syntax is simpler and easier to understand. Plus haven’t found a single package missing with Gulp (the ones I’m using)

    • Gulp is like comparing a Ferrari to a Fiat. Grunt being the Fiat, of course, without the “grunt”. Gulp is the Ferrari, gulping all your petrol whilst serving you faster speeds. PS you can easily deploy WP with Gulp. Start with gulp-ftp. :)

    • justinisamaker

      Gulp is more focused on the code you write in your gulpfile, whereas grunt looks at how you have your repo configured and is a little more rigid in that sense. Other than that, they’re both JS task runners and both good at it.

  • People who prefer graphical user interfaces and work alone can achieve these tasks using Codekit

    I see the necessity of task runners like grunt or gulp mainly for big teams who need a shared tool chain with complex tasks. For example WordPress Core is using a 600+ lines Gruntfile:

  • Aaawesome tutorial! Finally going to switch over from using the compass gui to gulp. Thanks!

  • julienetie

    Great tuts…
    I had some problems installing the list of gulp packages,
    it was resolved when I placed –save-dev at the end of the list.

  • Krishna Kumar

    How to RUN it without running CMD + R ?
    What is use for “livereload” ?
    I am working on compile less/sass file to css file on browser side without compile CMD + R.

  • in the list of install npm is mising gulp –save-dev i think