Wordpress Theme Javascript Optimization

This post shows how to combine and minify multiple javascript files in a Wordpress theme into one javascript file. The benefit is a single request to a javascript file that has been compressed by minification instead of multiple request to larger javascript files.

package.json

The package.json file contains meta data about your app or module and it includes the list of dependencies to install from Node Package Manager (NPM) when running npm install. NPM is bundled with Node.js; if you have not done so already, install Node.js so you have it. Then create and save this file in your themes root directory, for example /wp-content/my-theme/package.json. Then when you run npm install, the package.json file is read and the respective node modules are installed. More information is available here.

/* package.json */
{
  "name": "my-theme",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-jshint": "~0.10.0",
    "grunt-contrib-uglify": "~0.6.0"
  }
}
# install node_modules
$ npm install
gruntfile.js

The Grunt Javascript Task Runner will be used to configure and run the minification of /js/src/*.js into /js/main.js using UglifyJs.

/* gruntfile.js */
module.exports = function(grunt) {
  'use strict';
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
      build: {
        files: {
          'js/main.js': ['js/src/*.js']
        }
      }
    }
  });
  // Load the plugin
  grunt.loadNpmTasks('grunt-contrib-uglify');
  // Default task(s).
  grunt.registerTask('default', ['uglify']);
};
file structure

Here is what the themes javascript file structure looks like for this example. The /js/src folder contains all of the individual javascript files for your theme. When you run grunt, these are all combined and minified into /js/main.js

javascript file location
Partial view of themes files showing location of javascript

functions.php

The functions.php file controls the loading of the themes javascript resources. In the functions.php file, the wp_enqueue_script() function links the script to the page. The pre-existing wp_enqueue_script() function calls are no longer valid since the javascript files have been moved to the /js/src/ folder. Here is an example of the code from the pre-existing functions.php that was linking the scripts:

function my-theme_scripts() {
  wp_enqueue_style( 'my-theme-style', get_stylesheet_uri() );

  wp_enqueue_script( 'my-theme-deflist', get_template_directory_uri() . '/js/deflist.js', array('jquery'), '20141011', true );

  wp_enqueue_script( 'my-theme-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '20120206', true );
  
  wp_enqueue_script( 'my-theme-skip-link-focus-fix', get_template_directory_uri() . '/js/skip-link-focus-fix.js', array(), '20130115', true );

  if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
  wp_enqueue_script( 'comment-reply' );
  }
}
add_action( 'wp_enqueue_scripts', 'my-theme_scripts' );

Here is an example of the code from functions.php after making the changes to link /js/main.js instead. Since /js/src/deflist.js depends on jQuery, so does /js/main.js and the $deps array parameter is set to 'jquery'. For more information, refer to the wp_enqueue_script function reference

function my-theme_scripts() {
  wp_enqueue_style( 'my-theme-style', get_stylesheet_uri() );

  wp_enqueue_script( 'my-theme-main', get_template_directory_uri() . '/js/main.js', array('jquery'), '20141011', true );

  if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
  wp_enqueue_script( 'comment-reply' );
  }
}
add_action( 'wp_enqueue_scripts', 'my-theme_scripts' );

Time to Grunt

Run Grunt when you are ready to create or overwrite /js/main.js

# run the default task(s)
$ grunt

Resources

comments powered by Disqus