4

I want to do 2 things : redirect http://www.example.com (with www) to http://example.com/fr (without www, AND subdirectory)

Of course, I also want http://example.com to redirect to http://example.com/fr.

I saw this solution :

RewriteCond %{HTTP_HOST} ^(www\.)?example.com$ [NC]
RewriteCond %{REQUEST_URI} !^/fr/.*$
RewriteRule ^(.*)$ /fr/$1 [L,R=301,NC]

But it slows down my website like crazy (impossible to load the page afterwards).. What should I fix in the above code?

Here is my complete code

Options +FollowSymLinks
RewriteEngine on

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

RewriteCond %{HTTP_HOST} ^(www\.)?beastof\.com$ [NC]
RewriteCond %{REQUEST_URI} /(.*)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule !^fr(/|$) /fr/%1 [R=301,L]

RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]

(It's a WordPress multisite on subdirectories.)

MrWhite
  • 11,643
  • 4
  • 25
  • 40
  • This question isn't a duplicate of the referenced "canonical" mod_rewrite question. This question specifically asks about an apparent "slow down", but otherwise appears to work OK. The linked question makes no mention of static resources, exceptions, front controllers and slow downs of this nature. – MrWhite Dec 08 '16 at 15:32

1 Answers1

2
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$ [NC]
RewriteCond %{REQUEST_URI} !^/fr/.*$
RewriteRule ^(.*)$ /fr/$1 [L,R=301,NC]

These directives don't simply redirect "http://www.example.com to http://example.com/fr". They redirect http://www.example.com/<anything> to http://www.example.com/fr/<anything>.

But it slows down my website like crazy...

There is nothing particularly wrong with the directives you have posted, but...

My guess is that you are linking to other pages/resources without the /fr/ path segment. Which is then resulting in multiple external redirects for each page view - this could potentially slow down your site (although these are 301 redirects so should be cached by the browser).

If this is the case, then you either need to fix your internal links to include this /fr/ path segment. Or, perhaps exclude static resources from this redirect (if the URL is still valid without the /fr/ path segment)?

For example, to exclude all static resources, modify your directives like:

RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$ [NC]
RewriteCond %{REQUEST_URI} /(.*)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule !^fr/ /fr/%1 [R=301,L]

This will now prevent static resources (physical files) from being redirected (whether that is still valid I don't know).

I've also optimised your directives slightly (nothing that will cause a major speed up though). I've moved the negated check for /fr/ to the RewriteRule pattern, rather than using a RewriteCond directive for this. The RewriteRule pattern is processed first, so it is better to include your first check here if you can (otherwise every URL will be processed). The URL is then grabbed from the condition instead (%1 instead of $1 backreference in the RewriteRule substitution). No need to use the NC (NOCASE) flag if it's not explicitly needed.


UPDATE#1:

example.com/fr (without the trailing slash at the end), [...] redirects to example.com/fr/fr

To resolve this, you can change the RewriteRule pattern to exclude an exact match for /fr or a URL that starts /fr/, for example:

RewriteRule !^fr(/|$) /fr/%1 [R=301,L]

This will now prevent example.com/fr from being redirected. (However, is that a valid URL? You now have two URLs: example.com/fr and example.com/fr/ presumably accessing the same resource?)

Here is my complete code

:
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
:

Since you've added your "complete code" to your question I see that you already have an "exception" block (the 3 directives above) that excludes static resources from be rewritten - it's just that it's in the wrong place, now that you've added the additional directives above.

You should move these 3 directives to directly below the RewriteBase directive (ie. at the top). Although you'll need to exclude the document root from this (by changing ^ to !^$ - see below) in order to allow / to be redirected to /fr/ - since the document root is also a directory. You can then remove the RewriteCond %{REQUEST_FILENAME} !-f directive from the block above (in the first part of this answer).


UPDATE#2 So, in summary...

(Updated to include the canonical www to non-www redirect at the start. This then allows us to simplify the later condition that checks against HTTP_HOST.)

Options +FollowSymLinks
RewriteEngine on

RewriteBase /

# Canonical www to non-www redirect
RewriteCond %{HTTP_HOST} ^www\.(example\.com)$ [NC]
RewriteRule (.*) http://%1/$1 [R=301,L]

# Exception: Exclude files and directories (except the document root)
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule !^$ - [L]

RewriteRule ^index\.php$ - [L]

# Redirect all requests to /fr/ subdirectory
RewriteCond %{HTTP_HOST} =example.com [NC]
RewriteCond %{REQUEST_URI} /(.*)
RewriteRule !^fr(/|$) /fr/%1 [R=301,L]

RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]
MrWhite
  • 11,643
  • 4
  • 25
  • 40
  • 1
    First of all thanks for your time and your help w3dk. I'm really grateful for people like you who dedicate their time to help others by sharing their knowledge. Your solution almost works ;) It works in most cases, except if I go to example.com/fr (without the trailing slash at the end), in which case it redirects to example.com/fr/fr, for some reason. Any way to get this fixed ? – Amaury Lefebvre Dec 08 '16 at 14:21
  • That can be corrected by changing the `RewriteRule` _pattern_. I've updated my answer, with some additional notes. – MrWhite Dec 08 '16 at 15:05
  • Thanks a lot for your answer. I updated my code, following what you advised (I hope I understood properly). I edited the code section in my original answer. Now example.com/fr redirects to example.com/fr/, it works like a charm thank you (and yes, boh urls have the same content so no worries). But I guess I did something wrong because now example.com no longer redirects to example.com/fr as it did before, ahah. Also some javascript I'm calling on my page (a countdown script, "Flipclock.JS") no longer displays the CSS properly (shall I change the paths to absolute or something ?) – Amaury Lefebvre Dec 09 '16 at 20:06
  • "`example.com` no longer redirects to `example.com/fr`" - Sorry, my bad. With moving the code around we need to also exclude the document root, otherwise it won't get redirected. I've updated my answer with a complete summary (what you had wasn't quite what I intended, but it was confusing, particularly as some the directives are similar). "no longer displays the CSS properly" - If you are using _relative_ paths then that could well be the problem. Either use absolute paths or use the `base` tag. See my answer on this Webmasters question: http://webmasters.stackexchange.com/q/86450/1243 – MrWhite Dec 09 '16 at 21:43
  • Just realised... this code did not specifically remove the `www` subdomain. I've included this as a separate rule block at the top (preferable I think) of the "summary". This also allows us to simplify the later condition when we check for the _host_, since it now won't contain the `www` subdomain. – MrWhite Dec 09 '16 at 22:09
  • Dude, you are the best. It works perfectly (and the CSS issue has been fixed automatically, for some reason lol). Thanks infinitely for your help and the time you dedicated to fix this issue. I am very very grateful ! If I can do something for you in return, let me know :) – Amaury Lefebvre Dec 10 '16 at 15:03