Updated: August 30th, 2014

Introduction

wordpress logo In this tutorial, I am going to introduce a WordPress technique that I believe was unpublished until I raised the question a few days ago on the WordPress forums.

In short, the problem I was trying to solve was plugins unnecessarily loading their JavaScript and CSS on *every* page of the blog, even when doing so would achieve absolutely nothing and the plugin wouldn't do any work.

Update #1: I have posted a follow-up in response to some comments received around the web.

Update #2: There is a solution that can be considered a compromise as it works well for loading JavaScript but doesn't handle CSS.

I briefly mentioned this approach here but Scribu decided to expand on it by providing a nice Jedi-themed tutorial. It is available here.

Let me explain using this example:

  • a code formatter plugin only does something useful when it sees a [code] shortcode in any post on the page.
  • most of your posts do not contain the [code] shortcode as you don't include code snippets that often or you only started using this particular plugin recently.
  • the plugin, however, loads the CSS and JS (which are most likely GeSHi and take up loads of space) on every page.
  • these CSS and JS do absolutely nothing on most page loads.
  • bandwidth is wasted, extra DNS and HTTP requests are processed, the browser is slowed down, and for what? For no good reason, other than the plugin author didn't know how to achieve this conditional loading.

If you think about it, there are many plugins that only do something once in a blue moon. Table of contents, text manipulators, galleries, sliders, etc, etc. If only they loaded their frontend code strictly when necessary, most page loads would suddenly become much lighter.

So what can we do to solve this? Let's look at a few techniques.

Loading CSS And JS In Place?

Here's one, albeit pretty bad, solution – only print the CSS and JS includes if and when you determine somewhere in the middle of loading the posts that the scripts and styles are indeed needed, then set a flag to avoid printing them again. In our example, that would be when the plugin detects the [code] shortcode.

This, however, is a mediocre solution because, while it's not a bad idea to load Javascript in the footer, CSS should be loaded in the header, otherwise the page might look unformatted until the CSS is reached.

Additionally, it's not the cleanest and most robust solution because you shouldn't be writing <script> and <style> tags manually but rather using wp_enqueue_style() and wp_enqueue_script() functions.

What's This About wp_enqueue_FOO?

Now, you might say: "What's this about wp_enqueue_style(), wp_enqueue_script(), and then hooking into 'wp_print_scripts', 'wp_print_styles', 'admin_print_scripts', and 'admin_print_styles' hooks"? You know about these, right? Right??

Allow me to explain this, in my opinion, greatest and most underused WordPress paradigm in a short refresher:

WordPress has a great system of queuing up the scripts and styles your script will need to use and printing them all in one go, rather than hooking into wp_head and printing <style> and <script> tags manually.

This queuing system achieves 2 main goals:

  • the same scripts are not loaded multiple times, such as jQuery, scriptaculous, or any other custom script or style your plugins may share between each other or even other plugins.
  • it introduces support for establishing dependencies. You can specify that your script or style depends on another script or style, and WordPress will take care of loading them in the right order. Guaranteed.
  • oh what the hell, here's a 3rd one: elegance.

Here is the way this usually works:

  • in the beginning of your plugin you attach to wp_print_scripts and/or wp_print_styles hooks. For example:

    1
    2
    
    add_action( 'wp_print_scripts', 'enqueue_my_scripts' );
    add_action( 'wp_print_styles', 'enqueue_my_styles' );

    What this will do is call the functions in the 2nd parameter when it's time to execute any functions associated with the hooks in the 1st parameter. It is the main principle behind the WordPress plugin architecture.

  • looking at the script example, in the enqueue_my_scripts() function, you can do something like:
    1
    
    wp_enqueue_script( 'my_awesome_script', '/script.js', array( 'jquery' ));

    which would queue up your script to be printed later but only after jQuery.

    If you or some other plugin calls wp_enqueue_script() with the same first parameter (unique handle), it will just be ignored, rather than printed to the page twice.

  • styles are exactly the same, except you use wp_enqueue_style()

There is a variation of this functionality for the admin styles and scripts – all you have to do is change the hooks to admin_print_styles and admin_print_scripts. Ozh made a nice post on this topic here – check it out.

Enqueuing Alone Is Not Enough

Enqueuing is great for loading your JS and CSS but using it alone doesn't achieve the conditional behavior that we are looking for here.

This is a classic case of Chicken or the Egg, because WordPress makes only one pass through all of the content.

You see, since the header needs to be printed before the content, wp_print_scripts and wp_print_styles hooks are triggered before you even get to the posts. If you enqueue a script or style from within the 'the_content' hook, for example, the queued up scripts and styles will never get printed. It's too late to print them then anyway, as you're already in the middle of printing the posts.

The Solution

What we need to do is take a step back, before even printing the header, and then peek ahead.

Sure, this adds an extra pass over some data, but since no filters are applied during this process and if you avoid regular expressions (using stripos(), for example), this extra pass should be quite negligible.

A word of warning though: I'd rather see false positives (enqueuing when it's not needed) than false negatives (miss enqueuing when it's needed), so please do your matching wisely and test well.

The upside, however, can be potentially very substantial.

Credit goes to @white_shadow for the idea.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
add_filter('the_posts', 'conditionally_add_scripts_and_styles'); // the_posts gets triggered before wp_head
function conditionally_add_scripts_and_styles($posts){
	if (empty($posts)) return $posts;
 
	$shortcode_found = false; // use this flag to see if styles and scripts need to be enqueued
	foreach ($posts as $post) {
		if (stripos($post-&gt;post_content, '[code]') !== false) {
			$shortcode_found = true; // bingo!
			break;
		}
	}
 
	if ($shortcode_found) {
		// enqueue here
		wp_enqueue_style('my-style', '/style.css');
		wp_enqueue_script('my-script', '/script.js');
	}
 
	return $posts;
}

This simple function fires before the header gets printed, as it's attached to the 'the_posts' hook. However, this time it has full access to the posts' content.

I have tested this method and it works really well – if you have heavy scripts in your plugin, please do us, users, a favor and incorporate this logic into it.

Conclusion

In this tutorial, you have seen a method of loading scripts and styles for you plugin conditionally. This technique allows for less bloated pages and faster page loads.

Plugin developers, what is your take on this solution? Do you use another method? Please share in the comments.

● ● ●
Artem Russakovskii is a San Francisco programmer and blogger. Follow Artem on Twitter (@ArtemR) or subscribe to the RSS feed.

In the meantime, if you found this article useful, feel free to buy me a cup of coffee below.