htaccess redirect all urls with question mark parameter to without

I checked a lot, for my question. there are some close, but none that would solve my problem.

I need to permanently redirect ALL URLs that end in this:

?mode=list

AND

?mode=grid

to without (remove the question mark and what is after it)

Example:

example.com/random-url-here?mode=grid redirect to example.com/random-url-here

AND

example.com/whatever-url-here?mode=list redirect to example.com/random-url-here

I tried this:

RewriteEngine on 
RewriteRule (.*)$^mode=list $1
RewriteRule (.*)$^mode=grid $1

and this

RewriteEngine on 
RewriteRule (.*)$^mode=list $1 [L,R=301]
RewriteRule (.*)$^mode=grid $1 [L,R=301]

But it doesn't work. Clearly, I don't understand how this works. Please help.

Thank you


Solution 1:

example.com/random-url-here?mode=grid

The part of the URL after the first ? (ie. mode=grid in this example) is called the query string.

RewriteRule (.*)$^mode=list $1 [L,R=301]

The RewriteRule directive takes up to 3 arguments:

RewriteRule pattern substitution [flags]

The pattern (first argument) to the RewriteRule directive is a regular expression (regex) that matches against the requested URL-path only, which notably excludes the query string. Therefore you can't match the query string using the RewriteRule directive.

To match the query string you need to use an additional RewriteCond (condition) directive and check against the QUERY_STRING server variable. RewriteCond directives apply conditions to the RewriteRule directive that follows.

However, the regex (.*)$^mode=list (apart from trying to match the query string) will never match in this context. $ asserts the end-of-line and ^ asserts the start-of-line - so this will always fail.

In your example above, the $1 backreference (in the substitution string) is attempting to match the URL-path. However, this URL-path (in a directory context, ie. .htaccess) does not start with a slash (ie. it's relative), so will result in a malformed redirect unless you also have a RewriteBase directive defined elsewhere in your .htaccess file. A relative substitution string is seen as a filesystem path relative to the directory that contains the .htaccess file.

If you omit the R (redirect) flag in this context (as in your first example) then it will try to internally rewrite the request (not externally redirect), so the visible URL will not change.

Try the following instead, near the top of your root .htaccess file:

RewriteEngine On

RewriteCond %{QUERY_STRING} ^mode=(list|grid)$
RewriteRule (.*) /$1 [QSD,R=302,L]

The above states... for all URLs (.*) that have a query string of mode=list or mode=grid (exactly) then redirect to the same URL-path and discard the query string (QSD - Query String Discard). The QSD is new to Apache 2.4 (which I assume you are using). If you omit the QSD flag then you will get a redirect loop (since the query string will be re-appended to the redirected URL).

Note that the above matches the query string exactly (as in your examples). If there are any other URL parameters in the query string or the case is different then it will fail to match.

Note that this is a 302 (temporary) redirect. Only change it to a 301 (permanent) - if that is the intention - when you have confirmed that it works OK. 301s are cached persistently by the browser so can make testing problematic.

Reference:

  • https://httpd.apache.org/docs/2.4/rewrite/intro.html
  • https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html