Don’t do_shortcode()

If you do much WordPress development, sooner or later you’ll find that you want to call a shortcode programmatically. It’s easy to do this:

do_shortcode( '[shortcode]' );

But that is a very bad idea. The do_shortcode() function is expensive, and is actually a roundabout way of accomplishing this. We know exactly what shortcode we want to call, and what we want the attributes and content to be. But do_shortcode() doesn’t know that. It will use an intensive REGEX to evaluate that simple little string, searching for the shortcode. Instead, since we already know what the shortcode is, we should just call the function that handles that shortcode. Easy enough right?

For a function like this, it is simple:

function my_shortcode() {
	return 'my shortcode';
}
add_shortcode( 'shortcode', 'my_shortcode' );

We can just call the function directly: my_shortcode().

This is simple enough, but it does have a drawback. If this function is part of a project outside your control, there is the possibility that the function might get renamed. Also, there are cases where this approach is not even possible, and I encountered one of these this week.

The shortcode function was a class instance method, and there was no way to access the instance. Kind of like this:

class my_shortcode_class {

	public function __construct() {
		add_shortcode( 'shortcode', array( $this, 'my_shortcode' ) );
	}

	public function my_shortcode() {
		return 'my shortcode';
	}
}

new my_shortcode_class();

Now how are you going to call that programmatically, without do_shortcode()? I couldn’t just create a new instance of the class, because there was other stuff in the constructor that should only run once.

Well, here’s how I did it. All of the shortcode functions are stored in the global $shortcode_tags array. So, I just pulled the function from that based on the shortcode tag, and called it using call_user_func(). Here is a simple wrapper for this, which supports passing attributes and content:

/**
 * Call a shortcode function by tag name.
 *
 * @author J.D. Grimes
 * @link https://codesymphony.co/dont-do_shortcode/
 *
 * @param string $tag     The shortcode whose function to call.
 * @param array  $atts    The attributes to pass to the shortcode function. Optional.
 * @param array  $content The shortcode's content. Default is null (none).
 *
 * @return string|bool False on failure, the result of the shortcode on success.
 */
function do_shortcode_func( $tag, array $atts = array(), $content = null ) {

	global $shortcode_tags;

	if ( ! isset( $shortcode_tags[ $tag ] ) )
		return false;

	return call_user_func( $shortcode_tags[ $tag ], $atts, $content, $tag );
}

Examples:

$result = do_shortcode_func( 'shorcode' );

$result = do_shortcode_func( 'shortcode', array( 'attr' => 'value' ), 'shortcode content' );

So next time you want to do_shortcode(), you can use this wrapper function, or implement something similar within your code that needs to call a shortcode like this.

4 thoughts on “Don’t do_shortcode()

  1. Ansif

    do_shortcode() in revolution slider we use this on custom header section.

    So, how i need to call this without using do_shortcode function.

    Example : do_shortcode(get_post_meta($post->ID, ‘custom_header_html’, true)).

    If users enter the shortcode then this shortcode appear here. instead of do_shortcode([rev_slider name]) how to use?

    Reply
    1. J.D. Grimes Post author

      Ansif, in this case, you do need to use the do_shortcode() function. If you don’t know what the shortcode will be, then you should use do_shortcode(), as in your example. But if you already know what the shortcode is (as in do_shortcode( '[rev_slider name]' )), you should use my function instead.

      Reply
      1. Ansif

        Thanks for your quick response.

        Still now i’m not getting clear :(

        So, can you please review this do_shortcode() item.

        Then i get clear even in future visitors also get clear about what they looking for…

        Thanks!

        Reply
        1. J.D. Grimes Post author

          There are two scenarios:

          1. You have a string (like a post’s content) that has some shortcodes in it. You don’t know exactly what they are, and they might be interspersed with other content. In this case, use do_shortcode().
          2. You have a shortcode and you want to use it in a template. You know exactly the shortcode you want to use. You could do this: do_shortcode( '[cool_stuff]' ). But in this case you should use my function instead.
          Reply

Leave a Reply to J.D. Grimes Cancel reply

Your email address will not be published. Required fields are marked *