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 ;)
24 responses to “Optimizing WordPress Permalinks with htaccess”
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.
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.
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%/
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?
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.
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.
Don’t need use 404 page?
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.
Hello
Just wondering why you went for the year/post title format instead of just post title?
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.
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
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/
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
I would install AskApache’s rewrite viewer to get some ideas.. sounds like something is interfering, most likely WordPress’ built-in rewrite functionality.
Thanks, Jeff. I’ll look into that solution and let you know what my resolution is, if anything.
Problem Solved.
According to this post, http://wordpress.org/support/topic/410-errors-returning-404-pages, it’s an issue with cPanel. You have to set the location of the error page with ErrorDocument.
The combination of both will let the change take effect.
Good to know. Thanks for the update.
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…
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.
Oh, sadly
Now the old link structure
http://old.com/blog/xxx/
couldn’t Automatic change into new domainhttp://new.com/blog/xxx/
, but thehttp://old.com/
has changed intohttp://new.com/
, How can i deal it?Is the .htaccess located on the old domain? It must be there for the redirect to work..
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.