WordPress shortcodes run at priority 11 which is after wpautop(), wptexturize(), and other various default filters. While this can be desirable so that wpautop() doesn’t affect the output of the shortcode (the function is well known for not being perfect), it can also be a drawback as wptexturize() will malform your shortcode contents.
Take this shortcode usage for example:
This is some text.
[foobar]This is how you "quote" things.[/foobar]
This is some more text.
The “foobar” shortcode callback will receive the following string:
This is how you “quote” things.
Well that’s not obviously right. Okay, so you could fix it with some str_replace()‘es to reverse the fancy quotes and other changes, but why go to all the trouble?
Instead, let’s just make the shortcode run before priority 10 when wpautop(), wptexturize(), etc. mangle our shortcodes. That way we can process the shortcode as the user typed it and when once we’re done let wpautop() and it’s friends handle the content like they were designed to do.
First, here’s the code I use. I’ll explain it afterward.
function foobar_run_shortcode( $content ) {
global $shortcode_tags;
// Backup current registered shortcodes and clear them all out
$orig_shortcode_tags = $shortcode_tags;
$shortcode_tags = array();
add_shortcode( 'foobar', 'shortcode_foobar' );
// Do the shortcode (only the one above is registered)
$content = do_shortcode( $content );
// Put the original shortcodes back
$shortcode_tags = $orig_shortcode_tags;
return $content;
}
add_filter( 'the_content', 'foobar_run_shortcode', 7 );The function starts by global’ing the variable $shortcode_tags. This is the variable that contains a list of all registered shortcodes. We then make a copy of that variable (so we can restore it later) and then empty it out so that no shortcodes are registered.
Now that there’s no shortcodes registered, we register our shortcode and call do_shortcode() which is the function that replaces shortcodes with their contents. Once that’s done, we restore all of the previously registered shortcodes (this also unregisters our shortcode so it doesn’t run again) and return the result of the do_shortcode() call.
Lastly we register that function as a filter but at an earlier priority than wptexturize() so that it will run first. Any number between 1 and 9 will do — I just use 7 as it’s fairly late but still leaves room for other filters to come after it but before wptexturize(). That and it’s my favorite number. 
Questions? Improvements? Then leave a comment. 
about 3 months ago
What if some plugin registers shortcode earlier than 7 ? In such a case, the global $shortcode_tags would not be empty and the early do_shortcode would actually run twice those shortcodes, right?
about 3 months ago
$shortcode_tagsis almost certainly not empty by the time my filter comes along. The gallery shortcode for example is registered. That’s why we back it up before we clear it out.Then once it’s empty and no shortcodes are registered, we register the shortcodes we want to parse early. Once those shortcodes are processed (only those will be because they’re the only ones registered), we restore the original
$shortcode_tagsfrom the backup we made earlier which puts everything back exactly as it was and in turn removes our early shortcode.When my filter runs doesn’t matter as it puts things back exactly as they were before it ran.
By the way, I use this trick in my SyntaxHighlighter plugin so that I can replace my shortcodes with pre tags before
wpautop()adds paragraphs to the insides of my shortcodes (once the shortcode content is wrapped in a pre,wpautop()won’t touch it).about 3 months ago
Doh, me silly, I missed the clearing line of course.
about 3 months ago
Very neat hack. Sometimes I’m glad WordPress is a silly mess of non-OO global variables
about 3 months ago
In Reply To Jeremy Clarke:
Even if it was class based, you could just manipulate
$classvar->shortcode_tagsthough, right?about 3 months ago
In Reply To Viper007Bond:
That really depends. Most of the time a variable like that would be private or protected (although that obviously can’t be done in PHP 4). Instead there should be methods for manipulating it.
about 3 months ago
In Reply To Aaron D. Campbell:
Yeah, Aaron knows better than me. I’m pretty sure that in a real OO type project the trick from your post would be considered felonous, but in WordPress its just an unusual workaround. Don’t let Jacob Santos know about it though!
about 3 months ago
Rewrote the post to use a better example of why you may want to run earlier shortcodes, namely
wptexturize()wreaking havok on your shortcode contents.