# Fix WordPress SSL Mixed Content

Your site has an SSL certificate. You see the padlock icon in the browser. But sometimes it's crossed out, or you get a "mixed content" warning. This means your HTTPS page is loading some resources over HTTP. Browsers block insecure content on secure pages, breaking functionality and scaring visitors.

Mixed content happens when your WordPress URL settings, database content, or theme/plugin code still references HTTP URLs.

Quick Diagnosis

Open your site in Chrome DevTools (F12) and look at the Console. You'll see warnings like:

bash
Mixed Content: The page at 'https://yoursite.com/' was loaded over HTTPS,
but requested an insecure image 'http://yoursite.com/image.jpg'.

Or check with WP-CLI:

```bash # Check WordPress URLs wp option get siteurl wp option get home

# Should both be https://

# Find HTTP URLs in database wp db query "SELECT COUNT(*) FROM wp_posts WHERE post_content LIKE '%http://%'" wp db query "SELECT COUNT(*) FROM wp_postmeta WHERE meta_value LIKE '%http://%'" ```

Fix 1: Update WordPress URLs

The most common cause is incorrect WordPress URL settings.

Via WP-CLI

```bash # Update site URL to HTTPS wp option update siteurl 'https://yourdomain.com' wp option update home 'https://yourdomain.com'

# Verify wp option get siteurl wp option get home ```

Via wp-config.php

Force HTTPS URLs in wp-config.php:

php
define('WP_SITEURL', 'https://' . $_SERVER['HTTP_HOST']);
define('WP_HOME', 'https://' . $_SERVER['HTTP_HOST']);

Via Database

sql
UPDATE wp_options SET option_value = 'https://yourdomain.com' WHERE option_name = 'siteurl';
UPDATE wp_options SET option_value = 'https://yourdomain.com' WHERE option_name = 'home';

Via Admin Dashboard

  1. 1.Go to Settings > General
  2. 2.Update WordPress Address (URL) to https://
  3. 3.Update Site Address (URL) to https://
  4. 4.Save Changes

Fix 2: Search-Replace Database Content

Content in posts, pages, and meta often contains hardcoded HTTP URLs.

Using WP-CLI (Recommended)

```bash # Dry run first to see what will change wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' --dry-run

# Run the replacement wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' --all-tables

# Include www variants wp search-replace 'http://www.yourdomain.com' 'https://www.yourdomain.com' --all-tables

# Flush caches after wp cache flush wp rewrite flush ```

Using Better Search Replace Plugin

bash
wp plugin install better-search-replace --activate
  1. 1.Go to Tools > Better Search Replace
  2. 2.Search for: http://yourdomain.com
  3. 3.Replace with: https://yourdomain.com
  4. 4.Select all tables
  5. 5.Run as dry run first
  6. 6.Then run live

Handle Serialized Data

Don't break serialized PHP strings:

```bash # WP-CLI handles serialized data automatically wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' --all-tables --precise

# The --precise flag handles serialized data correctly ```

Fix 3: Force SSL in wp-config.php

```php // Force SSL for admin and login define('FORCE_SSL_ADMIN', true);

// Force SSL for all logins define('FORCE_SSL_LOGIN', true);

// Fix incorrect HTTPS detection behind proxy if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; } ```

Fix 4: Redirect HTTP to HTTPS

Apache (.htaccess)

Add before WordPress rules:

apache
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

For behind load balancer/proxy:

apache
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

Nginx

```nginx server { listen 80; server_name yourdomain.com www.yourdomain.com; return 301 https://$server_name$request_uri; }

server { listen 443 ssl; server_name yourdomain.com www.yourdomain.com; # SSL configuration... } ```

Cloudflare

If using Cloudflare:

  1. 1.Go to SSL/TLS > Edge Certificates
  2. 2.Set "Always Use HTTPS" to On
  3. 3.Set "Automatic HTTPS Rewrites" to On

Fix 5: Fix Hardcoded HTTP in Theme/Plugin Files

Some themes and plugins hardcode HTTP URLs.

Find HTTP URLs in Files

```bash # Find HTTP URLs in theme files grep -r "http://" wp-content/themes/ --include="*.php"

# Find HTTP URLs in plugin files grep -r "http://" wp-content/plugins/ --include="*.php"

# Find in JavaScript files grep -r "http://" wp-content/ --include="*.js" ```

Common Fixes

```php // Wrong <script src="http://example.com/script.js"></script>

// Right - Use protocol-relative URL <script src="//example.com/script.js"></script>

// Better - Use HTTPS <script src="https://example.com/script.js"></script>

// Best - Use WordPress functions <script src="<?php echo get_template_directory_uri(); ?>/script.js"></script> ```

Replace HTTP in Files

```bash # Replace in theme files (backup first!) find wp-content/themes/ -type f -name "*.php" -exec sed -i 's|http://yourdomain.com|https://yourdomain.com|g' {} +

# Same for plugins find wp-content/plugins/ -type f -name "*.php" -exec sed -i 's|http://yourdomain.com|https://yourdomain.com|g' {} + ```

Fix 6: Fix External Resources

External resources loaded over HTTP cause mixed content.

Find External HTTP Resources

bash
# Check for external HTTP resources
grep -r "src=['\"]http://" wp-content/ --include="*.php"
grep -r "href=['\"]http://" wp-content/ --include="*.php"

Common External Resources

```php // Google Fonts - change http to https wp_enqueue_style('google-fonts', 'https://fonts.googleapis.com/...');

// External scripts - use https wp_enqueue_script('external-script', 'https://cdn.example.com/script.js');

// API calls $api_url = 'https://api.example.com/endpoint'; ```

Fix 7: Fix Uploaded Media URLs

Images uploaded before SSL may still use HTTP URLs.

Update Media URLs

```bash # Search-replace in uploads wp search-replace 'http://yourdomain.com/wp-content/uploads' 'https://yourdomain.com/wp-content/uploads' --all-tables

# Regenerate image sizes (updates URLs) wp media regenerate --yes ```

Fix Image URLs in Content

bash
# Replace http with https in post content
wp search-replace 'src="http://yourdomain.com' 'src="https://yourdomain.com' wp_posts --precise

Fix 8: Fix WooCommerce SSL Issues

WooCommerce has additional SSL settings.

```bash # Force SSL for checkout wp option update woocommerce_force_ssl_checkout 'yes'

# Update WooCommerce endpoints wp wc tool run clear_transients --user=1 ```

Fix 9: Handle CDN and Proxies

Cloudflare

  1. 1.SSL mode should be "Full" or "Full (Strict)"
  2. 2.Enable "Always Use HTTPS"
  3. 3.Enable "Automatic HTTPS Rewrites"

Behind Load Balancer

If WordPress doesn't detect SSL correctly:

php
// In wp-config.php
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
    $_SERVER['HTTPS'] = 'on';
}
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
    $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}

AWS/CloudFront

php
// In wp-config.php
if (isset($_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO']) && $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO'] == 'https') {
    $_SERVER['HTTPS'] = 'on';
}

Verify the Fix

Browser Check

  1. 1.Open your site in Chrome
  2. 2.Open DevTools (F12) > Console
  3. 3.Look for "Mixed Content" warnings
  4. 4.Check Security tab for certificate details

Online Tools

```bash # Check with curl curl -I https://yourdomain.com

# Should return HTTP/2 200 with proper headers ```

Use online tools: - https://www.whynopadlock.com/ - https://www.sslshopper.com/ssl-checker.html

WP-CLI Verification

```bash # Check for remaining HTTP URLs wp db query "SELECT * FROM wp_posts WHERE post_content LIKE '%http://%' LIMIT 10"

# Verify site URLs wp option get siteurl wp option get home

# Check SSL is enforced curl -I http://yourdomain.com # Should redirect to https:// ```

Content Security Policy

Add CSP to prevent mixed content:

php
// In wp-config.php or header
header("Content-Security-Policy: upgrade-insecure-requests");

Or via .htaccess:

apache
<IfModule mod_headers.c>
Header always set Content-Security-Policy "upgrade-insecure-requests"
</IfModule>

This automatically upgrades HTTP requests to HTTPS.

Troubleshooting Checklist

  1. 1.[ ] WordPress URLs use HTTPS
  2. 2.[ ] Database URLs search-replaced
  3. 3.[ ] wp-config.php forces SSL
  4. 4.[ ] HTTP redirects to HTTPS
  5. 5.[ ] No hardcoded HTTP in themes/plugins
  6. 6.[ ] External resources use HTTPS
  7. 7.[ ] CDN configured for SSL
  8. 8.[ ] Proxy headers handled
  9. 9.[ ] Browser console shows no mixed content
  10. 10.[ ] SSL certificate valid

Mixed content warnings are straightforward to fix: update URLs in settings, replace HTTP with HTTPS in the database, redirect HTTP to HTTPS, and ensure all resources load over SSL. The challenge is finding all the places where HTTP URLs are hardcoded.