Shortcode Autoformatting HTML with Paragraphs and Line Breaks

So, I have been working on a client’s WP plugin that is relatively linked to their ThemeForest WordPress theme authored by the good folks at ThemeFuse using their theme framework.

Now, the easiest way to limit the reliance on the theme for the functionality I am building is to use shortcodes that output conditional content based on whether a user is logged in, based on user meta data, etc.

Shortcode Autoformatting Has Helped Doubled My Time

I have spent twice the amount of estimated time on this project, and at least 50% of that bloat has been this mysterious issue of my shortcode output being mysteriously auto-formatted with paragraph tags (<p>) and line-breaks (<br />).

I’ve spent days ripping out the tiny hairs on my head trying to figure out why I’m such a moron when it comes to WP’s shortcode API and core content filters (things I’ve been working with for YEARS).

I Do Something I Should Do More Often.

My e-friend Carl Hancock of Rocket Genius, the company behind the awesomeness of functionality and user-experience that is GravityForms, helped shed some light on this problem.

I figured he’d be the prefect person to reach out to, since the core of displaying a Gravity Form relies on WordPress’ Shortcode API.

As we are direct messaging on Twitter, I remember his comments about fixing MANY ThemeForest theme issues for clients using Gravity Forms due to terrible coding standards and overriding core functionality that affect both Gravity Forms and other plugins.

I hunt through some of the 100+ files embedded in this pre-built theme framework and fine this, well, poor code:

//Disable Automatic formatting in WordPress posts
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);

No sooner than I see this code, I get a DM from Carl with a link to a WP Recipe article with the exact same code.

I’m not sure WHO this code started with, but I know who used it.

Why is this a problem?

It’s globally removing two very important core content filters that WP has built-in for very good reasons. It is typically assumed by most themes and plugins that these filters are running. I don’t have a problem turning them off conditionally (i.e. specific post ID’s, specific page templates in a theme, etc.). Better yet, set this as a setting in a custom field, per page/post, and have it on by default. Give me the option to disable it and even know it exists if I’m walking into the theme from a distance.

At least give it the same priority as the wpautop and wptexturize filters so it does NOT affect shortcode output and behaves as similarly as possible! I realize this is to allow users to have “raw HTML output,” but you can do the same thing using it as a content filter and token replacement before/after these core filters are called.

This makes this theme work perfectly and negatively affects ANY and ALL plugins that have shortcodes or possibly filter content after the assumed priority of wpautop and wptexturize.

This is not a solution. It’s more of a hack that may or may not have cause the earthquake in Haiti, the tsunami in Japan and the tornados in the southern U.S…

How the hell do I fix this?

Don’t use a theme that poor code in it. That’s the optimal solution. Don’t expect a $36 purchase from a virtual Wal-mart to be stable, secure or provide you with a strong solution for communicating and interacting with your clients.

Okay, so realistically how do I fix this?

  1. You can comment these lines of code out, including the remove_filter() calls, so that WP behaves as expected.
  2. You can remove this filter in your shortcodes, which is what I did since my client is going to continue to use this theme:
    add_shortcode('andy_shortcode', 'andy_shortcode');
    function andy_shortcode( $atts, $content = '' ) {
    	remove_filter('the_content', 'my_formatter', 99);
    	extract(shortcode_atts(array(), $atts));
    	$output = '<div class="my_formatter_violated_my_output">';
    	$output .= 'Thanks for using the my theme framework.</div>';	
    	return $output;
    }

    Remeber you MUST enter their priority value of 99 (or whatever it is set to in your theme, chances are you’re using a theme from the same authors, or authors of the same mentality).

  3. You can stop using shortcodes or pray that it doesn’t affect you.

Final Thoughts

I understand what the intention of this functionality is. In fact, I think it’s a good idea, just a poor implementation.

Ultimately, I’d move away from these themes and check out some stronger theme directories with dedicate WP experts coding, not a hodge-podge marketplace. Being that I’m kind of against purchasing pre-built themes from both a designer and developer standpoint, I can’t recommend a good site, but I’m sure I can keep recommending sites NOT to use.

Good luck and God Speed.

11 Comments

  1. andy says…

    FYI, I have just submitted a plugin to replace this kind of functionality that will allow users to use REAL shortcodes to insert raw HTML the RIGHT way.

    It enables them to have a library of snippets they can call on by unique ID.

    Stay tuned, or install it yourself for free if you’re a WP hacker: http://pastebin.com/jcU8ajsG

  2. Plugin Embeds Snippets of Raw HTML into WordPress says…

    [...] since my über vent over fake shortcodes that autoformat the output of real shortcodes, I realized that the intention was good but the execution was [...]

  3. Ian says…

    You sir, are my hero. I have spent ages trying to debug this ridiculous filter. Thank you.

  4. Avani says…

    I echo Ian’s thoughts above, yours was the *only* thing I found on the world wide web resolving this really annoying issue I had!

    I also realize the importance of not keeping the little fixes I find just to myself – putting it out there FWIW – someone somewhere may actually find it useful :) Internet FTW!

  5. mike says…

    useful info but not sure the reference to recent natural disasters is in particularly good taste. if it was a funny comment it might seem a bit less shit.

  6. andy says…

    @mike sorry to hear you’re offended. Perhaps I should’ve omitted the ironic metaphor and opted for curse words? ;P

  7. Lenny says…

    Add a filter before wpautop (prio 1) that wraps elements (img, iframe, object or whatever) in a shortcode (pee-protection). Now you can add the shortcode and remove the pee-protection after WordPress has done it´s deeds.

    I call it “the pee-shield”

  8. Mayur Jobanputra says…

    Thanks for finding out this obscure borked issue. However, what if parts of my theme use the [raw] implementation already? If I remove the function as you suggest, I would lose some of the formatting.

  9. andy says…

    @Mayur I would stop using it. Do you have TONS of content using it in your theme?

    Try using something like my Raw HTML Snippets plugin to move away from the [raw] shortcode: http://wordpress.org/extend/plugins/raw-html-snippets/

    This is part of the problem – your content is tightly coupled with your theme now – what would happen if you switched themes one day? You’re stuck with the theme or perpetuating poor code.

    Good luck, I highly suggest moving it!

  10. Preserve inline JavaScript or HTML in the WP post editor | Danny van Kooten says…

    [...] (March 2013): Ben Goodyear pointed me to a post of Andy Stratton who raises a few good points on why you should not use this “raw” or “preserve” function inside your theme. Andy is right and luckily, he came up with a better solution which also looses the coupling [...]

  11. Displet says…

    We wrote a plugin that takes care of the most common implementations of this bad practice. It’s in the WordPress repository:
    http://wordpress.org/extend/plugins/displet-theme-code-helper/

RSS feed for comments on this post. TrackBack URL

Leave a Comment

May 10, 2011

Filed in Development, Wordpress

There are 11 comments »


« Back to the Blog