How to fix mixed content errors in WordPress
Mixed content happens when a page loaded over https pulls in images, scripts, stylesheets, fonts or frames over plain http. In WordPress it almost always appears just after a site moves to HTTPS, because years of posts, settings and theme files still hold the old http addresses. Browsers upgrade or block those requests, so you see a not fully secure warning, missing images, or a broken layout when a stylesheet or script is blocked. This guide shows you how to find every insecure URL, set the right site addresses, rewrite old links in the database safely with WP-CLI, fix hard-coded theme and plugin assets, and decide when an SSL plugin is a sensible stopgap rather than a fix.
- What a mixed content error means
- Where the http links come from in WordPress
- How to find every insecure URL
- Fixing the settings and the database
- Fixing themes, page builders and plugins
- Worked example: a bakery site after its HTTPS switch
- The fix, step by step
- Edge cases worth knowing
- Keeping mixed content away
- Questions and answers
What a mixed content error means
When a page is served over https, everything it loads should come over https too. If the HTML is secure but an image, script or stylesheet comes from an http address, an attacker on the same network could read or change that part of the page, so browsers treat it as a risk.
| Resource type | What current browsers do | What you notice |
|---|---|---|
| Images, audio, video | Try the https version of the same URL; block it if that fails | Missing images, a not fully secure note |
| Scripts, stylesheets, fonts, frames | Block outright | Broken layout, menus or sliders that do nothing |
| Forms posting to http | Show a warning before the form is sent | Visitors see a security warning on submit |
So mixed content is not only a cosmetic warning. A blocked stylesheet can make a page look unstyled, and a blocked script can stop a checkout or contact form working. For search engines, the page itself is still https, but a broken render hurts how the page looks and works for visitors and crawlers alike.
Where the http links come from in WordPress
| Source | Example | Fix |
|---|---|---|
| Site address settings still http | Every link and asset uses http | Set both addresses to https |
| Post and page content | <img src="http://example.com/wp-content/uploads/..."> | Database search and replace |
| Options and widgets | Logo, header image or a text widget with an http URL | Database search and replace, then check settings screens |
| Page builder data and generated CSS | Background images inside saved builder CSS files | Replace URLs, then regenerate the builder's CSS |
| Theme files | A hard-coded http:// in header.php or a stylesheet | Edit the theme or child theme |
| Plugins and embeds | An old slider, map or font loaded from an http address | Update, configure or replace the plugin |
| Proxy or CDN in front of WordPress | WordPress thinks requests are http and writes http asset URLs | Tell WordPress the request was https |
The database is usually the biggest source. WordPress saves full URLs in post content, in options and in post meta, so changing the site address does not touch links that were written in years ago.
How to find every insecure URL
Load a page over https, open Chrome DevTools and look at the Console. Each warning or error names the page and the exact http URL. Check the home page, a post, a page, an archive and any shop or form pages, because templates differ.
From a terminal you can list the http references in the HTML a page sends:
curl -s https://example.com/ | grep -oE "(src|href)=[\"']http://[^\"']+" | sort -u
That catches links in the HTML, but not those added by scripts or inside CSS files. The security audit lists mixed content found on a page alongside the certificate and redirect checks.
Counting them in the database
With WP-CLI on the server, a dry run of the search and replace counts matches per table without changing anything:
cd /var/www/example.com
wp search-replace 'http://example.com' 'https://example.com' --all-tables-with-prefix --dry-run --report-changed-only
The report shows which tables and columns hold old links, typically wp_posts, wp_postmeta and wp_options. Matches outside the database, in theme files or plugin settings stored elsewhere, need fixing separately.
Fixing the settings and the database
1. Set the site addresses
In Settings, General, change both WordPress Address (URL) and Site Address (URL) to https. If those fields are greyed out, they are fixed in wp-config.php:
define( 'WP_HOME', 'https://example.com' );
define( 'WP_SITEURL', 'https://example.com' );
2. Back up, then replace old links
Take a database backup first, then run the real replacement. WP-CLI handles serialised PHP data correctly, which a plain SQL REPLACE query does not; editing serialised values with SQL can corrupt widget and theme settings.
wp db export before-https.sql
wp search-replace 'http://example.com' 'https://example.com' --all-tables-with-prefix --skip-columns=guid
wp search-replace 'http://www.example.com' 'https://example.com' --all-tables-with-prefix --skip-columns=guid
wp cache flush
The guid column is skipped because WordPress uses it as a permanent identifier for feed readers, not as a link. Run the second line only if your old links used www and your site now uses the bare domain. If you have no shell access, a search and replace plugin that supports serialised data does the same job from the dashboard.
http:// with https:// also rewrites links to other sites that may not support https, which creates new broken links.3. Behind a proxy or CDN
If a CDN or load balancer handles HTTPS and talks to WordPress over http, WordPress believes every request is http and writes http asset URLs. Add this near the top of wp-config.php, above the line that loads WordPress settings:
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
$_SERVER['HTTPS'] = 'on';
}
Only trust this header when your server can only be reached through the proxy. The full explanation is in mixed content behind a proxy.
Fixing themes, page builders and plugins
Search the active theme and child theme for hard-coded http addresses:
grep -rn "http://" wp-content/themes/example-child/ --include=*.php --include=*.css --include=*.js
Replace hard-coded addresses with WordPress functions, which always use the configured https address:
<img src="<?php echo esc_url( get_stylesheet_directory_uri() . '/images/logo.svg' ); ?>" alt="Example Bakery">
wp_enqueue_script( 'example-slider', get_stylesheet_directory_uri() . '/js/slider.js', array(), '1.0', true );
Plugins should load files with wp_enqueue_script and wp_enqueue_style, which follow the site address automatically. If a plugin still loads an http file, update it, check its settings for a stored URL, or replace it. Page builders keep their own copies of URLs and generated CSS: after the database replacement, use the builder's tool to regenerate CSS so cached files pick up the new addresses. Also check the Additional CSS panel under Appearance and any custom HTML widgets.
When an SSL plugin helps
SSL plugins can rewrite http to https in the page output on the fly, add the HTTPS redirect and set the proxy fix. That is a quick way to clear warnings on a site you cannot fix properly yet, but the old links stay in the database and every page is rewritten on every request. Treat it as a stopgap: fix the database and theme, then the plugin's rewriting is no longer needed. As an extra safety net, a Content-Security-Policy: upgrade-insecure-requests header tells browsers to request every http resource on your pages over https; see security headers in WordPress.
Worked example: a bakery site after its HTTPS switch
Example Bakery moved to https, but its menu page showed missing photos and the slider stopped working. The Console listed eleven mixed content messages.
- Nine were images under
http://www.example.com/wp-content/uploads/inside post content. A WP-CLI dry run found 412 matches inwp_postsand 37 inwp_postmeta. - One was the slider script, loaded by the child theme's
functions.phpfrom a hard-coded http address. It was blocked outright, which is why the slider failed. - One was a background image in the page builder's generated CSS file.
- The owner exported the database, ran the search and replace for the www and bare http addresses with
--skip-columns=guid, and flushed the cache. - They changed the theme to load the script with
get_stylesheet_directory_uri(), regenerated the builder's CSS and purged the CDN. - The Console was clean on every template, and the security audit reported no mixed content.
The fix, step by step
Step 1
List the insecure URLs
Open the home page, a post, a page, an archive and any shop or form page over https in a private window, with the DevTools Console open. Copy every mixed content URL it reports into a list and note which template it appeared on. Group them by source: uploads, theme files, plugins or external services. This list is your checklist, and you will repeat the same check at the end to confirm it is empty.
Step 2
Set both site addresses to https
In Settings, General, change WordPress Address (URL) and Site Address (URL) to the https version of your main address, then save. If the fields are greyed out, edit WP_HOME and WP_SITEURL in wp-config.php instead. You may be logged out after saving; log back in on the https address. Check the page source of the home page and confirm the canonical tag and menu links now start with https.
Step 3
Back up the database
Before changing stored content, export the database with wp db export before-https.sql, or use your host's backup tool or phpMyAdmin's export. Keep the file somewhere off the web root so it cannot be downloaded. Check the export finished and that its size looks sensible for your site. If anything goes wrong in the next step, you can restore this file and try again without losing content.
Step 4
Replace http links in the database
Run wp search-replace with your full old http address and the new https address, adding --all-tables-with-prefix and --skip-columns=guid. Use --dry-run first to see the count, then run it for real. Repeat for the old www address if it differs. Avoid plain SQL replacements, which corrupt serialised settings. Afterwards run wp cache flush and reload a post that previously showed mixed content to check its images now load over https.
Step 5
Fix the proxy setting if needed
If your site sits behind a CDN, load balancer or reverse proxy that handles https, check whether WordPress still writes http asset URLs after the previous steps. If it does, add the HTTP_X_FORWARDED_PROTO check to wp-config.php so WordPress treats the request as https. Only do this when the server cannot be reached directly. Reload a page and confirm stylesheet and script URLs in the source now start with https.
Step 6
Fix hard-coded theme addresses
Search the active theme and child theme for http:// in PHP, CSS and JavaScript files. Replace links to your own site with home_url(), get_stylesheet_directory_uri() or relative paths, and change external links to https where the service supports it. Edit the child theme rather than the parent, so updates do not undo your changes. Upload the changes and confirm the Console no longer lists those files.
Step 7
Update plugins and page builders
Update every plugin, then check the settings of any plugin that loads sliders, maps, fonts or forms for stored http URLs. Replace plugins that still load insecure files. If you use a page builder, run its tool to regenerate CSS so its cached stylesheets pick up the new addresses. Check the Additional CSS panel and custom HTML widgets too, because they keep their own copies of URLs.
Step 8
Purge every cache layer
Clear the caching plugin, any server cache your host provides and the CDN, so visitors stop receiving old pages that still contain http links. Minified and combined CSS or JavaScript files often hold old URLs, so clear those caches as well. Then load each template in a fresh private window. If a URL still appears that is not in the database or theme, it is probably coming from a cached file.
Step 9
Recheck and add a safety net
Repeat the Console check on every template from your first list and confirm no mixed content messages remain. Run the security audit on the main pages to confirm a clean result. Optionally add the Content-Security-Policy: upgrade-insecure-requests header so any future http resource on your own pages is fetched over https. Finally, make sure every http address redirects to https with a single 301, so old links from other sites still land safely.
Edge cases worth knowing
- Third-party resources without https. If an external service has no https version, the browser keeps blocking it. Host the file yourself or replace the service.
- Multisite. Run the replacement with
--network, and update each site's address in the network admin as well as in thewp_blogsandwp_sitetables. - Links in emails and feeds. Old newsletters and feed readers may still point at http pages; a working 301 redirect handles those, as covered in WordPress redirects.
- Warnings only for logged-in users. Admin bars and editor plugins can load their own assets. Test logged out in a private window, which is what visitors see.
Keeping mixed content away
Make sure every http request redirects to https in a single hop, following HTTPS redirects, so any old link still lands on a secure page. Teach editors to upload images through the media library rather than pasting addresses from other sites. After installing a new theme, plugin or page builder template, check the Console on a few pages. When you move the site to a new domain or host, run the same search and replace as part of the move; WordPress migration fixes covers the rest of that checklist. Run the security audit every few months to catch anything new.
1. How do I fix a mixed content issue in WordPress?
You fix a mixed content issue in WordPress by changing both site addresses to https, replacing old http links in the database with a tool that handles serialised data, and fixing any hard-coded http addresses in the theme or plugins. Start by listing every insecure URL from the browser Console so you know where each one comes from. Back up the database before replacing anything, then purge every cache and check the Console again on each template until it is clean.
2. Why does WordPress show mixed content after installing SSL?
WordPress shows mixed content after installing SSL because the certificate only secures the connection, while years of posts, widgets and settings still contain full http addresses. WordPress saves complete URLs in the database when you insert images and links, so changing the site address does not rewrite them. Theme files and plugins can also hard-code http addresses. A database search and replace from the old http address to the new https address fixes most of it in one go.
3. Is a plugin enough to fix mixed content in WordPress?
A plugin can hide mixed content warnings quickly, but it is a stopgap rather than a complete fix. SSL plugins rewrite http to https in the page output on every request, which leaves the old links in your database and adds work to each page load. If the plugin is ever turned off, the warnings return. It is better to fix the database and theme properly, and keep a plugin only if you need its redirect or proxy settings.
4. Can I use SQL to replace http with https in WordPress?
You can for simple text columns such as post content, but it is risky across the whole database because WordPress stores many settings as serialised PHP data. Serialised values record the length of each string, so changing the text without updating the length breaks the value, and widgets or theme settings can disappear. WP-CLI search-replace or a search and replace plugin that understands serialised data updates the lengths for you, which is why they are the safer choice.
5. Does mixed content affect SEO in WordPress?
Mixed content does not stop Google indexing a page, but it can still affect SEO because blocked stylesheets and scripts change how the page renders for visitors and crawlers. A broken layout, missing images or a failed menu can hurt how people use the page. Mixed content also shows that http addresses are still in use, which often goes with redirect chains and http canonical tags. Fixing the source cleans up all of these at once.
6. Why do I still see mixed content after the search and replace?
You still see mixed content after the search and replace because the remaining URLs are not in the database, or a cache is serving old pages. Check the theme and child theme files, plugin settings, page builder CSS files and minified asset caches. Purge the caching plugin, the server cache and the CDN, then test in a private window. If a third-party service has no https version, the browser keeps blocking it, and the only fix is to host the file yourself or replace it.
7. What does upgrade-insecure-requests do in WordPress?
The upgrade-insecure-requests directive tells the browser to fetch every http resource on your pages over https instead, without you changing the links. It is set as a Content-Security-Policy header, through your server, a security headers plugin or the CDN. It works well as a safety net for links you have missed, but only if the resource exists at the https address. It does not fix links in emails or other sites, so still clean up the database and theme.
Run the security audit on your WordPress pages to list mixed content, check the certificate and confirm http redirects to https, so you know exactly what is left to fix.
Open Security Audit Fixes โ