Avoid SSL Mixed Content Errors in WordPress

Published on by Joe Casabona

Recently, an interesting bug popped up, post launch, during a WordPress project. This bug caused certain styles and images (assets from here on out) to not load in Chrome and Firefox, because these browsers do not allow “mixed content” (different content coming from both secure and non-secure sources). Problems like this occur when your URL is using https:// but some asset on your page is not. While there are settings in WordPress that should safeguard from this, it can still happen and here's how you can fix it:

Tracking Down the Problem

The first step in troubleshooting is to make sure the settings for the URLs were set properly. All examples here will use the domain test-site.dev.

Screenshot 2016-01-22 11.44.57

When we saw that the URLs were properly set to use https://, the next step was to investigate why certain assets were displaying using the correct protocol and others were not. Part of this issue came from WordPress' latest addition in the 4.4 release: native responsive image support.

While the original image source was using https://, anything found in the srcset attribute (which tells browser to dynamically change the image based on screen size) was using http://, causing both Chrome and Firefox to not load those assets. When this happens, we see something like this:

<img width="200" height="133" src="https://test-site.dev/wp-content/uploads/2013/03/sunset_600x400_mr-200x133.jpg" class="attachment-four-by-three-thumb size-four-by-three-thumb wp-post-image" alt="sunset_600x400_mr" srcset="http://test-site.dev/wp-content/uploads/2013/03/sunset_600x400_mr-300x200.jpg 300w, http://test-site.dev/wp-content/uploads/2013/03/sunset_600x400_mr-200x133.jpg 200w, http://test-site.dev/wp-content/uploads/2013/03/sunset_600x400_mr.jpg 600w" sizes="(max-width: 200px) 100vw, 200px">

It turns out some functions, including the one used to upload files, did not always support https, so somewhere along the way the non-secure URLs were making their way into srcset. It's a known issue that is noted here in Trac and it's targeted to get fixed in WordPress 4.5.

Fixing the Issue

In order to fix this issue, as noted in the Trac ticket, we had to modify the wp-config.php file to force WordPress to use a specific URL.

$protocol = "http://";
$domain = $_SERVER['HTTP_HOST'];

if ( $_SERVER['HTTPS'] == 'on' ) {
 $protocol = "https://";

$url = $protocol . $domain;

define('WP_DOMAIN', $domain);
define('WP_HOME', $url);
define('WP_SITEURL', $url);

The first step is to set a default protocol, namely http://. This will serve as a fallback in case SSL is ever disabled or broken. After grabbing the domain from the server, we check to see if https is turned on; if it is, we can use this as part of our solution. Finally, we combine the protocol with the domain and explicitly set the WordPress Site and Home URLs.

This fixed our problem and all assets were loading using the proper (and secure) protocol. The only drawback is that users cannot change the URL, using the WordPress admin, afterwards.

Screenshot 2016-01-22 13.35.19

Why Does this Work?

This process makes no changes to the database or the content itself, so why does it work? The basic idea is that anytime WordPress is supposed to check the database for the proper site URL, it checks for a value we explicitly set and uses that. This means it's making no assumptions about the protocol (http vs. https) we use and that protocol must be specified when changing the URLs in wp-config.php.

This method is also great if you are developing a site locally or are moving WordPress to a different host, database and all. You can read more about changing your site URL over at the WordPress Codex.