Conditional Scripts & Styles for WordPress Shortcodes

WordPress is not great at loading resources when it comes to shortcodes. In fact, I’d say it’s pretty bad. For theme and plugin developers to make sure a necessary script or style will be available when a shortcode is used, they have to enqueue those resources on EVERY page.

This means that I might use a contact form plugin for one page on my site, but any styles or scripts for that form are on every other page for no reason.

You could argue that once a user downloads a resource they will have a local cached version available for faster delivery, and you would be right. But users still take a bit of a performance hit even from local cached resources. The performance hit is teeny-tiny, almost nothing, but they add up.

So how many plugins do you use on your sites..?

Fortunately, there is hope. I’ll explain at a couple options I’ve found first, or you can scroll down to the good stuff below.

Option #1 – Enqueue Scripts in the Shortcode Output

I’ve come across one method to conditionally load scripts which works OK. The concept goes something like this: first you use wp_register_script() to register your script with a unique handle so WordPress knows where to find it; then, where you would actually output your shortcode, you sneak in a quick wp_enqueue_script() with your unique handle, and WordPress will add it to the page along with the markup. If the shortcode is never used, your script is never added. Cool!

Matt Cromwell wrote a nice article with more details on how to do this: Enqueuing Scripts Only When Widget Or Shortcode Is Present.

The problem:

  • The shortcode fires with the content, so your scripts can only be loaded at the bottom of the page.
  • This doesn’t work for some scripts that should be at the top of the page (jQuery, Typescript, Google Fonts, etc.).
  • This also doesn’t work for styles. Otherwise you get FOUC. “What the FOUC!?”

Option #2 – Live Search the Content for Shortcodes

How about searching the content of a page or post for the presence of a shortcode? Here’s how it works: as WordPress is building out the page, check whether a shortcode exists in the content, and if the shortcode tag is present, enqueue the resources. In other words, every time a page loads, WordPress will search the content of that posts for a shortcode’s tag and conditionally load the scripts and styles. So now we get styles too. Cool!

The problem:

You’re doing a PHP string search EVERY time the page loads. This is becomes very resource intensive and would probably cause more performance issues than it’s worth. Of course server side caching could solve this issue, but it’s still not a great solution.

Option #3 – Use a Plugin

There are a few plugins out there that let you conditionally load or exclude styles and scripts on your site. My two favorite are Plugin Organizer and WP Asset CleanUp. There’s pros and cons for each, but the bottom line is this: you configure the plugin to enqueue/dequeue styles and scripts on your site based on whatever page is being loaded.

The problem:

  • This process is very manual since you need to know the content of each page and set it up accordingly.
  • This is really only an option for site administrators that know what content is on what page.
  • This method is therefore not available to theme and plugin developers.

Maybe there’s another way…

I had this crazy idea the other day. What if we only enqueue scripts and styles if a shortcode exists in the content, but we only search for a shortcode tag whenever the page/post is saved? That way we aren’t running a resource intensive process on every page load.

Here’s the idea:

  • Set up a function and only run it when a post is saved (using the ‘save_post’ hook).
  • In that function we map a shortcode tag to resource handles for it’s respective styles and/or scripts.
  • We then do a search of the content to see if that shortcode exists, and if it does, we add the mapped resource handles to a custom field.
  • Finally, whenever a page loads, we enqueue all the handles in the posts’ custom field (using the standard ‘wp_enqueue_scripts’ hook).

Want to see what it looks like (View on GitHub):