Develop WordPress Themes Faster with Gulp
WordPress’ simple theme development is partly responsible for its success. A developer with front-end and PHP knowledge can consult the excellent Codex and get started on their next masterpiece.
Theme development is possible with just a text editor and graphics package, but modern toolsets can revolutionize your workflow. In this tutorial we’ll use Gulp to run tasks including:
- copying newer PHP theme files
- optimizing images
- compiling Sass SCSS files into a single, minified CSS file
- merging ordered JavaScript files, remove debugging statements and minifying
- automatically refreshing the browser when files are updated.
What is Gulp?
Gulp is a JavaScript-based build system which takes your source files and transforms them into optimized versions. If you’re new to Gulp, please refer to An Introduction to Gulp.js for full installation and usage instructions. A summary of the initial steps:
- Install Node.js.
- Install Gulp globally:
npm install gulp-cli -g
- Create a project folder and navigate into it:
mkdir mytheme
followed bycd mytheme
. - Initialize your project with npm:
npm init
Your Project Files
A Gulp (or any) build process requires a set of original source files containing your unmodified code and images. These are processed, manipulated and minified to create build files.
WordPress is installed to a web server folder, perhaps /var/www/
on a Linux/Apache installation. Your WordPress theme must be defined in its own sub-folder within /wp-content/themes/
. Therefore, the folder containing our built files could be /var/www/wp-content/themes/mytheme/
. At a minimum, themes require two files:
- a
style.css
stylesheet containing meta-data in comments at the top, and - an
index.php
template file.
Most themes contain many more files for presenting posts, pages, indexes, categories, tags, and errors. Cross-page partials such as headers and footers are usually defined as are image and JavaScript files.
You could place your source files somewhere within the mytheme
folder. That may be useful if you’re distributing a theme to be downloaded, modified and built by others. However, for the purpose of this tutorial, we’re going to use a source folder which is inaccessible from the web server, e.g. ~/mytheme/
. The benefits of this approach:
- Your theme source files can be managed in a single folder and repository without polluting the build or WordPress folders.
- The final built theme folder contains only the files it requires.
- Gulp, its plug-ins and other applications are not contained in the theme folder. They cannot be accidentally copied to a production server which is unnecessary and could have security implications.
The source project folder requires a further four sub-folders:
template
- the WordPress PHP theme filesimages
- images used by your themescss
- Sass SCSS source filesjs
- any number of separate client-side JavaScript source files.
Install Dependencies
From the source folder (~/mytheme/
), run the following npm
command to install Gulp and all plug-ins as development dependencies:
npm install --save-dev autoprefixer browser-sync css-mqpacker cssnano gulp gulp-concat gulp-deporder➥gulp-imagemin gulp-newer gulp-postcss gulp-sass gulp-strip-debug gulp-uglify gulp-util ➥postcss-assets
A node_modules
folder will be created which contains the module code. That should be omitted from your source control system (for Git users, add node_modules
to your .gitignore
file).
Create a Gulp Configuration File
Create a new gulpfile.js
configuration file in the root of your source folder. Add this code to get started:
// Gulp.js configuration'use strict';
const
// source and build folders dir = { src : 'src/', build : '/var/www/wp-content/themes/mytheme/' },
// Gulp and plugins gulp = require('gulp'), gutil = require('gulp-util'), newer = require('gulp-newer'), imagemin = require('gulp-imagemin'), sass = require('gulp-sass'), postcss = require('gulp-postcss'), deporder = require('gulp-deporder'), concat = require('gulp-concat'), stripdebug = require('gulp-strip-debug'), uglify = require('gulp-uglify');
// Browser-syncvar browsersync = false;
// PHP settingsconst php = { src : dir.src + 'template/**/*.php', build : dir.build};
// copy PHP filesgulp.task('php', () => { return gulp.src(php.src) .pipe(newer(php.build)) .pipe(gulp.dest(php.build));});
We’re defining our default folders, loading modules, then creating a php
task to copy new and updated files to the theme folder. The task has been kept intentionally simple to copy the PHP source files as-is.
Save gulpfile.js
and create a few .php
files in the source template
folder. Then enter the following command:
gulp php
All the files will be copied to the theme folder (/var/www/wp-content/themes/mytheme/
).
Image Processing
Image files can often be compressed further using tools such as imagemin. Add the following code to gulpfile.js
:
// image settingsconst images = { src : dir.src + 'images/**/*', build : dir.build + 'images/'};
// image processinggulp.task('images', () => { return gulp.src(images.src) .pipe(newer(images.build)) .pipe(imagemin()) .pipe(gulp.dest(images.build));});
Save then run gulp images
. Compressed versions of any new or updated images in the source images
folder are copied to /var/www/wp-content/themes/mytheme/images/
.
Sass Compilation
WordPress cannot use Sass files directly; you must compile to a single style.css
file. Add the following code to gulpfile.js
:
// CSS settingsvar css = { src : dir.src + 'scss/style.scss', watch : dir.src + 'scss/**/*', build : dir.build, sassOpts: { outputStyle : 'nested', imagePath : images.build, precision : 3, errLogToConsole : true }, processors: [ require('postcss-assets')({ loadPaths: ['images/'], basePath: dir.build, baseUrl: '/wp-content/themes/wptheme/' }), require('autoprefixer')({ browsers: ['last 2 versions', '> 2%'] }), require('css-mqpacker'), require('cssnano') ]};
// CSS processinggulp.task('css', ['images'], () => { return gulp.src(css.src) .pipe(sass(css.sassOpts)) .pipe(postcss(css.processors)) .pipe(gulp.dest(css.build)) .pipe(browsersync ? browsersync.reload({ stream: true }) : gutil.noop());});
Launch this new task with gulp css
to:
- run the Gulp
images
task first (images may be required in your CSS) - compile the Sass code in the source
scss/style.scss
file using the fast LibSass compiler - use PostCSS to automatically add asset references, apply vendor prefixes, pack media queries together, and minify the resulting CSS code
- output the stylesheet to
/var/www/wp-content/themes/mytheme/style.css
. - force a Browsersync CSS reload (more about that later).
The source scss/style.scss
file must include the WordPress theme meta data at the top, e.g.
/*! Theme Name: My Theme Theme URI: http://www.sitepoint.com/ Description: Demonstration theme Version: 1.0.0 Author: Craig Buckler (@craigbuckler) Author URI: http://www.sitepoint.com/ Tags: Gulp
License: MIT License URI: http://opensource.org/licenses/mit-license.php*/
@import'_base';@import'_forms';@import'_tables';@import'components/_widget1';// etc...
It is important to use /*!
as the first line. This ensures the cssnano minifier does not remove the comment and render your theme unusable.
The postcss-assets plugin allows you to refer to image assets using code such as:
.widget1 { width: width('myimage.jpg'); height: height('myimage.jpg'); background-image: resolve('myimage.jpg');}
You can also inline images with automatic Base64 encoding:
.widget2 { background-image: inline('myimage.jpg');}
JavaScript Processing
Add the following code to gulpfile.js
:
// JavaScript settingsconst js = { src : dir.src + 'js/**/*', build : dir.build + 'js/', filename : 'scripts.js'};
// JavaScript processinggulp.task('js', () => {
return gulp.src(js.src) .pipe(deporder()) .pipe(concat(js.filename)) .pipe(stripdebug()) .pipe(uglify()) .pipe(gulp.dest(js.build)) .pipe(browsersync ? browsersync.reload({ stream: true }) : gutil.noop());
});
Run this new task with gulp js
to:
- process all JavaScript files in the source
js
folder - order the files appropriately. Add comments at the top of your JavaScript files to declare dependencies, e.g.
// requires: lib1.js
or// requires: config.js lib1.js
. - concatenate into a single file
- strip all debugging and console logging statements
- minify the code
- output the resulting code to
/var/www/wp-content/themes/mytheme/js/scripts.js
. - force a Browsersync CSS reload (more about that later).
Run Everything
Rather than calling each task separately, we can add the following code to gulpfile.js
:
// run all tasksgulp.task('build', ['php', 'css', 'js']);
You can now use gulp build
to run the php
, js
, css
and images
tasks in parallel. (Note images
is a dependency of the css
task so we need not call it directly.)
Enable File Watching and Browsersync
Your workflow can be radically improved by:
- Letting Gulp watch for file changes before launching the appropriate task.
- Automatically reloading CSS and JavaScript files when they change (without a page refresh).
- Automatically refreshing the page when a template file changes.
First, we need to define a browsersync
task in gulpfile.js
. This will create a proxy server to your web server running WordPress on localhost
(change this domain or use an IP address as necessary):
// Browsersync optionsconst syncOpts = { proxy : 'localhost', files : dir.build + '**/*', open : false, notify : false, ghostMode : false, ui: { port: 8001 }};
// browser-syncgulp.task('browsersync', () => { if (browsersync === false) { browsersync = require('browser-sync').create(); browsersync.init(syncOpts); }});
Now add a watch
task to run Browsersync, watch for file changes and run the appropriate task:
// watch for file changesgulp.task('watch', ['browsersync'], () => {
// page changes gulp.watch(php.src, ['php'], browsersync ? browsersync.reload : {});
// image changes gulp.watch(images.src, ['images']);
// CSS changes gulp.watch(css.watch, ['css']);
// JavaScript main changes gulp.watch(js.src, ['js']);
});
Finally, add a default
Gulp task which runs an initial build and starts the watch
task:
// default taskgulp.task('default', ['build', 'watch']);
Now run gulp
from the command line. The console will display output which includes lines similar to:
[BS] Proxying: http://localhost[BS] Access URLs: ------------------------------------- Local: http://localhost:3000 External: http://192.168.1.99:3000 ------------------------------------- UI: http://localhost:8001 UI External: http://192.168.1.99:8001 -------------------------------------[BS] Watching files...
Rather than loading your development site from http://localhost/
, enter the address http://localhost:3000/
or the External URL if you are viewing from another device. Your WordPress site will load as before but Gulp will watch for changes and apply the updates immediately. You’ll need never switch to your browser and click refresh again!
Hit Ctrl/Cmd + C when you want to stop Gulp processing.
Enhance Further
We’ve covered the basics of WordPress theme development with Gulp but there are several thousand plug-ins to aid your workflow. You could consider additional tasks to:
- lint your PHP and JavaScript code
- create WordPress theme styles from
package.json
infomation - cache-bust WordPress assets
- automatically deploy your theme to a production server.
A few hours writing Gulp tasks could save many days of manual processing over the long term.