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.