Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

Optimizing WordPress Permalinks with htaccess

[ Optimizing WordPress Permalinks with htaccess ] Okay, so Summer’s over, kids are back in school, and I’m finding all sorts of free time to continue writing and posting. One of my Summer projects involved updating & optimizing one of my old project sites, DeadLetterArt.com. It was basically a huge clean-up session that included lots of content consolidation and permalink restructuring. So that’s the topic of this post, how to use htaccess to optimize WordPress permalinks. I’ll go through some htaccess techniques and explain how they can improve your WordPress-powered site.

Change year/month/day permalinks to year only

The first thing I wanted to do is restructure the site’s permalinks. When I designed the site back in 2006, long URLs were all the rage, so I went with the convention du jour:

/%year%/%monthnum%/%day%/%postname%/

This permalink structure makes your WordPress URLs look like this:

http://deadletterart.com/2008/09/10/impertinent-art-review/
http://deadletterart.com/2011/06/18/california/
http://deadletterart.com/2011/06/19/join-the-empire/

And so on. Obviously these days long URLs are out and “shorter is better” is the current trend. After some thought, I decided to keep the four-digit year and remove the month and day numbers.

http://deadletterart.com/2008/impertinent-art-review/
http://deadletterart.com/2011/california/
http://deadletterart.com/2011/join-the-empire/

Not exactly bitly sized, but an improvement that results in a flatter directory structure, which they say is good for SEO. So there are numerous ways to make this change using htaccess, and after experimenting with several different approaches, I crafted this tasty little htaccess snippet:

# change year/month/day permalinks to year only
RedirectMatch 301 ^/([0-9]+)/([0-9]+)/([0-9]+)/(.*)$ http://deadletterart.com/$1/$4

To use this on your own site, change deadletterart.com to match your own domain. No further edits are required, but you should test thoroughly that everything is working properly. Note that we’re using a 301 status code for the redirects, so the search engines know that the URL changes are permanent.

Redirect removed pages

After optimizing the permalink structure, I consolidated a bunch of content, mostly pages that are no longer needed. Of course, whenever you delete a post or page on your site, the search engines panic, and seem to request those pages over and over and over again. That’s way too many 404 requests for my comfort, so I made sure that these missing pages are redirected to someplace useful, like the home page of the site. This is simple to do with a few lines of htaccess, as seen here for a handful of removed pages:

RedirectMatch 301 /feeds/?$ http://deadletterart.com/
RedirectMatch 301 /submit/?$ http://deadletterart.com/
RedirectMatch 301 /contact/?$ http://deadletterart.com/
RedirectMatch 301 /sitemap/?$ http://deadletterart.com/
RedirectMatch 301 /guestbook/?$ http://deadletterart.com/
RedirectMatch 301 /slideshow/?$ http://deadletterart.com/

These redirects share a common pattern, so we can optimize our code by rewriting this in single-line format:

RedirectMatch 301 /(feeds|submit|contact|sitemap|guestbook|slideshow)/?$ http://deadletterart.com/

Notice that we’re redirecting these page requests to the site’s home page, which you may edit to whatever URL you wish. This is good for SEO as it preserves any page rank that the removed pages may have accumulated. You can funnel that love wherever you would like, such as a sales page or other key resource.

Make dead pages go away

For pages that you would rather not redirect, but rather just declare them as officially “gone”, well there’s a code for that. As explained by Mark Pilgrim (404 link removed – what happened to diveintomark.org?), you can return a 410 - Gone status code to all requests for pages that you’d rather forget about. For example:

RedirectMatch gone /nu\-
RedirectMatch gone /nuer
RedirectMatch gone /renu
RedirectMatch gone /nuwest
RedirectMatch gone /nustyle
RedirectMatch gone /big\-nu

As before, we can take advantage of mod_alias’ pattern-matching skillz to combine rules into a single line, like so:

RedirectMatch gone /(nuer|renu|nuwest|nustyle|big\-nu)

So with this technique, we’re telling search engines (and anything else) that these resources are literally gone. This is an effective way to eliminate pages from the search engines, so be careful. A note about the pattern-matching – it’s a little bit different than in our previous example. This example excludes the following characters from the match:

/?$

So this example will match any URL that begins with /nustyle, such as:

/nustyle-1
/nustyle-1-2-3
/nustylebananaspiders

Admittedly the term “nustyle” is rare enough to avoid unwanted redirects, but more common terms require some fiddling with the pattern-matching. Moving on..

Redirect entire category to another site

Another part of the site’s restructuring involved branching a category into a new site. At the DLa site, a friend of mine and I had started posting a series of weird, random images in a category named “Chunks”. After about 15 pages worth of these bizarre chunks, we decided it would be a better idea to move ’em to a new site and then continue posting from there.

To do this, we created a “Chunks” category at the new chunks site, and re-posted everything. After that, redirecting the entire category requires a single line of htaccess:

RedirectMatch 301 ^/category/chunks/?(.*)$ https://example.com/category/chunks/$1

Update: I had to change “echunks.com” to “example.com” in the previous code snippet due to Googlebot’s aggressive crawl tactics and subsequent erroneous 404 errors.</update>

That’s about as clean as it gets. The only trick when redirecting category (and other) URLs to other WordPress sites is getting the post permalinks to match exactly. It takes some time, especially if you tend to punctuate post titles with apostrophes and such. For some reason that I haven’t figured out, apostrophes were not included in permalink URLs at one site, but they were included in the other. Just a head’s up.

More stuff on the way

Stay tuned ;)

About the Author
Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
WP Themes In Depth: Build and sell awesome WordPress themes.

24 responses to “Optimizing WordPress Permalinks with htaccess”

  1. Excuse my general ignorance, but couldn’t you just change the permalink structure to %year%/%postname% ?

    Plus, I thought WordPress automagically handled redirects if you altered your permalink structure.

    • Jeff Starr 2011/09/13 2:05 pm

      Yes, I need to mention that in the post. As far as I know, changing permalink structure works for existing and future posts. The “year-only” htaccess code provides more control over where and how the redirects are handled.

    • Peter Wilson 2011/09/13 4:24 pm

      You’re right, WordPress can handle this.

      Making the changes in the .htaccess file allows redirects to occur before WordPress is activated, avoiding unnecessary database calls and PHP execution.

      A change of structure without a predictable redirect would best be left to WordPress. For example changing
      /%postname%/ to /%post_id%-%postname%/

  2. As far as I know, changing permalink structure works for existing and future posts.

    It does most of the time. Sometimes not so much.

    This is awesome, though! I’ve consolidated a ton of my 301s! Can you put variables in? Like would

    RedirectMatch 301 /(foo|([0-9]{4})/([0-9]{2})/([0-9]{2})/bar) ...

    Work?

    • Jeff Starr 2011/09/13 8:39 pm

      Yep, you can do that with .htaccess :)

      So definitely useful for matching subdirectories and other custom permalink configurations, which WP has been known to misdirect occasionally.

  3. Great stuff Jeff. Perfect timing with all the hype of a 3.3 fix on /%postname%/ permalinks triggering verbose rewrite rules. Would be cool to do a write-up on a simple search and replace SQL query to fix old permalinks found the database.

  4. airoschou 2011/09/14 1:40 am

    Don’t need use 404 page?

  5. comments closed on the snippets post? too many questions I suppose? Your design is nice but I didn’t see the point in the “expanding div” unless the text went with it, eh?
    Thanks for sharing your brilliant brain, tho.

  6. Hello

    Just wondering why you went for the year/post title format instead of just post title?

  7. Jan-Willem Bobbink 2011/09/25 3:12 am

    I’ve the same question as Paul, why don’t choose for the most simple option? It is plain, logical and the most user friendly option. Besides that, for SEO purposes, the keyword density in the URL is higher.

    • It’s a good question, but no big secret, really. I prefer including the year for informational purposes. It’s just nice to be able to see when the post was published without having to search around for it. Feel free to choose whatever you think is best.

      • From my understanding, having the year in the URL will make for more efficient rewrite rules, i.e. minimize the size of rewrite_rules in the wp_options table.

        That said, I’m up against my own dilemma here: I want to add the year to my existing url structure.

        Current
        http://site.com/category/the-post-title

        Desired
        http://site.com/2011/category/the-post-title

        Again, aiming for greater efficiency. Any recommendations for rewrite rule wizardry?

        Regardless, thanks for maintaining a spot-on site.

  8. From the SEO point you need to move year after post-name,like http://www.mypage.com/mypost/2011 , or remove year it will be better for SERP

  9. Alo Konsen 2012/03/26 2:13 pm

    How would I properly write an htaccess line to redirect all requests so that wp/ is inserted after the domain name and .htm is replaced by a slash? For example, when someone requests …

    http://somedomain.com/2008/11/18/pagename.htm

    … I want them to get …

    http://somedomain.com/wp/2008/11/18/pagename/

  10. Hi Jeff,

    I have WordPress installed and am editing the htaccess file found in the root of my server.

    I’m setting Redirect 410 /bookmarks in the htaccess file however the server is still returning a 404 status code.

    Any thoughts on why that would be?

    Thanks,
    Tom

  11. airos chou 2013/01/15 2:52 am

    Hello, Jeff
    I’ve a problem, and need your hand again.

    I bought a new Domain, XXX.com.
    http://xxx.com/blog/ is my wordpress link structure,
    now “http://old.com” has changed into “http://xxx.com”, but the “http://old.com/blog/$1” have’t changed, i have a no idea to deal it,
    hope your help…

    • Jeff Starr 2013/01/15 1:13 pm

      Hi airos,

      I would try something like this to redirect from the old domain to new:

      RedirectMatch 301 ^/blog/(.*) http://xxx.com/blog/$1

      Place this code in the root .htaccess file located on your old domain. Test thoroughly, adjust as needed.

      • airos chou 2013/01/16 12:57 am

        Oh, sadly

        Now the old link structure http://old.com/blog/xxx/ couldn’t Automatic change into new domain http://new.com/blog/xxx/, but the http://old.com/ has changed into http://new.com/, How can i deal it?

      • Jeff Starr 2013/01/16 3:03 pm

        Is the .htaccess located on the old domain? It must be there for the redirect to work..

  12. airos chou 2013/01/16 6:54 pm

    The search engine keep the a lot of my old link address – example: ”http://old.com/blog/xxxxxx/“ such as this links hava a lot of keep in the search engine.
    Now if you visit these links that can’t redirect into new domain.
    But if only”http://old.com/blog/”, not take /xxxxx/
    these links canbe redirect into ”http://new.com/blog/”.
    by the way, my .htaccess is on the old domain root directory.

Comments are closed for this post. Something to add? Let me know.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
.htaccess made easy: Improve site performance and security.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.