2

I tried doing searching and trying to understand how to do a redirect with (multiple) query strings but I didn't have luck. I'm hoping someone here can help me understand this issue :)

I'm working on this ecommerce shop and people are searching the ecommerce search input for content located in a different CMS. For example, the word "returns". This isn't a product in the ecommerce system so of course it returns an error for the results (no products found).

My idea was simply to manually redirect those quieres to the proper landing pages in the CMS.

Here's an example of the URL for "return" on the ecommerce system:

http://www.domain.com/catalog/search.php?mode=search&page=1&substring=return

And here's where I would like to send people:

http://www.domain.com/catalog/Returns.html

Any thoughts on how to do this? Thanks in advance!

7
  • I would have thought that this would be generally a bad idea. To illustrate with an example: assuming that you sell DVDs; what happens when a customer searches for returns and doesn't get shown Batman Returns, Superman Returns, LOTR: Return of the King etc. as their search results? Surely you'd do better to add the other pages as suggested pages within the results? Commented Feb 21, 2014 at 19:19
  • Very true, but in this case, there are no products that would ever match the search queries I'm looking to redirect. Good catch though! Commented Feb 24, 2014 at 19:17
  • Just thought I'd throw it out there. Anyway, Phil's solution is correct but has a problem which - hopefully - I've explained below. Commented Feb 24, 2014 at 20:51
  • Phil, you were correct regarding having Pretty URLs. Forgot to mention this. Steven, your suggestion works but not 100% as expected. I added the ? at the end of the RewriteRule but since the page I'm redirecting to is rewritten based on the Pretty URL htaccess code, it doesn't work correctly. If I redirect the substring code to another 302 redirect www.domain.com/returns -> www.domain.com/catalog/Returns.html then it works. In sum, I have this redirecting now, but I loop through another redirect to work. Any ideas on how to consolidate? Here's the relevant htaccess: jsfiddle.net/d67g2 Commented Feb 26, 2014 at 19:15
  • Oh, using the X-Cart ecommerce system if that makes any difference. Commented Feb 26, 2014 at 19:16

2 Answers 2

5

Solution

The way to do this is as Phil suggested; but with a few (small) modifications:

RewriteEngine On
RewriteCond %{QUERY_STRING}  substring=returns?  [NC]
RewriteRule  . /catalog/Returns.html? [L]
RewriteCond %{QUERY_STRING}  substring=shipping  [NC]
RewriteRule  . /catalog/Shipping.html? [L]

N.B. In the event you only want to remove one parameter see the Additional Information and Explanations below.

N.B. For more strict matching see Where & becomes a problem below.



Explanation

Background

The best way for me to explain the difference (between the above and Phil's original) and why you were having a problem is to explain what is going on...

RewriteCond %{QUERY_STRING} substring=returns? [NC] checks the query string for instances of the regex that follows it in this case substring=returns?*.

The [NC] flag simply means to match upper and lower case letters.

*Clarification: The regex(substring=returns?) means substr=return is matched literally with or without an s.

Problem

If the condition is met (i.e. the regex pattern is matched in the query string) then the rewrite rule is triggered. This is where the problem lies...

Given the URL: http://example.com/?substring=returns

The original rule:

RewriteRule  . /catalog/Returns.html [L]

Rewrites the URL leaving the query string in place, like so:

http://example.com/?substring=returns
http://example.com/catalog/Returns.html?substring=returns
http://example.com/catalog/Returns.html?substring=returns
http://example.com/catalog/Returns.html?substring=returns
http://example.com/catalog/Returns.html?substring=returns
...and so on until limit is reached...

Side note: The [L] flag stops the .htaccess file from going through any more rules but it doesn't stop it looping again.

Solution

The solution then is to overwrite the query string (since we no longer need it) you can do this simply by adding a ? to the end of the RewriteRule:

RewriteRule  . /catalog/Returns.html? [L]

N.B. In the event you only want to remove one parameter see the Additional Information and Explanations below.

N.B. For more strict matching see Where & becomes a problem below.



Resources

The following resources may come in helpful in the future:

.htaccess flags

http://httpd.apache.org/docs/current/rewrite/flags.html

Regular expressions

http://www.regular-expressions.info/ - Check out the tutorials section



Additional Information and Explanations

Where & becomes a problem

RewriteCond %{QUERY_STRING}  &substring=returns?  [NC]

In the above the regex means to match the characters &substring=return with an optional s appended to it.

So it would match the following as expected:

http://example.com/?var1=somvalue&substring=return
http://example.com/?var1=somvalue&substring=returns
http://example.com/?var1=somvalue&substring=return&var2=othervalue
http://example.com/?var1=somvalue&substring=returns&var2=othervalue

Which is fine and given the original query string wouldn't be a problem, however, if I were to navigate to the page and write in the parameters in a different order, the & wouldn't necessarily be there and therefore it wouldn't match (when it should):

http://example.com/?substring=return&var1=somevalue
http://example.com/?substring=returns&var1=somevalue

Simply getting rid of it (as I did) would solve this problem, but it doesn't come risk free.

RewriteCond %{QUERY_STRING}  substring=returns?  [NC]

If you were to introduce a new parameter secondsubstring for example it would match when it shouldn't:

Good Match > http://example.com/?substring=return&var1=somevalue
Good Match > http://example.com/?var1=somevalue&substring=return
Bad  Match > http://example.com/?secondsubstring=return&var1=somevalue

To solve this potential issue you could do the following:

RewriteCond %{QUERY_STRING}  ^(.*&)?substring=returns?

The above will match:

http://example.com/?substring=return&var1=somevalue
http://example.com/?var1=somevalue&substring=return

But won't match:

http://example.com/?secondsubstring=return&var1=somevalue

One more potential problem is that the expression would match:

http://example.com/?substring=returning&var1=somevalue
http://example.com/?substring=return%20television&var1=somevalue

My understanding, again, is that this wouldn't be a problem in the given situation. However if it were to be a problem you could do:

RewriteCond %{QUERY_STRING}  ^(.*&)?substring=returns?(&|$)

The above checks that the character following return/returns is either an & signalling the end of the variable and the start of a new one or the end of the query string.

Rewriting one parameter

In some circumstances as Phil pointed out it may be preferable to only remove one parameter at a time and leave the rest of the query string untouched.

You can do this, quite simply, by implementing capture groups in the RewriteCond and outputting them in the RewriteRule:

RewriteCond %{QUERY_STRING}  ^(.*&)?substring=returns?(&.*)?$  [NC]
RewriteRule  . /catalog/Shipping.html?%1%2 [L]

Rewrite explanation

You use %N to insert capture groups from the rewrite condition and $N to insert capture groups from the rewrite rule.

So in this case we redirect to:

/catalog/shipping.html?(RewriteCond Group1)(RewriteCond Group2)
/catalog/Shipping.html?%1%2

The [L] flag - as previously - stops the processing of any rules further down the .htaccess file

Regex explanation

^(.*&)?substring=returns?(&.*)?$
  • ^ Start of string
  • (.*&)? First capture group
    • Capture any character . 0 or more times *
    • Followed by an &
    • The ? makes the entire group optional
  • substring=returns? Matches substring=return literally with an optional s
  • (&.*)? Second capture group
    • Capture an &
    • Capture any character . 0 or more times *
    • The ? again makes the group optional
  • $ End of string

[L] flag vs [END]

For completeness sake...

The [L] flag stops the .htaccess from going over any more rules further down the .htaccess file.

The [END] flag stops the rewrite process completely.

To illustrate with an example:

while(TRUE){
    if(condition1){ continue; }
    if(condition2){ continue; }
    if(condition3){ continue; }
    if(condition4){ continue; }
}


while(TRUE){
    if(condition1){ break; }
    if(condition2){ break; }
    if(condition3){ break; }
    if(condition4){ break; }
}

In the above code blocks the [L] flag acts like a continue statement in that it skips the rest of the code block and starts again. Whilst the [END] flag acts as a break statement and stops the loop entirely.

If we were to replace the [L] flag with [END] in Phil's original answer then it would work. With the caveats mentioned in the Where & becomes a problem section above.

Sign up to request clarification or add additional context in comments.

3 Comments

Interesting. Was not suppressing the original Query String the problem, or did the leading & on the pattern contribute? What if they have other variable terms (than 'substring') that they want to keep? It would be simpler if in these special cases they don't care about keeping other Query String entries (as your solution did), but I was assuming they might. However by not removing substring= from the flow, I can see that would force a loop. If they do need to keep other variables, they could handle them one by one? +1
@PhilPerry Yes, the problem is/was leaving the query string intact, the & doesn't have any special meaning in the regex pattern so it's fine having it at the beginning. Anyway, I'll update the answer with more on the & issue and how to only rewrite the one variable - since it's more than can really be explained in a comment.
@PhilPerry It's now a bit of a long read... But hopefully covers all points?
2
RewriteEngine On
RewriteCond %{QUERY_STRING}  &substring=returns?  [NC]
RewriteRule  . /catalog/Returns.html [L]
RewriteCond %{QUERY_STRING}  &substring=shipping  [NC]
RewriteRule  . /catalog/Shipping.html [L]

etc.

Would something like that do the job for you? Note that 'returns?' means 'return' or 'returns'. Are you limited to one search term at a time, or might customers type in a phrase? I think & is safe to use there, but it's possible it's not.

Don't forget to do this stuff ahead of any commands to rewrite Returns.html to Returns.php, do SEO, etc.

2 Comments

I inserted the code into the top of the .htaccess located inside the /catalog dir and now I receive an error 500 when I search "return" or "returns". I opened the error_log via SSH and it says "Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace" Thoughts?
Hmm. What exactly did you put into .htaccess (cut and paste to here), and what kind of URL (including the query string) triggers the error? Do you have .htaccess code to convert .html URIs to blahblah.php?term= (SEO)? I'm wondering if that's sending you back around to the lines you just put in (looping).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.