2

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.

7
  • 1
    '<' is a html tag character, hence why you'll find an issue - try using &lt; or &#60; ?
    – Aravona
    Oct 15, 2015 at 6:39
  • The problem is probably not related to html character escaping. Using &lt; will simply output &lt; instead of < Oct 15, 2015 at 7:12
  • is it boken both on text and visual editors? Oct 15, 2015 at 8:52
  • @MarkKaplun Visual editor is disabled. Only text editor is being used Oct 15, 2015 at 8:59
  • 1
    Why don't you use the visual editor when editing, so it will convert your entities? In the text editor you will need to do that before or you need to stop some WordPress filters to work with that. Oct 15, 2015 at 10:40

3 Answers 3

2

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...

1
  • Thanks for pointing out. For a change, I decided to write my own shortcode parser using code from previous version of wordpress, and now it works like before Oct 16, 2015 at 12:25
2

Short codes should not be used as a replacement to html tags. In this case if you want to use <pre> just use it, don't invent a shortcode for it.

The usage of "<" breaks the validity of the html in the content which might break all kinds of parser and probably break the shortcodes parser (and will almost for sure break it even harder in versions 4.4+).

In your case, the opposite of what you are trying to do is probably the better approach. Instead of encoding html elements, you should assume they are already encoded and you decode them to put them into a <pre>. This way you will also be able to use the visual editor for the shortcode.

5
  • I am not merely replacing an html tag with shortcode, there is a lot of markup and css involved which is used frequently, so shortcodes make it very convenient Oct 15, 2015 at 10:32
  • I am not sure, but the wordpress shortcode parser should not need to do any kind of html parsing, such that a "<" would break it. Oct 15, 2015 at 10:34
  • the text editor is a convenience, not a norm and I am not sure how much core developers will be willing to put on effort to support a features which ignores the way 99.9% of wordpress users use it. This specific syntax in the question will get lost in switching to visual editor and back. As for if it is possible or not to write a parser that works with that syntax, it is the wrong question as core developers are not interested to have html fragments in shortcodes, mostly because it proved to generate security holes when people made their shortcode too complex. Oct 15, 2015 at 11:22
  • 4.4 will start making big changes in how shortcodes work - make.wordpress.org/core/2015/09/29/shortcode-roadmap-draft-two Oct 15, 2015 at 11:22
  • What will 4.4+ precisely do when there are "<" characters in the contents of a shortcode ? Oct 15, 2015 at 12:35
1

I would try using htmlspecialchars() instead of htmlentities() and see if that solves the issue.

1
  • no, that does not solve the problem. And the problem seems to be in how wordpress is selecting the shortcode block rather than escaping of html characters. Oct 15, 2015 at 9:10

Your Answer

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

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