Quick Tip: Improving Shortcodes with the has_shortcode() Function

Quick Tip: Improving Shortcodes with the has_shortcode() Function

Tutorial Details
  • Difficulty: Intermediate
  • Estimated Completion Time: 5 Minutes
  • Version (if applicable): 2.8+
  • Program: WordPress

One of the mistakes that many developers make when creating shortcodes (in themes and plugins) is always loading all scripts and styles. For efficiency’s sake, and also to better prevent conflicts, scripts and styles should only be loaded when they are needed. This is a really handy function that will let you perform any action you want, such as loading scripts and styles, when, and only when, a post has a particular shortcode.


Step 1 Writing the Function

The functions is really pretty simple. All we’re going to do is pass a short code as a parameter, then check the content of the current post for that short code

You can paste this code in your functions.php or your own plugin file.

// check the current post for the existence of a short code
function has_shortcode($shortcode = '') {
	
	$post_to_check = get_post(get_the_ID());
	
	// false because we have to search through the post content first
	$found = false;
	
	// if no short code was provided, return false
	if (!$shortcode) {
		return $found;
	}
	// check the post content for the short code
	if ( stripos($post_to_check->post_content, '[' . $shortcode) !== false ) {
		// we have found the short code
		$found = true;
	}
	
	// return our final results
	return $found;
}

The first thing we do is pass a parameter to the function called $shortcode and we set it to be blank. Next we get the post object of the currently displayed post. We do this by using the get_post() function to return the post object of the given ID, which we obtain with get_the_ID(), from the database. Once we've stored the post object in a variable, $post_to_check, we can search through its content for the specified short code

After we've retrieved the post object, we set the $found variable to false, and then make sure that $shortcode parameter is not empty, and if it is, we exit the function by returning the $found variable as false.

Now we're ready to search through the post's content for the desired short code. We do this by using the stripos() function. This function takes two parameters, the string in which to search (the haystack), and the string for which to search (the need). In case, our haystack is the post's content, which is accessed with $post_to_check->post_content, and the needle is the short code we passed to our custom function as a parameter. Notice that we have left the closing "]" off of the needle parameter; this is because we need to take into account short codes that accept parameters, and thus will not have the closing bracket immediately after the short code name.

If stripos() finds the short code, we set the $found variable to true and then return our results. That's it, our function is complete.


Step 2 Using the Function

This function can be used anywhere in your theme templates (not only in the loop) and is extremely useful for selectively loading scripts and styles.

To check if the current post has a specific short code, you can use the function like this:

if(has_shortcode('your_short_code')) {
	// perform actions here
}

Probably one of the most common places you would use this function is in your header.php when loading styles and scripts, like so:

if(has_shortcode('contactform')) {
	wp_enqueue_style('contactfom', get_bloginfo('template_directory') . 'includes/contactform.css');
	wp_enqueue_script('contactfom', get_bloginfo('template_directory') . 'includes/contactform.js');
}

Conclusion:

When plugins and themes that fail to make use of good coding standards are so abundant, it is important that we always strive to develop with high quality standards in mind so that we can help prevent as many possible script / style conflicts as possible. One of the ways that we can do this is by only loading scripts / styles for our short codes when they are actually needed.

Read more about using and creating shortcodes in your projects here!

Pippin Williamson is mordauk on Codecanyon
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.wpexplorer.com AJ

    Plus 1 – I am already using it :)

    • http://pippinspages.com Pippin

      Sweet, thanks :)

  • http://www.onyxsolution.com hawaii web design

    cool! this is a great quick tip, I will deff use it in my next web designs =)

  • http://digitalzoomstudio.net DigitalZoom Studio

    Yes, but that is dangerous for users who want to put your plugin in template file or widget via the direct php code :)

    • Pippin

      You mean with do_shortcode() ?

  • http://shabushabu.eu Boris

    You really shouldn’t use wp_enqueue_script or wp_enqueue_style in your theme templates, like header.php, or outside an action. It can lead to problems (see here:http://codex.wordpress.org/Function_Reference/wp_enqueue_script). Instead attach them to the correct hooks, like wp_enqueue_scripts for the frontend and admin_enqueue_scripts for the backend.

    Here’s a solution I tend to use in my code:

    class SOME_Shortcode
    {
    static $add_script;

    function init()
    {
    add_shortcode( ‘someshortcode’, array( __CLASS__, ‘handle_shortcode’ ) );
    add_action( ‘init’, array( __CLASS__, ‘register_scripts’ ) );
    add_action( ‘wp_footer’, array( __CLASS__, ‘print_scripts’ ) );
    }

    function register_scripts()
    {
    // use wp_register_script to register all your scripts
    }

    function handle_shortcode()
    {
    self::$add_script = true;

    // deal with the actual shortcode code here
    }

    function print_scripts()
    {
    if( ! self::$add_script )
    return;

    // use wp_print_scripts( array(.., .., ..) ) to add all scripts in the footer
    }
    }
    SOME_Shortcode::init();

    It doesn’t work well with CSS, but you’re much more likely to need extra JS, rather than extra CSS. You should be using standard WP classes as much as possible for your HTML. You can also use the above method with widgets.

    • Pippin

      Boris, you’re right about using the hooks for loading scripts and styles. A user could still use this function to call the add_action() function, which would fire the correct hook.

  • Jacob Dubail

    What would you recommend for situations where site owners could use the `do_shortcode()` method in their template?

    As a plugin author, I’m very interested in only loading resources when absolutely necessary, but I want to be sure that I account for a case like this.

    Thanks for the tip!

    • http://pippinspages.com Pippin

      That’s a really good question. This method will not work for that. You would have to include some sort of hook in your shortcode that you could then check for, though it would be rather difficult to do.

  • http://andrewnacin.com/ Andrew Nacin

    What about prefixing functions such as these?

    • http://pippinspages.com Pippin

      Andrew, you’re absolutely right. The function should be prefixed with something unique to better avoid conflicts.

  • HHS

    That sounds like a huge performance hit – seems like it would be better to use the function to set a hidden custom field on publish/update and check for the meta key when loading up a post instead.

    Also, why not start the function off with the check for $shortcode right off the bat? And also pass in the post content instead, so you don’t retrieve the post twice.

    • http://pippinspages.com Pippin

      Using a meta key wouldn’t work any better because you would still have to search through the post content for the short code before you could add the meta key. Passing the post content, however, is a good idea. That would reduce the resources consumed.

  • http://www.jaskni.com JASKNi

    thnx for this tutorial.

  • http://madebyraygun.com Dalton

    Hey Pippin,
    I think I asked about this when you posted something similar on your blog a while back – is there any way to get this to work on index pages? It seems by using get_the_ID() that it would only work on single posts & pages.
    Dalton

    • http://pippinspages.com Pippin

      Yeah, this won’t work on the index page, but I bet I could put something together that would work on the index. Email me if you want.

  • http://www.Rarst.net Rarst

    While scripts don’t really care where they go, styles only can be queued for header. Queuing them later is useless.

    Why make extra query to database with get_post() instead of using global $post?

    And overall – why bother with scanning through post body at all and not just trigger script loading in shortcode code, like in scribu’s tutorial http://scribu.net/wordpress/optimal-script-loading.html

    • http://pippinspages.com Pippin

      Rarst, I’d never seen that post by Scribu, so thanks for linking to it! It’s fantastic, and definitely a better method.

  • http://barre.me -S

    Nice. Since this post is about efficiency and speed, loading the post contents and parsing it is also a small penalty hit.

    Here is what I would do to improve. Execute a method (i.e. attach an action) whenever a post is saved. That method would parse the post as you describe (but it has the contents already), then sets a custom metadata field that indicates if the shortcode is there or not (true if it’s there, false if the shortcode is gone).

    The has_shortcode() function itself would “just” check if that custom metadata field is here. If it’s here, check if it’s true or false and include your plugin. If it’s not there then call the method mentioned earlier to create the custom metadata (so that it works on old posts that were not saved recently), I think that would a bit faster than getting the whole post and parsing it.

    • Pippin

      That’s a great idea. It would (very minutely) slow down the publishing process, but the loading process on the front end would be faster. I like it :)

  • Pingback: BlogBuzz August 20, 2011

  • http://vlagas.com jimmy

    i think the best solution is to load script and css depending on page with a function is_page provided in themes like stalkers because in contact form for example i may not use the word contact form so your fuction will provide false . Also your fuction may return true if in my header in my menu i have the word contactform in an li element.

    • Pippin

      Don’t forget that the function doesn’t just search for the word, it combines it with the [, and so it only returns true if the short code is found.

  • http://rommelcastro.me Rommel Castro A.

    gret tip!

  • Michael Schinis

    For some reason this doesnt seem to work for my plugin.. It always returns false..

    • http://pippinspages.com Pippin

      Where / how are you using it? Can you show me?

  • http://joshriser.com Josh

    Is there a way to check if the post contains any shortcode, instead of having to specify one specific shortcode?

    • http://joshriser.com Josh

      Scratch that, I figured it out. I just took out this line.

      if (!$shortcode) {
      return $found;
      }

  • Michael

    I can’t get this to work..

    I have this function just before my plugin_init() function.

    and i have used the has_shortcode(‘myplugin’) function inside the plugin_init() function but for some reason it always returns false.

  • Pingback: The WordPress Gallery Shortcode: A Comprehensive Overview | Simpler Design's

  • Pingback: has shortcode http wp tutsplus com articles quick… « Riz Notes

  • http://studio.quintalinda.com/ Websites Made Easy

    A bit cleaned up.. :) – nice one…

    if ( !function_exists( ‘has_shortcode’ ) ) {

    function has_shortcode($shortcode = ”) {

    // if no short code was provided, return false
    if (!$shortcode) {
    return false;
    }

    // load the post
    global $post;

    // content to scan ##
    $content = isset( $post->post_content ) ? $post->post_content : ” ;

    // check the post content for the short code
    if ( stripos( $content, ‘[' . $shortcode) !== false ) {

    // we have found the short code
    #echo 'shortcode ['.$shortcode.'] found’;
    return true;

    }

    }}