As developers we should always be looking for ways to speed up and automate our workflow as much as we can but this isn't always an easy process. We have to remember to compile, minimize, concatenate and overall make our files more efficient to ensure faster load times to our end users while keeping an organized file structure that allows us apply changes easily. Luckily there are tools that help us with this process and I would like to share how I have set them up to improve my WordPress theme development.
Tools of the Trade
We all know we should optimize our CSS and JavaScript files before deploying our WordPress site. Bombarding our stylesheets with @import
statements or including multiple files using <script>
or <link>
tags isn't the most efficient way, since it'll increase the number of requests the browser has to make when loading our sites. Changing this manually could be a daunting task, add the fact that we also should be optimizing our images and HTML pages – we're in for a lot of work.
Fortunately some really smart folks have created great tools that can assist us make our workflow as straight forward as possible:
I'd like to focus on how to implement these technologies for WordPress theme development. I don't mean to give an in-depth analysis of these tools since there are some articles already in the Tuts+ Network that do a great job explaining how to install and configure them, such as:
- Mastering Sass
- Meet Grunt: The Build Tool for JavaScript
- The Official Guide to HTML5 Boilerplate
- Introducing Nettuts+ Fetch
The Workflow
Without further ado, I'm going to develop a small test theme that will describe the steps I take to incorporate these tools together.
Step 1 Download WordPress
We'll use the Nettuts+ Fetch bundle to download the latest version of WordPress, of course if your using an IDE other than Sublime Text 2 you'll need to use a different method.
Step 2 Set Up the Theme File Structure
For our test theme we'll create the following file structure:
Let's take a quick look at each folder and file and see what they are for:
- build – H5BP build script
- img – Images
- js – JavaScript files
- sass – Stylesheets
- src – Grunt/Compass configuration files
functions.php – You can include any function you need in this file, I start out loading jQuery in my wp_head
action (best practices say to load jQuery and other scripts before the closing body tag but plugins like to load custom scripts in wp_head
and if they rely on jQuery they won't work), also I load my scripts in the wp_footer
action (we haven't created this file yet).
function jvs_theme_setup() { // Enqueue jQuery wp_enqueue_script('jquery'); // Enqueue custom theme scripts in footer wp_enqueue_script('custom-scripts', get_bloginfo('template_url') . '/js/script.min.js', array('jquery'), false, true); } add_action('after_setup_theme', 'jvs_theme_setup');
index.php – Nothing extra special here just a file I like to start with in all my projects, notice that the main stylesheet is being called after wp_head
this allows us to override custom styles added by plugins without using nasty !important
declarations.
<!DOCTYPE html> <html <?php language_attributes(); ?> class="no-js"> <head> <meta charset="<?php bloginfo('charset'); ?>" /> <link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" /> <link rel="profile" href="http://gmpg.org/xfn/11" /> <meta name="viewport" content="width=device-width" /> <title><?php wp_title(' | '); ?></title> <?php wp_head(); ?> <link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>" /> </head> <body <?php body_class(); ?>> <?php wp_footer(); ?> </body> </html>
You may have noticed that neither the style.css nor script.min.js files exist yet, don't worry we'll take care of that.
Step 3 Set Up Stylesheets With Sass/Compass
First we need to set up our config.rb file since this will tell compass where our stylesheets are and how we want to compile them, we'll store it inside the src folder:
# Theme directories: http_path = "" css_dir = ".." sass_dir = "../sass" images_dir = "../img" javascripts_dir = "../js" # You can select your preferred output style here (can be overridden via the command line): output_style = :compact # To enable relative paths to assets via compass helper functions. relative_assets = true # To disable debugging comments that display the original location of your selectors. # line_comments = false
Nothing fancy here, this just means that Compass will look for our .scss files inside the sass folder and put the compiled stylesheets inside our theme's root folder, if you want to know more about how to set up the config file just refer to the official documentation.
Let's revisit our sass folder again and see what we can do now.
Now we can separate related styles into their own files inside a sub-folder called partials and have a single style.scss file where can we put the main styles which should look like this:
// Compass library @import "compass"; // Global variables @import "partials/base.scss"; // Normalize elements @import "partials/normalize.scss"; /* ==|== Primary Styles ===================================================== Author: ========================================================================== */ // Main styles go here /* ======================================================================= */ // WP-Specific CSS Styles @import "partials/wp.scss"; // Non-semantic helper classes @import "partials/helpers.scss";
Notice how we prefixed the partial files with an underscore, this tells compass to ignore them since we just want to compile the main stylesheet. Now if we navigate to our src folder in our terminal and run compass compile
it'll create a new style.css file inside our sass folder with all our partials concatenated in a single stylesheet. However, we're missing the required comment header lines for WordPress themes, right?
Step 4 Set Up Grunt
You'll need to have Grunt installed which at the same time requires Node.js but I'll assume you already have it. By default Grunt only supports functionality for JavaScript files but luckily there are third party extensions like grunt-css and grunt-compass that can take care of the rest of the files we need.
So let's navigate to our src folder in our terminal and run the following commands:
npm install grunt-css npm install grunt-compass
This will install both extensions locally so we can import / load them with Grunt.
Now let's organize our js folder:
I created a sub-folder called libs where we can place any third-party script that we need, I also created a script.js file where we'll code our custom functions that get executed usually when the DOM's ready.
Now to set up Grunt's configuration options we'll need to create a new file called grunt.js, so let's make one in our src folder with the following content:
/*global module:false*/ module.exports = function(grunt) { // Project configuration. grunt.initConfig({ meta: { version: '0.1.0', banner: '/*! PROJECT_NAME - v<%= meta.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %>\n' + '* http://www.yoursite.com/\n' + '* Copyright (c) <%= grunt.template.today("yyyy") %> ' + 'Your Company; Licensed MIT */', wpblock: '/*! \n' + 'Theme Name: Test Theme \n' + 'Theme URI: http://www.yoursite.com \n' + 'Description: Test theme \n' + 'Author: Your Name \n' + 'Author URI: http://www.yoursite.com \n' + 'Version: 1.0 \n' + '*/' }, lint: { files: ['grunt.js', '../js/script.js'] }, concat: { dist: { src: ['<banner:meta.banner>', '../js/libs/*.js', '../js/script.js'], dest: '../js/script.min.js' } }, min: { dist: { src: ['<banner:meta.banner>', '<config:concat.dist.dest>'], dest: '<config:concat.dist.dest>' } }, cssmin: { dist: { src: ['<banner:meta.wpblock>', '../sass/style.css'], dest: '../style.css' } }, watch: { files: ['<config:lint.files>', '../sass/*.scss'], tasks: 'default' }, jshint: { options: { curly: true, eqeqeq: true, immed: true, latedef: true, newcap: true, noarg: true, sub: true, undef: true, boss: true, eqnull: true, jquery: true, devel: true, browser: true }, globals: {} }, uglify: {}, compass: { dist: { forcecompile: true } } }); // Default task. grunt.registerTask('default', 'lint concat min compass cssmin'); // Compass tasks grunt.loadNpmTasks('grunt-compass'); // CSS tasks grunt.loadNpmTasks('grunt-css'); };
Wow! That's a lot more complex than our Compass file but I'll do my best to try to explain it, again read grunt's official documentation to know more about it.
What the config file does is to tell Grunt to do the following, in order, every
time we run the grunt
command from our terminal inside our src folder:
- Check for errors in our grunt.js and js/script.js files using JSHint.
- Concatenate all our javascript libraries and custom scripts together in a
file called script.min.js which is the one we reference in our functions.php file. - Minimize the script.min.js file.
- Use grunt-compass to compile our stylesheets using our config.rb file.
- Use grunt-css to minimize our style.css file and place the new version in our theme's base folder. It'll also prepend the comments block that we set on the wpblock option to the stylesheet so it can be read by WordPress.
Even better, we can run grunt watch
in our terminal and it'll watch for changes
in our JavaScript and Sass files and run the tasks automatically. Sweet huh?
By the way, Grunt not only minifies javascript files by removing whitespace and new lines, it optimizes your scripts by renaming variables like var myLongVariable = true;
to var a = true;
plus other kinds of magic to make them even smaller! I have to admit I was a bit skeptical about this feature but it's actually really smart to make sure it won't break your code (so far it hasn't broken mine).
grunt-compass can't minify (at least without removing comments) and grunt-css can't read .scss files, that's why we needed to compile Sass files first into a single .css file.
Step 5 Set Up H5BP Build Script
We could use what we have so far and start coding our theme but why stop now when we still have dirty templates and images? To handle this I have modified the ant build script that used to come bundled with the HTML5 Boilerplate. This one depends on ant so make sure you have it installed.
This one's really long and I don't want to bore you guys displaying the whole config build file here, but in summary every time you're ready to deploy your theme into the real world we just need to navigate to our build folder in our terminal and run ant build
, this will:
- Optimize our PNG and JPEG images.
- Optimize our template files (index.php, single.php, etc).
- Remove all unnecessary folders and files (src, sass, etc).
So in the end we'll end up with a new folder in our theme base folder called
publish that'll look like this:
All theme files ready for deployment.
Final Thoughts
So there you have it, that's basically my theme development workflow. Keep in mind that even though it looks really long you just have to set it up once and fetch the base theme files every time you need them so in the end you'll just need to:
- Fetch WordPress
- Fetch the base theme files
- Run
grunt
orgrunt watch
in your terminal
I'm sure there are ways to improve it so let me know in the comments below if you guys find anything interesting to make this even better.
Update: We've made a couple of minor fixes to the code snippets above. Also, there's now a download link to the GitHub repository for this tutorial, and you can find the full build files etc. there.
Comments