Jump Menu : Content | Explore | Comments | Search | Home | Sitemap | Contact | Login | Access.

htaccess Combo Pack: WordPress Permalinks and non-www Redirect

WordPress users employing permalinks via htaccess to optimize their dynamic URLs transform complicated-looking links such as:

http://example.com/blog/index.php?page=33

..into search-engine friendly links such as:

http://example.com/blog/post-title/

Every rewritten URL relies on a common set of htaccess rules to transform the links. The htaccess rules for all WordPress permalinks look like this for root WP installations:

# BEGIN WordPress
<ifmodule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</ifmodule>
# END WordPress

..and like this for subdirectory WP installations:

# BEGIN WordPress
<ifmodule mod_rewrite.c>
RewriteEngine On
RewriteBase /subdirectory/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /subdirectory/index.php [L]
</ifmodule>
# END WordPress

Unfortunately, although this default htaccess code affects all WordPress-generated URLs, it does not take into consideration the basic canonicalization issue of the infamous www prefix.

As visitors navigate through your WordPress-powered site, each and every page is accessible via at least two (and probably several more) distinctly different URL addresses: one with the www prefix and one without.

This of course presents duplicate content issues that tend to lower the ranking effectiveness of your pages. Fortunately, it is relatively easy to eliminate duplicate content generated via identical www and non-www content.

Given the previously defined, default WordPress htaccess rules for permalinks, simply insert the following code after the line RewriteEngine On:

RewriteCond %{HTTP_HOST} ^www\.domain\.tld$ [NC]
RewriteRule ^(.*)$ http://domain.tld/$1 [R=301,L]

So, to clarify, let’s say your WordPress installation is located in the root html directory of your domain. In this case, replace the default permalink htaccess code with this:

[ WordPress installed in site root ]

# BEGIN WordPress
<ifmodule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.domain\.tld$ [NC]
RewriteRule ^(.*)$ http://domain.tld/$1 [R=301,L]
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</ifmodule>
# END WordPress

Now, all visitors will be directed to the non-www version of the permalink URL for your pages. Similarly, when your blog is installed in a subdirectory of the html root, replace the default code with this:

[ WordPress installed in subdirectory ]

# BEGIN WordPress
<ifmodule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.domain\.tld$ [NC]
RewriteRule ^(.*)$ http://domain.tld/subdirectory/$1 [R=301,L]
RewriteBase /subdirectory/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /subdirectory/index.php [L]
</ifmodule>
# END WordPress

This code will ensure that all pages within the subdirectory are served with non-www permalinks. To rewrite all pages above the subdirectory level, such as pages located “above” the blog in the root html directory, add a copy of the following code to your site’s root htaccess file:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.domain\.tld$ [NC]
RewriteRule ^(.*)$ http://domain.tld/$1 [R=301,L]

One final note: if you would rather employ the www-versions of your site’s pages as the official canonicalized URLs, replace these two lines:

RewriteCond %{HTTP_HOST} ^www\.domain\.tld$ [NC]
RewriteRule ^(.*)$ http://domain.tld/$1 [R=301,L]

..with these:

RewriteCond %{HTTP_HOST} ^domain\.tld$ [NC]
RewriteRule ^(.*)$ http://www.domain.tld/$1 [R=301,L]

And that should do it. With our new and improved WordPress permalink rules, we eliminate duplicate content, serve search-engine friendly permalinks, and thus preserve more link equity and SEO value for our pages. Nice! ;)

Related articles

About this article

This is article #413, posted by Jeff Starr on Monday, October 01, 2007 @ 11:08am. Categorized as Function, WordPress, and tagged with apache, code, htaccess, mod-rewrite, permalink, redirect, tips, tricks, WordPress. Updated on November 05, 2007. Visited 25095 times. 10 Responses »

BookmarkTrackbackCommentSubscribeExplore

« 88Teeth Site Redesign • Up • Fixing Mint after Switching Servers »


10 Responses

1 • October 1, 2007 at 12:11 pm — Louis says:

I have a good and a bad new for you.

The bad new is that this method obsolete.

The good new is that this method has been made absolete by the new WordPress 2.3, which takes care of the canonical URL automatically.

Indeed, your work is still useful and pedagogic, but it’s important to know that the last WP does it internally.

This said, i want to thank you for the nofollow serie you wrote. It must’ve taken a lot of time, so thanks for sharing this with us !

2 • October 1, 2007 at 1:35 pm — Perishable says:

Yes, I recall reading that WordPress 2.3 incorporates this functionality by default. However, I have to disagree that such implementation renders obsolete the information presented in this article. There are many people running WordPress versions less than 2.3, and for them, this htaccess technique may indeed prove useful. Nonetheless, it is very thoughtful of you to point this information out to us, and your kind remarks concerning the no-nofollow/dofollow series are appreciated as well. Thanks for the feedback! ;)

3 • October 1, 2007 at 10:33 pm — Louis says:

Also, before switching to 2.3, I used the no-www plugin by the wordpress creator Matt him-self.

http://photomatt.net/2006/06/13/wordpress-no-www/

It did the job very well.

4 • October 25, 2007 at 2:32 pm — Jim Spencer says:

Curious.

I copied this:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^domain\.tld$ [NC]
RewriteRule ^(.*)$ http://www.domain.tld/$1 [R=301,L]
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

And when I visit the www version or the non www version the URL stays the same as I typed it. If I click on links, the URL never shows the www.

I switched the code example and it performs exactly the same.

Where else should I be looking?

5 • October 25, 2007 at 2:46 pm — Jim Spencer says:

I found another string, replaced it, and it works for me. I hope it helps someone else too.

# BEGIN WordPress

RewriteEngine On
#RewriteCond %{HTTP_HOST} ^jbspartners\.tld$ [NC]
#RewriteRule ^(.*)$ http://www.jbspartners.tld/$1 [R=301,L]

#RewriteEngine on
RewriteCond %{HTTP_HOST} !^www\.jbspartners\.com
RewriteRule (.*) http://www.jbspartners.com/$1 [R=301,L]

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

6 • October 28, 2007 at 4:15 pm — Perishable says:

Interesting, Jim — Thanks for sharing this with us. I have heard of certain browsers not displaying the redirected URL in the address bar under certain situations. When this happens, an easy way to verify that the page redirected as intended is to check the URL of any image (background or otherwise). If the image shows the redirected URL, there is nothing to worry about from an SEO perspective, however getting the address bar to display the redirected URL may be necessary as well. If your suggested htaccess code does the trick, then more power to you. In any case, thanks again for sharing this information — it is greatly appreciated!

7 • October 31, 2007 at 12:37 pm — Jim Spencer says:

I didn’t mean to blame the browser, I was describing the effect of the changes.

No conclusion yet, but it does seem that the order each line is written down the page is important. It’s not Latin where word order doesn’t matter.

Is that your experience as well?

8 • October 31, 2007 at 1:20 pm — Perishable says:

Yes, I realize that you were not addressing browser deficiencies, but these are widely used rewrite rules that are known to work effectively on virtually every compatible system. The reason I mention browser address fields specifically is that it is not uncommon for the rewrite to have taken effect at the server level, but not indicated as such by the address bar. The point being that the additional set of rewrite directives may not be necessary, unless of course you want your visitors to actually see the correct URL in their browser. Bottom line: if you verified the ineffectiveness of the rewrite rules at the server level (and not just via the browser), then by all means, add the extra lines and have at it. Otherwise, you may want to check again — the extra directives may prove unnecessary.

As for the order in which htaccess directives (and especially rewrite rules) are specified and processed, that would be an emphatic “yes!” — it is absolutely critical that every jot and tittle follow a precise chronological order in order to function as intended. Although there are a few exceptions, in my experience proper ordering is critical.

9 • November 26, 2007 at 9:08 pm — Jim Spencer says:

One thing that may not be clear from my post is that the first rule is commented out. So, there is really only one. I noticed this later, but it was already posted.

My blog had an operation tonight and now the code does not work. It resolves to the non-www. instead. Any suggestions for me? Here is what is in place now.

# BEGIN WordPress

RewriteEngine on

#RewriteCond %{HTTP_HOST} !^www\.jbspartners\.com
#RewriteRule (.*) http://www.jbspartners.com/$1 [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\ HTTP/
RewriteRule ^index\.php$ http://www.jbspartners.com/ [R=301,L]

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

10 • December 27, 2007 at 8:20 am — Dubai Property Blogger says:

Excellent page. I’m still having some problems with my .htaccess but getting there. This place has helped a lot. Thanks!

Drop a comment



Set CSS to lite theme
Set CSS to dark theme