Slightly smarter, slightly slower convert line breaks

Update: this hack is included in Movable Type 2.6, so you don’t need to do it yourself anymore.

While it’s not the truly smart convert line breaks I really want, I hacked in a smart-enough to suit me version that’s only moderately slow. The biggest drawback is that my version doesn’t convert line breaks inside the tags that it ignores, so if you want a line break in a table cell, you have to put in the <br /> yourself. However, it seems like a small price to pay for not having to turn off convert line breaks and add your own paragraph tags anytime you post a table, list, or blockquote. My version skips conversion inside table, ol, ul, pre, select, form, and blockquote, because those are the block-level elements I use that shouldn’t be wrapped in a <p></p> – if you use others, it’s easy enough to add them (or take out the ones you don’t use, to speed things up a bit). Assuming you installed Movable Type in a directory named mt, first save a backup copy and then edit /mt/lib/MT/ Find the section in sub html_text_transform that reads:

    for my $p (@paras) {
        $p =~ s!\r?\n!<br />\n!g;
        $p = "<p>$p</p>";

and replace it with:

    for my $p (@paras) {
        if ($p !~ m/^<(?:table|ol|ul|pre|select|form|blockquote)/){
            $p =~ s!\r?\n!<br />\n!g;
            $p = "<p>$p</p>";

What that says is “if the stuff that might be a paragraph doesn’t start with <table or <ol or <ul or <pre or <select or <form or <blockquote then replace any line breaks with <br /> and wrap a <p> around it; otherwise, leave it alone.” If you need to add another “non-paragraph”, say because you post lots of <dl>s, add it at the end: “|^<dl”. To remove something, say because you would never post a <select> outside a <form>, delete the ^, the tag, and either the leading or trailing |: “^<select|”.

Then, when you need to post a list, table, or blockquote, just do what you would probably do anyway: set it off with two returns, both before and after, just like a paragraph, and avoid using two returns together inside the tag (note that if you are in the habit of using blockquote to quote multiple paragraphs, you are already pissing Mozilla off, and you would be better off using a separate blockquote for each quoted paragraph).


Comment by Tobias #
2002-06-11 08:29:25

Very nice, Phil! As you said: not 100% the solution I was looking for, but a huge step in the right direction. One less annoyance in MT.

Comment by Dorothea Salo #
2002-06-11 10:46:44

Sweeeeet! I’m a-hackin’ this one in! One of my major annoyances too.

Thanks, Phil.

Comment by Jason Mevius #
2002-06-26 10:59:41

I’d been searching for the solution to this problem for awhiole, but I seem to have hit a snag. I’m running M.T. 2.1 and got this error message:

Got an error: Global symbol ”@paras” requires explicit package name at /home/jmevius/public_html/the/mt/lib/MT/ line 168. Global symbol ”@paras” requires explicit package name at /home/jmevius/public_html/the/mt/lib/MT/ line 172. Compilation failed in require at /home/jmevius/public_html/the/mt/lib/MT/App/ line 12. BEGIN failed–compilation aborted at /home/jmevius/public_html/the/mt/lib/MT/App/ line 12. Compilation failed in require at /home/jmevius/public_html/the/mt/mt.cgi line 21.

Any ideas?


Comment by Phil Ringnalda #
2002-06-26 11:24:13

I’m no Perl expert, but to me that sounds like you are missing the ”my” in the line before

for my $p (@paras) {

which should be

my @paras = split /r?nr?n/, $str;

my @paras should say ”this isn’t a global symbol”. If that doesn’t seem to be it, just paste your whole sub html_text_transform in here, and I’ll see if I can spot something else.

Comment by Jason Mevius #
2002-06-26 12:49:50

Beautiful. Works like a charm now. Such a helpful timesaver.

Comment by The One True b!X #
2002-06-27 02:24:42

Ahh, this hack is so sweet. The blockquote nested inside p tags was bugging me fiercely as I keep trying to work toward web standards.

Problem is, and this isn’t related, all the new tags that MT puts in for the TrackBack information is coming up as invalid when I run my site through — but that’s an issue for somewhere else.

Comment by Joshua Kaufman #
2002-06-28 08:06:51

Has this hack been tested on MT 2.2? If it works, I’m definitely using it! Thanks Phil!

Comment by Phil Ringnalda #
2002-06-28 08:14:41

Oh yeah, should have mentioned that. I got too busy trying to redo my ”stop spam pinging” hack, which is going to be really tough to fit into 2.2, and forgot to say that this one works just fine without any changes for 2.2 – at least that bit of code is still the same.

Comment by david #
2002-09-08 22:20:33

I’ve been trying to get this to work this evening on MT 2.21 but to no avail. I followed the instructions explicitly, but no matter what, I still wind up with the non-validating paragraph followed by blockquote sequence. Am I correct in assuming this code gets called whenever you submit the save post button on an existing entry or is there some delta that precludes that? I tried doing some really gross $p = ”junk”; stuff but even that didn’t seem to appear in the post. Any ideas? Thanks, I’d really like to get this solved.

Comment by Phil Ringnalda #
2002-09-08 22:35:40

Hrrm. No, html_text_transform should get called when you rebuild an entry (assuming convert line breaks is on for the entry), new or old. And although I said 2.2 above, it’s working fine for me on 2.21. So, for now at least, I’m baffled.

Comment by david #
2002-09-09 05:28:28

Thanks for the quick reply. Sigh. I’ll take another whack at it later this week. I guess this is why Greenspun says computer science is a religion. ;->

Comment by Phil Ringnalda #
2002-10-08 21:55:14

Update for MT 2.5: still works just fine, exactly the same as before.

Comment by Joshua Kaufman #
2002-10-11 12:30:29

I gotta wonder why they haven’t included this already? Phil: have you suggested it to them?

Thanks again for the slick hack.

Comment by Sergi #
2002-12-10 07:32:35

wow, great hack. Anyone has a PHP hack to do the same stuff? That’d be great too.

Comment by Phil Ringnalda #
2002-12-10 08:46:52

NOT widely tested, but I borrowed the first two lines from photomatt’s b2 function and got:

function autop($pee, $br=1) {
    $pee = preg_replace("/(rn|n|r)/", "n", $pee);
    $pee = preg_replace("/nn+/", "nn", $pee);
    $pees = explode("nn", $pee);
    for ( $i=0; $i<sizeof($pees); $i++ ){
        if ( $br ) {
            $pees[$i] = preg_replace("/n/","<br />n", $pees[$i]);
        if ( !preg_match("/^<(?:table|ol|ul|pre|select|form|blockquote)/", $pees[$i]) ){
            $pees[$i] = "<p>$pees[$i]</p>";
    $pee = implode("nn", $pees);
    return $pee;

which seems to work with the things that occurred to me to test. Just call autop($text) to convert breaks and paragraphs, or autop($text, 0) if for some reason you want paragraphs but don’t want single newlines converted to breaks.

Comment by Joshua Kaufman #
2003-02-14 06:28:32

It’s about friggin time this is included. Thanks, Phil!

Comment by Anonymous #
2003-06-05 09:14:27

If you customize your templates and end up including headings in your entries, this hack is still very useful. Just add the headings you use in your entries after blockquote in the hack.

Trackback by protocol7 #
2003-01-06 15:37:05

Better link breaks

”Slightly smarter, slightly slower convert line breaks” – I really want this functionality but has so far been unable to

Trackback by photomatt #
2003-01-29 09:01:44

Updated autop

Most of the scripts I offer on this site are things I’ve written myself, for myself. As part of this living site they are constantly updated and tweaked, yet sometimes I don’t update the scripts section with what’s running live here, usually b…

Trackback by A. L. #
2003-04-24 04:03:21

Movable Type, côté technique

Aujourd’hui, je parle de quelques petits trucs géniaux pour Movable Type. Par exemple. Quand on écrit un post, que l’on…

Name (required)
E-mail (required - never shown publicly)
Your Comment (smaller size | larger size)
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <del datetime="" cite=""> <dd> <dl> <dt> <em> <i> <ins datetime="" cite=""> <kbd> <li> <ol> <p> <pre> <q cite=""> <samp> <strong> <sub> <sup> <ul> in your comment.