Skip to Content

Advanced Redirection: Changing your variables within htaccess.

Malcolm Slade, Head of Technical SEO

The author

Malcolm Slade

Head of Technical SEO

Recently I was set the task to remove certain URLs completely from a website with no access to the source code or CMS.

At first I thought this impossible, until I discovered I was allowed to create an .htaccess file that would be put in the root. The following presumes you know what .htaccess is, what it does and you (like me) love to tinker.

Let’s say that your site has an issue where it lets you select the colour as white (even though white is the default when no colour is specified) and you want to stop colour=white from appearing in any URLs.

Not a common issue I admit, but if you have arrived on this page you probably want to know how to redirect a URL and change the variables, and the whole colour thing is just the example to show how it all works.

Below are the details of the process I went through to in order to redirect the following:

http://www.site.com?colour=white
- to - http://www.site.com

http://www.site.com?colour=white&trim=blue
- to - http://www.site.com?trim=blue

http://www.site.com?cuff=felt&colour=white
- to - http://www.site.com?cuff=felt

http://www.site.com?cuff=felt&colour=white&trim=blue
- to - http://www.site.com?cuff=felt&trim=blue

Firstly, the way to strip the query string (?blah=blah… bit) is to add ? to the end of your redirect URL.

RewriteRule ^(.*)$ /$1? [R=301,L]

This covers the first URL but leaves us with no variables at all, so is no good. Next we look at how we can tweak the query string.

As you should already know, with RewriteCond anything within brackets can be looked up via $#. In the above example, $1 is the whole URL. You can do the same when querying the query string, as below.

RewriteCond %{QUERY_STRING} ^(.*)colour=white(.*)$

In the above, %1 would look up the first (.*) and %2 the second, so the following should work:

RewriteCond %{QUERY_STRING} ^(.*)colour=white(.*)$
RewriteRule ^(.*)$ /$1?%1%2 [R=301,L]

It does work, but not exactly how we would like it to.

http://www.site.com?colour=white
- rightly becomes - http://www.site.com

http://www.site.com?cuff=felt&colour=white
- rightly becomes - http://www.site.com?cuff=felt

But then it goes a bit Pete Tong - too many ampersands...

http://www.site.com?colour=white&trim=blue
- becomes - http://www.site.com?&trim=blue

http://www.site.com?cuff=felt&colour=white&trim=blue
- becomes - http://www.site.com?cuff=felt&&&trim=blue

After several attempts to find the answer on Google (complete failure) and lots of tinkering on my private dev site, I discovered that I needed several rules (all similar) and a little tweak. This doesn’t seem to be documented anywhere, so for the three people who might want to do this over the next year, here it is:

RewriteCond %{QUERY_STRING} ^(.*)colour=white$
RewriteRule ^(.*)$ /$1?%1 [R=301,L]

RewriteCond %{QUERY_STRING} ^colour=white(&+)(.*)$
RewriteRule ^(.*)$ /$1?%2 [R=301,L]

RewriteCond %{QUERY_STRING} ^(.*)(&+)colour=white(&+)(.*)$
RewriteRule ^(.*)$ /$1?%1&%4 [R=301,L]

The top one handles URLs with a query string that ends in colour=white. The second handles URLs with a query string that start with colour=white and the final one covers URLs with colour=white somewhere in the query string.

The important bit is the placement of (&+) which catches any stray ampersands. It seems that after the first variable, each reference is proceeded by an ampersand (variable1=1, &variable2=2; &variable3=3 etc.) which makes it really hard to control the ampersands in the final redirect destination.

So I now have an answer to my problem, but surely there is a way to do this with a single rule....

Thanks to my new friend Andy, reminding me about non-capturing parenthesise, I give you the most efficient and final iteration of my solutions:

RewriteCond %{QUERY_STRING} ^(.*)(?:^colour=white&?|&colour=white)(.*)$ [NC]
RewriteRule ^(.*)$ /$1?%1%2 [R=301,L]

In the above, we have covered all three options in a single non-capture or statement. (?: basically says don't create a %# reference for this element and the second ? set the previous ampersand to be present or not meaning all three cases are covered.

As always, feel free to comment, add to the discussion, prove I’m wrong etc. and if you'd like to find out more, just get in touch.