New htaccess Code for WordPress Permalinks
While manually upgrading a bunch of old WordPress sites, I realized that the WordPress htaccess rules for permalinks had changed. For many years and versions, the htaccess code that enables WordPress permalinks went unchanged, resulting in an almost sacred set of htaccess directives. Here are the original permalink rules as currently provided at the WordPress Codex:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
When working with WordPress, that snippet is the only htaccess code that is actually required by WordPress, and even then, it’s only necessary if you are using so-called “pretty-permalinks” on your site. Needless to say, there are probably millions of instances of these original permalink rules in place on servers and sites all across the Web. The code is so familiar that many WordPress devs can probably write it from memory. So changing things is actually kind of a big deal.
The NEW WordPress Permalink Rules
There’s really no reason to get all excited about anything. I just tend to get hyped up for anything relating to WordPress or htaccess. So mix them together and I’m all over it. For the new WordPress permalink rules, only a single line was added, and it’s a good one to have in there:
RewriteRule ^index\.php$ - [L]
So that’s the new hotness, and it works great at what it does, which we’ll get to here in a moment. For now, let’s go ahead and add that new directive to our original htaccess ruleset to get the new WordPress permalink rules:
For sites installed in root directory:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
And for sites installed in a subdirectory:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /subdirectory/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /subdirectory/index.php [L]
</IfModule>
# END WordPress
I’m not sure exactly when the htaccess permalink rules were changed, and I’m not sure it really matters, but I’m thinking it happened sometime between versions 3.0.0 and 3.0.4. I didn’t notice it until version 3.0.4, but I am guessing that it happened at 3.0. Somebody let me know that I’m wrong here.
So what does it do?
What is the purpose of the new htaccess directive? Why change something that has worked so well for so long? Better have a good reason to go tampering, right? Yes, and as it turns out, this new rule is involved with canonicalization [1] of your WordPress URLs. I don’t think it was by any means necessary, but it’s definitely an improvement over the original code. The new directive basically strips off any dangling index.php
from your WordPress permalinks.
mod_rewrite
; it has nothing to do with canonicalization, which is handled automatically by WordPress.For example, with the original permalink rules (and no other htaccess modification), the following URLs all refer to the same page:
https://digwp.com/
https://digwp.com/index.php
http://www.digwp.com/index.php
Fortunately, WordPress already handles the www
canonicalization, and so the new line of htaccess takes care of the other end of the URL: the index.php
. This may not seem like a big deal, but can have a big impact on script performance, search-engine optimization, and user-experience.
Updating your htaccess rules
So the question now is “do I need to go back and add this new directive to my existing permalink rules?” I think the best answer is that you don’t need to do anything – your WordPress-powered sites will continue to work just fine. But if you want the additional canonicalization that the new rule provides, then you probably should stick it in there.
A couple of things to keep in mind about the new htaccess code:
- No need to update existing htaccess files unless you want to
- As with the original code, the new htaccess works in all versions of WordPress
- If you do add the new line, make sure to remove/adapt any similar/related htaccess rules
For example, as I was going through and updating all of those old sites, I had been using my own recipe for proper permalink canonicalization:
# CANONICAL WP RULES
<IfModule mod_rewrite.c>
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php [NC]
RewriteRule ^index\.php$ http://example.com/ [R=301,L]
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
</IfModule>
This code works on any site – not just WordPress installs – to clean up both ends of the URL: the www
and the index.php
. As I updated my htaccess files with the new WordPress permalink rules, I had to remove this custom canonicalization code to make room (functionally speaking) for the new stuff, which is a much more elegant solution.
29 responses
-
Hi Chris! I just confirmed with a local wordpress install I had on my PC that this line was added in WordPress 3.0.
And I believe it’s a good addition for all those wordpress users who never tweaked .htaccess file for “index.php” canonicalization.
-
Sorry, I was so busy reading the post I didn’t cared to read the author and goofed up with the author name. Thanks Jeff for a wonderful post. :)
-
-
Hi,
Using fixed:
define('NOBLOGREDIRECT', '%siteurl%');
in wp-config.php the www problem is Be solved.-
That’s actually a multisite directive.
-
-
This was added in 3.0, as Gautam said, and went relatively unnoticed. It would take an .htaccess aficionado like Jeff Starr to write a detailed post about it. :-)
Links to the ticket and the changeset:
If I remember correctly, the ticket was originally filed under the Performance component, which is now merged into the Optimization component.
Cheers!
-
When I add this rule to my file I get a 404 message when I click on a post.
RewriteRule ^index\.php$ - [L]
Things work again when I change it back to
# BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress
Any ideas?
-
Sorry Jeff, it’s not about canonicalization at all. It’s an optimization tweak for mod_rewrite’s internal idiosyncrasy.
When mod_rewrite runs the directive …
RewriteRule . /index.php [L]
… the “L” option does not tell it to stop, but only to skip the remaining rules on the current pass. It then begins an implicit rewrite from the top of the rule set, which may be somewhere above the WordPress block. When that happens, the -f check is repeated unnecessarily, and the rule processing crashes through the bottom of the WordPress block. With the extra rule, the second pass will end without any rewrite.
Enjoy,
Robert Chapin
(I wrote the patch ;) -
Hi Jeff,
This is helpful. I’m currently redoing a website in WordPress which means there will be a number of page redirects. Would these redirects be placed in this same htaccess file? WordPress will be installed in a subdirectory. Thanks! (BTW, Digging Into WordPress is fabulous.)
-
Thanks Jeff for helpful tips.
-
This TOTALLY worked. Thanks so much, Jeff!!!
-
I’m at dead-end.
Currently developing a wp theme for some hebrew business. It actually needs to support hebrew characters in URL. For now, it just opens up 404 page. Maybe you got any ideas, how to get hebrew URLs working? I might think that it has something to do with .htaccess.
-
anyone?
-
-
so the difference is on RewriteBase
can we change them via DashBoard > Settings ?
-
I am developing a new WPMU v3.1 version of my site. On my old site I had no problem making posts programmatically from a php file in my top directory of wordpress.
Now when executing the file from a browser it redirects to the “Not Found” page. My htaccess file has three extra lines you didn’t mention. Are they creating the problem?
RewriteRule ^ - [L]
RewriteRule ^[_0-9a-zA-Z-]+/(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^[_0-9a-zA-Z-]+/(.*.php)$ $1 [L]
-
Sorry, I made one mistake in the previous post: I was redirected to the home page, but since I have no posts on the site that’s why it returned “Not Found”.
-
When I set up my WordPress site using simple script, I placed it in a folder hereafter name mainblog.com. The root of my store has my main ecommerce site. After install I noted that WordPress does not display properly and the layout and formatting are non-existent.
The problem I encountered is that whether or not I have permalink structure changed, when I combine the WordPress .htaccess rewrite into my cubecart .htacess file which is at the root, my cubecart main store “main.com” shows the main page, but clicking on any product or category redirects to the WordPress site as determined by the rewrite as shown below
# BEGIN WordPress RewriteEngine On RewriteBase /mainblog/ RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /mainblog/index.php [L]
How can I integrate the WordPress .htaccess info into another .htaccess file? Any suggestions?
-
Hi, Jeff…
I try add this to my .htaccess:
## DISABLE DIRECTORY LISTINGS
Options -Indexes
but when i try to browser my site, it’s error… can you help me to figured this out, why it’s happen.
-
Jeff,
Great post. I’m running a multi-site blog farm and am having trouble with spammers registering as users of my sub-blogs. Then, when I mark them as spam, the whole blog is marked spam.
Ideally, anyone who tries to register at a sub-blog should be redirected to the main blog registration page (
register.php
cause I’m using buddypress).Here’s what I’ve got, but it isn’t working. What am I doing wrong?
RewriteCond %{HTTP_HOST} ^site.com$ [OR]
RewriteCond %{HTTP_HOST} ^www.site.com$
RewriteRule ^wp-login.php/?(.*)$ "http://site.com/register/$1" [R=301,L]
Thanks!
-
Just tried it, but it won’t let me log out of the site now.
-
Clarify – when I added that to htaccess, I am unable to log out of my account.
It’s possible the redirect part worked though…
-
hallo and good morning, i found this post very useful. so I hope someone could help me. I have this problem: want to install wordpress on a reseller domain. the problem is that in the htaccess i have to add those line, to make the login page for domains works:
# This is the code that handles login., cpanel., and webmail. RewriteEngine On RewriteCond %{HTTP_HOST} ^login\. [NC,OR] RewriteCond %{HTTP_HOST} ^cpanel\. [NC,OR] RewriteCond %{HTTP_HOST} ^webmail\. [NC] RewriteCond %{REQUEST_URI} !^/(cgi-sys|rhost_login) RewriteRule ^(.*)$ /cgi-sys/login.cgi [NC,L]
added these lines the login page works only if I remove the line
RewriteRule . /index.php [L]
oherwise does not work. but if login works, wordpress does not. i can see only the home page and nothing else. someone has any suggestion?
thank you