1

My client has a WordPress site which is hosted on a CPanel Linux server.

Their old URL is https://old-example.co.uk. Their new URL is https://new-example.co.uk.

Both URLs are pointing to the same A record and have been added as domain aliases via CPanel.

All database URLs have been replaced with https://new-example.co.uk using Interconnect's Search & Replace tool. wp-config.php also has been updated to reflect the new URL.

We then tried this via .htaccess:

#Force SSL
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://new-example.co.uk/$1 [R,L]
</IfModule>

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

With the above code, when you visit https://old-example.co.uk directly via the browser it redirects to https://new-example.co.uk perfectly.

However, when you click on a an old link via SERPs, e.g. https://old-example.co.uk/about, the old URL remains in the browsers address bar.

We'd like the new URL to always appear in the browsers address bar. To achieve this, we tried adjusting our .htaccess like so:

#Redirect old domain
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !new-example.co.uk$ [NC]
RewriteRule ^(.*)$ https://new-example.co.uk/$1 [L,R=301]
</IfModule>

#Force SSL
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://new-example.co.uk/$1 [R,L]
</IfModule>

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

This hasn't work and fails to load some images and stylesheets.

Where are we going wrong here?

  • I highly doubt that the redirects are based on referrer as you seem to suggest. What is more likely happening is that you are seeing different behavior when testing directly because your browser has cached the redirect. When you test, you need to clear your browser cache each time, or test on the command line with curl. – Stephen Ostermiller Feb 6 '18 at 18:12
  • Yes, "that rule" will certainly "break your site" - it will result in a redirect loop (if not A then B, if not A then B, etc.) Your "Force SSL" directive is in the wrong place and won't do anything. What happens when you visit https://old-example.co.uk/about "directly"? As @Stephen suggests, there should be no difference between typing the URL directly in the browser and clicking on a URL in the SERPs. "With the above code, when you visit https://old-example.co.uk directly, it re-directs to https://new-example.co.uk perfectly." - the above code is not doing that (probably WP itself). – MrWhite Feb 6 '18 at 20:39
  • @StephenOstermiller all testing is being performed within private browsing with the cache cleared. – Sam Feb 7 '18 at 13:11
  • @MrWhite Can you please recommend the correct directive for forcing SSL? When you visit old-example.co.uk/about directly, the URL remains within the browser bar and doesn't change to new-example.co.uk/about. This is the same behaviour when visiting from SERPs. – Sam Feb 7 '18 at 13:18
  • 1
    MrWhite is saying that the www needs to match between the RewriteCond and the RewriteRule They should either both have the www or both not. That rewrite rule and the force SSL rule need to come before the WordPress rewrite rules. – Stephen Ostermiller Feb 7 '18 at 13:42
1

With the above code, when you visit https://old-example.co.uk directly via the browser it redirects to https://new-example.co.uk perfectly.

"The above code" does not actually do that. The only redirect in "the above code" is an HTTP to HTTPS (only) redirect. So, it would redirect http://old-example.co.uk (not https) to https://new-example.co.uk. So, if you were seeing this redirect then something else was doing it, perhaps WordPress itself or even a cached redirect?

...fails to load some images and stylesheets.

What do you mean exactly by "some images and stylesheets"? So, some images and stylesheets are loading correctly? What is different about the images and stylesheets that fail to load?

Images and stylesheets should not be getting redirected anyway. These should already be linked correctly in the HTML. (?)

However, your updated code does contain an error (although not an error that would necessarily fix "some" of your images and stylesheets) and it could certainly be simplified...

#Redirect old domain
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} !new-example.co.uk$ [NC]
RewriteRule ^(.*)$ https://new-example.co.uk/$1 [L,R=301]
</IfModule>

#Force SSL
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://new-example.co.uk/$1 [R,L]
</IfModule>

The "error" is in the first RewriteCond directive:

RewriteCond %{HTTP_HOST} !new-example.co.uk$ [NC]

You are missing the start-of-string anchor on the CondPattern, so this condition is successful when the host does not end with new-example.co.uk, so it will fail to canonicalise a request for www.new-example.co.uk (the www subdomain), since this also ends with new-example.co.uk.

The above should be rewritten:

# Redirect old domain
RewriteCond %{HTTP_HOST} !^new-example\.co\.uk$
RewriteRule (.*) https://new-example.co.uk/$1 [R=301,L]

# Force SSL
RewriteCond %{SERVER_PORT} 80
RewriteRule (.*) https://new-example.co.uk/$1 [R=301,L]

Notes for the above:

  • As discussed above, the start of string anchor (^) has been added to the CondPattern: !^new-example\.co\.uk$ - also note the escaped dots, otherwise these match any character.

  • No need for the <IfModule> wrappers. (See my answer to this recent question: Is Checking For mod_write Really Necessary?)

  • No need for the additional RewriteEngine and RewriteBase directives. These are already stated in the WordPress code block. The directives specified later in the file (in the WP block) override the earlier directives anyway.
  • Removed the NC flag on the negated condition. (Note it is a negated condition.) Since you want it to be successful when it is not new-example.co.uk only, all lowercase. If you include the NC flag then it will fail to match malformed requests such as NEW-EXAMPLE.CO.UK.
  • The "Force SSL" redirect should ultimately be a 301 as well. By stating just R then it will default to a temporary 302 redirect. (Although it is good to test with 302 redirects in order to avoid browser caching.)
  • I changed the RewriteRule pattern from ^(.*)$ to (.*) - these two regex are essentially the same, since * is greedy by default. (.*) is shorter/simpler so is generally preferred. However, some people do still prefer to include the start/end anchors as they find it easier to read.
  • 1
    Thank you for such a detailed, well explained answer. I now have a much better (and cleaner) understanding of how this all works. Your new code works perfectly. – Sam Feb 13 '18 at 11:27

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.