What is the best way to enable nested shortcodes?

Is this the best way to enable nested shortcodes?:

add_filter( 'the_content', 'do_shortcode' );

Read More

I keep finding mixed results and want to be sure I won’t break anything else!

Related posts

Leave a Reply

2 comments

  1. Here’s a specific answer, to avoid relying on the official WP docs in the other answer (which, it seems, don’t really offer the explicit instructions anyway).

    Run do_shortcode() on the input

    Here is an example registration of a shortcode that supports nested shortcodes inside of it:

    function register_example_shortcode_with_nesting($atts, $text) {
    
        $output = do_shortcode($text);
        
        return $output;
    }
    add_shortcode('example_shortcode_with_nesting', 'register_example_shortcode_with_nesting');
    

    You would use this like:

    [example_shortcode_with_nesting]
    [nested_shortcode]
    [other_nested_shortcode]
    [/example_shortcode_with_nesting]
    

    The key ingredient, of course, is running the $text content (that comes from between the opening and closing shortcode tag) through do_shortcode(). By default WP grabs the first shortcode it can see, then ignores any shortcodes inside that, so we need to tell it to “look again”, and this code does the trick.

    Of course, the example above does nothing useful, you’ll need to take action on the $output using $atts etcetera to make it do something.

    Warnings about nesting shortcodes with closing tags

    • This does support having shortcodes inside that have closing tags, i.e. ones where there is $text content.
    • But it can go wrong if you have several of the same shortcode nested as siblings.
    • If you have the same shortcode several times, WP can get confused about which “opening” tag applies to which “closing” tag, and it will automatically apply the first instance to the first closing.

    So here’s my rule of thumb: If a nested shortcode has a closing tag, it must either be first, the only of it’s kind, or all of the matching nested shortcodes need to have closing tags.

    So an example like this won’t give you what you expect:

    [example_shortcode_with_nesting]
    [nested_shortcode id=1]
    [nested_shortcode id=2][/nested_shortcode]
    [/example_shortcode_with_nesting]
    
    

    What happens? You get the first shortcode with id=1 rendered with the [/nested_shortcode] as its closing tag, and the id=2 shortcode as its unrendered content! Yikes!

    So like I said above, either avoid having the same shortcode multiple times, or make sure that ALL of them have both the opening and closing shortcodes!