Using Grunt for WordPress Theme Development and Deployments

March 12, 2013 | 11 Minute Read

There are plenty of options if you're looking to use CSS preprocessors and JavaScript linting in your development workflow, but none as flexible and extensible as Grunt.

In the past, I used CodeKit to handle all of this work, but Grunt has since taken over, giving me additional options such as deployments with greater control over the entire process. With one JavaScript file in the root of my WordPress theme, I can control Compass output paths, JSHint options, UglifyJS concatenation and minification, setup browser live reloading and multiple server deployments, allowing for easy expansion and adaption as things continue to change and grow.

Keep reading to find out how to use Grunt with your WordPress themes to speed up your development and allow you to deploy your code to your servers.

What is Grunt?

Grunt is an elegant task runner from Ben Alman written in Node. In it’s latest version 0.4, Grunt has become an elegant wrapper for any task you can imagine. There is a large community behind Grunt with many contributed plugins that you can add to your projects. Whether you’re looking to create a full build process or just watch files for changes, Grunt has you covered.

What Can Grunt Do?

There are countless tasks that Grunt can do for you, but in this case, we’re going to focus on those that will help our WordPress theme development: Compass preprocessing, JSHint to check out JavaScript, UglifyJS to concatenate and minify all JavaScript files, Watch to watch files for changes, trigger our tasks and LiveReload the browser, ImageMin to optimize all PNG and JPG images, and Rsync to deploy our files to remote servers.

All of this is accomplished by adding two files to your theme, a package.json to define which Grunt plugins to use as dependencies, and a Gruntfile.js to define our tasks and options. For more information on getting that all setup, my friend Jonathan Christopher has a great article about using Grunt with WordPress.

We first setup the livereload task, but give it no options (you can change the port here if you feel the need).[Update: This is now handled the Watch task.] You’ll need to install the LiveReload browser extension to connect, which you can get for Chrome, Firefox or Safari. Next, we give JSHint our options for how to lint our JavaScript and tell it which files to check in the all setting, followed by configuring Uglify to create source maps and concatenate and minify our files. In my setup, I have it automatically pull assets/js/source/plugins.js and all files inside assets/js/vendor other than Modernizr and put them into assets/js/plugins.min.js, as well as taking our main.js script and minifying.

Next, we tell Compass to use the settings in our external config.rb file for processing our SCSS. I chose to break config.rb out into a separate file instead of putting the options directly inside the Gruntfile.js in case I wanted to use the Compass ruby gem directly or use CodeKit, as both will work using the config.rb file.

The next section sets up Regarde for our watch task to monitor for changed files and triggering our tasks. The reason for using Regarde instead of Grunt Watch is that Watch doesn’t give access to changed files because it spawns tasks in subprocesses, which doesn’t play nice with LiveReload. It’s essentially a drop-in replacement, so swapping back to Watch won’t be an issue if the way it spawns processes changes. We tell Regarde to fire the compass and livereload tasks whenever an SCSS file is changed, and to fire jshint, uglify and livereload whenever a JS file is changed.

[Update: Watch now works with LiveReload and has it built in, so the above Regarde code is swapped out for Watch. It’s essentially the same code, we’re just adding an option to LiveReload the browser.]

The last task for this section is imagemin, which doesn’t automatically run as file are changed, but run manually with:

grunt imagemin

This will run OptiPNG and jpegtran on your images to optimize them before you deploy to save on bandwidth.

At the end of the Gruntfile.js, we load all our tasks and register our default task. To run Grunt, at the terminal, just enter

grunt

Now, let’s get right on the most fun part: using Grunt to deploy your theme to your servers.

Deploying Your WordPress Theme with Grunt

There are a number of deployment choices when it comes to Grunt tasks. You can use SSH to connect and run commands or transfer files over SFTP, you can use FTP to transfer files if you don’t have SSH access, or you can use Rsync to sync up your directories over an SSH connection. After trying all three, I settled on Rsync as it provided the best and quickest way to update my theme files on the servers I use most. I typically have SSH or SFTP access, so it’s not an issue for me, but if you have only have FTP access, it’s trivial to swap out the Rsync plugin with the FTP plugin for your deployments. I’ve used this method for client sites in the past and it works seemlessly.

In our Gruntfile.js, we have two servers setup: staging and production. Each sets the source as the root of our theme project locally and sets a destination and hostname for our remote server. Setting recursive tells rsync to traverse all subdirectories to make sure we’re getting all of our files, and syncDest will delete any files on the remote server that no longer exist in your local repository. I’m excluding a number of files as they aren’t needed for the theme to run on the server.

To trigger a deployment, at the Terminal, enter:

grunt rsync:staging

or

grunt rsync:production

And like that, you’ve now deployed your files to your server!

Wrap Up

I’ve changed over my deployments to using Grunt now instead of setting up Git post-commit hooks and bare repositories. Having the general framework in Grunt makes it quicker than configuring post-commit hooks on multiple servers, and it works just as well. With so many tasks available to extend and customize Grunt, it’s an invaluable tool for any development process.

This method can be easily tweaked to work with any development process, from Drupal themes to ExpressionEngine sites to static site builds and use in other systems. I love the flexibility of Grunt and plan to keep using and evolving my Gruntfile going forward. I hope you do the same!