3

The issue that I'm currently forced to handle is related to a folder structure URL being redirected to the same folder structure URL but with a different string.

So page-a used to exist but that document is now known to be page-b. All the other documents are still being requested through the same method and they all work fine.

# Redirect
Redirect 301 /page/page-a/ /page/page-b/   [R,L]

RewriteEngine On

RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^page/(.*)/ index.php?type=page&id=$1                             [L,NC]

I've tried using RewriteRule, redirectMatch and Redirect 301. It either shows me

www.example.com/?type=page&id=page-a

or it displays

www.example.com/page/page-b/?type=page&id=page-a

All the other urls work fine and display www.example.com/page/page-c/.

2
Redirect 301 /page/page-a/ /page/page-b/   [R,L]

On Apache this would have resulted in a 500 Internal Server Error because the [R,L] argument is not valid on a mod_alias Redirect directive. [R,L] are RewriteRule (mod_rewrite) flags.

or it displays www.example.com/page/page-b/?type=page&id=page-a

This is the result of a conflict between mod_alias (Redirect) and mod_rewrite (RewriteRule). You should avoid mixing redirects from both modules. Different modules run independently and at different times throughout the request, despite their apparent order in the .htaccess file.

On Apache, mod_rewrite runs first, so the URL is internally rewritten to /index.php?type=page&id=page-a before the Redirect occurs. Redirect (acting on the initial request) then externally redirects the request to /page/page-b/, but copies the query string from the rewritten URL, so you end up with the garbled redirect.

I've tried using RewriteRule

Well, a single RewriteRule is all you require, so it's not clear why this was not working for you. This needs to go before the generalised rewrite, instead of the mod_alias Redirect:

RewriteRule ^page/page-a/$ /page/page-b/ [R,L]

This maintains any query string that was present on the original request. However, your later rewrite currently overrides this, so it would be lost anyway (see below) - unless you explicitly parse the requested URL. To discard the query string, add the QSD flag to the RewriteRule.

This is currently a temporary (302) redirect - always test with 302s to avoid caching issues. Only change to a permanent (301) - if that is the intention - once you have confirmed it works OK. To do this, change the R flag to R=301.

RewriteRule ^page/(.*)/ index.php?type=page&id=$1                             [L,NC]

The RewriteRule pattern looks far too generic - it would seem to match too much - although maybe that's the intention? It would match URLs of the form /page/x/y/z/page-b/1/2/3 and rewrite to /index.php?type=page&id=x/y/z/page-b/1/2.

To specifically match URLs of the form /page/<page-id>/ only then you should use a RewriteRule pattern like ^page/([^/]+)/$ or to be slightly more restrictive: ^page/([\w-]+)/$. Generally, you want to be as restrictive as necessary.

To append any query string from the initial request, add the QSA flag to the RewriteRule.

Do you need the NC flag? This allows the directive to match /page, /PaGe and /PAGE etc. and since this is a "rewrite" (and not a "redirect") could potentially result in duplicate content.

In Summary

RewriteEngine On
RewriteBase /

# Redirect
RewriteRule ^page/page-a/$ /page/page-b/ [R=302,L]

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^page/([\w-]+)/$ index.php?type=page&id=$1 [L]   

But note my comments above regarding the QSD and QSA flags.

  • Thank you so much for your explanation. The NC was sadly needed due to the previous pages containing capitals. A current rework of the site is supposed to change everything to much friendlier urls. In the RewriteRule we do use pretty much every character that you can imagine, this is all due to the previous version of a site but, as mentioned, we're trying to clean that up. And thank you for the other recommendations. Much appriciated! – daniel4ing Sep 26 at 13:53
  • 1
    "we do use pretty much every character that you can imagine" - then maybe use the pattern ^page/([^/]+)/$ - which matches everything except / (slash) - providing you don't need to match multiple path segments. – MrWhite Sep 26 at 14:47
  • 1
    Again, thank you MrWhite, it seems to be working like a charm. – daniel4ing Sep 26 at 23:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.