Skip to content

How to fix mixed content warnings in WordPress

Mixed content means a page loaded over https asks for an image, a stylesheet or a script over plain http. Browsers block those requests or change them, so parts of the page go missing. The fix is to find where the http addresses come from and correct them there.

By
WP Ministry
Published
Tested on
WordPress 7.1.3, PHP 8.3.35

In short

  • Mixed content means an https page asked for a file over http. Browsers block the request or change it.
  • Your content is not damaged. The addresses are out of date, not the files.
  • Check the two addresses under Settings, then General first. Then replace the old addresses stored in the database.
  • If a CDN or proxy sits in front of the site, WordPress may not know that visitors are on https.

Mixed content means a page that was loaded over https asks for something else, such as an image, a stylesheet or a script, over plain http. Browsers do not let that pass. They change requests for images, audio and video to https by themselves, and they block the rest, stylesheets and scripts included. An image that is not there at its https address does not appear. A page whose stylesheet was blocked arrives without its styling.

Your content is not damaged. The files are where they were. What is out of date is the address the page uses to ask for them.

Find out where the http addresses come from

Open a page that has the problem. In Chrome, Edge or Firefox, right-click the page, choose Inspect, open the Console tab and reload. Each line about mixed content names the http address the page asked for.

  • An address on your own domain that points into /wp-includes/, or at a stylesheet or script inside /wp-content/: WordPress itself is writing http. Use the first fix, and the third if a CDN or proxy sits in front of the site.
  • An address on your own domain that points into /wp-content/uploads/: it is stored in your content. Use the second fix.
  • An address on another site, or anything left over: use the last fix.

Where it goes wrong

A page request passes through each of these in turn. This one comes from the secure connection (HTTPS).

  1. Browser
  2. DNS
  3. HTTPS (this error comes from here)
  4. CDN or firewall
  5. Web server
  6. PHP
  7. WordPress
  8. Database and files

What causes it

  • The site's own address settings still begin with http

    Common

    WordPress builds the addresses of its own stylesheets, scripts and links from two settings. If they still say http, so can the pages.

    Fix: Set the site's two addresses to https

  • Old http addresses are stored in the content

    Common

    An image placed in a post is saved with its full address. Content written while the site was on http still holds http addresses, whatever the settings say now.

    Fix: Replace the http addresses stored in the database

  • A CDN or proxy hides the visitor's https from WordPress

    Sometimes

    The visitor's https connection ends at the proxy, which asks your server for the page over plain http. WordPress sees an http request and writes http addresses.

    Fix: Tell WordPress the visitor is on https

  • An http address is written into the theme, a setting or an embed

    Sometimes

    A theme file, a box you pasted code into, or an embed from another site names an http address that nothing in WordPress rewrites.

    Fix: Correct addresses written into the theme, a setting or an embed

How to fix it

Set the site's two addresses to https

  • Easy
  • Low risk
  • About 5 minutes
  1. Step 1: Go to Settings, then General

    The two addresses are near the top of the page.

  2. Step 2: Check "WordPress Address (URL)" and "Site Address (URL)"

    Both should begin with https://. If either begins with http://, change those letters and nothing else in the address.

  3. Step 3: Press Save Changes

    WordPress logs you out. Log in again at the https address.

If the two boxes are greyed out, the addresses are set in wp-config.php, on the lines that define WP_HOME and WP_SITEURL. Change http:// to https:// there.

With WP-CLI, using your own domain in place of example.com:

bash
wp option update home 'https://example.com'
wp option update siteurl 'https://example.com'

If the site then redirects in a loop, a proxy in front of it is hiding https from WordPress. Do the third fix. If it is only the login page that keeps coming back, see the login page refreshing and redirecting.

To undo it: Change the two addresses back to http.

Replace the http addresses stored in the database

  • Takes care
  • Back up first
  • About 20 minutes
  • Steps tested on WordPress 7.1.3

WP-CLI's search-replace command rewrites every stored copy of the old address in one pass.

  1. Step 1: Do a dry run

    Use your own domain in place of example.com, here and in the next step.

    It lists each table and column that holds the old address, and ends with a line such as "Success: 2 replacements to be made." Nothing has been changed yet.

    bash
    wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid --report-changed-only --dry-run
  2. Step 2: Run it for real

    This is the same command without --dry-run.

    bash
    wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid --report-changed-only
  3. Step 3: Repeat it for the other form of your domain

    If the site has also been reached with www. in front of the domain, or without it, run both commands again for that address.

  4. Step 4: Clear the cache and reload

    If the site uses a page cache, clear it, then reload the page with the Console open.

What the command does, and what it leaves alone:

  • It searches the tables WordPress itself registers. A plugin that keeps tables of its own may hold addresses too. Add --all-tables-with-prefix to include them.
  • It understands the serialized format that themes and plugins store their settings in, and keeps it valid. A plain find-and-replace in a database tool does not, and can corrupt those settings.
  • --skip-columns=guid leaves each post's permanent identifier as it is. Feed readers use it to tell which posts they have already shown.
  • It changes the two address settings from the first fix as well, if they still said http.
  • It does not touch files. An address written into a theme file is for the last fix.

No WP-CLI? Use a search-and-replace plugin. Choose one that says it handles serialized data and offers a dry run, and take the same backup first.

To undo it: Restore the database backup you took before you began.

Tell WordPress the visitor is on https

  • Takes care
  • Back up first
  • About 10 minutes
  • Steps tested on WordPress 7.1.3

This applies when a CDN, a load balancer or another proxy sits in front of your site and connects to your server over plain http. WordPress then writes http addresses for its own stylesheets and scripts, and the visitor's browser blocks them.

A proxy usually says what the visitor used in a header named X-Forwarded-Proto. These lines make WordPress take notice of it.

  1. Step 1: Open wp-config.php

    It is in the site's main folder, beside the wp-content folder.

  2. Step 2: Add these lines above "That's all, stop editing"

    wp-config.php
    if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && strpos( $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https' ) !== false ) {
    	$_SERVER['HTTPS'] = 'on';
    }
  3. Step 3: Save the file and reload the site over https

    WordPress's own stylesheets and scripts now have https addresses. If nothing has changed, your proxy does not send that header. Ask its support which header says that the visitor used https.

  4. Step 4: Set the two addresses to https

    Do the first fix now, if the addresses still begin with http://.

If your proxy can be set to connect to your server over https as well, that is the better arrangement. WordPress then sees https for itself, and these lines are not needed.

To undo it: Remove the three lines from wp-config.php.

Correct addresses written into the theme, a setting or an embed

  • Takes care
  • Low risk
  • About 30 minutes
  1. Step 1: List what is left

    Reload the page with the Console open, as described above. Work through the addresses it still names.

  2. Step 2: An address on your own domain

    It is written into a theme file, or saved somewhere the replace did not reach. Look through the theme's options, your widgets and any box where you pasted code, such as a tracking snippet. Change http:// to https://. If it is in a theme file, ask the theme's developer for an update, or make the change in a child theme so that an update does not undo it.

  3. Step 3: An address on another site

    Open the address in your browser with https:// in place of http://. If the file loads, use the https address wherever you pasted the original. If it does not, that service does not offer the file over https: host a copy yourself if you are allowed to, or take it out.

When to get help

If the Console still lists http addresses after all four fixes, they are written by code at the moment the page is built, such as a plugin or the layouts a page builder has stored. Tracing each one back to its source takes someone who can read the theme's and the plugins' code.

Common questions

Is mixed content dangerous?

It can be. Anything sent over http can be read or changed on its way to the visitor, which is why browsers refuse to run a script that arrives that way. On a page that takes a login or a payment, fix it before anything else.

Why did some images disappear when the site moved to https?

The browser now asks for each image over https, even where the page says http. An image that lives on a server with no https, or behind a certificate that does not match, cannot be fetched that way and is left out.

Can a plugin fix this for me?

Some plugins rewrite http addresses to https each time a page is built. That clears the warning while the plugin is active, and nothing stored is changed. It is a fair stopgap. Replacing the stored addresses is the lasting fix.

I replaced everything and the warning is still there. Why?

You are probably looking at a saved copy. Clear the site's page cache, the CDN's cache if you use one, and your browser's. Then look at the Console again: what it still lists is real, and belongs to the last fix.

More on this subject

Would you rather we fixed it?

Quick Fix is $49. One issue, one site, up to about an hour. No fix, no fee. 30-day warranty. It starts with a free diagnosis.