JavaScript the WordPress Way / Part 2

In Part 1 we discussed the conflicts that can occur on a WordPress site if themes and plugins add JavaScript using <script> tags. We introduced the wp_register_script and wp_enqueue_script functions developed to avoid these conflicts.

In this section we’ll deal with a more complicated example and use Google’s AJAX libraries API to lower your bandwidth costs. We’ll also take what we’ve learnt about including JavaScript and apply it to our CSS.

A more complicated example

The sample code yesterday included a simple example of using the same JavaScript file throughout your site. Let’s spice things up slightly by introducing the following circumstance. Consider that you have three JavaScript files:

  • base.js is the base JavaScript file to be used throughout the site. It uses the jQuery library and must load in the HTML <head>;
  • posts.js loads on pages and posts and only calls functions from the base JavaScript file but doesn’t use the jQuery library directly. It can load in the HTML footer.
  • archives.js loads on all other pages throughout your site (except admin). It calls functions from your base JavaScript file and makes direct use of the jQuery library. It can load in the HTML footer.

In this situation, you could change your base.js to use another library – say, Prototype – and it would have no effect on the posts.js. So, posts.js can be said not to depend on jQuery directly.

Changing libraries would require edits to the third file, in which case archives.js does depend on jQuery directly.

Registering the Files

The code to register those JavaScript files and conditions with WordPress is:

wp_register_script (
  'mytheme-base', /* handle */
  get_bloginfo('template_url') . '/base.js', /* source */
  array('jquery'), /* requires jQuery */
  1.0 /* version 1.0 */
);

wp_register_script (
  'mytheme-posts', /* handle */
  get_bloginfo('template_url') . '/posts.js', /* source */
  array('mytheme-base'), /* requires base.js */
  1.0, /* version 1.0 */
  true /* load in footer */
);

wp_register_script (
  'mytheme-archives', /* handle */
  get_bloginfo('template_url') . '/archives.js', /* source */
  array('jquery', 'mytheme-base'), /* requires jQuery & base.js */
  1.0, /* version 1.0 */
  true /* load in footer */
);

This code says to WordPress:

  • If loading posts.js, also load base.js;
  • If loading archives.js, also load jQuery and base.js;
  • If loading base.js, also load jQuery;

Each of these are separate checks (if) rather than a series of options (if, else if).

Enqueueing the files

All the hard work has been done registering the files, WordPress knows what each file requires to work and where in the HTML (<head> or footer) the <script> tags should be inserted.

Now it’s a simple process of checking if the visitor is loading a post or page and requesting the appropriate file.

We need to delay the check slightly, otherwise WordPress won’t know if the user is on a page, post or elsewhere. The first step is to enclose the check in a function.

function que_scripts(){
  if (!is_admin()) { //visitors only
    if (is_singular()) { // pages & posts
      wp_enqueue_script('mytheme-posts');
    }
    else {
      wp_enqueue_script('mytheme-archives');
    }
  }
}

Then tell WordPress when to execute the function. For this we use the action wp_print_scripts. This runs the code above before WordPress attempts to output the <script> tags to your HTML.

add_action('wp_print_scripts', 'que_scripts')

There is no need to enqueue jQuery or base.js directly. WordPress knows to add those to the HTML based on the dependancies listed when registering the files.

Using the Google AJAX Libraries API

Loading all these libraries from your own server may seem like a waste of your bandwidth considering you could be loading the libraries directly from Google’s servers.

With a bit of luck, your visitor will have Google’s version of the libraries in their browser’s cache already and your site will load a little quicker.

It’s a bit messy to do this yourself, especially since jQuery needs to be kept in noConflict mode. Fortunately Jason Penny has developed a plugin, called “Use Google Libraries”, to do the hard work for you.

“Use Google Libraries” is the first plugin I add when setting up sites for me and my clients.

Making our super-broken example super-fabulous

If, when developing their theme and plugin, George and Richard from our example in Part 1, had used the wp_register_script and wp_enqueue_script WordPress functions to load their JavaScript, WordPress would know that only one version of jQuery needs to be loaded for both the theme and the plugin to work.

As WordPress releases come in fits and bursts, sometimes the version of the JS libraries included with WordPress fall behind the current version of the library available otherwise.

This is a small price to pay for the knowledge that our sites will remain super-fabulous rather than super-broken, at least when it comes to the JavaScript.

A bonus for CSS

By now the reasons for using wp_register_script and wp_enqueue_script should be clear. If you want to go that one step further, you can use the equivalent functions for your CSS.

As CSS should always be loaded in the HTML <head>, there is no option to load the CSS files in the footer of the HTML. Otherwise the CSS functions take the same arguments as their JavaScript equivalents. The CSS functions are:

  • wp_register_style
  • wp_enqueue_style

The four parameters they take are:

$handle
(required for both functions) Name of the style sheet
$source
(required for wp_register_style) – URL of the script. Also required by wp_enqueue_style if the style is unregistered.
$dependancies
(optional) – an array of handles the style sheet depends on
$version
(optional) – version number

WordPress doesn’t include any style sheets bases, such as YUI CSS, in the default distribution, so the main purpose of the CSS functions is to allow you to keep track of your version numbers and to call in style sheets only as they’re needed.

Conditional comments

Unfortunately the WordPress functions for JavaScript do not allow for conditional comments, so scripts targeting older versions of IE (okay, I’m referring to PNG fixers for IE6) need to be coded directly into your theme’s header.php or footer.php.

On the other hand, the CSS functions do allow for conditional comments, in a round-about fashion. Let’s register a CSS file we’ll be targeting at IE6.

wp_register_style (
  'mytheme-ie6', /* handle */
  get_bloginfo('template_url') . '/ie6.css', /* source */
  array('mytheme-css'), /* requires mytheme-css (not shown) */
  1.0 /* version 1.0 */
);

Behind the scenes WordPress is adding the stylesheet to the object $wp_styles. To add the conditional comments you need to access the object more directly. To target the above to IE6, the command is:

$wp_styles->registered['mytheme-ie6']->extra['conditional'] = 'IE 6';

If, as in the complicated example above, you need to check where a user is before enqueueing your stylesheet, again you need to enclose the enqueueing command in a function and run it on an action, in this case the action wp_print_styles.

For example, to output the IE6 stylesheet above on pages and posts only, the full code would be:

function que_styles(){
  if (!is_admin()) { //visitors only
    if (is_singluar() {
      wp_enqueue_style('mytheme-ie6');
    }
  }
}

add_action('wp_print_styles', 'que_styles')

Conclusion

The methods described in this tutorial may appear to complicate matters for little pay off, especially if you’re developing a theme or plugin for your own site.

Replacing your <script> tags with the code above, it is true, will have almost no effect on the HTML or JavaScript output by WordPress. What’s worse, if you use the $ alias for jQuery in your JavaScript, you’ll need to edit both the theme’s php and JavaScript files.

These functions, wp_register_script and wp_enqueue_script, aren’t about now, however, they’re about “then”.

  • Then… I activated this plugin and my JavaScript stopped working.
  • Then… I changed the theme and my favourite plugin stopped working
  • Then… I looked at the source code, and two copies of jQuery were being sent to every visitor

The WordPress developers have seen the problems JavaScript conflicts can cause, and developed these functions to make your theme or plugin more robust. It’s the added robustness, for such little effort, that make these functions worth using.