How to stop wpautop from messing your shortcodes

The WordPress editor offers a pretty enjoyable writing experience even for those who don’t know a thing about HTML. No matter whether you are using the “Visual” editor or the raw text editor, wpautop is one of the things that makes it friendly.

wpautop is a function that filters the_content when it is being displayed on the front-end. It conveniently replaces line breaks with relevant <p> and <br /> tags.

It only runs dynamically when the content is pulled for front-end display, so it does not touch the content that is being saved in your database. As a result, these tags never end up in your editor, which could otherwise quickly become messy and/or confusing.

When wpautop goes wrong

This is a quite clever function that allows you to focus on your content, without the need to think about line breaks and paragraph formatting. It is also pretty good at finding out where to add these tags and when not to add them.

Until you start using shortcodes. Then things start to become messy.

Shortcodes tend to end up wrapped in <p> tags, or to get a <br /> tag prepended to their content. This is not always a big deal, but can often cause formatting issues. It may also trigger your OCD when you realize that your code is not as clean as it was supposed to be.

Johann Heyne came up with a cool snippet to fix this issue and turned it into a plugin modestly called Shortcode empty paragraph fix. It works by adding another filter that runs after wpautop has done its thing and removes the unwanted tags around shortcodes with a simple string replacement.

This does the job most of the time, and I actually used this code quite a lot in the past.

Now we’re in trouble, again

Recently though wpautop struck again when I was creating my own implementation of prismjs, which I’m now using right here on this blog to display code snippets with cool syntax highlighting (details about this coming up in a future post!).

The issue was that wpautop was adding <p> and <br /> tags to the content inside the shortcode.

So if I entered this in the editor:

[myshortcode]function hello_world(){
	echo 'Hello World';
}[/myshortcode]

The result would look like this on the front end:

function hello_world(){<br />
	echo 'Hello World';<br />
}

It isn’t exactly an issue that wpautop is running on the content inside the shortcode, it does what it is supposed to.

Except it is an issue because I don’t want it to do that here!

Make it stop!

One solution would have been to simply disable wpautop entirely. That’s easy enough to do, all it takes is this line:

remove_filter( 'the_content', 'wpautop' );

I could live without it and format my content by adding <p> and <br /> tags everywhere by hand.

Except I don’t want to do that. I actually enjoy the comfort of just hitting return in my editor and having my ramblings put together in nicely formatted paragraphs automatically.

Now let’s take a step back for a moment to identify the root of the problem. Considering how my code ended up looking on the front-end, it appears that wpautop ran and added the <br /> tags before my shortcode made it look cool.

And this is exactly what it seems: wpautop does run before do_shortcode (the function that filters the_content to run the shortcodes).

If my shortcode could do its thing earlier, wpautop would not mess it (mainly because this shortcode wraps its content in <pre> tags, and wpautop leaves the content of these tags alone).

And here was the solution: let’s make wpautop run later, at least after do_shortcode (props to Phil Banks who suggested this solution a few years ago already here).

wpautop filters the_content with a priority of 10, so we can simply remove this filter and immediately re-add it with a lower priority. 11 would work, but Phil Banks suggests to set it to 99, to make sure it runs last after everything else, which is probably a good idea.

If you have other plugins or custom filters that run on the_content, this might take some tweaking to find the right priority to make it run at the right moment.

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

Share the love!