# 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:
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:
define('WP_SITEURL', 'https://' . $_SERVER['HTTP_HOST']);
define('WP_HOME', 'https://' . $_SERVER['HTTP_HOST']);Via Database
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.Go to Settings > General
- 2.Update WordPress Address (URL) to https://
- 3.Update Site Address (URL) to https://
- 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
wp plugin install better-search-replace --activate- 1.Go to Tools > Better Search Replace
- 2.Search for:
http://yourdomain.com - 3.Replace with:
https://yourdomain.com - 4.Select all tables
- 5.Run as dry run first
- 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:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>For behind load balancer/proxy:
<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.Go to SSL/TLS > Edge Certificates
- 2.Set "Always Use HTTPS" to On
- 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
# 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
# Replace http with https in post content
wp search-replace 'src="http://yourdomain.com' 'src="https://yourdomain.com' wp_posts --preciseFix 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.SSL mode should be "Full" or "Full (Strict)"
- 2.Enable "Always Use HTTPS"
- 3.Enable "Automatic HTTPS Rewrites"
Behind Load Balancer
If WordPress doesn't detect SSL correctly:
// 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
// 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.Open your site in Chrome
- 2.Open DevTools (F12) > Console
- 3.Look for "Mixed Content" warnings
- 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:
// In wp-config.php or header
header("Content-Security-Policy: upgrade-insecure-requests");Or via .htaccess:
<IfModule mod_headers.c>
Header always set Content-Security-Policy "upgrade-insecure-requests"
</IfModule>This automatically upgrades HTTP requests to HTTPS.
Troubleshooting Checklist
- 1.[ ] WordPress URLs use HTTPS
- 2.[ ] Database URLs search-replaced
- 3.[ ] wp-config.php forces SSL
- 4.[ ] HTTP redirects to HTTPS
- 5.[ ] No hardcoded HTTP in themes/plugins
- 6.[ ] External resources use HTTPS
- 7.[ ] CDN configured for SSL
- 8.[ ] Proxy headers handled
- 9.[ ] Browser console shows no mixed content
- 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.