Mixed content warnings on an HTTPS site
The page arrived over HTTPS and then asked for something over HTTP. Browsers block the active parts and drop the padlock for the rest.
Mixed Content: The page at 'https://example.com/' was loaded over HTTPS, but requested an insecure resource 'http://example.com/…'.
The browser console names the exact offending URLs — start there, not with a plugin. Most of them are absolute http:// links stored in post content by an editor that saved them before the certificate existed, and the durable fix is a search-replace in the database rather than a filter that rewrites output forever.
What causes it, most likely first.
Work down the list. Each check is written to rule its row in or out before you change anything, because the fixes below it are different and a guess costs more than a command.
| Cause | How to check | Fix |
|---|---|---|
| http:// URLs stored in post content | View the page source and search for "http://" followed by your own domain. Hits inside post body markup are stored data, not theme output. | Run a database search-replace across the content tables. Do it with a tool that understands serialised data, because widget and meta values break if the string length is edited naively. |
| siteurl and home still say http | Read both options directly. If either begins with http://, WordPress builds its own asset URLs from it and every page inherits the problem. | Update both options to the https:// form. Everything WordPress generates — scripts, styles, canonical tags — is derived from these two values. |
| WordPress cannot tell it is behind TLS | is_ssl() returns false on a site that is plainly served over HTTPS. This is the signature of a reverse proxy terminating TLS upstream. | Trust the forwarded protocol header before WordPress loads, so is_ssl() answers correctly. Without it, WordPress keeps generating http:// links no matter what the database says. |
| A hardcoded third-party asset | The blocked URL is on somebody else's domain — a font, a script, an embedded player — with an explicit http:// scheme. | Change it to https:// in the theme or the embed. If the remote host has no certificate, the asset has to be self-hosted or dropped; there is no way to load it securely. |
Fixing it, step by step.
Commands assume WP-CLI and shell access. Where you have neither, each step says what it is doing so it can be done from the dashboard or over SFTP instead.
Get the list from the browser, not from a guess
Open the console on a failing page. Every mixed-content entry names the resource, and the pattern across them usually identifies the source immediately.
Check what WordPress thinks its own address is
These two options sit underneath everything else, so they are worth confirming before changing any content.
wp option get siteurl wp option get home
Rewrite stored URLs safely
Dry-run first and read the report. Skipping the GUID column is deliberate: it is an identifier, not a link, and changing it re-notifies feed readers.
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid --dry-run wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid
Teach WordPress it is behind TLS
Add this above the “stop editing” line in wp-config.php when a proxy terminates the certificate.
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) { $_SERVER['HTTPS'] = 'on'; }Purge and re-check
Cached HTML holds the old URLs. Clear it, then reload with the console open and confirm the list is empty.
wp cache flush
What the platform takes off the list.
TLS terminates at the proxy and the site's nginx passes the forwarded protocol through to PHP, so is_ssl() is correct without a wp-config.php edit and WordPress generates https:// links from the first request. Certificates are issued and renewed automatically, which removes the situation this error usually grows out of: a site that ran on http for months and accumulated absolute links.
Questions, answered.
Can I just use a plugin that rewrites URLs on output?
Why is only one image broken when everything else is fine?
The padlock is there but the console still complains. Which is right?
Do I need to redirect http to https as well?
If that was not it.
These fail in ways that look similar from the browser.