If you’ve tried to use code samples in WordPress, you might have noticed unexpected behavior from the WYSIWYG editor. It will edit the whitespace inside of <pre>
tags, leaving you with some poorly formatted, hard-to-read code. Today, I set out to stop that.
What causes this?
Whenever the WYSIWYG editor opens, it sends the content of the post through a few filters. You can find most of these in wp-includes/formatting.php
. The culprit here is the function wpautop
. This function runs a long list of regular expressions to make your content a little prettier and better formatted. But we don’t want that to happen to our <pre>
tags; they’re pre-formatted. We want those left alone. To do that, I had to find a way to keep the content of the <pre>
element from going through that filter.
WordPress’s plugin system allows you to change its behavior without altering the core code, so you don’t have to re-alter it every time you upgrade. As easy as it would have been, in the short-term, to just edit wpautop
to make it behave properly, I wanted a longer-term solution that would be easier to share with other WordPress users. Therefore, a plugin.
Since a plugin can’t just intercept an arbitrary function call, you have to find a filter hook that can call your function at the appropriate time. wpautop
is called by wp_richedit_pre
. wp_richedit_pre
, in turn, is hooked into the filter system through the hook the_editor_content
.
Finally, step one, cut
Remove wp_richedit_pre
from the the_editor_content
filter.
Step two, redirect
Replace that with a similar function that will call something other than wpautop
.
Here I create a new class to hold my plugin’s functions, aptly named PreservePre
. The the_editor_content
filter will call this class’s preformat_intercept
method, which will do the same thing as wp_richedit_pre
, but replace the call to wpautop
with a call to PreservePre
‘s safe_autop
method.
Step three, recurse
safe_autop
performs a pretty simple function.
- If there are no
<pre>
tags in the text, it just sends everything on towpautop
and returns the result. - If the text starts with a
<pre>
tag,safe_autop
splits it into two parts, the<pre>
element and everything after the<pre>
element. The latter part is sent back throughsafe_autop
to let recursion run its course. The two parts are then stuck back together and returned. - If there is a
<pre>
tag anywhere else,safe_autop
splits the text into two parts: everything before the<pre>
and everything else. Each half is sent back tosafe_autop
, with the results stuck back together and returned. That means the part before the<pre>
will match the first case and be sent towpautop
, the rest will match the second case and continue with the recursion.
So after all that, anything not in a <pre>
element goes through wpautop
; anything that is in a <pre>
element is left alone.
So now we’re in good shape, right? When WordPress opens the WYSIWYG editor, <pre>
elements are left alone, their whitespace untouched. But wait, there’s more!
Step four, gnashing of teeth
The WYSIWYG editor has both a “Visual” tab and “Code” tab. If you visit the “Code” tab, you can see all of the HTML for the post. When you go back to the “Visual” tab, the editor sends your content through wpautop
again (you might have changed something you shouldn’t have, after all). But this isn’t the same wpautop
; this time, it’s JavaScript. Yes, the same function runs client-side anytime you move from the “Code” tab to the “Visual” tab.
Step five, intercept
JavaScript, fortunately, allows you to redefine previously declared functions. So you just rename wpautop
to old_wpautop
, and redefine wpautop
to point to the safe_autop
function, reimplemented in JavaScript. Use the wp_print_scripts
action hook to tell WordPress to run your script, and you’re all set.
The Plugin
If you’ve made it this far, here’s your reward: the Save My <pre>
WordPress plugin.
UPDATE (2008-03-07): Fixed a small bug in the JavaScript. I forgot to check for the existence of wpautop
before mucking about with it. This didn’t cause any problems, other than throwing an exception. Version 1.1 is now available from the same place.
UPDATE (2008-03-12): Now also available from http://wordpress.org/extend/plugins/save-my-pre/.
UPDATE (2008-09-27): Recent versions of WordPress don’t eat whitespace like they used to. The WYSIWYG still eliminates any leading or trailing whitespace inside of a <pre>
, but everything else remains intact. That seems acceptible to me, so I see no reason to further maintain this plugin. Thanks to all who used it and commented.
I spent all day reading about various workarounds for how to insert line breaks into WordPress and decided to go with your plugin rather than some of the other options like using a different visual editor. Since I am using WordPress to design a public library web site, I hoped to have some of the static pages mimic the look of more traditional web sites. I decided to use your plugin and already fixed the spacing on some images that took up more space than the accompanying text. Bravo! Thank-you so much for writing this plugin.
I spoke too soon. after I published it the break tags were stripped out. For us non-geekie types, can you please give an exact example of how you use the tag. Would I type ? I am using version 2.3.3 and have activated the plugin. I entered the above in code version. I’m guessing I don’t understand how to use the pre tag precisely? Can you give the dummies version?
Hi, Sharani. I’m not quite sure what you’re hoping the plugin will do. The use I had in mind is when you’re putting samples of code in a page. For an example, say you want to share some HTML on a page, as I did here not long ago. You would put it inside of <pre> tags so that all your indentation is preserved. My HTML looked like:
But the WordPress WYSIWYG wanted to turn that into:
So, all that said, it sounds like you’re trying to use the <pre> tag to help you layout your page. If that’s the case, there are much better ways to that using CSS. Or, perhaps I’m misunderstanding what you’re saying. Let me know if that helps, and if I can be of service to you.
Hi
Sorry but it doesn’t work in 2.5
I enter the pre tags in HTML, then go to visual – It shows everything OK in visual and protects code!
Now I select html again – bam – code has been changed in html! Now back to visual -real mess. Back to html – more changes!….
Very nice!!
please don’t consider this plugin dead. i’d love to continue using the visual editor, even for posts that contain code.
if you do ever update this plugin, consider including support for other tags too, such as the one used by code colorer:
[cc language=”actionscript”]
package {
public class HelloWorld {
public function HelloWorld () {
}
}
}
[/cc]