Definitive Guide to WordPress Rewrites
There are many tutorials that exist on implementing rewrites and redirects in wordpress. However all of the ones I’ve found have fallen short and the most applicable advice is buried deep within some indirectly related forum. What I aim to do is address the most common questions and pitfalls people run into when modifying .htaccess and implementing rewrites in wordpress.
There are many reasons why you may need to put a redirect on your blog, perhaps one of the most common is when content changes or is moved; maybe you’re migrating an existing web page or blog into wordpress.
So let’s look at the migration scenario, we have a number of files which we want to move into wordpress posts and pages and since we are the authority on the modern stone age family, countless Bedrock fans link to us. Since we would like to maintain the integrity of these links, we look to htaccess and mod_rewrite to rewrite incoming requests for the old content hierarchy to our wordpress hierarchy.
Before we go futher, here is a look at the default wordpress .htaccess file, this file should reside in the wordpress root directory.
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Now, let’s consider the files (links) which we wish to maintain. Some are static html and others dynamic php which take arguments to determine the content.
/about.html
/bedrock.html
/bio.php?character=fred
/bio.php?character=wilma
/bio.php?character=pebbles
/bio.php?character=dino
No problem, let’s knock about.html first, the mod_rewrite rule should look like this
RewriteRule ^about\.html$ /about [R=301,L]
This rule is fairly straight forward, but requires some knowledge of regular expressions, let’s break it down. RewriteRule is the configuration directive. ^about\.html$ is where it starts to look confusing.
The ^ indicates the beginning of the request, without this a request for whatabout.html or nothingabout.html would match the same as a request for about.html would.
Much like ^ does for the beginning of the request, $marks the end of the request. Without $ requests such as about.html.backup would match the same as about.html.
Finally, . is a special character in regular expressions which means match any character, so we escape it with a backslash to represent a literal period. Without escaping it, you would match requests such as aboutahtml.
Returning to our rewrite rule, /about is what we are rewriting about.html with.
[R=301,L] are the flags you’re passing the rewrite rule. R means redirect and 301 is a redirect code for permanent redirect, which is perfect in our scenario. L means this is the last rule, if we match, apply the rewrite and stop evaluating rules.
Now, let’s address /bio.php?character=fred, while you might logically try
# This does not work
RewriteRule ^bio.php\?character=fred$ /fred [R=301,L]
It does not work and can lead to hours of frustration, the mod_rewrite rule should look like this
# Working Rewrite
RewriteCond %{query_string} ^character=fred$
RewriteRule ^bio\.php$ /fred? [R=301,L]
We’ve introduced a new configuration directive, RewriteCond. As the name suggests, this directive allows you to pass conditions on which to assess the rewrite rule. In our scenario we want to assess RewriteRule if the query string, represented by %{query_string} is character=fred.
The RewriteRule should look familiar, as RewriteCond is already handling the arguments for the php script the only real difference is the trailing ? on the rewrite, without the trailing ?, when /bio.php?character=fred is requested, you would end up with /fred?character=fred after the rewrite. While this may be desirable in some scenarios, this is not what we want.
With these two scenarios addressed, we can complete our modification to .htaccess, after you’ve added the rewrite rules, your .htaccess should resemble the below.
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^about.html$ /about [R=301,L]
RewriteRule ^bedrock.html$ /bedrock [R=301,L]
RewriteCond %{query_string} ^character=fred$
RewriteRule ^bio\.php$ /fred? [R=301,L]
RewriteCond %{query_string} ^character=wilma$
RewriteRule ^bio\.php$ /wilma? [R=301,L]
RewriteCond %{query_string} ^character=pebbles$
RewriteRule ^bio\.php$ /pebbles? [R=301,L]
RewriteCond %{query_string} ^character=dino$
RewriteRule ^bio\.php$ /dino? [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Posted in Wordpress
July 13th, 2007 at 2:18 pm
Hi,
can you tell me why such construction doesn’t work?
# BEGIN WordPress
RewriteCond %{HTTP_REFERER} ^http://badsite.ru/.*$
RewriteRule ^/$ /you-suck.htm [L]
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
I mean the upper part with redirest function.
Thanks in advance!
July 13th, 2007 at 2:53 pm
I would write it like this, and place it below the RewriteBase /,
RewriteCond %{HTTP_REFERER} ^http://badsite.ru/.*$ [NC]
RewriteRule ^.* /you-suck.htm [R,L]
This way, badsite.ru will match the referer regardless of the case, and the rewrite rule will redirect anything (not just /) and the rewrite rule is to redirect.
July 14th, 2007 at 5:58 pm
[...] Good tutorial on this here. [...]
November 1st, 2007 at 12:11 pm
What if I wanted to do something like this?
RewriteRule /ask-me/(.*)/(.*)/$ index.php?page_id=71&start=$1
the first (.*) being an id number needed to grab some info from the db the second (.*) being a hyphenated title to help with SEO and to look nicer.
so my url would look like:
http://www.mysite.com/ask-me/2/two-plus-two/
which I want to resolve to
http://www.mysite.com/ask-me/?start=2
thanks in advance :)