1

I've been pulling my hair out for a couple of days over an .htaccess issue. I have a list of redirects which are all being done in this format:

Redirect 301 /my-page/ https://www.example.com/my-page/

That works just fine, but I need to redirect all other pages except the homepage and the contact page to the homepage of the new site. That's where the trouble comes in. There are several well-documented solutions for this, but I can't get a single one to work. Below the list of redirects, but above the WordPress rules, I have tried several solutions. Here are the three basic setups I tried:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^contact
RewriteRule ^(.+)$ https://www.example.com/ [R=301,L,NE]
</IfModule>

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^contact - [L]
RewriteRule ^(.+)$ https://www.example.com/ [R=301,L,NE]
</IfModule>

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(?!contact)(.+)$ https://www.example.com/ [R=301,L,NE]
</IfModule>

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.

But in every single situation, either nothing works at all, or the contact page is redirected with all of the other pages. I haven't had any trouble with the homepage, just the contact page. Oddly enough, if I remove the negative look-ahead in the first version, that code runs perfectly.

  • Is the URL /contact or /contact/ or both? – MrWhite May 14 at 18:56
  • @MrWhite it applies to both – dbrick May 14 at 19:09
1

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.

  • 1
    thank you for the wealth of information. Your last suggestion to add an exception for index.php worked perfectly (I used the first version you suggested). I'll add some notes here in case someone else runs across this info: 1. I had been testing in a new incognito window every time in order to avoid browser caching, but I hadn't considered testing with 302s. Good thought. 2. Good points about conflicts with the two types of rules. I knew about the prefix-matching, and had been careful about that, but I did not realize that the redirect everything rule would take precedence. – dbrick May 14 at 19:17
  • 1
    RewriteRule ^my-page/(.*) https://www.newsite.com/my-page/$1 [R=302,L] Would actually be the equivalent rule because it would redirect sub-pages to the correct corresponding page. It could also be written RewriteRule ^(my-page/.*) https://www.newsite.com/$1 [R=302,L] which has less duplication and possibility of mistake. – Stephen Ostermiller May 15 at 1:23
  • @StephenOstermiller Thanks, yes, I was a bit lazy in that part of my answer (as I didn't think it would be something the OP would be making use of). I've updated my answer with your suggestion, as otherwise it could be misleading. – MrWhite May 16 at 22:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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