Apr 03

Fixing broken links in WordPress after changing the permalink structure

Category: Linux,WWW   — Published by tengo on April 3, 2008 at 4:21 pm

After a fresh install of WordPress and the first posts you did to find your way around the admin panel and basic functionality of WP, some users start to fiddle with the knobs and begin to customise the appearance of their blog.

While this is OK for the human reader of your blog, it might not be quite as OK for search engines who have already begun to index your page. For example, this blogger here customised the way permalinks are written by WordPress. He chose to let it read like http://fooblog.bar/<postid>. Now, when he decided to change that to another scheme, for example to http://fooblog.bar/<post-title>/, all the legacy links in search engines and other blogs break. Your mileage may vary, but the problem may be essentially the same.

How to fix broken links from a change in the permalink structure?

The solution is easy: mod_rewrite. First, be sure that the rewrite engine is available for your installation of Apache (it shoudl when WP is working OK). Then track down the .htaccess file within the root directory of your WordPress installation. It should look like this:

RewriteEngine On
RewriteBase /

#uploaded files
RewriteRule ^(.*/)?files/$ index.php [L]
RewriteRule ^(.*/)?files/(.*) wp-content/blogs.php?file=$2 [L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule . - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-.*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*.php)$ $2 [L]
RewriteRule . index.php [L]

Now, open this file with an editor (via FTP or SSH2) and insert a rule that redirects a user visiting an outdated link to the new location.
If you changed the structure from the default one to a more compact and logical one, i.e. http://fooblog.bar/<year>/<month/<post-title>/ to http://fooblog.bar/<year>/<post-title>.html then a rule for that would look like

RewriteRule ^2006/03/my-first-post/ http://fooblog.bar/2006/my-first-post.html [R=301,L]

(Add a line like this for all your legacy urls.)

The first option after RewriteRule is the match pattern, the second option the redirect target. In the brackets follow the rule's attributes: R for "redirect", L for "last" so all following rules are ignored.

Be sure to use the R=301 attribute, as a standard redirect (like with [R,L]) would only print a "302 moved temporarily" redirect. But we do a permanent one here, with the code 301!

For other change scenarious you might need different rules. I fear you have to make yourself a bit more familar with mod_rewrite then. But as a first hint: you can access individual posts in wordpress via the url http://fooblog.bar/?p=<post-id>, if that is of any help for you.