Fixing themes with custom wpautop priority & breaking shortcodes

If you are reading this, then probably you are having issues like added line breaks or weird looking code on the output of some shortcodes. While, at first you may think from the title of the article, that it has nothing to do with the behavior, but trust me, this is exactly what is breaking the output of the shortcode from our plugin (and probably some other plugins as well, most of them if not all of them).

Understanding the problem

So, what is the problem really? To be honest the problem is not WordPress’ own. It is smart enough to do things in the right way. The problem arrives because of the necessity of two things that some (and we are not accusing anyone) theme developers and plugin developers find confusing and hard to solve.

  1. Providing a [raw] shortcode to print things as it is (without line breaks and texturize).
  2. Preventing WordPress from adding paragraphs to multiline contents inside a shortcode. Say for example

    [text][div]
    My paragraph.
    [/div][/text]

    will be converted to

    [text][div]
    <p>My paragraph.</p>
    [/div][/text]

    before the shortcode parsing happens.

To prevent this “self-proclaimed anomaly“, what some people do is tell WordPress to first parse the shortcode and then add paragraphs. The code for this essentially looks like this.

[php]remove_filter( ‘the_content’, ‘wpautop’ );
add_filter( ‘the_content’, ‘wpautop’ , 99 );[/php]

Also, to add the [raw] shortcode functionality,

[php]
function my_formatter($content) {
$new_content = ”;
$pattern_full = ‘{(\[raw\].*?\[/raw\])}is’;
$pattern_contents = ‘{\[raw\](.*?)\[/raw\]}is’;
$pieces = preg_split($pattern_full, $content, -1, PREG_SPLIT_DELIM_CAPTURE);

foreach ($pieces as $piece) {
if (preg_match($pattern_contents, $piece, $matches)) {
$new_content .= $matches[1];
} else {
$new_content .= wptexturize(wpautop($piece));
}
}

return $new_content;
}

remove_filter(‘the_content’, ‘wpautop’);
remove_filter(‘the_content’, ‘wptexturize’);

add_filter(‘the_content’, ‘my_formatter’, 99);
[/php]

While the codes above seems to get the job done for the developer, it has many unnecessary side-effects. For example, this will not add line breaks to anything inside [raw] shortcode true, but will essentially break other shortcodes by adding line breaks among their HTML content.

Due to this, the output of our very own plugin eForm

[html]
<input type="radio" class="ipt_uif_radio check_me validate[required]"
value="1"
name="ipt_fsqm_form_63[mcq][0][rows][1][]" id="ipt_fsqm_form_63_mcq_0_rows_1__1"
/>
<label for="ipt_fsqm_form_63_mcq_0_rows_1__1"></label>
[/html]

becomes

[html]
<input type="radio" class="ipt_uif_radio check_me validate[required]"<br />
value=&#8221;1&#8243;<br />
name=&#8221;ipt_fsqm_form_63[mcq][0][rows][1][]&#8221; id=&#8221;ipt_fsqm_form_63_mcq_0_rows_1__1&#8243;<br />
/><br />
<label for="ipt_fsqm_form_63_mcq_0_rows_1__1"></label>
[/html]

which ultimately results in this…

Broken Shortcode

Quite messy right? While the simplest fix to this kind of problem is to wrap our shortcode inside [raw], like

[text][raw][ipt_fsqm_form id="1"][/raw][/text]

but that still is _doing_it_wrong. If you develop theme, then please read on to know why, or if you are just another victim of it, then skip to the fix.

Why is it Wrong?

To understand, we have to discuss how WordPress’ Shortcode API works. WordPress has two nice APIs to texturize and add paragraphs to contents.

If we look into wp-includes/default-filters.php then it becomes clear.

[php]
add_filter( ‘the_content’, ‘wptexturize’        );
add_filter( ‘the_content’, ‘convert_smilies’    );
add_filter( ‘the_content’, ‘convert_chars’      );
add_filter( ‘the_content’, ‘wpautop’            );
add_filter( ‘the_content’, ‘shortcode_unautop’  );
add_filter( ‘the_content’, ‘prepend_attachment’ );
[/php]

It tells us essentially two things:

  • Paragraphs are added to content after “texturizing” it.
  • Then standalone shortcodes are stripped from any enclosing paragraphs.

Which in return tells us, WordPress is smart enough to not to convert, say

[text][my_shortcode][/text]

to

[text]<p>[my_shortcode]</p>[/text]

Which seemed to be the very concern about re-prioritizing wpautop anyway. So why bother doing it? Well, we didn’t do it, neither did you. Your theme developer or other plugin developer did it and they have their reasons. But still, it is breaking stuff, so it is time to fix it.

PS: If you are thinking about the [raw] code, then there are many plugins which do it in correct way. Say for example, SyntaxHighlighter Evolved. Personally I always prefer using this plugin when in the need for printing some raw code.

Possible Solutions

Due to unknown varieties of implementations, we can not provide exact solutions, but at least we can try. If you are an end user not a developer, then probably you’d stick to solution 1 and 3, but if you know your way around codes and all, then try solution 2 as well.

Solution 1: Using the raw shortcode

Although wrong, but still it would solve your problems temporarily. If your theme is breaking shortcode output, then probably it is providing a [raw] or [noformat] shortcode to prevent it as well. Consult your theme documentation to know about it, and wrap the shortcode which is breaking inside the raw one. For eg,

[text][raw][ipt_fsqm_form id="2"][/raw][/text]

Solution 2: Removing the code yourself

Inside the functions.php file of your active theme, you might be able to find code similar to this:

[php]
remove_filter( ‘the_content’, ‘wpautop’ );
add_filter( ‘the_content’, ‘wpautop’ , 99 );
// This line might not be present
add_filter( ‘the_content’, ‘shortcode_unautop’, 100 );
[/php]

Or this

[php]
function my_formatter($content) {
$new_content = ”;
$pattern_full = ‘{(\[raw\].*?\[/raw\])}is’;
$pattern_contents = ‘{\[raw\](.*?)\[/raw\]}is’;
$pieces = preg_split($pattern_full, $content, -1, PREG_SPLIT_DELIM_CAPTURE);

foreach ($pieces as $piece) {
if (preg_match($pattern_contents, $piece, $matches)) {
$new_content .= $matches[1];
} else {
$new_content .= wptexturize(wpautop($piece));
}
}

return $new_content;
}

remove_filter(‘the_content’, ‘wpautop’);
remove_filter(‘the_content’, ‘wptexturize’);

add_filter(‘the_content’, ‘my_formatter’, 99);
[/php]

Remove the one you find. If you can not find it inside functions.php, then you might still be able to find it inside some file called shortcode.php or filters.php or something similar. Best is to do a search for wpautop inside the theme directory.

Solution 3: Consult your theme developer

If everything fails, then contact the developers of your theme. They should have the solution for you. Also show them this page as a reference so that they can understand the problem right away and solve it.

Solution 4: Consult the forum

If everything else fails, then contact us through our support forum. The link is given on right. We will help you with this.

Swashata has written 257 articles

Hi there, I am the Lead Developer at WPQuark.com. I love to create something beautiful for WordPress and here I write about how to use them. When I am not working, usually I am doing a number of other creative things ;).

3 thoughts on “Fixing themes with custom wpautop priority & breaking shortcodes

  1. Joydeep Sengupta says:

    Hi Swashata,

    I was facing this issue with my WP theme that I purchased. The raw tag definitely helped however, the one in this post didn’t work. [raw][[ipt_fsqm_form id=”2″]][/raw]

    I guess, the code should be:
    [raw][ipt_fsqm_form id=”2″][/raw] – This one worked. This could be specific to my theme though. I am using “Karma” by TrueThemes.

    Link to their post for this issue: https://support.truethemes.net/?knowledgebase=using-third-party-shortcode-or-javascript-in-post-editor

    Please correct it, if that’s how it should be. I am no developer so, you’ll be the best judge of it. 🙂

    Thanks for the post, it saved me much of trouble.

    Cheers,
    Joydeep

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.