Back to blog

Site Still 'Not Secure' After Installing SSL? Find and Fix Mixed Content

IM Host EditorialOctober 25, 20267 min read
Site Still 'Not Secure' After Installing SSL? Find and Fix Mixed Content

You installed an SSL certificate, the address starts with https://, and the browser still shows "Not secure" or a padlock with a warning. In most cases the certificate is fine. The problem is mixed content: the page loads over HTTPS, but some of its images, scripts, stylesheets or fonts still load over plain HTTP.

This guide shows how to confirm that mixed content is the cause, how to find every insecure URL, and how to fix it properly on WordPress and on other sites. It also covers the few cases where the problem really is the certificate.

HTTPS protects the whole page only if every resource on it is encrypted. If a script loads over HTTP, anyone on the network path could change that script and take control of the page. Browsers treat this seriously.

  • Active mixed content (scripts, iframes, stylesheets, fetch and XHR requests) is blocked. The page may look broken: missing styles, sliders that do not move, forms that do not submit.

  • Passive mixed content (images, audio, video) is usually upgraded to HTTPS automatically by modern browsers. If the HTTPS version does not exist, the file is blocked and the page is marked as not fully secure.

Either way, the fix is the same: make every URL on the page use HTTPS.

Step 1: Confirm it is mixed content

Open the page in Chrome, Edge or Firefox, press F12 and open the Console tab. Reload the page. Mixed content shows up as messages like this:

Mixed Content: The page at 'https://example.com/' was loaded over HTTPS, but requested an insecure image 'http://example.com/wp-content/uploads/logo.png'. This content should also be served over HTTPS.

Each message names the exact file. In Chrome, the Security panel in DevTools also summarises whether the page has mixed content and whether the certificate is valid. Check more than the home page. Blog posts, product pages and the checkout often contain older content with hardcoded links.

Step 2: Find every http:// reference

The console only shows what the current page loads. To scan the HTML and CSS directly, use curl and grep:

# List http:// references in the HTML of one page
curl -s https://example.com/ | grep -oE '(src|href)="http://[^"]+"' | sort -u

# Check CSS files too (background images and fonts)
curl -s https://example.com/wp-content/themes/your-theme/style.css | grep -o 'http://[^)"]*' | sort -u

Typical sources of insecure URLs:

  • Image and link URLs saved inside posts and pages before the site moved to HTTPS.

  • Theme options and page builder settings that store full URLs, for example a logo or background image.

  • Hardcoded URLs in theme files, child theme CSS or custom JavaScript.

  • Third-party embeds and widgets added with an http:// address.

  • Fonts and icons loaded from an external CDN with http://.

Step 3: Fix it on WordPress

Set both site URLs to HTTPS

In Settings > General, make sure WordPress Address (URL) and Site Address (URL) both start with https://. If those fields are greyed out, they are set in wp-config.php with WP_HOME and WP_SITEURL. Change them there.

Replace old URLs in the database

Posts, widgets and many plugin settings store full URLs in the database. A plain SQL find-and-replace can break serialized data, so use a tool that understands it. With WP-CLI:

# 1. Back up the database first
wp db export before-https.sql

# 2. Preview what would change
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid --dry-run

# 3. Run it for real
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid

# 4. Repeat for the www version if your old URLs used it
wp search-replace 'http://www.example.com' 'https://www.example.com' --skip-columns=guid

# 5. Flush caches
wp cache flush

Why skip the guid column: WordPress uses it as a permanent ID for feeds, not as a link, and changing it can make feed readers show old posts as new. If you cannot use WP-CLI, a search-and-replace plugin that handles serialized data does the same job. Take a backup first either way.

Some page builders keep their own copy of URLs in generated CSS files. After the replace, use the builder's own tools to regenerate CSS or replace URLs, then clear its cache.

Fix hardcoded URLs in theme and plugin files

If grep still finds http:// after the database replace, the link lives in a file. Change http:// to https:// in your child theme. For your own domain, a root-relative path such as /wp-content/uploads/logo.png also works. If the URL comes from a plugin you cannot edit, update the plugin or replace it.

Clear every cache

A fixed page can still look broken because an old copy is cached. Purge your caching plugin (for example LiteSpeed Cache), any CDN cache, and test in a private browser window.

Step 4: Redirect all HTTP traffic to HTTPS

Fixing links stops the warning, but visitors and search engines may still reach the old http:// address. Send them to HTTPS with a permanent redirect. On Apache or LiteSpeed, add this near the top of .htaccess:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

On Nginx, use a separate server block on port 80 with return 301 https://$host$request_uri;. Many control panels also offer a "Force HTTPS" switch that does the same thing. Use one method, not several, to avoid redirect loops.

Behind a proxy or CDN? Watch for redirect loops

If HTTPS ends at a proxy or CDN and the proxy talks to your server over HTTP, WordPress may think every request is HTTP and keep redirecting. The fix is to trust the proxy's forwarded protocol header:

/* In wp-config.php, above the line "That's all, stop editing!" */
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

Only do this if your server really sits behind a proxy that sets this header.

A temporary safety net: upgrade-insecure-requests

A Content Security Policy directive can tell browsers to request every http:// resource over HTTPS instead:

Header always set Content-Security-Policy "upgrade-insecure-requests"

This hides the symptom while you clean up, and it is useful on large sites with years of old content. It does not help if a resource has no HTTPS version, and it does not fix links that search engines and other sites see. Treat it as a stopgap, not the fix.

When it is not mixed content

If the console shows no mixed content messages but the browser still warns, look at the certificate itself:

# Who issued the certificate, which names it covers, and when it expires
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -issuer -ext subjectAltName -dates
  • Name mismatch: the certificate covers example.com but not www.example.com, or the reverse. Reissue it for both names.

  • Expired: the notAfter date has passed. Renew it and check that automatic renewal is working.

  • Incomplete chain: the server sends the certificate without its intermediate. Some browsers and most phones will then reject it. Install the full chain your certificate authority provides.

  • Self-signed certificate: fine for testing, never trusted by public browsers.

Quick checklist

  1. Console shows no mixed content warnings on the home page, a post, a product page and checkout.

  2. Both WordPress URLs use https://.

  3. No http:// links to your own domain remain in the HTML or CSS.

  4. http:// redirects to https:// with a 301, and there is no redirect loop.

  5. The certificate covers every name you use and is not close to expiry.

Run your site with SSL on IM HOST

IM HOST WordPress Hosting includes free SSL, NVMe storage, LiteSpeed Cache and free daily backups for the whole subscription, so you can take a restore point before a search-and-replace. If you need a different certificate type, see our SSL certificates. Our 24/7 engineers can check your certificate and help you trace the remaining insecure URLs.

More from our blog

Discover more practical guides and product insights from the IM Host team.

View all articles