Shortcode output is screwed up when arrow symbol “

I have a very simple shortcode to print some text using pre tags

function term_shortcode( $atts, $content = null ) 
{
    return "<pre>" . htmlentities($content) . "</pre>";
}
add_shortcode( 'term', 'term_shortcode' );

But while using the shortcode, if there is an arrow symbol in the content, the output gets terribly screwed up. The shortcode picks up content beyond the shortcode end.

Here is an example

[term]    
ABC < DEF
[/term]
MORE CONTENT. This is also taken up by the above shortcode.

If the left arrow character “<” is removed, it outputs fine.

How do I fix this ?

Visual editor is fully disabled. Using just text editor and typing pure html.

3 Answers
3

This issue was introduced in WP 4.2.3 with the introduction of the do_shortcodes_in_html_tags() function, which does a HTML parse of content to protect against content containing shortcodes authored by untrustworthy contributors/authors who by specially crafting shortcode attributes can create XSS exploits.

If that security situation doesn’t apply to you and you only want this to work on your site then a simple workaround is to replace the default do_shortcode filter with your own version, with the call to do_shortcodes_in_html_tags() removed, eg

add_action( 'init', function () {
    remove_filter( 'the_content', 'do_shortcode', 11 );
    add_filter( 'the_content', function ( $content ) {
        global $shortcode_tags;

        if ( false === strpos( $content, '[' ) ) {
            return $content;
        }

        if (empty($shortcode_tags) || !is_array($shortcode_tags))
            return $content;

        $tagnames = array_keys($shortcode_tags);
        $tagregexp = join( '|', array_map('preg_quote', $tagnames) );
        $pattern = "/\\[($tagregexp)/s";

        if ( 1 !== preg_match( $pattern, $content ) ) {
            // Avoids parsing HTML when there are no shortcodes or embeds anyway.
            return $content;
        }

        // Avoid check for users without unfiltered html: $content = do_shortcodes_in_html_tags( $content, $ignore_html );

        $pattern = get_shortcode_regex();
        $content = preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content );

        // Always restore square braces so we don't break things like <!--[if IE ]>
        // Not needed if do_shortcodes_in_html_tags not called: $content = unescape_invalid_shortcodes( $content );

        return $content;
    }, 11 );
} );

On my testing you may also have to contend with wpautop() issues as well though…

Leave a Comment