2026年11月12日
2026年11月12日
Fix Mixed Content in WordPress: Find the Cause and Replace URLs
This article is a localized edition of the Japanese original. Read the Japanese original
After you switch a site to HTTPS, any images, scripts, CSS, or other resources on the page that still start with http:// cause "mixed content." This article shows how to identify which URLs are responsible and how to fix them in the database, in the theme, and in the server configuration.
What happens with mixed content
When an HTTPS page tries to load an http:// resource, browsers handle it as follows (major browsers such as Chrome and Firefox as of October 2026).
- Images, audio, and video: The browser tries to load them over
https://instead. If that URL does not exist, they are not shown - Scripts, CSS, iframes, and similar: The browser blocks them. The layout breaks or features stop working
In both cases, a message starting with "Mixed Content" appears in the console of the browser's developer tools.
Identify the URLs causing the problem
Check the browser console
Open the affected page and look at the "Console" tab in the developer tools (F12 on Windows). The message shows the http:// URL the page tried to load. The cause can differ by page, so check different kinds of pages: the front page, posts, pages, and so on.
Extract http:// from the page HTML
To check several pages at once, pull the URLs containing http:// out of the HTML.
curl -s https://example.com/ | grep -oE "(src|href)=[\"']http://[^\"']+" | sort -u
How you fix a URL depends on whether it belongs to your site (http://example.com/...) or to an external one (http://external-domain/...).
Check the site URL settings
First, confirm that the WordPress URLs themselves use HTTPS.
wp option get home
wp option get siteurl
In the admin, these are "WordPress Address (URL)" and "Site Address (URL)" under "Settings" → "General" (設定 → 一般 in the Japanese UI). If wp-config.php defines WP_HOME or WP_SITEURL, those take precedence, so check them too.
grep -n -E "WP_HOME|WP_SITEURL" wp-config.php
In WordPress 5.7 and later, if the site still uses HTTP and the server supports HTTPS, "Tools" → "Site Health" shows a button that switches both URLs to HTTPS at once.
About automatic replacement in WordPress 5.7 and later
In WordPress 5.7 and later, when an existing site with content switches its URLs to HTTPS, an option called https_migration_required is turned on. While it is on, WordPress replaces http:// URLs of your own site in post content, excerpts, widgets, and Additional CSS with https:// at display time. The database content is not rewritten, so once you complete the replacement in the next section, you no longer need this mechanism.
Replace URLs in the database in bulk
Replace http://example.com stored in post content, widgets, theme settings, and elsewhere using WP-CLI's wp search-replace. Serialized data (PHP arrays and similar stored as strings) is also replaced with the string lengths adjusted.
# 1. Take a backup
wp db export before-https.sql
# 2. Dry run: see how many rows change in which table and column
wp search-replace 'http://example.com' 'https://example.com' \
--all-tables-with-prefix --skip-columns=guid \
--dry-run --report-changed-only
# 3. If everything looks right, run it
wp search-replace 'http://example.com' 'https://example.com' \
--all-tables-with-prefix --skip-columns=guid --report-changed-only
# 4. Flush the object cache if you use one
wp cache flush
--all-tables-with-prefix targets every table that starts with the prefix in wp-config.php (for example, wp_), including custom tables created by plugins. If you used URLs both with and without www, replace each one.
Some plugins, such as page builders, store URLs in JSON with escaped slashes, like http:\/\/example.com. Check this form in a dry run as well, and if there are matches, replace them the same way.
wp search-replace 'http:\/\/example.com' 'https:\/\/example.com' \
--all-tables-with-prefix --skip-columns=guid --dry-run --report-changed-only
Once the replacement is done, you can turn off the automatic replacement from the previous section.
wp option delete https_migration_required
Don’t change the guid column
The guid column in the wp_posts table is a unique identifier for each post, and feed readers use it to track what has already been read. The official WordPress documentation also says not to change it when moving a site. It isn't used to display pages, so exclude it from the replacement with --skip-columns=guid.
When media URLs stay on http://
Image URLs are built from the relative path stored in the attachment metadata _wp_attached_file (for example, 2026/10/photo.jpg) combined with the upload URL. Normally they switch along with the site URL, but if the upload URL is set in the upload_url_path option, check that as well.
wp option get upload_url_path
If the value starts with http://, change it to https://, or leave it empty unless you have a specific reason to set it.
Fix URLs written in themes and plugins
If errors remain after replacing URLs in the database, http:// may be hard-coded in theme or plugin files.
grep -rn --include='*.php' --include='*.css' --include='*.js' 'http://' wp-content/themes/your-theme/
If it is your own theme or a child theme, fix the files directly. Build URLs within your site with functions such as home_url() and get_stylesheet_directory_uri() so they follow automatically when you switch to HTTPS. For external resources, confirm that the provider supports HTTPS before changing them to https://. Switch anything not available over HTTPS to another provider, or remove it.
If a distributed theme or plugin can't be edited directly, report it to the author and rewrite the loaded URLs with a filter for the time being. Put the following file in wp-content/mu-plugins/ (create the folder if it doesn't exist).
<?php
/**
* Plugin Name: Force HTTPS for enqueued assets
*/
add_filter( 'script_loader_src', 'mysite_force_https_src' );
add_filter( 'style_loader_src', 'mysite_force_https_src' );
function mysite_force_https_src( $src ) {
if ( is_ssl() && is_string( $src ) && 0 === strpos( $src, 'http://' ) ) {
$src = set_url_scheme( $src, 'https' );
}
return $src;
}
This filter only affects files loaded with wp_enqueue_script() and wp_enqueue_style(). Anything written directly into a template as <script src="http://..."> is not changed.
When WordPress runs behind a reverse proxy or CDN
If a load balancer or CDN terminates HTTPS and forwards requests to the WordPress server over HTTP, WordPress may decide it is running on HTTP and output http:// URLs. If the proxy forwards requests with an X-Forwarded-Proto header, add the following lines to wp-config.php above require_once ABSPATH . 'wp-settings.php';, as shown in the official WordPress documentation.
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && false !== strpos( $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https' ) ) {
$_SERVER['HTTPS'] = 'on';
}
Any client can set this header, so don't use this if the WordPress server can be reached directly without going through the proxy.
Set the CSP upgrade-insecure-requests directive
With the Content-Security-Policy (CSP) directive upgrade-insecure-requests, the browser rewrites every http:// resource on the page to https:// before loading it. You can use it as a stopgap until the remaining URLs are fixed.
Apache .htaccess (when mod_headers is enabled):
<IfModule mod_headers.c>
Header always set Content-Security-Policy "upgrade-insecure-requests"
</IfModule>
Nginx server configuration:
add_header Content-Security-Policy "upgrade-insecure-requests" always;
If you can't change the server configuration, send the header from PHP. add_action() is not loaded yet when wp-config.php runs, so put this in the theme's functions.php or in the same mu-plugins file as in the previous section.
<?php
add_action( 'send_headers', function () {
header( 'Content-Security-Policy: upgrade-insecure-requests' );
} );
Resources with no HTTPS version at the rewritten URL fail to load. If you already send another CSP, add upgrade-insecure-requests to the existing policy so the header isn't duplicated. CSP is only a helper; the real fix is changing the URLs themselves to https://.
Confirm the fix
- Clear the cache of any caching plugin or CDN
- Reload without the browser cache (
Ctrl+Shift+Ron Windows) and check that no "Mixed Content" appears in the console - Check in the address bar that the connection is shown as secure
- Check not only the front page but also different kinds of pages, such as posts, pages, and archives
Summary
- Use the browser console to identify the
http://URLs causing the problem - Check that
homeandsiteurl, andWP_HOMEandWP_SITEURLinwp-config.php, use HTTPS - For the database, check with
wp search-replaceand--dry-run, then replace with--skip-columns=guid. Also check the escapedhttp:\/\/form - Fix URLs hard-coded in themes and plugins in the files, and use a filter in
mu-pluginsas a temporary workaround when you can't - Behind a proxy, set
$_SERVER['HTTPS']based onX-Forwarded-Proto upgrade-insecure-requestsis a stopgap. Don't put code that usesadd_action()inwp-config.php
Related articles:
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)