5

I have created an extremely simple shortcode:

function my_shortcode($atts, $content) {
    return '<div class="block">' . do_shortcode($content) . '</div>';
}

add_shortcode('block', 'my_shortcode');

Then, in the Text (HTML) editor for a page, I enter:

[block]<h2>Test</h2>[/block]

I expect the shortcode to render as:

<div class="block"><h2>Test</h2></div>

But instead I get:

<div class="block"><br /><h2>Test</h2></div>

Why is WordPress inserting a <br />? Is there a way to prevent this behavior or at least work around it?

1 Answer 1

4

The <br> tag is coming from wpautop(), which is one of a number of display filters added to the content via wp-includes/default-filters.php:

// Display filters
add_filter( 'the_content', 'wptexturize'                       );
add_filter( 'the_content', 'convert_smilies',               20 );
add_filter( 'the_content', 'wpautop'                           );
add_filter( 'the_content', 'shortcode_unautop'                 );
add_filter( 'the_content', 'prepend_attachment'                );
add_filter( 'the_content', 'wp_make_content_images_responsive' );

...

// Shortcodes
add_filter( 'the_content', 'do_shortcode', 11 ); // AFTER wpautop()

WordPress runs the do_shortcode filter after wpautop has has already been run on the content.

Here's a function that will remove the <br> tag (source):

function shortcode_wpautop_fix( $content ) {

    // Define your shortcodes to filter, '' filters all shortcodes
    $shortcodes = array( '' );

    foreach ( $shortcodes as $shortcode ) {

        $array = array (
            '<p>[' . $shortcode => '[' .$shortcode,
            '<p>[/' . $shortcode => '[/' .$shortcode,
            $shortcode . ']</p>' => $shortcode . ']',
            $shortcode . ']<br />' => $shortcode . ']'
        );

        $content = strtr( $content, $array );
    }

    return $content;
}
add_filter( 'the_content', 'shortcode_wpautop_fix' );

An alternative approach is to ensure that do_shortcode is applied before wpautop. This can be accomplished by changing the priority of the display filters.

remove_filter( 'the_content', 'wpautop' );
add_filter( 'the_content', 'wpautop', 99 );
add_filter( 'the_content', 'shortcode_unautop', 100 );

Note that do_shortcode is already run at priority 11, so the goal of running it before wpautop is accomplished with the code immediately above.

Also worth noting, shortcode_unautop deals specifically with the markup on the outside of the shortcode, not the inside.

2
  • 1
    Why does WP do this?
    – MrWhite
    Sep 17, 2016 at 23:11
  • I added some additional notes and an alternate solution, but I do not know the specific reasoning behind the decision to run wpautop before do_shortcode. I think it's because changing priorities could break plugins. I'm also getting the feeling that a bug could involved here: #6984, #34722, #19411. Search do_shortcode wpautop on trac Sep 18, 2016 at 0:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.