WordPress and mod_rewrite

Apologies in advance that this is a long and confusing post…

Part 1: The problem

I decided I wanted to migrate my old Land of Devastation website at http://www.landofdev.com/ over to a subsection of http://www.smbaker.com/. There are several reasons for this, chief among them being that the Land of Devastation website doesn’t really stand by itself and doesn’t have a whole lot of pages. I’d rather discuss all of my door games together at my main site.

So, as part of the process I setup my provider to map the domain name www.landofdev.com into my existing www.smbaker.com website at a subdirectory of /landofdev. All I needed to do then was some simple rewriting or redirecting of pages that well into /landofdev/ to send them to the appropriate location in the main website.

Well, I thought it would be simple…

Part 2: Understanding mod_rewrite and wordpress

I spent a great deal of time one night trying to figure out how the wordpress mod_rewrite rules worked, and more specifically trying to figure out how to internally rewrite pages from one of my domains into another. Let’s start by looking at the rules that wordpress puts into the .htaccess file:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

If you’re familiar with mod_rewrite then this probably makes a lot of sense to you. If you’re not familiar with mod_rewrite, then let me explain it. The first RewriteCond checks to see if the current request maps to an existing file. If it does, then the remainder of the rule is skipped. The second RewriteCond checks to see if the current request maps to an existing directory. If it does then the remainder of the rule is skipped. These two checks allow you to mix static webpages on your site with WordPress permalinks. For example, say my website has a file:

/foo/bar.html

If a user request arrives for /foo, then the ‘-d’ rule sees this and aborts any further rewriting. If a request comes in for /foo/bar.html then the ‘-f’ rule sees this and aborts further rewriting. On the other hand if a request arrives for “/foobar/some-permalink”, then this request will be rewritten since /foobar/some-permalink is neither an existing file nor an existing directory.

Finally, the last line of the rule is the RewriteRule. It says to that anything that has made it this far should be rewritten to /index.php. Index.php is the main entrypoint for your wordpress site. The result is that anything that didn’t exist as a file or a directory gets sent to inedx.php where wordpress can do with it whatever it wants (normally, interpreting the URL as a permalink).

Part 3 – What I wanted to do and why it doesn’t work

Late one night I decided I wanted requests on my site for /landofdev/ to be rewritten to /games. “games” was a permalink on the website. This sounds like a pretty simple rewrite rule, doesn’t it? You might think of coding it up like:

RewriteRule ^/landofdev/$ /games [L]

Unfortunately, it doesn’t work. Not worth a damn. The RewriteRule itself goes off as expected, rewriting a request for landofdev/ to /games. Then it hits the wordpress rewrite rules, which further rewrite /games as /index.php. So far, so good – we’ve managed to route our request into wordpress. However, wordpress doesn’t really care what the page was rewritten to. It uses the REQUEST_URI variable from the web server when parsing the permalink. Mod_rewrite doesn’t modify the REQUEST_URI. So, although my little rewrite rule managed to get /landofdev/ routed to the right place, wordpress never saw the “/games” that I’d intended to rewrite it to, instead getting “/” out of REQUEST_URI, trying to find a permalink named “landofdev” and failing with a 404 error.

minor confusing footnote – the reason REQUEST_URI for http://www.landofdev.com/ contained in “/” instead of “/landofdev/” is because of whatever mojo the web provider is doing to map that domain into that subdirectory.

Part 4: How I bent wordpress to my will

I eventually solved with problem with an ugly hack. I placed a wordpress index.php inside of /landofdev/ on the website and added an ugly little if statement to it.

<?php
define('WP_USE_THEMES', true);
if ($_SERVER[REQUEST_URI] == “/”)  {
    $_SERVER[REQUEST_URI] = “/games”
}
require('../wordpress/wp-blog-header.php');
?>

Additional if statements could be added to remap additional pages, and you can also use wp_rewrite to help out a bit (one if statement to do a blanket redirect of everything in /landofdev, plus wp_rewrite regex rules to send individual pages to the right spots)

One small point of clarification – you might have expected me to use “/landofdev” in the if statement rather than “/”. On the website, “/landofdev” is actually representing an alternate domain name. I’m not sure exactly how godaddy does this, whether it’s a virtual host or some other magic, but the REQUEST_URI that show up at /landofdev are relative to the directory. Thus if someone requests http://www.landofdev.com/” it arrives in the /landofdev directory with a REQUEST_URI of “/”.

Finally, if someone does have a *better* way to do this, I’m looking for suggestions.

Leave a Reply

Your email address will not be published. Required fields are marked *