Redirects and Rewrites

Weird link of the day: Mean Kitty for Veronica

I ought to be doing some Boston blogging now that two guys can get married in the state of Massachusetts, but the truth is that Jemima has been geeking while Rome burns. I figure as long as we’re redefining words here in Mass., I can rewrite some URL’s for you.

So, I have the usual geek MT file structure in my moveabletype directory (with an extra e for character):

moveabletype/index.html        (the main index)
moveabletype/index.rdf         (one of several RSS formats)
moveabletype/archives.html     (the MT archive index page)
moveabletype/cat_anomaly.html  (one of 20 or so category archives)
moveabletype/2001_09.html      (one of 40 or so monthly archives)
moveabletype/2004/05/08/iq_by_state.html
                               (one of 900 or individual entries)
moveabletype/blogages/         (image directory for icons, etc.)
moveabletype/templates/        (template directory)

The new WordPress virtual file structure is a bit different:

wordpress/index.php         (the main index)
wordpress/wp-rss2.php       (the single RSS format)
wordpress/category/anomaly/ (one of 20 or so category archives)
wordpress/2001/09/          (one of 40 or so monthly archives)
wordpress/2004/05/08/       (one of 900 or so daily archives)
wordpress/2004/05/08/iq-by-state/
                            (one of 900 or individual entries)

So the question is, how do I redirect the first set of URL’s to the second set? I’ve seen advice out there for a few approaches involving PHP, JavaScript or mod_rewrite.
I decided to use mod_rewrite only rather than rebuild my thousand MT pages (never again!). I’ve been playing with it for a while now, and here’s my final answer:

I already have WordPress set up with the option to rewrite URL’s to a style not unlike my MT setup. This is the standard output of the WP Permalinks option, for the input /%year%/%monthnum%/%day%/%postname%/. I added the IfModule tags to soothe an angry server, and put it all into the file wordpress/.htaccess manually. Indented line breaks should be spaces, not line breaks. (Use the full files linked at the end to get the correct formatting.)

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /jemimap/wordpress/
RewriteRule ^([0-9]{4})/?([0-9]{1,2})?/?([0-9]{1,2})?/?([0-9a-z-]+)?/?([0-9]+)?/?$
   /jemimap/wordpress/index.php?year=$1&monthnum=$2&day=$3&name=$4&page=$5 [QSA]
RewriteRule ^category/?(.*)
   /jemimap/wordpress/index.php?category_name=$1 [QSA]
</IfModule>

Next, I put some basic redirection in the file moveabletype/.htaccess in order to handle the main static pages. Note that WordPress has no analogue of archives.html, so I just sent that to the main page. All the different RSS files now point at the one RSS 2.0 file in WP. [Update: I found the other WP RSS files and changed a couple of the redirects.] I also (manually) moved my image and template directories elsewhere and redirected to them, just to get them out of the way. (I don’t really need the MT templates, but it’s possible that I’ve pointed at them in the past for educational purposes, and I didn’t want to break the links with later rewrites.)

Redirect permanent /jemimap/moveabletype/index.html
   http://www.ficml.org/jemimap/wordpress/index.php
Redirect permanent /jemimap/moveabletype/index_summaries.rdf
   http://www.ficml.org/jemimap/wordpress/wp-rss.php
Redirect permanent /jemimap/moveabletype/index.rdf
   http://www.ficml.org/jemimap/wordpress/wp-rss2.php
Redirect permanent /jemimap/moveabletype/index.xml
   http://www.ficml.org/jemimap/wordpress/wp-rss.php
Redirect permanent /jemimap/moveabletype/archives.html
   http://www.ficml.org/jemimap/wordpress/index.php
Redirect permanent /jemimap/moveabletype/blogages
   http://www.ficml.org/jemimap/gifs/blogages
Redirect permanent /jemimap/moveabletype/templates
   http://www.ficml.org/jemimap/style/mt-templates

Since these are redirects, the surfer sees the new URL rather than the old one.

Now I was left with the basic rewriting - turning moveabletype/cat_fanfic.html into wordpress/category/fanfic/ or moveabletype/2001_09.html into wordpress/2001/09/. The following rewrite rules fix that:

RewriteRule ^200([0-9]{1})_?([0-9]{1,2}).html$
   /jemimap/wordpress/index.php?year=200$1&monthnum=$2 [L]
RewriteRule ^cat_?(.*)?(.html)
   /jemimap/wordpress/index.php?category_name=$1 [QSA,L]

People requesting these pages will see the original URL with “moveabletype” still in it, but these aren’t cases I expect to come up too often so I don’t mind that.

The really big issue is individual entry pages, because MT uses underscores to separate the names, but WP more wisely uses dashes. So moveabletype/2004/05/08/iq_by_state.html must become wordpress/2004/05/08/iq-by-state/. I started with this mod_rewrite file from idly.org. (He has a PHP plugin solution as well, but I prefer mod_rewrite.) Since I’m not working from the root of my server, I needed to make some changes. Here’s what I did:

RewriteRule ^([0-9]{4})/?([0-9]{1,2})?/?([0-9]{1,2})?/([^_]*)_([^_]*)_([^_]*)_([^_]*)_([^_]*)_(.*)?(.html)$
   /jemimap/wordpress/$1/$2/$3/$4-$5-$6-$7-$8-$9/ [R=301,L]
RewriteRule ^([0-9]{4})/?([0-9]{1,2})?/?([0-9]{1,2})?/([^_]*)_([^_]*)_([^_]*)_([^_]*)_(.*)?(.html)$
   /jemimap/wordpress/$1/$2/$3/$4-$5-$6-$7-$8/ [R=301,L]
RewriteRule ^([0-9]{4})/?([0-9]{1,2})?/?([0-9]{1,2})?/([^_]*)_([^_]*)_([^_]*)_([^_]*)?(.html)$
   /jemimap/wordpress/$1/$2/$3/$4-$5-$6-$7/ [R=301,L]
RewriteRule ^([0-9]{4})/?([0-9]{1,2})?/?([0-9]{1,2})?/([^_]*)_([^_]*)_(.*)?(.html)$
   /jemimap/wordpress/$1/$2/$3/$4-$5-$6/ [R=301,L]
RewriteRule ^([0-9]{4})/?([0-9]{1,2})?/?([0-9]{1,2})?/([^_]*)_(.*)?(.html)$
   /jemimap/wordpress/$1/$2/$3/$4-$5/ [R=301,L]
RewriteRule ^([0-9]{4})/?([0-9]{1,2})?/?([0-9]{1,2})?/([^_]*)?(.html)$
   /jemimap/wordpress/$1/$2/$3/$4/ [R=301,L]

[Updated to include the last rule, for one-word titles with no underscores.]

I added a more few levels of _’s than were in the original file because I have some very long titles like moveabletype/2004/05/15/pastwatch_walk_to_the_end_of_the_world_motherlines.html. However, mod_rewrite doesn’t allow me to exceed $9 in my variables, so the rules above would not handle that link. Back when I was despairing of getting any of this to work, I had considered the easy out of rewriting all individual entries to the day archive in WP. Since I tend to write only one entry a day, the solution would work pretty well for me, though the user would have to click for comments. I decided to handle the extra-long titles this way, and this is the rule that does it:

RewriteRule ^([0-9]{4})/?([0-9]{1,2})?/?([0-9]{1,2})?/([^_]*)_([^_]*)_([^_]*)_([^_]*)_([^_]*)_([^_]*)_(.*)?(.html)$
   /jemimap/wordpress/$1/$2/$3/ [R=301,L]

It needs to appear before the previous set.

You can get the whole moveabletype/.htaccess file in the correct order and layout here: mt-htaccess.txt. The WordPress one is here: wp-htaccess.txt. You’ll need to change the jemimap’s to something more appropriate, and save them as .htaccess in the relevant directories.

This is the full extent of my knowledge of mod_rewrite, so some bits may be wrong or redundant. Please leave a comment if something breaks or could be improved. [The missing case for one word titles has been fixed.]

One Response to “Redirects and Rewrites”

  1. Jadie Says:

    Ack!!!! you lost me. But you knew that would happen. Jemi, you are the geekiest! :-D My hats off to your well documented geekitude. I hope your new blog is good to you.