This is my current .htaccess:

# Remove filename extension
<IfModule mod_rewrite.c>
# This will remove the .php extension if it is not a directory, the file does not exist and it's not a WordPress specific admin page
RewriteCond %{REQUEST_URI} !/wp-(content|admin|includes)/ [NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php !-f
RewriteCond %{THE_REQUEST} ^(.+)\.php([#?][^\ ]*)?\ HTTP/
RewriteRule ^(.+)\.php$ $1 [R=301,L]

# BEGIN rlrssslReallySimpleSSL rsssl_version[3.2.5]
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# END rlrssslReallySimpleSSL

# 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]

# END WordPress

The code works fine by removing .php extension of URLs indexed already by Google and redirecting them to new ones. But .php extension of wp-login, and other wp-admin URLs also get removed.

So I would like to add an exception to URLs /wp-login.php or under wp-admin directory.

  • 1
    What's the reasoning behind this? No PHP files under wp-includes or wp-admin should get indexed, and anything else gets routed via permalinks
    – Tom J Nowell
    Oct 17, 2019 at 23:19
  • Hi Muneeb, welcome to WordPress Development. Your question may need editing to get the best answers. For example what your goal is, (you have already added what you have done and the result). There may be an easier way to get what you want. As a quick guide, pretend you are talking to a busy colleague and have to tell them everything they absolutely need to give you a clear answer before they rush away. Check our guide to asking good questions if you need to. Oct 18, 2019 at 2:01
  • 1
    The old site was based on php and there are lot of pages which are indexed, since we are keeping same urls in new wp sites but without .php extension at the end... the above mention code also remove .php from admin pages too.
    – MMK
    Oct 18, 2019 at 8:36
  • I found an exact answer to my question here: stackoverflow.com/questions/52762607/…
    – MMK
    Oct 18, 2019 at 21:38

1 Answer 1


The old site was based on php and there are lot of pages which are indexed, since we are keeping same urls in new wp sites but without .php extension at the end...

Assuming your "old site" .php documents no longer exist (they shouldn't) then your current rule block to remove the .php extension would seem to be far more complex than it needs to be (and/or incorrect). (See below.)

the above mention code also remove .php from admin pages too.

Ok, something a bit odd here... Your existing rule block already excludes any URL that contains /wp-admin/ - so this should already exclude your admin pages. To also exclude wp-login.php you could simply modify this same condition, although this would seem to be unnecessary (see below). wp-login.php is not the only exception you need to make and adding many exceptions in this way quickly becomes impractical.

A quick assessment of your current rule block...

1. RewriteCond %{REQUEST_URI} !/wp-(content|admin|includes)/ [NC]
2. RewriteCond %{REQUEST_FILENAME} !-d
3. RewriteCond %{REQUEST_FILENAME}\.php !-f
4. RewriteCond %{THE_REQUEST} ^(.+)\.php([#?][^\ ]*)?\ HTTP/
5. RewriteRule ^(.+)\.php$ $1 [R=301,L]
  1. As noted above, this already excludes any URL that contains /wp-content/, /wp-admin/ or /wp-includes/. However, assuming none of your old site URLs start with wp- then why not simply exclude any URL that starts /wp- - which naturally includes wp-login.php, /wp-admin, etc. There are potentially more than just wp-login and wp-admin URLs that need to be excluded here.

  2. Why do you need to check that the request does not map to a filesystem directory? Do you have directories that also end in .php?! Filesystem checks are relatively expensive and this condition looks superfluous.

  3. This check is not doing what (I think) you think it's doing. The preceding comment states "the file does not exist" - that's not what this condition does. If it did then you probably would not be asking your question. No part of this code checks that "the file does not exist", which is really your main problem. If you request /foo.php then this condition checks that /foo.php.php does not exist (which I'm sure it doesn't), or if you request /foo/bar/baz.php (where /foo/bar does not exist as a physical directory) then it checks that /foo.php does not exist - probably not the intention.

  4. The purpose of the check against THE_REQUEST server variable is to avoid a redirect loop - however, it can be simplified (the fragment identifier is never passed to the server, so # is never matched). If your old URLs never contain a query string then it can be simplified further. But note that if your old URLs did/do contain a query string, then this will currently be passed onto the new target URL - is this the intention?

  5. This redirect only works because of the RewriteBase directive that is set later in the # BEGIN WordPress section. Ideally, you would include the slash prefix on the substitution or include the canonical protocol + hostname (an absolute URL) and avoid a potential second redirect later.


Bringing the above points together, try something like the following instead (there is no need for the <IfModule mod_rewrite.c> wrapper):

RewriteCond %{REQUEST_URI} !^/wp-
RewriteCond %{THE_REQUEST} "^GET /.+\.php(\?\S*)? HTTP/"
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(?!index\.php$)(.+)\.php$ /$1 [R=301,L]

Surrounding the CondPattern in quotes (ie. "..") avoids the need to escape spaces in the regex.

\S is a shorthand negated character class that matches any non-whitespace character. Similar to [^\ ] as you had initially.

(?!index\.php$) - This negative lookahead assertion in the RewriteRule pattern ensures we don't try to process the request after it has been rewritten to index.php by the WP front-controller.

The filesystem check (really just a failsafe) is the last condition since this is the most "expensive", so it's only processed when the other conditions (and RewriteRule pattern) are successful.

You will need to clear your browser cache before testing. Preferably test with 302 (temporary) redirects to avoid caching issues.

  • 1
    thanks for giving a detailed explanation.
    – MMK
    Oct 20, 2019 at 18:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.