First off, you should be testing with 302 (temporary) redirects to avoid caching issues. It's possible that you have some erroneous 301 (permanent) redirects cached by the browser. So you will need to make sure the browser cache is cleared before continuing. (You can also test with Chrome's object inspector open and the cache disabled - checkbox on the Network tab.)
You should also avoid mixing redirects from both mod_alias (Redirect
and RedirectMatch
) and mod_rewrite (RewriteRule
). These two different modules work independently and at different times during the request, so it's most likely you will get a conflict. Your mod_alias Redirect
directives, despite appearing earlier in the .htaccess
file actually execute last and work on the original request. But in this case the redirect-everything RewriteRule
will take priority.
The Redirect
directive is also prefix-matching, so a redirect like you example: Redirect 301 /my-page/ ...
with also match /my-page/foo
and /my-page/foo/bar
- should those be URLs on your site.
You need to convert your mod_alias Redirect
directives to the equivalent mod_rewrite RewriteRule
directive. For example:
Redirect 301 /my-page/ https://www.example.com/my-page/
is equivalent to:
RewriteRule ^(my-page/.*) https://www.example.com/$1 [R=302,L]
UPDATED To include @Stephen's correction from comments.
Note that $1
is a backreference to the captured group in the RewriteRule
pattern.
However, if this should only match /my-page/
exactly (as I expect you require) and not /my-page/<everything>
then append an end-of-string anchor to the RewriteRule
pattern and remove the .*
catch-all. For example:
RewriteRule ^(my-page/)$ https://www.example.com/$1 [R=302,L]
Obviously, if the new URL is different then this needs to be explicitly stated:
RewriteRule ^my-old-page/$ https://www.example.com/my-new-page/ [R=302,L]
NB: Test with 302s.
RewriteCond %{REQUEST_URI} !^contact
RewriteRule ^(.+)$ https://www.example.com/ [R=301,L,NE]
The REQUEST_URI
server variable contains the full URL-path, starting with a slash, so this condition to not match ^contact
will always be successful (the CondPattern should read !^/contact
), so /contact
will end up being redirected.
RewriteRule ^contact - [L]
RewriteRule ^(.+)$ https://www.example.com/ [R=301,L,NE]
This will prevent /contact
being handled by WordPress - so it just won't work at all.
RewriteRule ^(?!contact)(.+)$ https://www.example.com/ [R=301,L,NE]
This should be OK, however, you'll likely have to make an exception for index.php
as well, to avoid conflicting with the WordPress front-controller (or make sure you only target the initial request). For example:
RewriteRule ^(?!(contact|index\.php))(.+)$ https://www.example.com/ [R=301,L,NE]
OR
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(?!contact)(.+)$ https://www.example.com/ [R=301,L,NE]
I've also tried every combination of RewriteBase /
, an %{HTTP_HOST}
, and a slash before the contact url that I can think of, as well as the [NC]
flag.
RewriteBase
is not relevant here, although it could potentially break the WordPress front-controller (depending how this is written). The argument to RewriteBase
is only used when you have a relative path substitution - you are specifying an absolute URL. I'm not sure how you would be using %{HTTP_HOST}
here? - again, this doesn't seem relevant.
/contact
or/contact/
or both?