0

I've searched SO and Google long and hard for this one and I'm really surprised not to have found an answer (or stumbled upon the solution by trial and error!). It's a slightly tough search as most of the keywords lead to people wanting to exclude query strings as part of their redirect, whereas I want to exclude certain query strings from the subsequent redirect entirely.


We have migrated a content site from olddomain.com (running Drupal) to newdomain.com (running Wordpress). All the paths stay the same and so we want to redirect like-for-like from one domain to the other. However, we still want to be able to access Drupal's admin panel (and other associated admin URLs) for a variety of reasons. These exceptions must be done by exclusion so that, when we are not redirecting to the new domain, Drupal's existing generic mod_rewrite rules still activate in order to serve the redirect- excluded URLs correctly.

The main "like for like" redirect rule looked like this, and works well:

RewriteCond %{REQUEST_URI} !^/?(admin/|index.php|install.php|authorize.php|cron.php|update.php|xmlrpc.php|batch)
RewriteRule ^(.*) https://newdomain.com/$1 [R=301,L]

However, some admin-only paths (typically for editing a piece of content) don't always use "admin" in the path, e.g.:

/node/4823/edit

So what I want to do is to be able to manually add a noredirect query string variable which is then used as a further negated RewriteCond of my existing RewriteRule so in essence I am saying "do a like-for-like redirect on all paths as long as they are not in any of these folders and noredirect doesn't appear in the query string".

This is as far as I've got, you can see some of the steps I've taken, all of which have failed so far:

RewriteCond %{REQUEST_URI} !^/?(admin/|index.php|install.php|authorize.php|cron.php|update.php|xmlrpc.php|batch)
#RewriteCond %{QUERY_STRING} !^noredirect=([^&]+)
#RewriteCond %{QUERY_STRING} !^/noredirect/
#RewriteCond %{QUERY_STRING} !^.*(\bnoredirect\b)
#RewriteCond %{QUERY_STRING} !^.*(noredirect)
RewriteCond %{QUERY_STRING} !(noredirect)
RewriteRule ^(.*) https://newdomain.com/$1 [R=301,L]

As I've gone on I've tried to make it more and more generic in order to try and simplify the task; all I care about is checking for "noredirect" anywhere in the query string, so I'd be happy with all of these query strings matching the exclusion and thus preventing the redirect:

?noredirect
?noredirect=
?foo=bar&noredirect=whatever
?thisbitsaysnoredirectinit&foo=bar

As always, I look forward to basking in your expertise...

Matt Morrison
  • 1,540
  • 1
  • 14
  • 19

1 Answers1

0

After much fiddling, and reordering and testing the rules separately (stupid I didn't do this before, this clearly showed the query string rule in itself was fine), this was the solution:

RewriteCond %{REQUEST_URI} !(^|/)(admin/|index.php|install.php|authorize.php|cron.php|update.php|xmlrpc.php|batch|node)
RewriteCond %{QUERY_STRING} !(noredirect)
RewriteRule ^(.*) https://newdomain.com/$1 [R=301,L]

So it required the change from ^/? to (^|/) in the "exclude these folders" rule.

I'll happily admit I don't understand why this has fixed it. Unfixed, this condition itself was working fine, it was just preventing the next condition from being looked at. If there was a problem with the syntax it seems to me that the condition should have been broken entirely rather than messing with other conditions. If anyone can shed any light on that for me, thank you!

For what it's worth, RewriteBase is unspecified (so I assume defaults to root).

Drupal-specific bonus

Also note the addition of "node" to the list of folders I'm excluding from the 1:1 redirect to the new domain.

When I thought about this more I realised that this would mean the admin-only extensions of "node" (e.g. /node/123/edit) would be safe as they are not rewritten to an alias. The public views of nodes (e.g. /node/123) would be initially ignored but then subsequently rewritten to their aliases by Drupal's own functionality, at which point .htaccess is called a second time and the redirect to the new domain (as the alias does not begin with "node") is activated.

This is not only a better system (anyone trying to go to an original Drupal node URL rather than an alias will not get redirected too soon) but of course means I now only have to use the ?noredirect query string in much rarer use cases.

Community
  • 1
  • 1
Matt Morrison
  • 1,540
  • 1
  • 14
  • 19