Conditionally Loading JavaScript/CSS for Shortcodes

I released a plugin that creates a shortcode and requires a JavaScript file and a CSS file to load on any page that contains that shortcode. I could just make the script/style load on all pages, but that’s not the best practice. I only want to load the files on pages that call the shortcode. I’ve found two methods of doing this, but both have problems.

Method Best Answerets a flag to true inside the shortcode handler function, and then checks that value inside a wp_footer callback. If it’s true, it uses wp_print_scripts() to load the JavaScript. The problem with this is that it only works for JavaScript and not CSS, because CSS should be declared inside <head>, which you can only do during an early hook like init or wp_head.

Method 2 fires early and “peeks ahead” to see if the shortcode exists in the current page content. I like this method much better than the first, but the problem with it it won’t detect if the template calls do_shortcode().

So, I’m leaning towards using the second method and then trying to detect if a template is assigned, and if so, parse it for the shortcode. Before I do that, though, I wanted to check if anyone knows of a better method.

Update: I’ve integrated the solution into my plugin. If anyone is curious to see it fleshed out in a live environment you can download it or browse it.

Update 2: As of WordPress 3.3, it’s now possible to call wp_enqueue_script() directly inside a shortcode callback, and the JavaScript file will be called within the document’s footer. That’s technically possible for CSS files as well, but should be considered a bad practice because outputting CSS outside the <head> tag violates W3C specs, can case FOUC, and may force the browser to re-render the page.

7

Based on my own experience, I’ve used a combination of method 1 & 2 – the architecture and footer scripts of 1, and the ‘look-ahead’ technique of 2.

For the look-ahead though, I use regex in place of stripos; personal preference, faster, and can check for ‘malformed’ shortcode;

preg_match( '#\[ *shortcode([^\]])*\]#i', $content );

If you’re concerned about authors using do_shortcode manually, I would opt to instruct them to use an action call enqueue your pre-registered style manually.

UPDATE: For the lazy author who never RTFM, output a message to highlight the error of their ways 😉

function my_shortcode()
{
    static $enqueued;
    if ( ! isset( $enqueued ) )
        $enqueued = wp_style_is( 'my_style', 'done' ); // cache it so we don't repeat if called over and over

    // do shortcode
    $output="";

    if ( ! $enqueued )
        // you can output the message on first occurence only by wrapping it in the previous if
        $output .= <<<HTML
<p>Attention! You must enqueue the shortcode stylesheet yourself if calling <code>do_shortcode()</code> directly!</p>
<p>Use <code>wp_enqueue_style( 'my_style' );</code> before your <code>get_header()</code> call inside your template.</p>
HTML;

    return $output;
}

Leave a Comment