Forum Moderators: phranque

Message Too Old, No Replies

htaccess Redirect with URL Parameters

         

JoshS

3:48 pm on Jan 10, 2020 (gmt 0)

10+ Year Member



I'm trying to redirect all of my products from my old zen-cart store to my new shopify store.

RewriteCond %{QUERY_STRING} products_id=1408
RewriteRule ^ https://shop.xyz.com/collections/products/mno? [L,R=301]

RewriteCond %{QUERY_STRING} ^products_id=1282 [NC]
RewriteRule ^ https://shop.xyz.com/collections/products/abc? [L,R=301]

RewriteCond %{QUERY_STRING} ^products_id=12 [NC]
RewriteRule ^ https://shop.xyz.com/collections/products/xyz? [L,R=301]

However, I can't figure out why products_id 12 and 1282 both redirect to https://shop.xyz.com/collections/products/xyz?

Any help is greatly appreciated!


[edited by: not2easy at 4:24 pm (utc) on Jan 10, 2020]
[edit reason] URL readability [/edit]

w3dk

4:21 pm on Jan 10, 2020 (gmt 0)

10+ Year Member Top Contributors Of The Month



I can't figure out why products_id 12 and 1282 both redirect to ... xyz


They shouldn't - at least not with the directives in the order you've posted (1282 before 12) - 1282 should redirect to abc. Make sure you're not seeing a cached redirect (301s are cached by the browser - so if you had these directives in the "wrong" order earlier then the erroneous redirect will likely be cached - test with 302s to avoid acaching issues).

But therein lies an underlying issue with the directives posted - they are very much dependent on order. The regex "^products_id=12" will also match the query string "?products_id=1282". If you only want it to match the query string "?products_id=12" exactly then use an end-of-string anchor. ie. "^products_id=12$". Now, the order of the directives do not matter.

But is the query string always just the "product_id"? Or can there be other URL parameters?

JoshS

4:35 pm on Jan 10, 2020 (gmt 0)

10+ Year Member



Very helpful, w3dk!

The query string is just "product_id". Is there a better way to do it?

w3dk

6:06 pm on Jan 10, 2020 (gmt 0)

10+ Year Member Top Contributors Of The Month



The query string is just "product_id". Is there a better way to do it?


Just use the end-of-string anchor "$" (and start-of-string anchor "^" in the case of your first rule) as mentioned above.

Alternatively, you can use the "=" operator on the CondPattern, which then treats the string as a literal string (not a regex) and performs a lexicographical string comparison instead. For example:


# Only matches "products_id=1408" exactly
RewriteCond %{QUERY_STRING} =products_id=1408
:

# Only matches "products_id=1282" exactly
RewriteCond %{QUERY_STRING} =products_id=1282
:

RewriteCond %{QUERY_STRING} =products_id=12
:


The NC flag is not necessary, unless you do need to match "products_id" in any case (eg. "PRODUCTS_ID" and/or "PrOdUcTs_Id" etc.)?

lucy24

7:59 pm on Jan 10, 2020 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Instead of the end-of-string anchor $ I'd use the word-boundary anchor \b. That way, if there happen to be other components to the query string, it will still work.

In general, don't use the [NC] flag unless the string you're testing against can legitimately occur in a variety of casings. Otherwise it's just extra work for the server, having to flatten the casing of both pattern and test-string before comparing them. If the only possibilities are "name" and "NAME" it's probably more efficient to say (name|NAME) instead of name [NC].

JoshS

3:07 am on Jan 11, 2020 (gmt 0)

10+ Year Member



Thank you, all! It does seem to work correctly! Now to plug away at a few hundred redirects....

lucy24

3:14 am on Jan 11, 2020 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



A few hundred? Yikes. It might be to your advantage to rewrite along the lines of

RewriteCond %{QUERY_STRING} products_id=\d
RewriteRule ^ /allredirects.php [L]
and then let /allredirects.php do the lookup and issue the redirect. Keep the rule in the same place in htaccess--that is, among the specific redirects with R=301 flag, not down below with the rewrites.

But wait, come back. I remain a bit uneasy about the pattern in the rule
RewriteRule ^
and-that's-all. As written, this means the RewriteCond will be evaluated on all requests ever: interior pages, ErrorDocuments, supporting files, everything. This seems awfully wasteful. Surely the "products_id=blahblah" parameter will only be found attached to specific URLs, either within some directory, or with paths in some particular format? Those should be given in the body of the rule.

JoshS

3:23 am on Jan 11, 2020 (gmt 0)

10+ Year Member



Here is the full url of a product in the old store:

www.domain.com/catalog/index.php?main_page=product_info&products_id=12

phranque

11:54 am on Jan 11, 2020 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



As written, this means the RewriteCond will be evaluated on all requests ever: interior pages, ErrorDocuments, supporting files, everything. This seems awfully wasteful. Surely the "products_id=blahblah" parameter will only be found attached to specific URLs, either within some directory, or with paths in some particular format? Those should be given in the body of the rule.

agreed.
Here is the full url of a product in the old store:

www.domain.com/catalog/index.php?main_page=product_info&products_id=12


i would go something like with this:
RewriteCond %{QUERY_STRING} \bproducts_id=1408\b
RewriteRule ^catalog/index\.php$ https://shop.xyz.com/collections/products/mno? [L,R=301]

w3dk

12:32 pm on Jan 11, 2020 (gmt 0)

10+ Year Member Top Contributors Of The Month



Here is the full url of a product in the old store:

www.domain.com/catalog/index.php?main_page=product_info&products_id=12


Although, rather confusingly, you stated that "The query string is just 'product_id'" - that's not what it looks like in the above URL? Your original redirects wouldn't have work at all if that was the URL being requested?

phranque

1:50 pm on Jan 11, 2020 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



Although, rather confusingly, you stated that "The query string is just 'product_id'" - that's not what it looks like in the above URL?

Instead of the end-of-string anchor $ I'd use the word-boundary anchor \b. That way, if there happen to be other components to the query string, it will still work.

like this:
\bproducts_id=1408\b