How to Update Your WordPress Permalinks Without Causing Link Rot

by Rick Beckman on January 18, 02008

If you are chang­ing your perma­links struc­ture dif­fer­ently than what is described below (e.g., going from name-based perma­links back to name and date-based perma­links), there is a Word­Press plu­gin that can take care of you. If all you want to do is change from name and date-based perma­links to name-based perma­links, the method described below should be a bit faster, as the redi­rect is han­dled at the server level rather than at the PHP level.

This is a follow-up to my ear­lier post Seam­less Perma­link Updat­ing. The prob­lem I faced was that I wanted to change my Word­Press perma­link set­tings from being date and name based to some­thing which was sim­ply name based.

Why did I want to do this?

  1. Perma­links would be shorter; remov­ing the date infor­ma­tion results in URIs which are eleven char­ac­ters shorter.
  2. Perma­links would not only be more read­able, they would be more mean­ing­ful to humans; dates aren’t as impor­tant as the con­tent the page itself con­tains. If pre­sented with a list of perma­links from this site, users should have a good idea of what they’ll get when they click them. There’s no rea­son to muddy those waters by inject­ing date infor­ma­tion into the mix, dilut­ing the impact of the domain and post slug.
  3. The con­tent part of the perma­links (domain name + post slug) would carry more impact in var­i­ous search engines, with­out date infor­ma­tion (that may or may not be rec­og­nized as dates by search engine algo­rithms) dilut­ing the value of what­ever key­words may be present.
  4. Yes, this is a blog, and yes infor­ma­tion is posted chrono­log­i­cally; how­ever, this isn’t a novel, and the mate­r­ial here need not be read in a chrono­log­i­cal man­ner in order to under­stand it. Hav­ing date-based perma­links cre­ates the illu­sion that the date the mate­r­ial was posted is more impor­tant than it really is. Besides, posts are dis­played with the date any­way; why give it to the user twice when I’m bet­ting the date included with the post is glanced over by most users.

Great rea­sons, I think, which should suf­fice for now. So I wanted to change my perma­links; what did I do about it?

Word­Press makes the process ridicu­lously simple.

  1. Visit the Perma­links page of the admin­is­tra­tion panel (/wp-admin/options-permalink.php).
  2. Select the but­ton labeled “Cus­tom, spec­ify below.”
  3. In the box labeled “Cus­tom struc­ture,” enter the text /%postname%/
  4. Sub­mit the change via the “Update Perma­link Struc­ture »” button.
  5. Visit your site and ver­ify that posts are not being given perma­links in the style example.com/post-name-here/. Beau­ti­ful, no?

Like I said, ridicu­lously easy!

But con­sider: What hap­pens to all the links out there on the Inter­net to your blog which make use of the pre­vi­ous style of perma­links? Try it out for your­self; find an old perma­link in your browser’s his­tory that still makes use of “Date and name based” perma­links and visit it.

404! You broke the Inter­net! File not found! It’s the end of the world as you know it!

But don’t worry, you can feel fine about it because I have a solu­tion, pro­vided that you are using Apache as your server envi­ron­ment (chances are, you are) and mod_alias is enabled (I’m unsure how com­mon it is). We’ll be fix­ing our prob­lem using the RedirectMatch direc­tive of mod_alias.

  1. Down­load your blog’s pri­mary .htaccess file; most likely, it’ll be in the same direc­tory as your blog’s wp-config.php file.
  2. Open it up, and find Word­Press’ perma­links code. If you’ve never edited your .htaccess file before, it will most likely be the only code present. The code looks like this, give or take a line break:

    # BEGIN WordPress
    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    </IfModule>
    # END WordPress
  3. Before that Word­Press code, you’ll want to add one of the following:
    • If your Word­Press is installed in your domain’s root direc­tory (e.g., example.com/wp-config.php), add this code, adjust­ing example.com to your proper domain name:

      RedirectMatch permanent ^/[0-9]{4}/[0-9]{2}/[0-9]{2}/([a-z0-9\-/]+) http://example.com/$1
    • If your Word­Press is installed in a sub­di­rec­tory of your domain (e.g., example.com/blog/wp-config.php), add this code, adjust­ing example.com/blog to your proper domain name and directory:

      RedirectMatch permanent /blog/[0-9]{4}/[0-9]{2}/[0-9]{2}/([a-z0-9\-/]+) http://example.com/blog/$1
  4. Save & upload the .htaccess file, and revisit one of your older date-based perma­links. If all went accord­ing to plan, you should be seam­lessly redi­rected to your new name-based permalinks.

That’s all there is to it! If any­one can pro­vide a bet­ter means, I’m open to it, but I’ve tested this out, and it works exactly as I want it to — posts work, paged posts work, pages work, and so on. I can’t promise this won’t break any Word­Press plu­g­ins, so be pre­pared to give up this method (which is as easy as delet­ing what­ever you add to .htaccess and switch­ing your perma­link struc­ture back).

For the curi­ous, this is what the code above does, piece by piece:

Redi­rect­Match
Begins the call to Apache’s mod_alias module.
per­ma­nent
Sends the client (i.e., the user, whether human or robot) instruc­tion that this redi­rect is a per­ma­nent redi­rect and that the old address is invalid and should be from now on replaced with the new.
^/[0–9]{4}
The address which we’re try­ing to match begins with a four-digit year stamp, so we first look for a slash fol­lowed by four numbers.
/[0–9]{2}
The address will next have a two-digit month stamp, so we check for another slash fol­lowed by two numbers.
/[0–9]{2}
The address will next have a two-digit day stamp, so we check for yet another slash fol­lowed again by two numbers.
/([a-z0-9\-/]*)
The address will then have the post slug, which can con­sist of a vari­ety of low­er­case let­ters, num­bers, and dashes. So we look for any num­ber of those. A post slug may include addi­tional infor­ma­tion after it, such as a page num­ber on paged posts, so we include any num­ber of slashes in our search as well. It’s enclosed in paren­the­ses so we can cap­ture that data and use it in the next section.
http://example.com/$1
This is the loca­tion of where we want to redi­rect to. The $1 at the end will be replaced by what­ever was matched by the code in paren­the­ses in the pre­vi­ous statement.

Edit: Whoops! Using the above RedirectMatch code pre­vented view­ing of day archives (e.g., /2008/01/01/); swap­ping the aster­isk (*) out for a plus sign (+) resolved the issue and allows day archives to be viewed. The code above has been corrected.

{ 38 voices in the conversation. Speak up! }

Jeff_ January 20, 2008 at 11:54

Excellent post, Rick.

I am seriously (re-)considering removing the date portion of my permalinks. One of the last (logical) reasons I can think of to avoid this change involves the ability to display posts via year, month, and day views. To what extent are the archive pages working with this method in place? And finally, have you noticed any conflicts with plugins, etc.?

Also, you may be amused to know that in an attempt to solve this mystery, I had discovered the same htaccess technique and even wrote a (remarkably similar) article explaining the implementation process.. I was ready to roll with it, but by the time I had finished my work week and returned to the computer, you had already devised a solution and published an article — doh!

Rick Beckman January 20, 2008 at 14:22

Jeff_ — Using the above method, all of the following work:

None of those archive permalinks match the RedirectMatch regex, and so that directive is skipped and the address is parsed by the WordPress-added .htaccess directives.

Rick Beckman January 25, 2008 at 11:45

Looks like there’s actually a WordPress plugin that allows for redirecting old permalinks to new ones. I added a note at the beginning of the post above with a link to it.

Chris January 27, 2008 at 13:05

Ran across this post and thought you might be interested in reading it: http://thuledingles.com/?p=191

Rick Beckman January 27, 2008 at 13:17

Chris — Saw that linked to earlier from Weblog Tools Collection. I only read the excerpted quote then, but followed your link and read it in full.

He’s absolutely right when he implies that permalink design is very site specific.

However, it would be interesting to tinker around and see how much pull a permalink has on how Google indexes — for instance, if the above post had a permalink which referenced Britney Spears, Paris Hilton, and so on, how long would it take for traffic to show up looking for that kinda stuff, if at all?

It’d make for an interesting experiment, I think!

Chris January 27, 2008 at 16:58

Lol, I’ll leave the tinkering and experimenting to you :-) I had a post and poll about credit cards a while back, and I noticed a big change in amount and type of spam…

Rick Beckman January 27, 2008 at 21:10

Oh I’m sure. I might try it a bit further down the road when I’m more confident in the wall of protection in place here against spam!

Rick Beckman January 30, 2008 at 17:24

Hehe, just got this in my stats: A referral from search results for britney spears roots rot

ryan woodrum March 15, 2008 at 23:37

Great post, worked like a charm for converting my wordpress permalinks from the default ?p=\d+ format to the /%postname%/ format. Thanks!

Latest from ryan woodrum: H&R Block TaxCut bogus “password protection”

amy March 24, 2008 at 19:40

We want to thank you for this simple, easy-to-follow instructions on the redirection. We’ve been trying to do this for weeks now and, because of your post, I just fixed it in 2 minutes! We’re bookmarking this!! Thanks so much.

Amy and Jonny – http://www.weareneverfull.com

Rick Beckman March 24, 2008 at 19:57

ryan woodrum & amy — I’m glad both of you were able to benefit from this guide! If you have any problems related to permalinks as a result of following any of the above advice, just drop a comment, and I’ll do my best to sort out your issue(s)!

James May 19, 2008 at 17:11

Hi, I tried the htaccess rule you suggest, of course I change example.com to my website, but all I get is an error page about server configuration and additional 500 error. My WP installation is in my domain’s root. Any Idea?

Thanks you :-)

Rick Beckman May 19, 2008 at 17:30

Could you post the contents of the modified .htaccess you are using? You can paste it onto this site [ http://pastebin.com/ ] and give me the link to the resulting code page.

A Server Configuration problem could be caused by any number of things, unfortunately, but I’ll take a look for ya!

James May 19, 2008 at 17:47

That was fast :-)
Right now I set up a cpanel redirect but that’s for a couple of old posts. I haven’t actually change the permalink structure in WP, I just change some posts date and since then I’m seeing few errors caused by visitors coming from search engines.
Anyway, here’s my htaccess http://pastebin.com/d3ad3a557

Rick Beckman May 19, 2008 at 18:45

James: Try adding the lines I added — they should be highlighted:
http://pastebin.com/f3d55d0a9

If the server error goes away and the redirecting does not work, then the cause is because Mod_Alias is not configured on your server and a solution using Mod_Rewrite will need to be used.

For more information on Mod_Alias:
http://httpd.apache.org/docs/1.3/mod/mod_alias.html

Jeff over at Perishable Press presents the Mod_Rewrite rules if you want to try them out.

Miles August 13, 2008 at 11:33

Thank you so much for the information. The plugin that many people use doesn’t work for converting from default pages, but luckily I stumbled upon your solution, and it works perfectly. Thanks again for your helpful article.

Alexander - StrategieVincenti August 17, 2008 at 17:28

Hi Rick,

I had the month and name structure for the permalinks of my blog. Recently, due to other problems, I deleted the whole WP installation and did a new clean one, then I re-imported all my posts and now I’ve set directly the permalink structure to /%postname%/.

So now I’ve the problem that in the old blogs I’ve still internal links with the old “month and name” permalink structure. I thought to fix the problem with your redirection, but it doesn’t work: I get an 404 error.

Take a look at my .htaccess file http://pastebin.com/m15779b1e and please help me to find where I fail.

Thanks in advance & ciao

alexander

Rick Beckman August 17, 2008 at 20:49

Alexander – StrategieVincenti: Troubleshooting HTAccess problems is not something at which I’m at all skilled. If my solution above doesn’t work for you, try out this one from a friend of mine. We were both working at solving the problem of shortening permalinks at the same time. I’m pretty sure his solution will work in a wider variety of cases as it uses the same technology as WordPress permalinks. My solution uses a different Apache module than the WordPress rewrite rules do; it may not be present or enabled on all systems.

Alexander - StrategieVincenti August 18, 2008 at 07:12

Hi Rick,
finally I installed the plugin you mentioned in the post and that fixed my problem.

Thanks & ciao

Rick Beckman August 18, 2008 at 16:07

Alexander – StrategieVincenti: Glad to hear it. :D

Max Forlani August 25, 2008 at 04:17

Hi Rick,

very interesting article.

Over the weekend, I actualy did a double change. I switched from a windows based server to the Apache version, to get rid of the stupid index.php

And on top of that, I wanted to get rid of the day in the url, but keep the year and month.

To do all this, I used the tool that you mention and that may have a security breach. So I’m certainly willing to give your suggestion a go, but how would that string look like in my case?

Original url:
http://www.domain.com/index.php/%year%/%monthnum%/%day%/%postname%/

Current URL:
http://www.domain.com/%year%/%monthnum%/%postname%/

Beside the already mentioned plugin, I also use the Objection Redirection plugin (http://www.biggnuts.com/objection-redirection-wordpress-plugin/). I read about this in an article on a Permalink Change by DoshDosh. Does this still make sense if I apply the .htaccess tool?

Kind regards,
Max

Michelle September 19, 2008 at 14:18

I just did a hellish move from an extremely outdated Movable Type installation to Wordpress. All I wanted was to redirect my old permalink format:
/blog/archives/123456.php

to my new format:
/blog/archives/123456

I Googled for hours and tried all sorts of redirect rules, and nothing worked until your Redirect Match tip. THANK YOU!

Latest from Michelle: Mouldy Speeches

jgoode January 2, 2009 at 18:41

Awesome, exactly what I was looking for. Thank you so much for your fantastically clear information, your help pointing me to this article and your willingness to share additional outside links for further insight. I ended up having to go with the mod-rewrite version, but it works perfectly!

bongkersz April 3, 2009 at 00:07

Awesome! Thanks a lot dude. You made my day, after searching up and down in the internet, trying few plugins which needs more tweaking works.. this one piece of code save the day!!!!!!!!!!!!!! :D

Money Off Shop April 30, 2009 at 15:05

Hi Rick – just wanted to say a HUGE thank you for your clear and concise instructions. They worked a treat when I changed my permalink structure and the search engines love it!

Thanks again – you’re a genius :-)

Ari Herzog May 25, 2009 at 21:42

You rock, Rick! But you already knew that, right? :)

I switched around my permalink structure last night–courtesy of http://www.keenerliving.com/leaving-the-dates-out-of-your-urls-blogging-tip/ — but the RedirectMatch line wasn’t working correctly.

After emailing back and forth with Bruce, I had it down to

RedirectMatch 301 /([0-9]+)/([0-9]+)/(.*)$ http://ariwriter.com/$3

That solved the posts, but created a conflict with date-based archive pages and uploaded images in date-based wp-content folders. One link led to another–and I came across this. I now have:

RedirectMatch 301 ^/[0-9]{4}/[0-9]{2}/([a-z0-9\-/]+) http://ariwriter.com/$1 and it works great!

Better to use htaccess than plugins I figure; cleaner!

Joel K June 25, 2009 at 13:45

When you say add it BEFORE the wordpress code, do you mean before the line that starts “# BEGIN WordPress” or just after that??

Thanks

Rick Beckman June 25, 2009 at 16:46

Before it. :)

simon July 9, 2011 at 19:24

Wish I had stumbled on this site first, could have saved a lot of time. Thanks for the clear instructions, worked a treat.

Paul September 19, 2011 at 07:54

I’ve just removed the date from my permalinks. Used to have the year and month in the URL but now changed it to just the post title. Haven’t seen an effect for SEO yet. I’m hoping that removing the date will increase click through as people don’t want to click on a link where they know the content is a couple months old.

Tevya October 31, 2011 at 12:53

Thanks for this great info. I’m just trying to figure out a few details before proceeding with this, and hope you can help. My current permalink structure is (setup to mimic Blogger, since it was originally there):
/%year%/%monthnum%/%postname%.html
I want it to be:
/%post_id%/%postname%/
because some articles (like this one http://wpmu.org/the-best-wordpress-permalink-structure-for-scaling-performance-and-seo/ ) suggest it’s bad for long-term scaleable performance to go directly to postname.

So based on your article, I assume I’ll just remove the “/[0 – 9]{2}” part, because I’m not using the day in the current permalink? Then do I also need to do something other than the “$1″ on the end, since it will now have the post ID before the name/slug? Thanks.

Rick Beckman November 1, 2011 at 00:52

I haven’t tested this, but try this out:

RedirectMatch permanent ^/([0-9]{4})/[0-9]{2}/[0-9]{2}/([a-z0-9\-/]+)\.html http://example.com/$1/$2/

This assumes a /%year%/%postname%/ format. The problem with using the post number is that your original permalinks don’t have that information, so i’m unsure how to map it via regex to the new permalinks. Using the year alleviates the issue you mentioned, though.

Based on reports i’ve seen, the inefficiency with /%postname%/ permalinks is only an issue if you have many, many pages (posts are irrelevant). By adding a number (year, post number, whatever) to the permalink, WordPress more easily distinguishes between posts & pages and so the inefficiency is no longer there.

Actually, i seem to recall an update in WordPress that fixed that issue altogether. Still, i chose to add the year to my permalinks here out of anticipation of some day having lots of pages (which may or may not actually happen).

Tevya November 1, 2011 at 18:47

Thanks for the response Rick. I was wanting to use this plugin: http://wordpress.org/extend/plugins/old-post-promoter/ to promote old posts (most of this site’s content is not time-sensitive). It won’t work if you use any dates in your permalinks.

Now that you say that about it only being related to pages (not posts) and possibly fixed in a recent version of WP, I seem to remember at least the latter, as well. I’ll just go with the slug/post name, no post number or anything. But I will add the “.html” on the end of the first part, to make it work correctly.

So I don’t remove the “/[0-9]{2}” even though my current URL doesn’t have the day in it?

Rick Beckman November 1, 2011 at 23:47

No, you’re right about that: remove the unnecessary pointer to the day!

Also, WordPress does a pretty good job of getting users to the correct location after you change your permalinks. When i updated permalinks here to include the year, i didn’t have to do anything special to get old links to point to the correct place. It just worked. I’m not sure if it’ll still work correctly with the “.html” bit of yours, however, so try it to see, and if it does work, you won’t need to modify your .htaccess file.

Rick Beckman November 1, 2011 at 23:50

Also, it seems like you’d be able to promote old posts by setting their status to sticky temporarily rather than having their post time adjusted. That’ll make them reappear in feeds, which could annoy longtime subscribers. Probably not, though. Just thinking allowed. There’s just gotta be a better way to accomplish promoting old posts than by modifying post time, which would lead to the situation of having post content from 2011 that has comments on it dating from 2009 or so… Not a huge deal, but i’m just obsessive enough to be bothered by it. :P

Tevya November 3, 2011 at 15:44

Agreed. I’d prefer another method without rewriting the date, but haven’t been able to find anything. Since most of my RSS subscribers are new, but a decent amount of content is not (revived somebody else’s old blogger blog), I actually want it to post and show up in the RSS as well. This is the best solution I’ve found, so I’m going to give it a try.

Thanks much for your help.

Tevya November 7, 2011 at 12:03

I added this:
RedirectMatch permanent ^/[0-9]{4}/[0-9]{2}/([a-z0-9\-/]+)\.html http://mormonlifehacker.com/$1

And it worked perfectly! I decided to go without the post number. I installed that plugin and we’ll see how it works….

Rick Beckman November 7, 2011 at 22:36

Awesome! Glad you got it all sorted.

Leave a Comment

{ 3 linkbacks }

Previous post:

Next post: