When you have to make changes in URLs or migrations in WordPress you always have to take special care not to lose the SEO positioning of the previous URLs.
No matter what the change will be, a single URL or a complete domain, it is vital that, if you already had a URL well positioned in Google or other search engines, after the change of URLs, the positioned links do not lead to a 404 error page, but to the new URL.
For this purpose, there is nothing better than knowing the 301(permanent redirection) redirection rules that we must add to the .htaccess
file of the server to maintain the SEO of the old URLs, that this is transferred to the new ones, and that they do not lead to error pages.
Important note: Always make a backup copy of the
.htaccess
file before applying any new redirection, and if after saving the changes your website gives an error, recover the backup copy and talk to your hosting provider to ask them why the redirection did not work, in case they have any limitation on their side.
Note: In the redirection examples always change the example domains to your own.
Table of Contents
301 redirection of URLs without www to URLs with www
If you want to force your domain URLs, previously without www, to become URLs with www, add the following to the .htaccess
file on the server where your domain is hosted.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^yourdomain.com$
RewriteRule (.*) http://www.yourdomain.com/$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
301 redirection of URLs with www to URLs without www
The opposite example, to not use the www, would look like this:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.yourdomain.com$
RewriteRule (.*) https://yourdomain.com/$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
301 redirection of HTTP URLs to HTTPS URLs
If you have just installed an SSL certificate for your website it is essential that you redirect all HTTP requests to HTTPS, so:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
Code language: HTML, XML (xml)
301 redirection of HTTPS URLs to HTTP URLs
If your situation is the opposite, that you have decided not to serve with HTTPS, what you should add would be this other:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_PORT} ^443$
RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
Code language: HTML, XML (xml)
301 redirection from one domain to another
This situation is probably the most common one, when you make a domain change for some reason. In this case you must add the following to the .htaccess
file of the old domain installation.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
This also means that you should not cancel or delete the hosting where the old domain is, or the 301 redirects will stop working. Of course, you can delete all the WordPress installation and files, as well as the rest of the previous rules in the .htaccess
of the old domain, the only one that normally matters will be this one, the redirect to the new domain.
How long should you leave it active? Well, as an extreme example, I redirected the domain x.com to y.com about 5 years ago, and I still keep the hosting (minimum) associated to x.com with the redirection. Maybe it’s too long, and I could cancel the hosting, but it doesn’t ask for bread and with Google’s designs I prefer not to risk.
But well, maybe it is exaggerating a little. The idea is that you keep an eye on the domain change, and when you no longer see in your usual searches for your content results with the old domain, and you see that these have been replaced by results with the new domain, you could cancel the hosting where the old domain was, and leave only a direct redirection from domain to domain from the hosting, without having to maintain any hosting.
Finally, although Google will pick up URL changes after a domain change without any problem, and has long since announced that PageRank is not lost when changing domains if a correct 301 redirect is made, it may help to use its domain change tool to keep track from the Search Console.
301 redirection from a subdomain to a domain
Here you must do the same as in the previous example, in this case in the .htaccess file where the subdomain is:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
301 redirection from a folder to a domain
Exactly the same as in the 2 previous cases, the source installation does not matter, it works anyway, the important thing is to indicate where the 301 redirections should be made:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
301 redirect from domain to subdomain
Now let’s put us in the opposite case, in which after years of paying for a domain you have decided that you want your installation in a subdomain. Well, after moving all your installation, in the .htaccess
file of the previous domain add the following:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^(.*)$ https://subdomain.mydomain.com/$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
301 redirect from domain to subfolder
And the same would be true if you have decided to move your content to a subfolder on a domain:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^(.*)$ https://mydomain.com/my-folder/$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
301 redirect from subdomain to subfolder
A slightly different example would be to change from subdomain to subfolder. In this case, it would be like this:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^(.*)$ https://mydomain.com/my-folder/$1 [L,NE,R=301]
</IfModule>
Code language: HTML, XML (xml)
301 redirection from one page to another
These redirects are the most common in any website, WordPress or not, as they serve to redirect traffic from one entry or page to another when we delete, it becomes obsolete, or whatever, the first one. They are done like this:
<IfModule mod_rewrite.c>
RewriteEngine On
Redirect 301 /my-previous-page/ /my-new-page/
</IfModule>
Code language: HTML, XML (xml)
Another way to make these redirections, exactly as effective as the previous one, would be like this:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^my-previous-page/$ https:/mydomain.com/my-new-page/ [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
If you are going to create several such redirects, you do not need to add IfModule
and RewriteEngine On
for each one, just do it once, as in this example:
<IfModule mod_rewrite.c>
RewriteEngine On
Redirect 301 /my-previous-page/ /my-new-page/
Redirect 301 /my-other-previous-page/ /my-other-new-page/
</IfModule>
Code language: HTML, XML (xml)
And with the other method exactly the same:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^my-previous-page/$ https:/mydomain.com/my-new-page/ [R=301,L]
RewriteRule ^my-other-previous-page/$ https:/mydomain.com/my-other-new-page/ [R=301,L]
</IfModule>
Code language: JavaScript (javascript)
Important note: If you are going to do a lot of redirects of posts or pages, better use a plugin like Redirection. You will avoid having to edit the
.htaccess
file and possible typing errors, and also the plugin can automatically make redirects for you when you make a slug change.
301 redirection from URLs with day and name to URLs with only the name
This is very common in sites that have migrated from WordPress.com to WordPress, because in Automattic’s blogging service the default URLs are with day name (/%year%/%monthnum%/%day%/%postname%/
), and cannot be changed in most plans.
In any case, if you have changed the permalinks from day and name (/%year%/%monthnum%/%day%/%day%/%postname%/
) to name only (%postname%
) you must add the following to avoid losing positioning:
RedirectMatch 301 ^/([0-9]{4})/([0-9]{2})/([0-9]{2})/(?!page/)(.+)$ https://mydomain.com/$4
Code language: JavaScript (javascript)
301 redirection from URLs with month and name to URLs with name only
If the previous permalinks were of type month and name (/%monthnum%/%day%/%postname%/
), and you have changed to name only (%postname%
), then you must add this other one:
RedirectMatch 301 ^/([0-9]{4})/([0-9]{2})/(?!page/)(.+)$ https://mydomain.com/$3
Code language: JavaScript (javascript)
301 redirection from numeric URLs to URLs with name only
If you had the numeric permalinks (/files/%post_id%
) and you want them to have only the name (%postname%
) then this is the redirect:
RedirectMatch 301 ^/files/(\d+)$ https://mydomain.com/?p=$1
Code language: JavaScript (javascript)
301 redirection of simple URLs to named URLs
This redirect is not necessary, as simple WordPress URLs (?p=123
) will always redirect to the currently active permalink structure, whatever it is.
301 redirection of URLs with category and name to URLs with name only
If at some point you created custom permalinks, which included the category in the URL (/%category%/%postname%/
), something very common by the way, and at some point you want to go back to URLs with just the name (%postname%
), you should add a 301 redirect so you don’t ruin your SEO, like this:
RedirectMatch 301 ^/<category>/(.*)$ https://mydomain.com/$1
Code language: JavaScript (javascript)
301 redirection of URLs without a trailing slash (/) to URLs with a trailing slash
This happens when you want to redirect all URLs of a website with trailing slash to URLs without trailing slash.
It would be done like this:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
</IfModule>
Code language: HTML, XML (xml)
All URLs of the type https://mydomain.com/my-entry/
would become https://mydomain.com/my-entry
301 redirection of URLs with trailing slash (/) to URLs without trailing slash
If your case is just the opposite, what you would have to add would be the following:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*[^/])$ /$1/ [L,R=301]
</IfModule>
Code language: HTML, XML (xml)
Here you get the opposite, that all URLs https://mydomain.com/my-entry
become https://mydomain.com/my-entry/
Redirection of URLs with extension to URLs without extension
Imagine that at the time you decided to add an extension to the permalinks of your website, for example .htm
, but then you regret it and want to remove the extensions, but without losing the SEO achieved.
Or another example, you are going to redirect all the URLs of a simple HTML website, all with .html
extension, to URLs created with WordPress, without extension.
If this is what you need, an example of the code if they come from the .html
extension would be like this:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^/?(.*).(html)$ /$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
All URLs such as https://mydomain.com/my-entry.html
would become https://mydomain.com/my-entry
Another example, in this case if the URLs end in .php
, typical of other CMS installations, would be like this:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^/?(.*).(php)$ /$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
301 redirection from AMP URLs to non-AMP URLs
If you have recently decided to disable AMP from your website, it is vital that you add the following 301 redirects from your AMP URLs to non-AMP URLs:
RewriteEngine On
RewriteCond %{REQUEST_URI} (.+)/amp(.*)$
RewriteRule ^ %1/ [R=301,L]
RewriteCond %{QUERY_STRING} ^(.*)?amp=1$
RewriteRule (.*) /$1? [R=301,L]
301 redirection of uppercase URLs to lowercase URLs
You probably already know that web servers are case-sensitive, right?
In other words, for a server and your browser, the URL https://mydomain.com/MY-ENTRY/
is not the same as the URL https://mydomain.com/my-entry/
Well, you may find yourself in the situation where you have had to change uppercase URLs to lowercase URLs, in which case you should force permanent redirects (301) from the old uppercase URLs to the new lowercase URLs.
This is what you should add to your .htaccess
file:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule [A-Z] - [E=HASCAPS:TRUE,S=1]
RewriteRule ![A-Z] - [S=28]
RewriteRule ^([^A]*)A(.*)$ $1a$2
RewriteRule ^([^B]*)B(.*)$ $1b$2
RewriteRule ^([^C]*)C(.*)$ $1c$2
RewriteRule ^([^D]*)D(.*)$ $1d$2
RewriteRule ^([^E]*)E(.*)$ $1e$2
RewriteRule ^([^F]*)F(.*)$ $1f$2
RewriteRule ^([^G]*)G(.*)$ $1g$2
RewriteRule ^([^H]*)H(.*)$ $1h$2
RewriteRule ^([^I]*)I(.*)$ $1i$2
RewriteRule ^([^J]*)J(.*)$ $1j$2
RewriteRule ^([^K]*)K(.*)$ $1k$2
RewriteRule ^([^L]*)L(.*)$ $1l$2
RewriteRule ^([^M]*)M(.*)$ $1m$2
RewriteRule ^([^N]*)N(.*)$ $1n$2
RewriteRule ^([^O]*)O(.*)$ $1o$2
RewriteRule ^([^P]*)P(.*)$ $1p$2
RewriteRule ^([^Q]*)Q(.*)$ $1q$2
RewriteRule ^([^R]*)R(.*)$ $1r$2
RewriteRule ^([^S]*)S(.*)$ $1s$2
RewriteRule ^([^T]*)T(.*)$ $1t$2
RewriteRule ^([^U]*)U(.*)$ $1u$2
RewriteRule ^([^V]*)V(.*)$ $1v$2
RewriteRule ^([^W]*)W(.*)$ $1w$2
RewriteRule ^([^X]*)X(.*)$ $1x$2
RewriteRule ^([^Y]*)Y(.*)$ $1y$2
RewriteRule ^([^Z]*)Z(.*)$ $1z$2
RewriteRule [A-Z] - [N]
RewriteCond %{ENV:HASCAPS} TRUE
RewriteRule ^/?(.*) /$1 [R=301,L]
</IfModule>
Code language: HTML, XML (xml)
These redirection rules are the most common, but if you know of any other interesting ones, let us know in the comments and I will add them to the list.