htaccess Combo Pack: WordPress Permalinks and non-www Redirect

Posted on October 1, 2007 in Function, WordPress by

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

29 Responses

  1. [ Gravatar Icon ] 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. [ Gravatar Icon ] 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. [ Gravatar Icon ] 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. [ Gravatar Icon ] 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. [ Gravatar Icon ] 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. [ Gravatar Icon ] 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. [ Gravatar Icon ] 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. [ Gravatar Icon ] 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. [ Gravatar Icon ] 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. Excellent page. I’m still having some problems with my .htaccess but getting there. This place has helped a lot. Thanks!

  11. [ Gravatar Icon ] WWW Redirect says:

    Usually it is a good idea to put the .htaccess file in the root directory. If you are worried about different names causing duplicate content issues or other things, the same concern exists with URLs outside of the blog too.

    Louis (@3), using a plugin is overkill. It increases the server load unnecessarily. If you can, stay away from it.

    I’ve written 301 redirect configuration code for Apache, lighttpd and nginx for www redirection to non-wwd vice versa.

    http://blogbuildingu.com/articles/www-redirect-right-way

    –Hendry

  12. I tried implementing the code above and I’m having a little trouble with it.

    I have the permanent 301 redirect in place redirecting non-www to www URL versions in the root domain. The problem is in the blog which is a sub-domain lying underneath the root.

    The redirects work properly at the root level, but for the blog sub-directory I’m still getting the non-www duped pages.

    I want to redirect the non-www blog URL’s to the www versions but after implementing your code here in my Wordpress .htaccess file it’s still not working properly for me:

    # BEGIN WordPress

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

    # END WordPress

    I want to redirect from mydomain.com/blog to http://www.mydomain.com/blog. The code above seems to be redirecting to root URL instead of the blog sub-directory.

    Any suggestions?

  13. [ Gravatar Icon ] Jeff Starr says:

    @Bill Hazelton: Sure. Place the rewrite directives in the subdirectory’s HTAccess file. Then add the following to the root HTAccess:

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

    To account for the root case. Edit as necessary.

  14. [ Gravatar Icon ] Inv says:

    At first I didn’t use permalinks at my site. Also, I used and I’m still using a non-www to www redirection in my .htaccess:

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

    The problem came when I started using permalinks. The non-www redirection stopped working and a page titled “301 Moved Permanently” showed with this error:

    Moved Permanently
    The document has moved here.

    Additionally, a 500 Internal Server Error error was encountered while trying to use an ErrorDocument to handle the request.

    So it seems that the code for the permalinks added to the .htaccess is overriding the non-www redirection, or there is some kind of trouble between the codes. The code for the permalink structure is this:

    # BEGIN WordPress

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

    # END WordPress

    Could you help me? Thanks in advance.

  15. [ Gravatar Icon ] Jeff Starr says:

    Hi Inv, sounds like you might have introduced a syntax error in your htaccess code. You may also want to try switching the order in which the two sets of directives appear in the file (i.e., processing order).

  16. [ Gravatar Icon ] GSTAR says:

    Hi Jeff,

    Can you help me with this slight issue I’m experiencing. I’ve got WP installed in a subdirectory, and I want the non-www version to point to the www version. I followed your instructions and it works fine except for one thing:

    http://mydomain.com/blog does not redirect properly; however http://mydomain.com/blog/ does (notice the trailing slash).

    Can you advise on how to fix this?

    Regards.

  17. [ Gravatar Icon ] Jeff Starr says:

    Not sure what the issue might be.. a lot depends on other factors, such as what scripts you are using, the version of WordPress, and the other contents of your htaccess file(s).

    I suggest that you look into the information provided in my article on comprehensive WordPress canonicalization. It takes into account just about every possible canonicalization issue that you might encounter while using WordPress.

    Also, keep in mind that newer versions of WordPress (from 2.5 forward, if I recall) handle the www/non-www redirect automatically, depending on how you specify your blog’s URL in the Admin Settings area. If you include the “www” prefix there, all of your pages should be redirected properly.

  18. [ Gravatar Icon ] Brett says:

    Fantastic solutions here! Thank you for the insight! I located a solution to having Wordpress not override my custom rewrite, however it only appears to work with the Permalinks setting set to Default. I enable permalinks and overrite the Wordpress settings with my own, however still receive a Wordpress Page Not Found. Is there any way to tweak the below so it will work with Wordpress Permalinks as well?:

    RewriteEngine On
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/(podcast|podcast/feed) [NC]
    RewriteRule . /index.php [L]
    RewriteRule ^podcast/?$ /index.php?category_name=podcast [QSA,L]
    RewriteRule ^podcast/feed/(atom|rss2)/?$ /index.php?feed=$1&amp;category_name=podcast [QSA,L]

  19. [ Gravatar Icon ] Jeff Starr says:

    Hi Brett, one thing that you might try is disabling the rewrite rules in the target directories. Here are three different ways of doing it.

  20. [ Gravatar Icon ] Rudy says:

    Jeff, i have been change my permalinks, & i also change my htaccess format! when i open my single post blog links, its work! But my category spoilers links was broken (error 404)! can you help me!

    Thanks for your attention!

  21. [ Gravatar Icon ] Jeff Starr says:

    @Rudy: Are you using any plugin for redirection (in addition to htaccess)?

  22. You seem like you really have got it together here. After countless searches, I humble beg your assistance!

    I want to keep my permalinks at default because I use the page id as a product id on my eShop Wordpress installation. The problem is that the 404 redirect does not function. My htaccess file is where it should be and writeable, but when I change permalinks back to the default, 404 does not redirect. It just stays on the same page. When I use the custom setting, 404 works exactly as it should.

    Any help you could offer would be a God-send.
    here’s the site:
    http://www.rewindyarn.com

  23. Duh!!! I hate wasting my time this way…and yours. Finally figured out that just setting to page id on my permalinks works. But still…why doesn’t the 404 redirect function with default permalink settings?

  24. [ Gravatar Icon ] Rudy says:

    I have been solve my trouble shoot permalinks by using 2 plugins! Advance Permalinks & Category permalinks! You can ceck it out in wordpress.org Extention!

    But anyway, i use 2 different type permalinks for my single post & Category!

    %category/post% for single post & category for category permalinks (without %)! & its work! ^_^

  25. [ Gravatar Icon ] Jeff Starr says:

    @Jessica Bosari: Good question — this is the first that I’ve heard about it not working. Have you tested on a clean install of WordPress?

    @Rudy: Awesome! Great to hear it. Thanks for following up with your solution.

  26. [ Gravatar Icon ] mw says:

    hi, thanks for your great post. I wanted to make my wordpress blog adress working from http://www.domain.org to domain.org I set an appropriate options in the admin area and it works on the main page. But when to use

    www.domain.org/2010/04/21/post-name-here

    instead of

    domain.org/2010/04/21/post-name-here instead it’s not working.

    There is a problem with / - when I manualy put the adress

    www.domain.org/2010/04/21/post-name-here

    instead of

    domain.org/2010/04/21/post-name-here in the browser,

    I get

    domain.org2010/04/21/post-name-here in the browser

    my .httaccess

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

    I have tried to use your solution, but it’s not working here. I use WP 2.9.2. Thanks for help!

  27. [ Gravatar Icon ] Jeff Starr says:

    @mw: unless I am missing something, there is no reason you need to use any htaccess at all for canonicalization. Just enter the desired URLs in the General Settings in the Admin and WordPress will handle the rest.

  28. [ Gravatar Icon ] r4ibOm says:

    Well one would help her,

    My website: http://www.dotamania.com.br

    sum subdirectory I created and installed wordpress on it for me to use separate from buddypress: http://dotamania.com.br/clan/

    but only that the permalinks are not working on the 2nd installation generating a 404 and from buddypress work, permalinks has to be enabled …

    be able to help me there, thx!

  29. Hello,can you post about how to change default post wordpress (-) to (+) ?

    example :

    http://www.domain.com/post/google-panda
    to
    http://www.domain.com/post/google+panda

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

Please use basic markup. Wrap code with <code> tags!