Redirect - remove custom query string

I have a problem with some page URLs. The page URL structure is like this:

www.example.com/wp/custom-taxonomy/somepagename/?token=12345

I want that when I access the URL above to redirect me to:

www.example.com/wp/custom-taxonomy/somepagename/

In /wp/ is WordPress installed. I tried this in .htaccess:

IfModule mod_rewrite.c
RewriteEngine On
RewriteBase /wp/
RewriteCond %{query_string} ^token=12345
RewriteRule (.*) /$1? [R=301,L]
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wp/index.php [L]
/IfModule

but it redirects me to:

www.example.com/custom-taxonomy/somepagename

Any ideas?

Later edit:

/wp/ - the folder where Wordpress is installed;

/custom-taxonomy/ - a custom taxonomy, like /partners/ where I enter all my partners.

/somepagename - a dynamic page, like /xyz-ltd, /abcd... dynamic pages created for the custom taxonomy.

I can not put a rule for every page, would need a general rule to remove the query string.

Topic apache mod-rewrite htaccess redirect Wordpress

Category Web


RewriteBase /wp/
RewriteCond %{query_string} ^token=12345
RewriteRule (.*) /$1? [R=301,L]

but it redirects me to:

www.example.com/custom-taxonomy/somepagename

There are two issues here with the redirected URL:

  1. The /wp prefix is missing.

  2. The trailing slash is missing.

To fix #1 you can either:

  • Hardcode the /wp prefix in the substitution string (as is done in the last RewriteRule - part of the WordPress front-controller - although that is arguably incorrect, see the next point). For example:

    RewriteRule (.*) /wp/$1? [R=301,L]
    
  • Since RewriteBase /wp is already defined, you can simply remove the slash prefix on the substitution string (to make it a relative path substitution). ie. $1?. mod_rewrite then prepends the /wp path segment to the resulting substitution. For example:

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

    Aside: This is really how the last RewriteRule should be written. ie. RewriteRule . index.php [L] (since that's the whole point of having RewriteBase /wp defined in the first place).

  • Change the rule to use the REQUEST_URI server variable instead of a backreference ($1). The REQUEST_URI contains the full root-relative URL-path, so already includes the /wp prefix. This is perhaps the preferred method (unless there are additional requirements) since it will work anywhere and is not dependent on the setting of RewriteBase. For example:

    RewriteRule ^ %{REQUEST_URI}? [R=301,L]
    

However, this does not resolve #2 - the missing trailing slash. This is not caused by this directive - something else is removing the trailing slash (if it is present on the initial request). A possible reason for this is the permalink structure as suggested in @IXN's answer. Providing the trailing slash is part of the initial request (as indicated in the question) then this directive specifically preserves it. If the trailing slash is missing from the initial request then the trailing slash will also be missing from the redirected response (see below on how to fix this). In order to debug this further, you should check for any additional redirects in the network traffic.

Additional notes:

  • You should avoid editing the code within the # BEGIN WordPress section, since WordPress will try to maintain this and overwrite your edits. This redirect should go near the top of the .htaccess file, before the # BEGIN WordPress section.

  • ^token=12345 - Include an and-of-string anchor ($) on the CondPattern to match this query string string only. As it stands, this matches any query string that simply starts with token=12345.

  • On Apache 2.4 use the QSD (Query String Discard) flag instead of appending an empty query string (a lone ?) on the substitution string.

  • As it currently stands, this rule matches any URL-path. Including all static resources (images, CSS, JS) etc. It doesn't specifically match /wp/<custom-taxonomy>/<somepagename>/ - the URL format as stated. Ideally, your rule should be as specific as possible, to match only the targetted URLs, so as to avoid unnecessary redirects and additional rule processing. For example:

    RewriteRule ^[\w-]+/[\w-]+/$ %{REQUEST_URI} [QSD,R=301,L]
    

    The \w shorthand character class matches the characters a-z, A-Z, 0-9 and _ (underscore) so naturally avoids matching static resources that typically have a file extension prefixed with a dot.

  • To match an optional trailing slash on the initial request, but always include the trailing slash on the redirected URL then you can do something like this:

    # Trailing slash optional on request and slash always appended
    # (Dependent on RewriteBase)
    RewriteRule ^([\w-]+/[\w-]+)/?$ $1/ [QSD,R=301,L]
    

    However, this is now reliant on the RewriteBase directive (to get the directory prefix) as mentioned above. Although you could use a condition (RewriteCond directive) to remove the dependency on RewriteBase. For example:

    # Trailing slash optional on request and slash always appended 
    # (Not dependent on RewriteBase)
    RewriteCond %{REQUEST_URI} (.*?)/?$
    RewriteRule ^([\w-]+/[\w-]+)/?$ %1/ [QSD,R=301,L]
    
  • Always test with 302 (temporary) redirects to avoid potential caching issues (301s are cached persistently by the browser - including redirects made in error). Clear the browser cache before testing.

In Summary

   # Trailing slash optional on request and slash always appended
   # Full URL-path used, including subdirectory preifx
   # Not dependent on RewriteBase
   RewriteCond %{QUERY_STRING} ^token=12345$ [NC]
   RewriteCond %{REQUEST_URI} (.*?)/?$
   RewriteRule ^([\w-]+/[\w-]+)/?$ %1/ [QSD,R=301,L]

   # BEGIN WordPress
   :

I think the problem is in your permalink configuration. It seems that WP redirects

www.example.com/slug/somepagename/

to

www.example.com/slug/somepagename

anyway. If you solve this, probably by setting your permalinks in wp admin, then the redirect will work.

It's funny but I'm doing the exact same thing right now for my site, redirecting mobile queries (?m=1) to the main pages. So I can confirm that your code is correct. The only thing different I do is add $ at the end of the query, like ^token=12345$, but I don't think this makes a difference.


Use this in your .htaccess-

Redirect 301 /slug/somepagename/?token=12345 http://www.example.com/wp/slug/somepagename/

You can use add_rewrite_rule in WordPress to capture the query args or add_rewrite_endpoint. If you really just want to redirect based on certain rules then template_redirect can be a good place to use a header redirect.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.