# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.example\.com [NC]
RewriteCond %{REQUEST_URI} !exclude
RewriteRule ^(.*) http://subdomain.example.com/$1 [L,R=301]
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
The WordPress front-controller conflicts with your redirect and ultimately causes a redirect to /index.php
. (Although that is not strictly the same as /
- as you've stated - maybe there is something else that removes the index.php
part, if it's not present in the resulting URL?)
When you initially request /post-exclude.html
, the RewriteCond
directive prevents the redirect, but after the request is internally rewritten to /index.php
(by the WordPress front-controller below), processing then loops which then triggers the redirect to /index.php
(the homepage). The internal rewrite results in the REQUEST_URI
server variable being updated to /index.php
(whilst the visible URL remains as /post-exclude.html
).
In other words, when you request /post-exclude.html
:
- Redirect code is bypassed because of the
RewriteCond
(condition) directive.
- Request is internally rewritten to
/index.php
(by the WordPress front-controller)
- The rewrite engine starts over... (as it does when the URL is rewritten)
- Now the redirect triggers since it is checking against
/index.php
, not /post-exclude.html
(whilst the visible URL remains as /post-exclude.html
).
- Redirects to
http://subdomain.example.com/index.php
.
You can avoid this second internal rewrite triggering the redirect by making sure you only target the initial request in the redirect. You can do this by either checking against THE_REQUEST
instead (which contains the first line of the HTTP request headers) or the REDIRECT_STATUS
environment variable (which is empty on the initial request and set to "200" - as in 200 OK HTTP status - after the first successful rewrite).
You should also avoid manually editing the code between the # BEGIN WordPress
and # END WordPress
comment markers as this is maintained by WordPress and your manual edits could be overwritten in a future update.
The redirect should go before the # BEGIN WordPress
line.
RewriteCond %{REQUEST_URI} !exclude
Note that this condition excludes any URL that simply contains exclude
(case-sensitive) anywhere in the requested URL. Whereas the example you posted looks quite specific. Note that if you only want to exclude a single URL, you don't need an additional condition as this can all be done in the RewriteRule
directive.
Try the following instead:
# Redirect to subdomain.example.com, excluding some URL(s)
# NB: REDIRECT_STATUS - Check the initial request only (not the rewritten request)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteCond %{REQUEST_URI} !exclude
RewriteRule (.*) http://subdomain.example.com/$1 [L,R=302]
# 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
As noted in comments, test with 302 (temporary) redirects and make sure your browser cache is cleared.
.htaccess
file have you placed this code? Please show the directives in-place - there might be a conflict with other directives. You should also test with 302 (temporary) redirects to avoid potential caching issues. Make sure you've cleared your browser cache.subdomain.example.com/
instead" - that wouldn't seem possible with just the code you posted, so there's likely a conflict if you've put the code in the wrong place for example?