
How to fix mixed content warnings on a website?
To fix mixed content warnings, you find every resource on your HTTPS pages that still loads over plain http://, such as images, scripts, stylesheets, fonts, iframes, or form actions, and change it to load over https:// instead. You do this by updating hard-coded URLs in your content, database, theme, and plugins, then optionally adding the upgrade-insecure-requests Content Security Policy directive as a safety net. Once no insecure requests remain, the browser shows a clean padlock again.
Mixed content usually appears right after a site moves to HTTPS, because old content still references the HTTP version of your own domain or of third-party services. This guide explains what mixed content is and why browsers care, how to find the offending resources, and how to fix them in WordPress and on any other website, including database updates, server config, and headers.
What Is Mixed Content?
A page has mixed content when the page itself is loaded securely over HTTPS, but some of the resources on it are loaded over insecure HTTP. For example:
<!-- The page is https://example.com/about/ but this image uses http -->
<img src="http://example.com/wp-content/uploads/team.jpg" alt="Our team" />
Browsers split mixed content into two broad categories:
- Upgradable (passive) content: Images, audio, and video. Modern browsers like Chrome, Edge, and Firefox now try to automatically upgrade these requests to HTTPS. If the HTTPS version doesn't exist, the resource fails to load.
- Blockable (active) content: Scripts, stylesheets, iframes, fonts,
fetchand XHR requests, and other resources that can change the page. Browsers block these outright on HTTPS pages.
That's why mixed content causes more than a cosmetic warning. Blocked stylesheets can break your layout, blocked scripts can break menus, sliders, and checkouts, and failed image upgrades leave broken images.
Why Mixed Content Is a Security Problem
HTTPS protects a page by encrypting everything between the browser and your server. When part of the page loads over HTTP, that part can be read or modified by anyone on the network path, such as a public Wi-Fi operator or a compromised router.
- An insecure script could be swapped for a malicious one that steals form data or injects ads.
- An insecure stylesheet could be modified to hide or rearrange content.
- An insecure image could be replaced, and it also reveals which page a visitor is viewing.
- An insecure form action sends whatever users type, including passwords, in plain text.
Browsers treat mixed content seriously because it undermines the security guarantee of the padlock.
Common Causes of Mixed Content
Before fixing anything, it helps to know where insecure URLs usually come from:
- Old content in the database: Posts and pages created before the HTTPS switch often contain absolute
http://URLs for images and links. - Hard-coded theme or plugin URLs: A theme's template might include
http://links to its own assets or to Google Fonts. - Site URL settings: If a CMS's site address is still set to
http://, it generates insecure URLs everywhere. - Third-party embeds: Old embed codes for videos, maps, widgets, or ad networks may use HTTP.
- CSS files: Background images and
@importrules inside stylesheets can reference HTTP URLs. - Page builder data: Builders like Elementor store their layouts in the database, often including absolute URLs.
- Reverse proxies and CDNs: If a CDN or load balancer terminates HTTPS and talks to your server over HTTP, your application may think the request was insecure and generate
http://URLs.
Step 1: Find the Mixed Content
Use Browser Developer Tools
The quickest way to find mixed content is your browser's console.
- Open the affected page over HTTPS.
- Press F12 (or right-click and choose Inspect) and open the Console tab.
- Reload the page and look for warnings mentioning "Mixed Content". Each one lists the page and the exact insecure URL.
The Security panel in Chrome and Edge DevTools, and the Network tab filtered by "http:" also help. Firefox shows a padlock with a warning triangle when passive content was loaded, and details appear in its console.
Check the Whole Site
Mixed content can appear on some pages and not others, so check more than your homepage. Useful approaches:
- Crawl the site with a tool like Screaming Frog SEO Spider, which can report insecure resources on HTTPS pages.
- Use an online checker, such as Why No Padlock or JitBit's SSL Check, for quick spot checks of individual pages or small sites.
- Search your codebase for hard-coded HTTP URLs:
grep -rn "http://" --include=*.php --include=*.html --include=*.css --include=*.js ./
Expect some harmless results, like links in comments or XML namespace URLs such as http://www.w3.org/2000/svg, which aren't requests and don't need changing.
Collect Reports With CSP
For larger sites, you can ask browsers to report mixed content back to you using a report-only Content Security Policy:
add_header Content-Security-Policy-Report-Only "default-src https: 'unsafe-inline' 'unsafe-eval' data: blob:; report-uri /csp-report" always;
This doesn't block anything, but browsers send a report to /csp-report whenever a page tries to load an HTTP resource. You'd need an endpoint or a reporting service to receive them. It's more work than the other methods, so it's mostly useful for big, content-heavy sites.
Step 2: Fix Your Site URL Settings
Make sure your application knows it lives at HTTPS.
In WordPress, open Settings > General and confirm both WordPress Address (URL) and Site Address (URL) start with https://. If they're greyed out, they're defined in wp-config.php:
define( 'WP_HOME', 'https://example.com' );
define( 'WP_SITEURL', 'https://example.com' );
Take a backup before changing these, since a wrong value can make the dashboard inaccessible.
In other platforms, look for a "base URL" or "site URL" setting in the configuration file or admin panel.
Step 3: Update URLs in the Database
Old content is the most common source of mixed content on WordPress sites. You need to replace http://example.com with https://example.com throughout the database.
Always take a full database backup first. A bad search-and-replace can break a site.
Use WP-CLI
WP-CLI's search-replace command is the safest option, because it correctly handles PHP serialized data, which a raw SQL query would corrupt:
wp db export before-https.sql
wp search-replace 'http://example.com' 'https://example.com' --all-tables --precise --dry-run
Review the dry-run output, then run it for real:
wp search-replace 'http://example.com' 'https://example.com' --all-tables --precise
wp cache flush
If your site also uses www, run it for http://www.example.com too.
Use a Plugin
If you don't have command-line access, plugins like Better Search Replace or Search & Replace do the same job from the dashboard. Run a dry run first, then replace across all tables.
Page Builders
Elementor has a built-in tool under Elementor > Tools > Replace URL. Run it after the database replacement, then use Regenerate CSS & Data so its generated CSS files pick up the new URLs.
Step 4: Fix Hard-Coded URLs in Themes and Plugins
If mixed content remains after updating the database, the insecure URLs are probably in code.
In Your Theme
Search your theme files for http:// and update any URLs that load resources. Better still, use WordPress functions that generate the correct scheme automatically:
// Instead of a hard-coded URL:
// <script src="http://example.com/wp-content/themes/mytheme/js/app.js"></script>
// Enqueue assets with WordPress functions (child theme functions.php):
function mytheme_enqueue_assets() {
wp_enqueue_style(
'mytheme-style',
get_stylesheet_directory_uri() . '/css/main.css',
array(),
'1.0.0'
);
wp_enqueue_script(
'mytheme-app',
get_stylesheet_directory_uri() . '/js/app.js',
array(),
'1.0.0',
true
);
}
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_assets' );
Functions like get_stylesheet_directory_uri(), home_url(), site_url(), and wp_get_attachment_url() respect your HTTPS settings. If you must output a URL manually, set_url_scheme() can force the right scheme:
$logo_url = set_url_scheme( 'http://example.com/logo.png', 'https' );
echo '<img src="' . esc_url( $logo_url ) . '" alt="' . esc_attr__( 'Logo', 'mytheme' ) . '">';
If the problem is in a third-party theme or plugin, don't edit its files directly, because updates will overwrite your changes. Check for an update first, contact the developer, or override the relevant template in a child theme.
In CSS Files
Check stylesheets for url() references and @import rules:
/* Before */
.hero {
background-image: url("http://example.com/images/hero.jpg");
}
/* After: use HTTPS or a relative path */
.hero {
background-image: url("/images/hero.jpg");
}
Relative paths like /images/hero.jpg automatically use the same scheme as the page. Avoid protocol-relative URLs such as //example.com/image.jpg for new code; always use explicit https:// for external resources.
In Widgets, Menus, and Customizer Settings
Custom HTML widgets, menu links, header scripts added through the Customizer or a plugin like WPCode, and theme options panels all store content in the database. The search-replace in Step 3 should catch most of these, but check them manually if warnings persist.
Step 5: Fix Third-Party Resources
Some mixed content comes from other domains. For each one:
- Check whether the resource is available over HTTPS: Try changing
http://tohttps://in your browser's address bar. Almost every reputable service supports HTTPS today. - Update the embed code: Replace old embed snippets with fresh ones from the provider, which will use HTTPS.
- Host it yourself: If a small file like an image or font is only available over HTTP, download it and serve it from your own domain.
- Remove it: If a widget or service doesn't support HTTPS at all, it's probably abandoned and should be replaced.
Step 6: Handle Reverse Proxies and CDNs
If your site sits behind a CDN, load balancer, or reverse proxy that handles HTTPS and connects to your server over HTTP, your application may think every request is insecure. The result is http:// URLs generated on an HTTPS page, or redirect loops.
Fix this by making the application trust the X-Forwarded-Proto header sent by your proxy. In WordPress, add this to wp-config.php above the "That's all, stop editing!" line:
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
$_SERVER['HTTPS'] = 'on';
}
Only do this if your server is actually behind a proxy that sets this header, and ideally make sure only the proxy can reach your origin. Otherwise, clients could spoof the header.
If you use Cloudflare, set the SSL/TLS encryption mode to Full (strict) with a valid certificate on your origin, rather than Flexible, which connects to your server over HTTP and commonly causes mixed content and redirect loops.
Step 7: Add upgrade-insecure-requests as a Safety Net
The upgrade-insecure-requests CSP directive tells browsers to automatically request any HTTP resource on your pages over HTTPS instead. It's a useful backstop for leftover URLs you haven't found yet.
In Nginx, inside your HTTPS server block:
add_header Content-Security-Policy "upgrade-insecure-requests" always;
In Apache (in your virtual host or .htaccess, with mod_headers enabled):
<IfModule mod_headers.c>
Header always set Content-Security-Policy "upgrade-insecure-requests"
</IfModule>
Or as a meta tag in your page's head:
<meta
http-equiv="Content-Security-Policy"
content="upgrade-insecure-requests"
/>
Keep two things in mind:
- It only works if the HTTPS version exists: If a third-party resource isn't available over HTTPS, the upgraded request simply fails.
- It's not a substitute for fixing URLs: Treat it as a safety net. Clean URLs are better for performance, SEO, and older browsers.
If you already send a Content-Security-Policy header, add upgrade-insecure-requests to it rather than sending a second header.
Step 8: Redirect HTTP to HTTPS
Make sure every HTTP request to your own domain redirects to HTTPS with a permanent 301 redirect. This doesn't fix mixed content by itself, because browsers block active mixed content before any redirect happens, but it ensures visitors and search engines always land on the secure version.
In Nginx:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
In Apache .htaccess:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Step 9: Clear Caches and Retest
After making changes, clear every cache layer so you're not looking at old pages:
- Page caching plugin: WP Rocket, W3 Total Cache, LiteSpeed Cache, WP Super Cache, and so on.
- Server cache: Nginx FastCGI cache, Varnish, or your host's cache.
- CDN cache: Purge everything in Cloudflare or your CDN.
- Browser cache: Use a private window or hard refresh.
Then reload key pages with the console open and confirm no mixed content warnings remain. Check your homepage, a few posts, category pages, the contact form, and checkout pages if you run a store.
What About Plugins That Fix Mixed Content Automatically?
Plugins like Really Simple Security (formerly Really Simple SSL) can detect HTTPS, fix site URLs, and rewrite insecure URLs in page output on the fly. They're a quick fix if you're not comfortable with the steps above.
However, on-the-fly rewriting adds processing to every page load and hides the underlying problem. It's better to fix URLs at the source with a database search-and-replace and proper theme code, then use a plugin only for its other features, or not at all.
FAQ: Fixing Mixed Content
It means your page loaded over HTTPS, but some resources on it, such as images, scripts, or stylesheets, were requested over insecure HTTP. Browsers warn about or block those resources because they can be read or modified in transit.
Indirectly, yes. Blocked scripts and styles can break layouts and functionality, and a missing padlock reduces visitor trust. Search engines favour secure, working pages, so it's worth fixing mixed content promptly.
Installing a certificate only enables HTTPS. Old content, theme files, and settings may still contain http:// URLs. Update your site URLs, run a database search-and-replace, fix hard-coded theme URLs, and clear your caches.
Yes, if you use a tool that handles serialized data, like WP-CLI's search-replace command or the Better Search Replace plugin. Always take a database backup and run a dry run first. Avoid raw SQL replacements, which can corrupt serialized settings.
It tells browsers to fetch HTTP resources over HTTPS, which fixes most leftovers, but only if the HTTPS version of each resource exists. Use it as a safety net alongside fixing the URLs themselves.
Open your browser's developer tools, go to the Console tab, and reload the page. Each mixed content warning lists the exact insecure URL. Online checkers like Why No Padlock can also help.
Conclusion
Mixed content warnings are almost always caused by leftover http:// URLs after a move to HTTPS. Finding them is straightforward with your browser's console, and fixing them comes down to a handful of steps: correct your site URL settings, run a safe database search-and-replace, update hard-coded theme and CSS URLs, refresh third-party embeds, and configure proxies to pass the right protocol.
Once the URLs are clean, add upgrade-insecure-requests as a safety net, clear your caches, and retest the pages that matter most. With every resource loading over HTTPS, your visitors get the full protection the padlock promises, and your site looks and works exactly as it should.


