1

My site structure is main site example.com and two subfolders sites /es/ and /en/

example.com redirects => example.com/es/ and example.com/en/ is the English version.

What is wrong?

The following:

example.com/<non-existing-page> redirects => example.com/es/

Some part of this main redirect is causing that every non-existing page inside mysite.com (This site is empty) is redirected to the main page which is in the subdomain example.com/es/ instead of getting a 404 error. I see where is the problem but I don't know how to modify the rule.

My redirect in the .htaccess file:

Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept"
RewriteCond %{ENV:REDIRECT_STATUS} ^$

# Main Redirect

RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule ^/?$ "https\:\/\/example\.com\/es\/" [R=301,L]

RewriteCond %{HTTP_HOST} ^example\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule ^index\.html$ "https\:\/\/example\.com\/es\/" [R=301,L]

RewriteCond %{HTTP_HOST} ^example\.com$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule ^indexingles\.html$ "https\:\/\/example\.com\/en\/" [R=301,L]

Works perfect for the following:

  1. Is perfect that example.com/index.php redirects => example.com/es
  2. Is perfect that index.html redirects => example.com/es
  3. Is perfect that indexingles.html redirects => example.com/en

Summarizing

Every URL that has example.com/<non-existent-page> redirects to the main page: example.com/es/.

It's wrong that a non-existent-page doesn't get a 404 error. I have to change this and I don't know how.

If the URL is example.com/es/<non-existent-page> it gets a 404 error which is OK.

If the URL is example.com/en/<non-existent-page> it gets a 404 error which is OK.

Note:

If somebody else is going to use this redirect, I want to add that Mr. White redirection is working just fine. However order to make the redirection of the backend to work properly I had to delete Wordfence plugin.

1
  • Do you have multiple domain names? Or it is just example.com?
    – MrWhite
    Feb 1, 2021 at 20:30

1 Answer 1

1

Every URL that has example.com/<non-existent-page> redirects to the main page: example.com/es/.

This is presumably being done by WordPress itself, as there is nothing in what you've posted (in .htaccess) that is doing this.

You probably need to add an additional "wildcard" redirect to redirect /<anything> (except for /es and /en) to /es/<anything>. For example:

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule !^(es|en)($|/) https://example.com/es%{REQUEST_URI} [R=301,L]

This will naturally encompass the root redirect (your first rule) as well. However, this redirect will need to go after the other two specific redirects that remove index.html and indexingles.html respectively.

The RewriteCond directive that checks against the REDIRECT_STATUS environment variable is necessary to ensure that only direct requests are redirected and not rewritten requests to index.php (the WP front-controller). This preventing a redirect loop. The REDIRECT_STATUS env var is not set on direct requests but set to "200" (as in "200 OK" HTTP response status) after the first successful rewrite. The alternative would be to include index.php in the alternation subpattern, however, that wouldn't then canonicalise direct requests to index.php itself.

There is no need to backslash escape the slashes, dots and colons in the RewriteRule substitution since these characters have no special meaning here.

Also, there is no need for the conditions (RewriteCond directives) unless you have multiple domains. But even if you are, this can be simplified to a single condition. For example:

RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]

You should test first with 302 (temporary) redirects in order to avoid potential caching issues. And only change to a 301 (permanent) when you are sure this is working OK. However, language redirects like this should probably be temporary anyway.

So, in summary, you should replace your existing redirect directives with the following:

RewriteEngine On

# Remove "index.html" and redirect to "/es/"
RewriteRule ^index\.html$ https://example.com/es/ [R=301,L]

# Remove "indexingles.html" and redirect to "/en/"
RewriteRule ^indexingles\.html$ https://example.com/en/ [R=301,L]

# Everything else default to "/es/<anything>"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule !^(es|en)($|/) https://example.com/es%{REQUEST_URI} [R=301,L]

UPDATE: What its not working is: https://example.com/wp-admin/network/ redirected you too many times.

I think you'll probably need to exclude any URL that starts /wp-admin (and /wp-login.php and /phpmyadmin) from the last redirect. Change the last rule to read:

# Everything else default to "/es/<anything>"
# With some exceptions...
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule !^(es|en|wp-admin|wp-login\.php|phpmyadmin)($|/) https://example.com/es%{REQUEST_URI} [R=301,L]

You could also consider excluding any URL that already maps to a physical file (ie. -f). And if more exclusions are required then consider adding additional RewriteCond directives instead. For example:

# Everything else default to "/es/<anything>"
# With some exceptions...
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} !^/wp-login\.php$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule !^(es|en|wp-admin|phpmyadmin)($|/) https://example.com/es%{REQUEST_URI} [R=301,L]

Note that the REQUEST_URI server variable includes the slash prefix on the URL-path, but the URL-path matched by the RewriteRule pattern does not.

29
  • Thanks!! Very grateful for your answer I will test your code in hours with less traffic, and I will came back with the answer. In the mean time I have a doubt about, what I see in my access log files It is as follows: Example: ' 13.66.139.138 - - [29/Jan/2021:18:17:58 +0000] "GET non-existent-file.html HTTP/1.1" 302 613 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http:// www.bing.com/bingbot.htm) X-Middleton/1" ' Bing and other bots are scrolling for files that I don’t have since 8 years ago: Despite the redirect in htaccess file is 301 in the access log is 302.
    – Irene
    Feb 2, 2021 at 15:18
  • @ MrWhite: Do you have multiple domain names? Or it is just example.com? 'example.com' is the only domain in this Multisite
    – Irene
    Feb 2, 2021 at 17:37
  • "Despite the redirect in htaccess file is 301" - you did not have a 301 in your .htaccess file for non-existent-file.html. (Unless you have other code you have not posted?) The 302 is most probably triggered by WordPress (as I mentioned above). The redirect I posted above will 301 redirect "non-existent-file.html" (assuming that file really does not exist) to /es/non-existent-file.html, which you say should generate a 404. However, search engine bots will likely still try and crawl these URLs for many years to come - that is just what they do.
    – MrWhite
    Feb 2, 2021 at 18:37
  • 1
    So far so good thanks! I can access the network and every site dashboard. I have network and subsite plugins, seems to be ok everything.
    – Irene
    Feb 3, 2021 at 21:41
  • 1
    That's great. If this answered your question then please mark it as "accepted" by clicking the tick/checkmark next to the answer (to help other readers and to remove the question from the unanswered question queue). Once you have 15 rep you can also upvote answers that you find helpful. Thanks, much appreciated. :)
    – MrWhite
    Feb 3, 2021 at 21:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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