<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>No Script</title>
	<atom:link href="https://noscript.info/feed/" rel="self" type="application/rss+xml" />
	<link>https://noscript.info</link>
	<description></description>
	<lastBuildDate>Sun, 01 Nov 2026 14:05:40 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>
	<item>
		<title>WP-CLI Search-Replace: Safe URL Changes, Dry Runs, and Verification</title>
		<link>https://noscript.info/wordpress/maintenance/search-replace/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Maintenance]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/maintenance/search-replace</guid>

					<description><![CDATA[Use WP-CLI to replace WordPress database URLs safely. Identify the site, check a dry run, preserve GUIDs, and verify remaining references and page assets.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .urgency-now{ background: #fdecea; border-left: 4px solid #c0392b; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .urgency-soon{ background: #fff9e6; border-left: 4px solid #e0a800; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }.usefulmix-article blockquote{ background: #f6f4ee; border-left: 4px solid #8a8377; margin: 1.4em 0; padding: 0.9em 1.1em; }.usefulmix-article blockquote strong{ display: block; margin-bottom: 0.3em; }
</style>
<div class="usefulmix-article">
<div class="short-answer">
<p>Use WP-CLI&#8217;s serialization-aware <code>search-replace</code> when you&#8217;ve confirmed URLs in your WordPress database need changing. Confirm which installation you&#8217;re targeting, keep a recoverable SQL backup, and approve the table scope with <code>--dry-run</code>. Then search the database for leftover references and load the pages visitors see. For WP-CLI, WordPress commands, and SSH, see how to <a href="https://noscript.info/wordpress/hosting/wp-cli/#os-identity">run and verify WP-CLI commands</a>.</p>
</div>
<p>The basic preview command is <code>wp search-replace OLD NEW --skip-columns=guid --dry-run</code>, with your old and new strings in place of OLD and NEW.</p>
<h2 id="when-wp-cli-search-replace-is-the-right-tool">When WP-CLI search-replace is the right tool</h2>
<p><img decoding="async" alt="WordPress URL replacement" src="/img/WordPress-URL-replacement.jpg"></p>
<p><code>wp search-replace</code> fits when a domain, staging-path, or HTTP-to-HTTPS change leaves old URLs in your database. Absolute links can linger in posts, widget settings, or plugin options. The command edits the database data you select. It can&#8217;t move site files or change web-server redirect rules.</p>
<ul>
<li><strong>You know the database references:</strong> You have the old value, the replacement, database access, and a way to recover.</li>
<li><strong>Only WordPress Address or Site Address is wrong:</strong> Fix the options or configuration that control the effective WordPress URL.</li>
<li><strong>The whole installation is moving:</strong> Plan the file transfer, database transfer, destination configuration, and cutover as a full migration.</li>
<li><strong>You have no usable CLI access:</strong> Use a supported hosting interface or a WordPress plugin.</li>
</ul>
<h2>Confirm the site and the exact strings before changing anything</h2>
<p><img decoding="async" alt="WordPress installation identity" src="/img/WordPress-installation-identity.jpg"></p>
<p>On a server with several WordPress installations, correct syntax can still target the wrong database. WP-CLI&#8217;s global <code>--path</code> option names the installation to operate on. Don&#8217;t rely on the current shell directory.</p>
<p>For a single-site installation, these commands inspect the target without changing anything:</p>
<pre><code>wp --path=/path/to/site core is-installed
wp --path=/path/to/site config get DB_NAME
wp --path=/path/to/site db prefix
wp --path=/path/to/site option get home
wp --path=/path/to/site option get siteurl</code></pre>
<p><code>config get DB_NAME</code> reads the configured database name from <code>wp-config.php</code>. The prefix shows how WordPress names its tables. It doesn&#8217;t prove that other applications or installations have no tables in the same database. On multisite, the selected site&#8217;s <code>--url</code> context also matters.</p>
<p>Find the exact old value in the records you want to change, including <code>http</code> or <code>https</code>, <code>www</code>, the hostname, and any subdirectory. <code>http://example.com</code>, <code>https://example.com</code>, and <code>https://www.example.com</code> are different strings.</p>
<p><img decoding="async" alt="Staging URL comparison" src="/img/Staging-URL-comparison.jpg"></p>
<p>One r/Wordpress poster planning a staging-directory test wrote, “I wish to test a manual migration process (from /staging to /test folder before moving to /root folder).” (<a href="https://www.reddit.com/r/Wordpress/comments/1m71k28" target="_blank" rel="noopener nofollow">r/Wordpress staging migration discussion</a>) The path matters: replacing <code>https://example.com/staging</code> with <code>https://example.com/test</code> leaves the hostname alone.</p>
<p>A fragment like <code>example</code> can also appear in unrelated data, so search for the full literal as stored.</p>
<h2>Back up the database before the replacement</h2>
<p><img decoding="async" alt="WordPress SQL backup" src="/img/WordPress-SQL-backup.jpg"></p>
<p>A bulk database change needs a recovery point. <code>wp db export</code>, also available as <code>wp db dump</code>, writes the database to SQL using your WordPress database configuration. Unless you restrict the tables, the dump includes every table in the configured database, which matters when another application shares it.</p>
<pre><code>wp --path=/path/to/site db export \
  /secure-backups/before-url-change.sql</code></pre>
<p>The destination directory must already exist and be writable. Store the export outside the publicly served site directory with suitable access controls. Then confirm the file exists, finished successfully, and can be accessed through your recovery procedure.</p>
<div class="callout">
<p><strong>Don&#8217;t confuse the SQL dump with a content export.</strong> <code>wp db export</code> creates an SQL database dump. <code>wp export</code> creates WordPress eXtended RSS (WXR), an XML file of content records, including posts, comments, terms, and attachment information. WXR omits site options and the actual media files, so it can&#8217;t serve as a complete database recovery snapshot. The <a href="https://developer.wordpress.org/cli/commands/export/" target="_blank" rel="noopener">WP-CLI WXR export reference</a> documents that narrower purpose.</p>
</div>
<p><img decoding="async" alt="SQL export distinction" src="/img/SQL-export-distinction.jpg"></p>
<p>If you need a complete recovery, copy the WordPress files too: uploads, themes, plugins, and configuration.</p>
<h2>Why serialized WordPress data needs a serialization-aware replacement</h2>
<p><img decoding="async" alt="PHP serialized strings" src="/img/PHP-serialized-strings.jpg"></p>
<p>PHP serialized strings store their byte lengths beside their values. The sample URL <code>https://old.example</code> contains 19 ASCII bytes and can appear as <code>s:19:"https://old.example";</code>. A blanket SQL text replacement that changes the length can invalidate the stored value and damage plugin or widget settings. WP-CLI&#8217;s <code>search-replace</code> handles serialized data, using PHP processing where necessary alongside SQL processing for other values. The optional <code>--precise</code> flag forces PHP processing for all columns and is slower.</p>
<h2>Select which tables and columns the command can change</h2>
<p><img decoding="async" alt="WordPress table scope" src="/img/WordPress-table-scope.jpg"></p>
<p>Table selection decides what a URL replacement can change.</p>
<table>
<thead>
<tr>
<th>Selection</th>
<th>Covers</th>
<th>Use it when</th>
<th>Watch for</th>
</tr>
</thead>
<tbody>
<tr>
<td>Default</td>
<td>Registered <code>$wpdb</code> tables for the selected site</td>
<td>The old URLs sit in the usual WordPress data</td>
<td>Plugin tables that aren&#8217;t registered are left out</td>
</tr>
<tr>
<td>Named tables</td>
<td>Only the tables you list</td>
<td>You know exactly where the old URLs are</td>
<td>Other tables holding the old URL stay untouched</td>
</tr>
<tr>
<td><code>--all-tables-with-prefix</code></td>
<td>Tables with the configured prefix</td>
<td>Plugin tables use your prefix</td>
<td>A matching prefix doesn&#8217;t prove the table belongs to this site</td>
</tr>
<tr>
<td><code>--all-tables</code></td>
<td>Every table in the database, regardless of prefix</td>
<td>Database-wide work is explicitly authorized</td>
<td>Unrelated applications or sites can be affected</td>
</tr>
<tr>
<td><code>--network</code></td>
<td>Registered tables across a multisite network</td>
<td>A network-wide change is approved</td>
<td>Arbitrary plugin tables aren&#8217;t included automatically</td>
</tr>
</tbody>
</table>
<p>Pick the smallest scope that covers the data you need to change. <code>--all-tables</code> extends the operation to the whole database, which matters most on shared hosting or a shared database.</p>
<h3>Protect GUIDs and know which tables get skipped</h3>
<p>During a URL migration, use <code>--skip-columns=guid</code>. A WordPress <code>guid</code> can look like an old permalink, but it works as a persistent identifier, and changing it can disrupt feed identification. The <a href="https://developer.wordpress.org/cli/commands/search-replace/" target="_blank" rel="noopener">WP-CLI search-replace command reference</a> documents column exclusions and scope options.</p>
<p>WP-CLI skips tables that lack a primary key and never modifies primary-key values. Both rules apply on top of the <code>guid</code> exclusion. If a table you need is missing, check its ownership and schema. A <code>DESCRIBE</code> query shows whether it has a <code>PRI</code> key.</p>
<p><img decoding="async" alt="Database column exclusions" src="/img/Database-column-exclusions.jpg"></p>
<h2>Run a dry run and read what would change</h2>
<p><img decoding="async" alt="WP CLI dry run" src="/img/WP-CLI-dry-run.jpg"></p>
<p>A dry run reports the replacements it would make and writes nothing to the database.</p>
<pre><code>wp --path=/path/to/site search-replace \
  'https://old.example' 'https://new.example' \
  --skip-columns=guid --dry-run</code></pre>
<p>The example assumes the single-site target from earlier and the default table scope. If default coverage doesn&#8217;t suit your site, add the approved table restriction to the preview.</p>
<table>
<thead>
<tr>
<th>What the preview shows</th>
<th>Cause</th>
<th>What to do</th>
</tr>
</thead>
<tbody>
<tr>
<td>Zero replacements</td>
<td>The old string isn&#8217;t there, the scheme or host differs, or you targeted the wrong site or tables</td>
<td>Check the exact string and confirm <code>--path</code> points at the right site</td>
</tr>
<tr>
<td>More matches than expected</td>
<td>A broad string, widespread old links, or too many tables</td>
<td>Check which tables and columns the matches come from</td>
</tr>
<tr>
<td>Expected plugin table absent</td>
<td>It isn&#8217;t registered, you excluded it, or it has no primary key</td>
<td>Check who owns the table and whether it has a primary key</td>
</tr>
<tr>
<td>Unexpected table present</td>
<td>The scope covers data outside the job</td>
<td>Narrow the table list</td>
</tr>
</tbody>
</table>
<p>Read the table and column names first, then the counts. Zero is correct when the old string isn&#8217;t in the database.</p>
<p><img decoding="async" alt="Replacement report interpretation" src="/img/Replacement-report-interpretation.jpg"></p>
<p>The preview can&#8217;t test rendered pages, and the real command runs against whatever the database holds at that moment.</p>
<h2>Apply only the replacement you have reviewed</h2>
<p><img decoding="async" alt="WordPress replacement command" src="/img/WordPress-replacement-command.jpg"></p>
<p>When the preview shows the tables and counts you expected, remove <code>--dry-run</code>. Keep the same installation, old and new strings, table restrictions or other scope flags, and column exclusions.</p>
<pre><code>wp --path=/path/to/site search-replace \
  'https://old.example' 'https://new.example' \
  --skip-columns=guid</code></pre>
<p>Record the command you ran, the installation, the values and scope, and the result.</p>
<h3>Write transformed SQL to a file instead</h3>
<p>With <code>--export</code>, <code>wp search-replace</code> writes transformed SQL to a file and leaves the source database unmodified.</p>
<pre><code>wp --path=/path/to/site search-replace \
  'https://old.example' 'https://new.example' \
  --skip-columns=guid \
  --export=/secure-backups/transformed.sql</code></pre>
<p>This file doesn&#8217;t replace the pre-change backup. The output directory must exist and accept writes. The official command reference describes <code>--old</code> and <code>--new</code> as options outside a stable release, so these examples use the established positional strings.</p>
<p><img decoding="async" alt="Transformed SQL export" src="/img/Transformed-SQL-export.jpg"></p>
<h2>Look for old URLs that remain in the database</h2>
<p><img decoding="async" alt="WordPress residual URLs" src="/img/WordPress-residual-URLs.jpg"></p>
<p>After the replacement, search the database for old references that remain. <code>wp db search</code> does this without writing anything:</p>
<pre><code>wp --path=/path/to/site db search \
  'https://old.example' --stats</code></pre>
<p>By default it searches registered WordPress tables and is case-insensitive, so a match can differ in letter case from your input. Look at the stored value before deciding which reference survived.</p>
<p>If the replacement covered a wider authorized scope, extend the search with <code>--all-tables-with-prefix</code>, <code>--all-tables</code>, or <code>--network</code>, as applicable.</p>
<p>You&#8217;re done when no unwanted old URLs remain. A leftover match points to one of these:</p>
<ul>
<li><strong>Active content or option:</strong> A page, link, or setting still uses the old location.</li>
<li><strong>Plugin storage outside the first scope:</strong> A table you intended to change wasn&#8217;t part of the first run.</li>
<li><strong>Preserved identifier:</strong> An old-looking <code>guid</code> stays valid because it identifies the post.</li>
<li><strong>Historical or unrelated record:</strong> A log or archived value correctly refers to the former address.</li>
</ul>
<p><img decoding="async" alt="Database search matches" src="/img/Database-search-matches.jpg"></p>
<h2>Check the live pages, admin area, and generated files</h2>
<p><img decoding="async" alt="WordPress page verification" src="/img/WordPress-page-verification.jpg"></p>
<p>Check the site as visitors see it. Open representative pages at the new address, including pages that had internal links or media, and test navigation, images, and the WordPress administration area.</p>
<p><code>search-replace</code> can&#8217;t modify file-based URLs or generated CSS, so page builders need their own check. A migrated Elementor page, for example, can show correct database values and still load a background image from the old hostname through generated CSS. If the next step involves WordPress backups, updates, and migration, see how to <a href="https://noscript.info/wordpress/maintenance/#hosting-roles">plan WordPress maintenance and recovery</a>.</p>
<div class="callout">
<p><strong>Elementor:</strong> Elementor documents a Replace URL tool and a Clear Files &amp; Data operation for URL and generated-file problems. On an Elementor site, run those tools and do a targeted generated-asset cache refresh before checking the affected page again.</p>
</div>
<h2 id="if-the-old-domain-still-appears-locate-its-source">If the old domain still appears, locate its source</h2>
<p><img decoding="async" alt="Old domain redirects" src="/img/Old-domain-redirects.jpg"></p>
<p>If the site redirects to its development domain after the database update, find the cause before running anything else. A wider replacement can change unrelated records without touching the redirect source.</p>
<p>After moving a development site to production on shared hosting, another r/Wordpress user described this exact symptom: “However, whenever I try to access the site, it keeps redirecting to the development URL.” (<a href="https://www.reddit.com/r/Wordpress/comments/1g6i5fp" target="_blank" rel="noopener nofollow">r/Wordpress development URL discussion</a>)</p>
<p>WordPress supports <code>WP_HOME</code> and <code>WP_SITEURL</code> constants in <code>wp-config.php</code>. When defined, they override the corresponding database-stored URL options.</p>
<ul>
<li><strong>The browser sends visitors to the former domain:</strong> Find out whether WordPress configuration, the web server, or the hosting platform issues the redirect.</li>
<li><strong>The page loads but its assets refer to the former domain:</strong> Trace each asset to its content or generated-file source.</li>
<li><strong>Database references are already fixed:</strong> Inspect the configuration and delivery mechanisms behind the remaining symptom.</li>
</ul>
<p><img decoding="async" alt="Redirect source diagnosis" src="/img/Redirect-source-diagnosis.jpg"></p>
<h2>When a hosted tool or plugin is the better route</h2>
<p><img decoding="async" alt="WordPress replacement methods" src="/img/WordPress-replacement-methods.jpg"></p>
<p>If you can&#8217;t open an SSH session, your hosting account can still offer search-and-replace controls. WP Engine and Kinsta describe provider-specific interfaces, and WordPress plugins are another route where the installation permits them.</p>
<p>WP-CLI needs authorized CLI access. A host tool needs a supported function in your hosting account, and a plugin needs WordPress and plugin permissions. WP-CLI gives you documented table and column options, documented handling of serialized values, <code>--dry-run</code>, and an SQL backup you control. Before using a host tool or plugin, confirm that it offers the same four things.</p>
<p><img decoding="async" alt="Hosting tool comparison" src="/img/Hosting-tool-comparison.jpg"></p>
<h2>Restore deliberately if the change has caused damage</h2>
<p><img decoding="async" alt="WordPress database recovery" src="/img/WordPress-database-recovery.jpg"></p>
<p>Before you restore, consider what changed after the backup was taken. <code>wp db import</code> imports SQL into the configured database, and restoring an earlier dump can overwrite valid later orders, comments, registrations, or edits on an active site.</p>
<p>If you know the mistake and the affected records, a targeted correction can preserve later changes. Otherwise, restore under the site&#8217;s recovery procedure and bring the database and files into a consistent state.</p>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Update WordPress Safely Without Breaking Your Site</title>
		<link>https://noscript.info/wordpress/maintenance/updates/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Maintenance]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/maintenance/updates</guid>

					<description><![CDATA[Update WordPress core, plugins, themes, and PHP with compatibility checks, backup and staging decisions, functional tests, and failure-specific recovery.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .urgency-now{ background: #fdecea; border-left: 4px solid #c0392b; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .urgency-soon{ background: #fff9e6; border-left: 4px solid #e0a800; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }.usefulmix-article blockquote{ background: #f6f4ee; border-left: 4px solid #8a8377; margin: 1.4em 0; padding: 0.9em 1.1em; }.usefulmix-article blockquote strong{ display: block; margin-bottom: 0.3em; }
</style>
<div class="usefulmix-article">
<div class="short-answer">
<p>Check compatibility and make sure you have a backup you can restore. Test PHP changes, uncertain plugins, and anything involving live customer data on staging first. After updating, test what your visitors use, and stop if a check fails.</p>
</div>
<h2>Choose an update path that fits your site</h2>
<p><img decoding="async" alt="WordPress update decisions" src="/img/WordPress-update-decisions.jpg"></p>
<p>Before you click Update, work out what will change and what a failure would interrupt. A routine plugin update on an informational site needs less preparation than a PHP upgrade on a store that is processing orders. Record which version you will return to if the release fails.</p>
<p>Read the release notes for the component and see whether the update fixes a security issue or is routine maintenance.</p>
<table>
<thead>
<tr>
<th>Situation</th>
<th>Update approach</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
<tr>
<td>Routine, known-compatible component update</td>
<td>Monitored update after basic preparation</td>
<td>Few parts of the site are affected</td>
</tr>
<tr>
<td>Major WordPress change or multiple dependent updates</td>
<td>Supervised update, with staging when needed</td>
<td>More interactions to test</td>
</tr>
<tr>
<td>PHP upgrade or aging custom code</td>
<td>Dependency review, then staging before production</td>
<td>Code written for the old PHP version can fail on the new one</td>
</tr>
<tr>
<td>Store, membership site, or other transactional website</td>
<td>Staging plus a plan to preserve live data</td>
<td>Orders, accounts, and submissions keep arriving</td>
</tr>
<tr>
<td>Time-sensitive security fix</td>
<td>Prompt patching with a recovery point ready</td>
<td>Waiting also carries risk</td>
</tr>
</tbody>
</table>
<p>On a brochure site, the contact form can be the most important feature. The plugin that runs it deserves close attention even when its update looks small.</p>
<p><img decoding="async" alt="Website change risk" src="/img/Website-change-risk.jpg"></p>
<h2>Check compatibility across WordPress, plugins, themes, and PHP</h2>
<p><img decoding="async" alt="WordPress compatibility checks" src="/img/WordPress-compatibility-checks.jpg"></p>
<p>WordPress core, your active plugins, the theme, custom code, PHP, and the database server all have to work together after the change. An update notice only tells you a new release exists. You still have to check whether it fits the rest of your installation.</p>
<p>The <a href="https://wordpress.org/about/requirements/" target="_blank" rel="noopener">WordPress requirements page</a> recommends PHP 8.3 or greater, MariaDB 10.11 or greater or MySQL 8.0 or greater, and HTTPS.</p>
<p>WordPress core&#8217;s PHP compatibility matrix covers core only. Plugins, themes, and custom PHP code have their own requirements and can fail even when core supports your PHP version.</p>
<ul>
<li><strong>WordPress core:</strong> Record the installed and proposed versions and read the release notes.</li>
<li><strong>Plugins:</strong> Check each active plugin affected by the change for its version requirements and dependencies.</li>
<li><strong>Theme and custom code:</strong> Look for vendor compatibility statements, direct customizations, and code that relies on older PHP behavior.</li>
<li><strong>Server stack:</strong> Record your PHP and database versions and the versions your host or administrator proposes.</li>
</ul>
<p><img decoding="async" alt="Plugin version requirements" src="/img/Plugin-version-requirements.jpg"></p>
<p>A self-hosted site owner facing a host-driven PHP 8.2 to 8.3 change wrote on r/Wordpress, “I&#8217;m not sure where to go from here &#8211; I can see that some of the error messages have to do with specific plugins, but I&#8217;m not sure what to do about that.”</p>
<p>Error messages that name a plugin, like the ones this owner saw, only tell you where to look, and so does a scanner flag. Compare the reported location with the plugin&#8217;s or theme&#8217;s requirements and changelog, then separate deprecation or compatibility warnings from fatal errors you can reproduce. An abandoned commercial theme can need repair or replacement before a runtime change can go ahead.</p>
<div class="callout">
<p>Hold the production change until you resolve any fatal compatibility problem you have reproduced. Test warnings with unclear effects on staging.</p>
</div>
<h2>Create a recovery point you can use</h2>
<p><img decoding="async" alt="WordPress backup verification" src="/img/WordPress-backup-verification-2.jpg"></p>
<p>Before a production update, secure a recovery point that covers both your files and your database. The <a href="https://developer.wordpress.org/advanced-administration/security/backup/" target="_blank" rel="noopener">WordPress backup documentation</a> treats them as separate components. For WordPress files, database, and backup archives, use the procedure to <a href="https://noscript.info/wordpress/maintenance/backup/#try-the-recovery-away-from-production">back up WordPress files and the database</a>.</p>
<p>A database export without those files can leave the recovered site incomplete. A folder of plugin files cannot restore the database.</p>
<ul>
<li><strong>Database:</strong> Confirm the backup includes your site&#8217;s database.</li>
<li><strong>Files:</strong> Include uploads, themes, plugins, and the configuration the installation needs.</li>
<li><strong>Timestamp, storage, and access:</strong> Know when the backup was taken, where it is held, and who can retrieve it.</li>
<li><strong>Restore path:</strong> Know the process and credentials you need to recover the site, and check whether you have ever tested a restore.</li>
</ul>
<p><img decoding="async" alt="Complete backup contents" src="/img/Complete-backup-contents.jpg"></p>
<p>The timestamp matters on any site that accepts new data. Restoring an older database can erase orders, contact submissions, registrations, and other records created after the backup. A store restored from yesterday&#8217;s database needs a separate way to preserve today&#8217;s orders.</p>
<h2>Test risky changes without overwriting live data</h2>
<p><img decoding="async" alt="WordPress staging environments" src="/img/WordPress-staging-environments.jpg"></p>
<p>Staging gives you a separate copy of the site for testing uncertain changes.</p>
<p>A Hostinger VPS operator described the setup on r/Wordpress: “I’m running a WordPress site on a Hostinger VPS and currently have a staging environment on a subdomain (staging.domain.com) and the live site on domain.com.”</p>
<p>While you update the staging copy, the live site keeps receiving orders, registrations, and form submissions in its own database. A full database push from staging can replace those newer records with older data. Kinsta documents this risk in its own staging deployment workflow.</p>
<table>
<thead>
<tr>
<th>What changed</th>
<th>State involved</th>
<th>Deployment decision</th>
</tr>
</thead>
<tbody>
<tr>
<td>Plugin, theme, or core files</td>
<td>Application code</td>
<td>Deploy the changed files at the versions you tested</td>
</tr>
<tr>
<td>Configuration</td>
<td>Files or database options</td>
<td>Find where the changed settings are stored and move them from there</td>
</tr>
<tr>
<td>Database schema or plugin data</td>
<td>Persistent structure or records</td>
<td>Run the required migration or a controlled transfer</td>
</tr>
<tr>
<td>Orders, accounts, and submissions</td>
<td>New live production records</td>
<td>Keep everything created since you copied staging</td>
</tr>
<tr>
<td>Generated output or caches</td>
<td>Environment-specific derived content</td>
<td>Check the output on production after deployment</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="Staging database changes" src="/img/Staging-database-changes.jpg"></p>
<p>A file-only deployment suits a code change that leaves persistent data alone. Some plugin updates also change tables or stored settings, and those need a data migration too. For work involving WordPress backups, updates, and migration, follow the steps to <a href="https://noscript.info/wordpress/maintenance/#updates">plan WordPress maintenance and recovery</a>.</p>
<h2>Update WordPress core, plugins, and themes</h2>
<p><img decoding="async" alt="WordPress update controls" src="/img/WordPress-update-controls.jpg"></p>
<div class="callout">
<p>WordPress 7.2 Beta 1, released on October 20, 2026, is a testing release meant for testing environments, not for normal stable production updates.</p>
</div>
<p>With the checks done and a recovery point in place, apply each update through the supported WordPress dashboard, your host&#8217;s controls, or WP-CLI. Note which component you changed and whether its updater reported an error.</p>
<h3>Use the WordPress dashboard</h3>
<ol>
<li><strong>Update core:</strong> Sign in to <code>wp-admin</code>, open <code>Dashboard → Updates</code>, and use the WordPress update button for the stable release you are installing.</li>
<li><strong>Update a plugin:</strong> Open <code>Plugins → Installed Plugins</code> and click <code>Update Now</code> next to any plugin with an update. <code>Dashboard → Updates</code> also lists plugin updates.</li>
<li><strong>Update a theme:</strong> Open <code>Appearance → Themes</code>, select the theme, and use its update control.</li>
<li><strong>Complete a database update:</strong> If WordPress prompts for a database upgrade after a core update, follow the on-screen action and wait for it to finish.</li>
<li><strong>Clear caches:</strong> If the site uses page or other caches, clear them through your caching controls so later checks show fresh output.</li>
</ol>
<p>The <a href="https://wordpress.org/documentation/article/updating-wordpress/" target="_blank" rel="noopener">WordPress updating guide</a> covers the core dashboard flow and the related completion steps.</p>
<p><img decoding="async" alt="Plugin theme updates" src="/img/Plugin-theme-updates.jpg"></p>
<p>Let dependencies set the order. A plugin with a stated WordPress version requirement, for example, can need the core update first.</p>
<p>Updates can replace the original software files, so direct edits to WordPress core or to an updated parent theme&#8217;s files can be lost. Account for those customizations before updating.</p>
<h3>Use WP-CLI when you administer the installation</h3>
<p>If you have the right access and permissions on the installation, WP-CLI offers matching commands:</p>
<ul>
<li><strong>WordPress core:</strong> <code>wp core update</code></li>
<li><strong>A selected plugin:</strong> <code>wp plugin update &lt;plugin-slug&gt;</code></li>
<li><strong>A selected theme:</strong> <code>wp theme update &lt;theme-slug&gt;</code></li>
</ul>
<p>If a core update requires a database upgrade, run <code>wp core update-db</code> in the target installation.</p>
<h2 id="handle-php-as-a-separate-server-change">Handle PHP as a separate server change</h2>
<p><img decoding="async" alt="PHP runtime updates" src="/img/PHP-runtime-updates.jpg"></p>
<p>Changing PHP is a hosting or server-administration task. Updating core, plugins, or themes through the dashboard does not change the PHP version your server runs.</p>
<p>Where their requirements allow, bring WordPress core, plugins, and the theme to versions that support the new PHP before switching.</p>
<p>For a PHP 8.2 to 8.3 move, use your compatibility inventory to find the plugins, themes, or custom code that need attention. On managed hosting, look for the PHP selector in the provider&#8217;s control panel. A self-managed VPS can need a qualified administrator who works with the installed PHP and web services.</p>
<p><img decoding="async" alt="Server PHP version" src="/img/Server-PHP-version.jpg"></p>
<p>Write down the current PHP version and find out how your host supports switching back.</p>
<p>Make the change through the documented hosting or server control, then confirm which PHP version WordPress is running on.</p>
<h2>Test what visitors use</h2>
<aside class="callout" id="audit-checklist-pg104" aria-labelledby="audit-checklist-pg104-title" data-audit-widget="checklist">
<h3 id="audit-checklist-pg104-title">Update verification checklist</h3>
<p>Mark an item only after checking it on your site. Nothing here runs a test or saves a result.</p>
<ul>
<li><label><input type="checkbox"> Compatibility of WordPress, plugins, themes and PHP has been checked.</label></li>
<li><label><input type="checkbox"> A usable recovery point exists before the update.</label></li>
<li><label><input type="checkbox"> Risky changes have been tested without overwriting newer live data.</label></li>
<li><label><input type="checkbox"> Critical visitor and administrator workflows still work after updating.</label></li>
<li><label><input type="checkbox"> Unexpected failures have an identified recovery route.</label></li>
</ul>
<p id="audit-checklist-pg104-progress" role="status" aria-live="polite">0 of 5 checks confirmed.</p>
<p><button type="button" id="audit-checklist-pg104-reset">Reset checks</button><br />
</aside>
<p><script>
(function() {
 'use strict';
 const root = document.getElementById('audit-checklist-pg104');
 const boxes = Array.from(root.querySelectorAll('input[type="checkbox"]'));
 const progress = document.getElementById('audit-checklist-pg104-progress');
 function update() {
  const checked = boxes.filter(function(b){return b.checked;}).length;
  progress.textContent = checked + ' of ' + boxes.length + ' checks confirmed.';
 }
 root.addEventListener('change', update);
 root.querySelector('button').addEventListener('click', function() { boxes.forEach(function(b) { b.checked=false; }); update(); });
 update();
})();
</script></p>
<p><img decoding="async" alt="WordPress functional testing" src="/img/WordPress-functional-testing.jpg"></p>
<p>An updater can report success while something visitors rely on is broken. Once the updates are done, test the site&#8217;s actual functions.</p>
<p>On r/Wordpress, a maintainer with two small-business clients wrote, “I&#8217;ve never had a good nor time-efficient method of checking to ensure nothing is broken after a pass of plugin updates.”</p>
<p>A short, repeatable checklist fixes that. Build yours from the features your site actually has:</p>
<table>
<thead>
<tr>
<th>Function</th>
<th>What to test</th>
<th>Pass condition</th>
</tr>
</thead>
<tbody>
<tr>
<td>Public content</td>
<td>Open the homepage and a typical internal page</td>
<td>Content and navigation load as expected</td>
</tr>
<tr>
<td>Administration</td>
<td>Sign in with an authorized account</td>
<td>The dashboard and the controls you need open</td>
</tr>
<tr>
<td>Contact or lead capture</td>
<td>Send a safe test form submission</td>
<td>The message or record reaches its destination</td>
</tr>
<tr>
<td>Customer accounts</td>
<td>Log in or use account functions</td>
<td>The account flow completes</td>
</tr>
<tr>
<td>Store functions</td>
<td>Run cart and checkout without creating a real charge</td>
<td>Each stage works</td>
</tr>
<tr>
<td>Updated plugin feature</td>
<td>Use the function the changed plugin provides</td>
<td>The feature behaves as it did before</td>
</tr>
<tr>
<td>Error signals</td>
<td>Review error messages or logs</td>
<td>No new fatal failure in the flows you checked</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="Website smoke tests" src="/img/Website-smoke-tests.jpg"></p>
<p>A company brochure site needs its contact form, navigation, and administrator sign-in tested. A WooCommerce store adds cart, checkout, and customer-account paths. Include the updated plugin&#8217;s central function when the site relies on it.</p>
<p>Record the checks you ran, whether each passed or failed, and the components and versions you changed. A pass covers only the flows you tested, on the day you tested them.</p>
<h2>Identify the failure before choosing recovery</h2>
<p><img decoding="async" alt="WordPress update failures" src="/img/WordPress-update-failures.jpg"></p>
<p>If an update fails or a feature breaks, stop making changes until you know which kind of failure you have.</p>
<p>One maintainer working on a live client store posted this on r/Wordpress: “Unfortunately after updating Yoast SEO plugin the website crashed and it returned a white screen.”</p>
<p>A white screen like that belongs in the last row below.</p>
<table>
<thead>
<tr>
<th>What you observe</th>
<th>Likely cause</th>
<th>First response</th>
</tr>
</thead>
<tbody>
<tr>
<td>Update operation remains active</td>
<td>Normal installation or maintenance work</td>
<td>Let it finish and do not interrupt it</td>
</tr>
<tr>
<td>Maintenance notice persists after the updater stops</td>
<td>Stale <code>.maintenance</code> file</td>
<td>Confirm the updater is inactive, then use the documented maintenance recovery</td>
</tr>
<tr>
<td>Plugin or theme installation fails</td>
<td>Installer failure that can qualify for supported rollback</td>
<td>Check the update status and the available recovery mechanism</td>
</tr>
<tr>
<td>Installation finishes but a feature fails</td>
<td>Application regression or compatibility fault</td>
<td>Investigate the affected feature and its errors</td>
</tr>
<tr>
<td>Site or dashboard becomes inaccessible</td>
<td>Critical error or access problem</td>
<td>Use the administrator and hosting recovery path</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="WordPress failure diagnosis" src="/img/WordPress-failure-diagnosis.jpg"></p>
<p>WordPress 6.3 introduced rollback protection for certain failed manual plugin and theme updates. The <a href="https://make.wordpress.org/core/2023/07/11/new-in-6-3-rollback-for-failed-manual-plugin-and-theme-updates/" target="_blank" rel="noopener">WordPress 6.3 rollback explanation</a> covers that installation-time protection. It does not cover completed updates that later break functionality, custom-code changes, or persistent database changes.</p>
<p>A “Briefly unavailable for scheduled maintenance” message that won&#8217;t go away can point to the <code>.maintenance</code> file. Do not remove it or touch update files unless the updater has stopped.</p>
<p>Use the updater&#8217;s result and any error logs to choose between supported component recovery, targeted troubleshooting, and restoring a complete backup.</p>
<h2>Regain access when wp-admin is unavailable</h2>
<p><img decoding="async" alt="WordPress admin recovery" src="/img/WordPress-admin-recovery.jpg"></p>
<p>A critical error can lock you out of <code>wp-admin</code> and tell you that recovery instructions went to the site&#8217;s administrator email. You can lack control over that inbox or the hosting account. Find out who owns the administrator email and the hosting access, follow the recovery instructions or ask hosting support, and give any plugin or theme problem to an authorized administrator for targeted critical-error troubleshooting. For WordPress, fatal errors, and plugin recovery, use the procedure to <a href="https://noscript.info/wordpress/troubleshooting/critical-error/#no-recovery-email-find-the-php-fatal-error-in-the-logs">recover from a WordPress critical error</a>.</p>
<h2>Decide which updates to automate</h2>
<p><img decoding="async" alt="WordPress automatic updates" src="/img/WordPress-automatic-updates.jpg"></p>
<p>Automatic updates work when the site has dependable recovery and someone can respond to failures. Supervised updates give you more control over staging and the timing of high-stakes changes. Which components are affected, what the business relies on, and how well the site is monitored set the right mix.</p>
<p>Plugin auto-update controls sit under <code>Plugins → Installed Plugins</code>, where each entry offers <code>Enable auto-updates</code> or the matching disable control. For themes, open <code>Appearance → Themes</code>, select the theme, and use its automatic-update setting.</p>
<p>Your installation&#8217;s configuration and your host&#8217;s policy set core update behavior. A managed provider can apply or defer certain WordPress releases through its own controls, so check your host&#8217;s settings too.</p>
<p><img decoding="async" alt="Automatic update settings" src="/img/Automatic-update-settings.jpg"></p>
<p>On a simple brochure site with recovery access and monitoring, automated updates cut manual work. A transactional site, or one that runs a plugin you are unsure about, can warrant supervised updates and staging for major releases. Security fixes need prompt attention either way.</p>
<ul>
<li><strong>Coverage:</strong> Decide which core, plugin, and theme updates run automatically and which you supervise.</li>
<li><strong>Ownership:</strong> Assign a person or team to receive failure notices and respond.</li>
</ul>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Fix WordPress Cron Jobs That Aren&#8217;t Running</title>
		<link>https://noscript.info/wordpress/maintenance/cron/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Maintenance]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/maintenance/cron</guid>

					<description><![CDATA[Find the failed WordPress cron layer: scheduled hook, trigger, loopback request, plugin callback, or WooCommerce queue. Choose a fix and verify the next run.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .urgency-now{ background: #fdecea; border-left: 4px solid #c0392b; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .urgency-soon{ background: #fff9e6; border-left: 4px solid #e0a800; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }.usefulmix-article blockquote{ background: #f6f4ee; border-left: 4px solid #8a8377; margin: 1.4em 0; padding: 0.9em 1.1em; }.usefulmix-article blockquote strong{ display: block; margin-bottom: 0.3em; }
</style>
<div class="usefulmix-article">
<div class="short-answer">
<p>Check whether the event was scheduled, whether anything ran it, and whether the task finished. Fix the layer that failed. If waiting on visitors causes the delay, move to a monitored server cron job.</p>
</div>
<p>A scheduled post can miss its publication time while other WordPress jobs run as expected. A backup plugin can register an event and still produce no backup. WooCommerce can accumulate pending actions while the store&#8217;s pages stay accessible.</p>
<h2>Find the failing task before changing WP-Cron</h2>
<p><img decoding="async" alt="WordPress cron symptoms" src="/img/WordPress-cron-symptoms.jpg"></p>
<p>Open <code>Tools → Site Health</code> and note any scheduled-event warning. For a missed post, compare the scheduled publication time with the site&#8217;s timezone under <code>Settings → General</code>, then check the post status and the public URL. A stale cache can also make an updated page look unchanged. The presence of an event in WP-CLI does not prove the server invoked it at the intended time.</p>
<table>
<thead>
<tr>
<th>What you see</th>
<th>What to check first</th>
<th>Likely cause</th>
</tr>
</thead>
<tbody>
<tr>
<td>One post says <code>Missed Schedule</code></td>
<td>Post status, scheduled time, timezone</td>
<td>Timing or publishing callback</td>
</tr>
<tr>
<td>Several events are overdue</td>
<td>Overdue events and what is running them</td>
<td>WP-Cron triggering or server cron job</td>
</tr>
<tr>
<td>An expected plugin event is absent</td>
<td>Plugin state and list of registered hooks</td>
<td>Event registration</td>
</tr>
<tr>
<td><code>wp cron test</code> reports disabled</td>
<td>Cron constant and host job</td>
<td>Server cron job setup</td>
</tr>
<tr>
<td>Manual execution works, automatic execution fails</td>
<td>Loopback response and server cron job logs</td>
<td>Loopback request or server cron job</td>
</tr>
<tr>
<td>Backup event runs but no file appears</td>
<td>Plugin and PHP logs, expected file</td>
<td>Plugin callback</td>
</tr>
<tr>
<td>WooCommerce actions pile up</td>
<td>Action status, age, hook, logs</td>
<td>Action Scheduler queue</td>
</tr>
</tbody>
</table>
<p>Site Health and a <code>Missed Schedule</code> label flag a problem without naming the cause. If unrelated scheduled jobs succeed, inspect the affected task before changing any site-wide setting. When WordPress backups, updates, and migration need a separate check, see how to <a href="https://noscript.info/wordpress/maintenance/#choose-task">plan WordPress maintenance and recovery</a>.</p>
<p><img decoding="async" alt="Missed scheduled post" src="/img/Missed-scheduled-post.jpg"></p>
<p>A publisher whose newsletter linked to a scheduled article described the failure in an <a href="https://www.reddit.com/r/Wordpress/comments/1jdt3es" target="_blank" rel="noopener nofollow">r/Wordpress discussion</a>: “This morning, our newsletter led to a 404, so I checked and found out that it was scheduled correctly but didn&#8217;t post.”</p>
<p>Write down the hook or post name, the expected local time and timezone, the warning&#8217;s exact wording, the visible result, and whether other scheduled jobs work.</p>
<h2>How WP-Cron gets triggered and what a server job changes</h2>
<p><img decoding="async" alt="WP Cron mechanism" src="/img/WP-Cron-mechanism.jpg"></p>
<p>WordPress registers scheduled hooks and checks for due ones when someone loads a page. On a quiet site, due events wait for the next visit. The HTTP spawning path uses a <code>doing_cron</code> transient lock. A server cron job starts the check on a fixed schedule whatever the traffic, but the callback registered for each event still decides whether the task succeeds. WordPress 6.9 moved the ordinary <code>wp_cron()</code> call to <code>shutdown</code>, except when alternate cron is enabled.</p>
<h2>Check scheduled events in Site Health, WP Crontrol, or WP-CLI</h2>
<p><img decoding="async" alt="Scheduled event inventory" src="/img/Scheduled-event-inventory.jpg"></p>
<p>WordPress can only run a registered event. An event list shows which hooks exist, when they are due and whether they repeat.</p>
<p>For a dashboard view, WP Crontrol 2.0.0 documents <code>Cron → Cron Events</code>, and the earlier <code>Tools → Cron Events</code> route remains available in its documentation. Its expanded event logs are opt-in: enable logging for the event you care about, then look under <code>Cron → Cron Logs</code>.</p>
<p>With SSH and WP-CLI access, run this from the intended WordPress installation:</p>
<p><code>wp cron event list</code></p>
<p>The default listing includes the hook, next run time and recurrence. To see arguments and registered actions too, use:</p>
<p><code>wp cron event list --fields=hook,next_run_gmt,recurrence,args,actions</code></p>
<p><img decoding="async" alt="WP CLI events" src="/img/WP-CLI-events.jpg"></p>
<p>The hook links the event to its callback, and the next run time shows whether the event is overdue. Recurrence tells you if it repeats. Arguments separate instances that share a hook name. Actions list the callbacks registered in the command&#8217;s execution context.</p>
<p>The list shows what is scheduled and when. It can&#8217;t tell you whether the task finished.</p>
<h3>When the expected event is missing</h3>
<p>The plugin can be inactive, or its code can register the hook only under certain conditions. Find which plugin owns the hook before changing anything about how cron runs. Developers can call <code>wp_next_scheduled()</code> to check for an existing hook and argument combination before scheduling recurring work.</p>
<h3>When WP Crontrol shows no action</h3>
<p>A hook can have no callback in the context where the inspection tool runs, even though the callback loads in another one.</p>
<h2>Check DISABLE_WP_CRON and test the actual trigger</h2>
<p><img decoding="async" alt="WordPress cron configuration" src="/img/WordPress-cron-configuration.jpg"></p>
<p>The <code>DISABLE_WP_CRON</code> constant turns off request-triggered spawning.</p>
<p>The line in <code>wp-config.php</code> looks like this:</p>
<p><code>define('DISABLE_WP_CRON', true);</code></p>
<p>WP-CLI can test HTTP spawning:</p>
<p><code>wp cron test</code></p>
<p>With <code>DISABLE_WP_CRON</code> set to true, the test reports spawning as disabled. That result is normal when a server cron job runs your events, so read it against your own setup.</p>
<p><img decoding="async" alt="Cron trigger inspection" src="/img/Cron-trigger-inspection.jpg"></p>
<p>On a site that relies on page requests, investigate any failure the HTTP test returns. On a site with a server cron job, check the hosting panel or system job: the account it runs under, the WordPress installation or multisite URL it targets, and its execution logs. The job log shows whether the server cron job fired.</p>
<p><code>ALTERNATE_WP_CRON</code> is a separate mode, so treat it separately from the disabling constant when you work out how your site schedules events.</p>
<h2>Trace blocked loopback requests and wp-cron.php HTTP errors</h2>
<p><img decoding="async" alt="WordPress loopback errors" src="/img/WordPress-loopback-errors.jpg"></p>
<p>WordPress can start due work with an HTTP request back to its own installation. A blocked or misdirected loopback request breaks that automatic path. WP-CLI takes a different route to the callbacks.</p>
<p>The error code tells you where to start:</p>
<table>
<thead>
<tr>
<th>Response</th>
<th>What it means</th>
<th>What to inspect</th>
</tr>
</thead>
<tbody>
<tr>
<td>cURL <code>6</code></td>
<td>DNS resolution failure</td>
<td>DNS resolution of the site&#8217;s configured hostname</td>
</tr>
<tr>
<td>cURL <code>7</code></td>
<td>Connection failure</td>
<td>Listener, target port, route and firewall</td>
</tr>
<tr>
<td>cURL <code>28</code></td>
<td>Timed-out loopback request</td>
<td>Request timeout and network path</td>
</tr>
<tr>
<td>cURL <code>35</code></td>
<td>SSL connection failure</td>
<td>TLS negotiation and certificate configuration</td>
</tr>
<tr>
<td>HTTP <code>401</code> or <code>403</code></td>
<td>Access restriction</td>
<td>Authentication, WAF and access-control logs</td>
</tr>
<tr>
<td>HTTP <code>404</code></td>
<td>Missing or inaccessible cron endpoint</td>
<td>Effective request URL and <code>wp-cron.php</code> path</td>
</tr>
<tr>
<td>HTTP <code>500</code></td>
<td>Server-side error</td>
<td>Web server and PHP error logs</td>
</tr>
</tbody>
</table>
<p>WP Crontrol&#8217;s <a href="https://wp-crontrol.com/help/problems-spawning-wp-cron/" target="_blank" rel="noopener">spawning-error guide</a> documents these categories.</p>
<p><img decoding="async" alt="HTTPS loopback mismatch" src="/img/HTTPS-loopback-mismatch.jpg"></p>
<h3>Manual WP-CLI execution works, but scheduled spawning fails</h3>
<p>A maintainer who saw Site Health failures despite successful manual WP-CLI runs wrote in a <a href="https://wordpress.org/support/topic/wp-cron-events-reported-as-failed-by-site-health-but-they-run-correctly-from-wp/" target="_blank" rel="noopener nofollow">WordPress.org support thread</a>: “My server is configured to work only over HTTPS and does not accept HTTP requests, so the cron trigger was failing silently.” Correcting the scheme resolved that case.</p>
<p>If you see the same symptom, match the loopback request&#8217;s URL, scheme, time, and status or cURL response against the access, security and PHP logs.</p>
<div class="callout">
<p>Never disable TLS certificate validation or weaken authentication to make a cron request pass. Fix the URL, access-control, network or server fault the logs point to.</p>
</div>
<p><img decoding="async" alt="HTTP failure logs" src="/img/HTTP-failure-logs.jpg"></p>
<h2>Diagnose callback errors, duplicate hooks, and tasks that run only manually</h2>
<p><img decoding="async" alt="WordPress callback failures" src="/img/WordPress-callback-failures.jpg"></p>
<p>A cron request can reach WordPress and the task can still fail inside its callback. The owning plugin or custom code can hit a PHP error, an execution limit, a missing permission or an unavailable external service.</p>
<p>Take a backup plugin whose hook is registered but whose backup file never appears. The callback and what it uses are the place to look, even when other scheduled tasks work.</p>
<h3>Read the callback&#8217;s evidence</h3>
<p>Find the plugin, theme or custom code that owns the hook.</p>
<p><img decoding="async" alt="Plugin execution logs" src="/img/Plugin-execution-logs.jpg"></p>
<ul>
<li><strong>PHP error:</strong> Look for the exception or fatal error tied to the operation.</li>
<li><strong>Remote dependency:</strong> Look for a failed API request or an unavailable service the callback uses.</li>
<li><strong>Missing artifact:</strong> Compare the logged attempt with the output it should have produced, such as a backup file.</li>
<li><strong>Duplicate event:</strong> Compare hook names and argument sets.</li>
<li><strong>Inactive integration:</strong> Check whether the callback code loads in the context where the event runs.</li>
</ul>
<h3>Understand the consequences of manual execution</h3>
<p><code>wp cron event run --due-now</code> executes every event that is currently due, and <code>--all</code> widens the scope further. Both can send messages, create files, call webhooks or trigger other operations. On a production site, work out what the events will do before you run them.</p>
<p><img decoding="async" alt="Cron callback output" src="/img/Cron-callback-output.jpg"></p>
<h2>Fix the proven cause or switch to monitored server cron when needed</h2>
<p><img decoding="async" alt="Cron repair decisions" src="/img/Cron-repair-decisions.jpg"></p>
<p>Task deadlines and the scheduling tools your host provides decide whether a server cron job fits.</p>
<table>
<thead>
<tr>
<th>What you found</th>
<th>What to do</th>
</tr>
</thead>
<tbody>
<tr>
<td>Default WP-Cron finishes tasks within an acceptable delay</td>
<td>Keep it</td>
</tr>
<tr>
<td>Normal spawning is disabled and no external job runs</td>
<td>Set up a server cron job so events don&#8217;t go unrun</td>
</tr>
<tr>
<td>HTTP spawning fails because of an identified configuration problem</td>
<td>Fix the request path the error and logs point to</td>
</tr>
<tr>
<td>A single callback fails after it starts</td>
<td>Fix the plugin or application error shown in the task logs</td>
</tr>
<tr>
<td>Visitor-dependent spawning makes tasks late, such as overdue hooks on a quiet site whose callbacks otherwise work</td>
<td>Use a monitored host or system cron job</td>
</tr>
<tr>
<td>WooCommerce background actions fail or accumulate</td>
<td>Investigate Action Scheduler (next section)</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="Server cron setup" src="/img/Server-cron-setup.jpg"></p>
<h3>A documented hosting-panel example</h3>
<p>SiteGround documents the path <code>Site Tools → Devs → Cron Jobs</code>. Its example schedules <code>wp cron event run --due-now</code> from the WordPress installation directory through the hosting panel.</p>
<div class="callout">
<p>Kinsta&#8217;s published managed example runs every 15 minutes, SiteGround&#8217;s every 30. Pick an interval based on how late a task can run and what your host allows.</p>
</div>
<p>Some vendor examples send command output to <code>/dev/null</code>. While you diagnose, keep a job log or error file so failures show up.</p>
<h3 id="switch-to-a-server-cron-job-in-a-safe-order">Switch to a server cron job in a safe order</h3>
<p>Set up the new job for the correct WordPress site and account. Wait for at least one run started by the host schedule and confirm it in the job log or in the expected task result. Then, if your setup calls for it, turn off request-triggered WP-Cron and keep a way to restore the old configuration.</p>
<p><img decoding="async" alt="Multisite cron scheduling" src="/img/Multisite-cron-scheduling.jpg"></p>
<p>On Multisite, each site has its own execution context, and every extra WordPress launch adds overhead. A single-site job copied unchanged across a network can miss the subsites you want.</p>
<h2>Separate WooCommerce Action Scheduler backlogs from WP-Cron failures</h2>
<p><img decoding="async" alt="WooCommerce scheduled actions" src="/img/WooCommerce-scheduled-actions.jpg"></p>
<p>WooCommerce uses Action Scheduler for background jobs, each with its own status and log. WP-Cron can start the queue.</p>
<p>Open <code>WooCommerce → Status → Scheduled Actions</code> and check the affected hook, the owning integration, status, age and failure messages. A pending action can be normal queued work. A failed action has a logged cause.</p>
<p>One merchant running a mid-size store described the symptoms in an <a href="https://www.reddit.com/r/woocommerce/comments/1wseji0/action_scheduler_queue_keeps_growing_on_a_woo/" target="_blank" rel="noopener nofollow">r/woocommerce discussion</a>: “Checkout and admin felt randomly slow. PageSpeed still looked fine.”</p>
<p><img decoding="async" alt="Action Scheduler backlog" src="/img/Action-Scheduler-backlog.jpg"></p>
<p>Action Scheduler has its own WP-CLI tooling for queue operations, including <code>wp action-scheduler run</code>. For WP-CLI, WordPress commands, and SSH, see how to <a href="https://noscript.info/wordpress/hosting/wp-cli/#check-existing">run and verify WP-CLI commands</a>.</p>
<div class="callout">
<p>Never bulk-delete or blindly rerun pending and failed actions on a live store. Orders, renewals, webhooks and payment integrations can rely on them.</p>
</div>
<p>If the fault belongs to one integration, recover it through that plugin or a dedicated Action Scheduler procedure.</p>
<h2>Verify automatic scheduling by checking the real result</h2>
<p><img decoding="async" alt="Cron recovery verification" src="/img/Cron-recovery-verification.jpg"></p>
<p>The next automatic run is your test. Let WordPress or the server <a href="https://noscript.info/servers/operations/crontab/#check-cron-logs-then-verify-what-the-job-produced">cron job</a> reach the event, then check what the task actually produced and whether the Site Health warning is gone.</p>
<table>
<thead>
<tr>
<th>Scheduled work</th>
<th>Evidence of completion</th>
</tr>
</thead>
<tbody>
<tr>
<td>Scheduled WordPress post</td>
<td>Published status and a post URL that loads publicly</td>
</tr>
<tr>
<td>Automated backup</td>
<td>Backup file exists and passes validation</td>
</tr>
<tr>
<td>Plugin background task</td>
<td>Logged success or the expected output</td>
</tr>
<tr>
<td>WooCommerce action</td>
<td>Completed status and log</td>
</tr>
<tr>
<td>Recurring maintenance job</td>
<td>Expected result at the next interval</td>
</tr>
</tbody>
</table>
<p>Compare the completion time with the delay your site can accept.</p>
<p><img decoding="async" alt="Scheduled task confirmation" src="/img/Scheduled-task-confirmation.jpg"></p>
<p>For recurring tasks that matter, watch several more cycles at the job&#8217;s own interval. Add the automatic run&#8217;s timestamp, what started it, the result and any new errors to the notes you made at the start.</p>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Fix the Critical Error in WordPress</title>
		<link>https://noscript.info/wordpress/troubleshooting/critical-error/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/troubleshooting/critical-error</guid>

					<description><![CDATA[Restore WordPress access with Recovery Mode or PHP fatal logs. Isolate a plugin or server fault, make a targeted repair, and verify the failed action.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .urgency-now{ background: #fdecea; border-left: 4px solid #c0392b; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .urgency-soon{ background: #fff9e6; border-left: 4px solid #e0a800; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }.usefulmix-article blockquote{ background: #f6f4ee; border-left: 4px solid #8a8377; margin: 1.4em 0; padding: 0.9em 1.1em; }.usefulmix-article blockquote strong{ display: block; margin-bottom: 0.3em; }
</style>
<div class="usefulmix-article">
<article>
<div class="short-answer">
<p>Use the WordPress Recovery Mode link if the admin email arrives. If it doesn&#8217;t, find the relevant PHP fatal error in your hosting or WordPress logs, then repair or reverse the change it points to. If you lack access or the evidence points to a server-level problem, send your host or developer the error details, and treat the repair as done once the original failing action works again.</p>
</div>
<h2>What the WordPress critical error message means</h2>
<p><img decoding="async" alt="WordPress critical error" src="/img/WordPress-critical-error-2.jpg"></p>
<p>The message “There has been a critical error on this website” means WordPress hit a serious failure in PHP. It doesn&#8217;t tell you what caused it. The error can appear on the public site, throughout <code>wp-admin</code>, or only during one action. Write down the exact wording and the failing URL or action before changing anything. A blank page, a standalone HTTP 502 response, or “Error establishing a database connection” is a different problem with a different fix.</p>
<h2>Find out what still works before choosing a recovery route</h2>
<p><img decoding="async" alt="WordPress recovery routes" src="/img/WordPress-recovery-routes.jpg"></p>
<p>An admin described a typical split in an <a href="https://www.reddit.com/r/Wordpress/comments/1rllizu/help_critical_error_on_wp_admin/" target="_blank" rel="noopener nofollow">r/Wordpress thread</a> on March 5, 2026: “My site is live, but trying to access admin is giving the &#8220;There has been a critical error on this website.&#8221; message for all pages in admin.” Match your own access to a route:</p>
<table>
<thead>
<tr>
<th>Access or evidence available</th>
<th>Recovery route</th>
</tr>
</thead>
<tbody>
<tr>
<td>Valid WordPress recovery email</td>
<td>Enter the protected Recovery Mode session</td>
</tr>
<tr>
<td>Hosting files or PHP logs, but no recovery email</td>
<td>Identify the relevant fatal error</td>
</tr>
<tr>
<td>Identified faulty extension or recent edit</td>
<td>Make a targeted reversible change</td>
</tr>
<tr>
<td>Server fault or insufficient technical access</td>
<td>Give the evidence to an authorized administrator</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="WordPress access options" src="/img/WordPress-access-options.jpg"></p>
<p>Before you touch site files or plugin state, work in a staging copy or make sure you have a backup you can restore. WordPress keeps its data in both files and the database.</p>
<div class="callout">
<p><strong>Limit the impact on a live site.</strong> A sitewide plugin shutdown can interrupt features that still work. On an active store or membership site, make sure you can reverse each step before trying anything broad.</p>
</div>
<p><img decoding="async" alt="WordPress backup components" src="/img/WordPress-backup-components-4.jpg"></p>
<h2 id="use-the-wordpress-recovery-mode-email-if-you-have-it">Use the WordPress Recovery Mode email if you have it</h2>
<p><img decoding="async" alt="WordPress recovery email" src="/img/WordPress-recovery-email.jpg"></p>
<p>WordPress Recovery Mode gets you back into administration when a fatal error traces to a plugin or theme. WordPress 5.2 introduced it, and it emails a special recovery link to the site&#8217;s admin address.</p>
<ol>
<li>Find the genuine WordPress recovery email in the admin mailbox, including spam and filtered folders.</li>
<li>Open the protected link and log in with an administrator account.</li>
<li>Check which plugin or theme Recovery Mode flags and use the controls it offers to fix it.</li>
</ol>
<p>The <a href="https://wordpress.org/documentation/article/recovery-mode/" target="_blank" rel="noopener">WordPress Recovery Mode documentation</a> explains that WordPress can pause the flagged plugin during your recovery session.</p>
<h3>Why the recovery email can fail to arrive</h3>
<p>An April 8, 2026 <a href="https://www.reddit.com/r/Wordpress/comments/1sfmwjx/critical_error_cant_access_recovery_mode/" target="_blank" rel="noopener nofollow">r/Wordpress post</a> shows the problem: “I am a site admin but have not received an email to say what the critical error was. This happened last week as well.”</p>
<p><img decoding="async" alt="Recovery email troubleshooting" src="/img/Recovery-email-troubleshooting.jpg"></p>
<p>Recovery Mode needs two conditions. The fatal error must occur where WordPress&#8217;s handler can process it, and WordPress must tie it to a plugin or theme. Email adds more failure points: outgoing mail handling before an email plugin loads, host delivery, spam filtering and notification rate limits.</p>
<p>Don&#8217;t try to build a recovery link by guessing URL parameters. The real link carries protected recovery information. For WordPress, PHP errors, and recovery, use the procedure to <a href="https://noscript.info/wordpress/troubleshooting/#access-options">troubleshoot WordPress errors by symptom</a>.</p>
<h2 id="no-recovery-email-find-the-php-fatal-error-in-the-logs">No recovery email? Find the PHP fatal error in the logs</h2>
<p><img decoding="async" alt="WordPress fatal error logs" src="/img/WordPress-fatal-error-logs.jpg"></p>
<p>The most useful evidence is the PHP fatal error tied to the failed action. Start with the PHP or web-server error log in your hosting account. If it tells you too little and you have file access, WordPress debugging gives you a second source.</p>
<h3>Read the error that matches the failure</h3>
<p>Find the entry whose timestamp matches your failing action, then read its error class, message, file, line and stack trace.</p>
<p><img decoding="async" alt="PHP fatal log fields" src="/img/PHP-fatal-log-fields.jpg"></p>
<p>A WordPress.org support report about NGG Smart Image Search shows what this looks like:</p>
<pre><code>PHP Fatal error: Uncaught Error: Call to undefined function shell_exec()</code></pre>
<p>PHP reports an uncaught <code>Error</code> from a call to the unavailable <code>shell_exec()</code> function, and the plugin file named line 2974. That points to the plugin and your host&#8217;s PHP environment. The WordPress core file visible elsewhere in the stack trace isn&#8217;t the suspect.</p>
<h3>Configure temporary WordPress logging if necessary</h3>
<p>If host logs are missing or too thin, the <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/" target="_blank" rel="noopener">WordPress debugging documentation</a> describes a log-first setup. Find <code>wp-config.php</code> in the WordPress installation and edit any existing definitions of these constants. Don&#8217;t add duplicates. For WordPress, wp-config.php, and database settings, use the procedure to <a href="https://noscript.info/wordpress/development/wp-config/#find-wp-config">edit wp-config.php without breaking the site</a>.</p>
<pre><code>define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );</code></pre>
<p>Place the settings before WordPress&#8217;s standard configuration marker:</p>
<pre><code>/* That's all, stop editing! Happy blogging. */</code></pre>
<p><img decoding="async" alt="WordPress debug settings" src="/img/WordPress-debug-settings.jpg"></p>
<p>WordPress writes the log to <code>wp-content/debug.log</code>. Setting <code>WP_DEBUG_DISPLAY</code> to <code>false</code> keeps errors off your public pages. Repeat the failing action once, then check <code>wp-content/debug.log</code> through your file manager or SFTP for the new entry. If the action can alter live data, rely on your host&#8217;s logs or reproduce the failure in staging.</p>
<div class="callout">
<p><strong>Keep diagnostic output private.</strong> WordPress recommends debugging in development or staging. If you have to log on a live site, keep it controlled and temporary. A file like <code>debug.log</code> can contain filesystem paths or sensitive information, and turning off on-page display doesn&#8217;t protect a log that anyone can open.</p>
</div>
<p>If <code>debug.log</code> is missing or empty, WordPress logging didn&#8217;t reach the failed operation or your host recorded the error elsewhere. Go back to the PHP or web-server logs.</p>
<h2>Fix the implicated plugin, theme, or recent code change first</h2>
<p><img decoding="async" alt="WordPress plugin isolation" src="/img/WordPress-plugin-isolation.jpg"></p>
<p>When the log or a recent change points to one plugin, theme or file, reverse that one change first. Deactivate the plugin, revert the theme or custom edit, or restore the previous version if an update caused the problem. A plugin installed just before an editor failure is your first suspect, especially if the fatal entry names its code. For work involving WordPress plugins, theme conflicts, and PHP errors, follow the steps to <a href="https://noscript.info/wordpress/plugins-themes/plugin-conflicts/#when-is-a-wordpress-failure-a-plugin-or-theme-conflict">isolate WordPress plugin and theme conflicts</a>.</p>
<h3>Deactivate a specific plugin</h3>
<p>If Recovery Mode gives you dashboard access, open the flagged plugin and use its deactivation or correction controls.</p>
<p>No admin access? Open your host&#8217;s file manager or SFTP and rename the plugin&#8217;s folder. WordPress documents this approach, for example:</p>
<pre><code>/wp-content/plugins/hello-dolly/
/wp-content/plugins/hello-dolly-1/</code></pre>
<p>The second path is the same folder under a temporary name. Use the folder of the plugin you&#8217;re investigating, write down its original name and keep the files so you can reverse the change.</p>
<p><img decoding="async" alt="Plugin directory isolation" src="/img/Plugin-directory-isolation.jpg"></p>
<p>With SSH and a working WP-CLI setup, you can deactivate a named plugin with:</p>
<pre><code>wp plugin deactivate example-plugin</code></pre>
<p>Replace <code>example-plugin</code> with the plugin&#8217;s slug.</p>
<p>Deactivate all plugins only if the targeted checks found nothing.</p>
<p><img decoding="async" alt="WordPress plugin reactivation" src="/img/WordPress-plugin-reactivation.jpg"></p>
<h3>Identify the culprit after broad plugin isolation</h3>
<p>WP-CLI can deactivate all regular plugins with <code>wp plugin deactivate --all</code>. You need the same CLI access, and the command can interrupt services on a live site.</p>
<p>If the failure disappears, restore the normal plugin directory arrangement where you renamed folders, then reactivate plugins one at a time. Repeat the failing operation after each activation. If the error returns after one activation, that plugin is your suspect, or it conflicts with a plugin that&#8217;s already active.</p>
<p>Run the reactivation tests during a maintenance window. Don&#8217;t knowingly reactivate a plugin you&#8217;ve confirmed crashes a critical production operation.</p>
<p>On multisite installations, check network-activated plugins too. WP-CLI&#8217;s global <code>--skip-plugins</code> option doesn&#8217;t skip must-use plugins, which can still matter when ordinary plugin isolation fails.</p>
<p>A temporary deactivation can restore access and remove a feature your site needs, so a lasting fix means a compatible release, repaired custom code or a controlled rollback.</p>
<h2 id="when-the-log-points-to-php-or-the-hosting-environment-instead">When the log points to PHP or the hosting environment instead</h2>
<p><img decoding="async" alt="PHP failure categories" src="/img/PHP-failure-categories.jpg"></p>
<p>A PHP fatal error can come from an unavailable function, an execution-time limit, exhausted memory or faulty code. Each needs a different fix.</p>
<table>
<thead>
<tr>
<th>Error category</th>
<th>Typical diagnostic wording</th>
<th>What to check</th>
</tr>
</thead>
<tbody>
<tr>
<td>Unavailable function</td>
<td><code>Call to undefined function ...</code></td>
<td>Whether the plugin works with your host&#8217;s PHP setup</td>
</tr>
<tr>
<td>Execution-time limit</td>
<td><code>Maximum execution time ... exceeded</code></td>
<td>What the operation does and which time limit applies</td>
</tr>
<tr>
<td>Memory exhaustion</td>
<td><code>Allowed memory size ... exhausted</code></td>
<td>How much memory the failing task needs</td>
</tr>
<tr>
<td>Type or syntax failure</td>
<td><code>TypeError</code> or a PHP parse error</td>
<td>Code or dependencies that changed recently</td>
</tr>
</tbody>
</table>
<p>The error class tells you where to start. Raise a PHP limit only when the error names a resource constraint.</p>
<p><img decoding="async" alt="PHP hosting diagnostics" src="/img/PHP-hosting-diagnostics.jpg"></p>
<h3>Disabled functions and plugin compatibility</h3>
<p>In an August 2026 WordPress.org support discussion, NGG Smart Image Search v4.0.0 hit the disabled-function failure from the log example above. It happened in editor-related functionality, and the developer then supplied a fix. One participant reported that v3.4.3 had worked on the same hosting setup, which made the version change a useful lead.</p>
<p>Enabling a server-disabled function just to suit one plugin is a poor default. Check how the plugin handles the restriction, then use a supported fix or ask the developer or host about compatibility.</p>
<h3>Execution time and code changes</h3>
<p>Another WordPress.org support case described a plugin update to version 1.64 followed by this fatal message:</p>
<pre><code>PHP Fatal error: Maximum execution time of 30 seconds exceeded</code></pre>
<p>The failure appeared while changing conditions in a complex operation. The reporter said restoring plugin version 1.63 recovered that operation.</p>
<p><img decoding="async" alt="PHP execution timeout" src="/img/PHP-execution-timeout.jpg"></p>
<p>That environment included WordPress 7.0.2 and PHP 8.2.14, and the discussion also mentioned WooCommerce order editing.</p>
<h2>If the first fix fails, stop guessing and escalate with evidence</h2>
<p><img decoding="async" alt="WordPress support escalation" src="/img/WordPress-support-escalation.jpg"></p>
<p>If a targeted change makes no difference, undo that test and reassess. Another plugin, a must-use plugin, custom code, the theme or the PHP environment can be involved. Contact your host or developer when you lack the logs or permissions you need, the cause is still unclear, or further experiments would disrupt an essential production workflow.</p>
<p>If disabling ordinary plugins changes nothing, look at other loaded code and the server environment. Don&#8217;t delete WordPress or replace core files.</p>
<p><img decoding="async" alt="Failed plugin isolation" src="/img/Failed-plugin-isolation.jpg"></p>
<h3>What to send your host or developer</h3>
<ul>
<li><strong>Symptom:</strong> The exact message, the affected URL and the action that triggers it.</li>
<li><strong>Timing:</strong> When it failed and any changes made just before.</li>
<li><strong>Error:</strong> The PHP fatal message, error class and a shortened stack trace with private details removed.</li>
<li><strong>Versions:</strong> WordPress, PHP and plugin versions.</li>
<li><strong>Tests:</strong> What you changed, what happened and what you reversed.</li>
<li><strong>Restore point:</strong> Whether you have a backup covering both files and database.</li>
</ul>
<p><img decoding="async" alt="Incident evidence packet" src="/img/Incident-evidence-packet.jpg"></p>
<h3>When a backup restore is justified</h3>
<p>A complete known-good backup is your option when no targeted fix is available and the incident requires restoration. The restore point must cover a consistent set of WordPress files and database information.</p>
<p>On a site that takes orders, membership updates or new content, a restore can overwrite changes made after the backup. What you lose follows from what was written since then and how you restore. Treat a full restore as its own procedure with a final test. Don&#8217;t improvise a database overwrite in the middle of a plugin investigation.</p>
<h2>Verify the repair and remove the temporary debugging setup</h2>
<p><img decoding="async" alt="WordPress repair verification" src="/img/WordPress-repair-verification.jpg"></p>
<p>You&#8217;re done when the action that failed works again and your debug settings are off. Loading the homepage proves little when the failure involved the editor or an admin action.</p>
<p><img decoding="async" alt="WordPress acceptance checks" src="/img/WordPress-acceptance-checks.jpg"></p>
<ul>
<li><strong>Repeat the original action:</strong> Open the same editor, dashboard screen or public-page operation and confirm it completes.</li>
<li><strong>Check the site:</strong> Load a few public pages and the admin screens you use, plus any feature the affected plugin provides.</li>
<li><strong>Leave Recovery Mode:</strong> Confirm normal behavior outside the temporary recovery session.</li>
<li><strong>Clean up:</strong> Turn debug off, then secure or delete <code>debug.log</code>.</li>
</ul>
<p>Test in a normal visitor or administrator session, since caching or an existing session can hide the result.</p>
</article>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Fix the WordPress White Screen of Death</title>
		<link>https://noscript.info/wordpress/troubleshooting/white-screen/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/troubleshooting/white-screen</guid>

					<description><![CDATA[Diagnose a blank WordPress site or wp-admin screen by symptom, Recovery Mode, error logs, and safe plugin or theme tests. Know when to restore or escalate.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .urgency-now{ background: #fdecea; border-left: 4px solid #c0392b; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .urgency-soon{ background: #fff9e6; border-left: 4px solid #e0a800; padding: 0.9em 1.1em; margin: 1.2em 0; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }.usefulmix-article blockquote{ background: #f6f4ee; border-left: 4px solid #8a8377; margin: 1.4em 0; padding: 0.9em 1.1em; }.usefulmix-article blockquote strong{ display: block; margin-bottom: 0.3em; }
</style>
<div class="usefulmix-article">
<div class="short-answer">
<p>When your WordPress site or dashboard goes blank, find out which requests fail and read the recovery message or error logs, then make the smallest repair those clues support and make sure you can undo it. If you have no safe fix and no reliable recovery point, stop experimenting and call your hosting provider or administrator. Confirm that public pages, the dashboard and essential functions work before closing the incident.</p>
</div>
<p>A blank white page tells you almost nothing about what broke. WordPress calls it the White Screen of Death (WSOD). The cause can be a plugin, a theme, PHP, the database or the host.</p>
<p>Start by noting where the failure stops. A working homepage with a blank admin screen points to a different problem than a site that fails on every URL.</p>
<h2 id="identify-the-blank-screen">Find out which part of WordPress is blank</h2>
<p><img decoding="async" alt="WordPress symptom triage" src="/img/WordPress-symptom-triage.jpg"></p>
<p>A white screen describes what the visitor sees. It doesn&#8217;t point to one cause or one HTTP status. The browser can show an empty page even when the server returns <code>200</code>, and then you need to look at what the application returned. Other incidents return an error such as <code>500</code>, and a <code>502</code> points to the web server and its upstream service. A completely blank response calls for checking the actual HTTP status and PHP error log even when WordPress displays no message.</p>
<p>Open the affected URL and compare it with the homepage, another public page and <code>/wp-admin</code>. Note which ones work. Then open the browser&#8217;s Developer Tools, the Network tab, reload the failing page and check the main document request: its status and response body.</p>
<table>
<thead>
<tr>
<th>What is blank?</th>
<th>What to check</th>
<th>What to do next</th>
</tr>
</thead>
<tbody>
<tr>
<td>Public pages, but not the dashboard</td>
<td>Which URLs fail, their status, recent front-end changes</td>
<td>Read existing error logs, then test the theme or plugin you suspect</td>
</tr>
<tr>
<td><code>/wp-admin</code>, but the public site works</td>
<td>Whether login, dashboard or both fail</td>
<td>Use Recovery Mode or a method that doesn&#8217;t need the dashboard</td>
</tr>
<tr>
<td>One post or page</td>
<td>The exact URL and whether neighboring pages load</td>
<td>Look at changes to that page and matching log errors</td>
</tr>
<tr>
<td>Nearly every site URL</td>
<td>Public and admin response statuses</td>
<td>Check recovery messages and hosting or PHP logs</td>
</tr>
<tr>
<td>One browser or user session</td>
<td>How logged-in, private and other sessions differ</td>
<td>Compare logged-in and private sessions, then check the cache</td>
</tr>
<tr>
<td>Requests return <code>500</code>, <code>502</code>, or <code>503</code></td>
<td>The exact status and the failing URL</td>
<td>Diagnose the web server or PHP service</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="Browser network response" src="/img/Browser-network-response.jpg"></p>
<p>An owner in a January 7, 2026 <a href="https://www.reddit.com/r/Wordpress/comments/1q68yf9/i_need_help_regarding_the_white_screen_during_the/" target="_blank" rel="noopener nofollow">r/Wordpress discussion</a> wrote, “For the past two days, my website hasn&#8217;t allowed me to log in directly from wp-admin, but the site itself functions normally.”</p>
<p>Also load the failing page in a private or logged-out window, and on another device or account. Write down any difference.</p>
<h2 id="wordPress-recovery-mode">Use Recovery Mode if WordPress offers it</h2>
<p><img decoding="async" alt="WordPress recovery mode" src="/img/WordPress-recovery-mode.jpg"></p>
<p>WordPress added Recovery Mode in version 5.2 for qualifying fatal errors. A fully blank site can produce no recovery message or email. If you do get a genuine recovery email, open its private link. That starts an administrator recovery session where WordPress temporarily pauses the failing plugin or theme, so you can find and fix it. The <a href="https://wordpress.org/documentation/article/recovery-mode/" target="_blank" rel="noopener">WordPress Recovery Mode documentation</a> explains the process. No valid link? Go to the error logs or your hosting access instead of waiting for an email that can fail to arrive.</p>
<h2 id="preserve-state-and-evidence">Check what changed and collect the first error messages</h2>
<p><img decoding="async" alt="WordPress recovery evidence" src="/img/WordPress-recovery-evidence.jpg"></p>
<p>Before you change anything, look at what changed around the failure: plugin or theme updates, PHP settings, deployments, <a href="https://noscript.info/wordpress/maintenance/updates/#handle-php-as-a-separate-server-change">WordPress updates</a> and host maintenance. If the failure started soon after one of those changes, suspect that change first.</p>
<p>Note these four things before testing anything:</p>
<ul>
<li><strong>Failure timeline:</strong> The approximate time of the first failure and your last visit when the page worked.</li>
<li><strong>Recent changes:</strong> The update, setting or deployment closest to that time.</li>
<li><strong>Recovery state:</strong> Which files and database data your backup contains, and how you would restore it.</li>
<li><strong>Existing errors:</strong> Hosting or PHP error entries from around the failed request. Copy the relevant message and keep it private.</li>
</ul>
<p><img decoding="async" alt="Hosting error evidence" src="/img/Hosting-error-evidence.jpg"></p>
<p>A log entry that names a plugin file, a theme file, exhausted memory or a parse error tells you where to look next. The stack trace shows where the error appeared.</p>
<p>You can get an error viewer in the control panel, while a server administrator reads separate PHP or web-server logs. If none of those entries explain the blank page, turn on temporary WordPress debugging.</p>
<h2 id="enable-safe-debugging">Log the error without showing it to visitors</h2>
<p><img decoding="async" alt="WordPress debug settings" src="/img/WordPress-debug-settings-2.jpg"></p>
<p>WordPress can write temporary diagnostic information to a log and keep debug output off the page. If you can reproduce the failure on staging, debug there. In a live incident you can need temporary protected logging on production.</p>
<p>Each of the three settings does one job:</p>
<table>
<thead>
<tr>
<th>Setting</th>
<th>What it controls</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>WP_DEBUG</code></td>
<td>Turns WordPress debugging on</td>
</tr>
<tr>
<td><code>WP_DEBUG_LOG</code></td>
<td>Sends debug information to a log when debugging is on</td>
</tr>
<tr>
<td><code>WP_DEBUG_DISPLAY</code></td>
<td>Decides whether debug output appears on the page</td>
</tr>
</tbody>
</table>
<p>Keep a copy of the original <code>wp-config.php</code>. Find any existing definitions of these settings and edit them in place, above the stop-editing line. Don&#8217;t add duplicates.</p>
<p>WordPress documents this temporary configuration:</p>
<pre><code>define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );</code></pre>
<p>The last line asks PHP to stop displaying errors for the running process. Your server-level PHP configuration must also block public error display, especially for failures that happen before WordPress loads.</p>
<p><img decoding="async" alt="Private WordPress logging" src="/img/Private-WordPress-logging.jpg"></p>
<p>With the standard log destination, WordPress writes to <code>wp-content/debug.log</code>. On many installations that path sits in a web-served directory, so block public access to the file before generating sensitive diagnostic information. If your environment supports it, use a secured destination or a protected host logging facility instead.</p>
<p>Apply the settings, reload the failing request and read the private log. The <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/" target="_blank" rel="noopener">WordPress debugging documentation</a> describes these constants and how to use them.</p>
<p>If <code>debug.log</code> doesn&#8217;t appear, check the PHP or hosting error log. Early PHP startup or configuration failures stop WordPress logging from running, and some installations use a different log location. When WordPress, fatal errors, and plugin recovery need a separate check, see how to <a href="https://noscript.info/wordpress/troubleshooting/critical-error/#when-the-log-points-to-php-or-the-hosting-environment-instead">recover from a WordPress critical error</a>.</p>
<h2 id="test-plugin-or-theme">Test the plugin or theme most likely to have changed</h2>
<p><img decoding="async" alt="WordPress plugin isolation" src="/img/WordPress-plugin-isolation-2.jpg"></p>
<p>If a recent change or an error points to a particular plugin, start with that one. Test one suspect at a time. If a test changes nothing, undo it before trying the next.</p>
<h3>When the dashboard still works</h3>
<p>Deactivate the suspect plugin on the Plugins screen, then reload the page that went blank. If the page loads again, that plugin is the cause.</p>
<p>To test a theme, temporarily switch to an installed default theme. Note any changes to the site&#8217;s appearance or functions when you read the result.</p>
<p><img decoding="async" alt="WordPress theme test" src="/img/WordPress-theme-test.jpg"></p>
<p>Deactivating many plugins or changing the active theme can break checkout, forms, membership access and other live functions. Run a wider test only when you can accept that and can&#8217;t narrow the suspect down.</p>
<p>Restoring service and fixing the underlying incompatibility are separate jobs. Before putting the plugin or theme back, review its recent changes and compatibility requirements with whoever maintains it.</p>
<h2 id="recover-without-dashboard">Recover when wp-admin won&#8217;t load</h2>
<p><img decoding="async" alt="WordPress alternative access" src="/img/WordPress-alternative-access.jpg"></p>
<p>If the dashboard is blank, you can&#8217;t use the usual plugin and theme controls. Your next step follows from whether you have a hosting file manager, SFTP or SSH with WP-CLI. Change only servers you are authorized to change.</p>
<table>
<thead>
<tr>
<th>Access you have</th>
<th>Recovery method</th>
</tr>
</thead>
<tbody>
<tr>
<td>Hosting file manager</td>
<td>Temporarily rename the suspect plugin or theme folder. Note its original path and name.</td>
</tr>
<tr>
<td>SFTP</td>
<td>Run the same folder-rename test. Make sure you&#8217;re in the correct WordPress installation.</td>
</tr>
<tr>
<td>SSH with WP-CLI</td>
<td>Deactivate a plugin with the WP-CLI command. Run it from the right site directory.</td>
</tr>
<tr>
<td>No file or command access</td>
<td>Ask the host or the person who maintains the site to recover it.</td>
</tr>
</tbody>
</table>
<h3>Temporarily isolate a plugin through files</h3>
<p>When the clues point to one ordinary plugin, find its folder under <code>wp-content/plugins</code> and rename it to something easy to recognize. Write down the original name and path. WordPress can no longer load the plugin from its original folder, so you can see whether the affected screen changes.</p>
<p>If you don&#8217;t know which plugin is responsible, WordPress documents a broader test: temporarily rename the whole plugins directory. For example:</p>
<pre><code>wp-content/plugins
wp-content/plugins.hold</code></pre>
<p>The second line is the temporary name for the first. After the test, restore the original directory name. WordPress can mark ordinary plugins as deactivated while the directory is missing, so restoring the name doesn&#8217;t reactivate every plugin that was active before. Re-enable only the plugins you want.</p>
<p><img decoding="async" alt="Plugin folder restoration" src="/img/Plugin-folder-restoration.jpg"></p>
<h3>Use WP-CLI when SSH access exists</h3>
<p>With WP-CLI working, deactivate the suspect plugin:</p>
<pre><code>wp plugin deactivate PLUGIN_SLUG</code></pre>
<p>Replace <code>PLUGIN_SLUG</code> with the real identifier. If plugin loading stops the command from starting, WP-CLI documents a form that skips plugin loading:</p>
<pre><code>wp plugin deactivate PLUGIN_SLUG --skip-plugins</code></pre>
<div class="callout">
<p><code>--skip-plugins</code> skips ordinary plugin loading for that one command. It leaves must-use plugins loaded and doesn&#8217;t change activation state. The separate <code>wp plugin deactivate --all</code> command deactivates all ordinary plugins.</p>
</div>
<h3>When the active theme is suspected</h3>
<p>If the failure followed a theme change and you&#8217;ve lost dashboard access, first confirm that an installed fallback theme exists. WordPress documents a file-based test: temporarily rename the active theme&#8217;s folder, so a suitable installed default theme can take over. If the test settles nothing, or WordPress can&#8217;t pick a valid alternative, rename the folder back.</p>
<p>After each no-dashboard test, check the page that failed and the relevant admin screen.</p>
<h2 id="follow-other-error-evidence">If plugins and themes aren&#8217;t the cause, follow the next clue</h2>
<p><img decoding="async" alt="WordPress failure diagnosis" src="/img/WordPress-failure-diagnosis-2.jpg"></p>
<p>If the plugin and theme tests leave the screen unchanged, look at another layer. A failed test still narrows the search, as long as it really stopped the component from loading. When WordPress plugins, themes, and updates need a separate check, see how to <a href="https://noscript.info/wordpress/plugins-themes/#how-to-evaluate-a-plugin-or-theme-before-installing-it">manage WordPress plugins and themes</a>.</p>
<p>An owner in an April 26, 2026 <a href="https://www.reddit.com/r/Wordpress/comments/1swjyd5/white_screen_of_death/" target="_blank" rel="noopener nofollow">r/Wordpress thread</a> wrote, “My website is showing a white screen. I tried to deactivate the plugins and themes folder, but no luck.”</p>
<table>
<thead>
<tr>
<th>What you find</th>
<th>Where to look next</th>
</tr>
</thead>
<tbody>
<tr>
<td>PHP reports exhausted memory</td>
<td>PHP resource usage and host memory limits</td>
</tr>
<tr>
<td>PHP startup or early runtime error</td>
<td>Hosting PHP configuration or service</td>
</tr>
<tr>
<td>HTTP <code>500</code>, <code>502</code>, or <code>503</code></td>
<td>The web server or upstream PHP service</td>
</tr>
<tr>
<td>Database error</td>
<td>The database connection and server availability</td>
</tr>
<tr>
<td>Blank output only from a cached view</td>
<td>Cache delivery versus origin response</td>
</tr>
<tr>
<td>Possible WordPress core modification</td>
<td>WordPress core integrity</td>
</tr>
<tr>
<td>Plugin tests don&#8217;t isolate the code that is running</td>
<td>Must-use plugins or other application components. Note which loading paths your test actually excluded.</td>
</tr>
</tbody>
</table>
<p>Whatever you find, save the exact error message, the request time and the failing URL. Keep database credentials out of any notes you share.</p>
<p><img decoding="async" alt="PHP service investigation" src="/img/PHP-service-investigation.jpg"></p>
<h3 id="when-the-error-points-to-php-memory">When the error points to PHP memory</h3>
<p>Look at memory limits only when logs or measurements show memory exhaustion. Find out which operation needs the memory and what your host allows before changing the limit.</p>
<h3>When cache changes what a visitor sees</h3>
<p>If you can get an uncached or origin response, compare it with the cached view. A cached blank page can persist after the underlying problem is fixed. If the origin itself fails, diagnose the origin.</p>
<h3>When WordPress core files are suspect</h3>
<p>If damaged or altered core files are a real possibility, WP-CLI can check them:</p>
<pre><code>wp core verify-checksums</code></pre>
<p>It compares your core files against the published WordPress checksums. The command checks core files only. If you get an unexpected mismatch, confirm that the comparison uses the installed WordPress version and locale.</p>
<h2 id="choose-recovery-or-escalation">Know when to stop changing files and recover the site another way</h2>
<p><img decoding="async" alt="WordPress recovery decision" src="/img/WordPress-recovery-decision.jpg"></p>
<p>Stop experimenting when you have no plausible next test, can&#8217;t undo a change, or can&#8217;t get into the failing service. Also stop when a production site handles important transactions and an unplanned restore can overwrite newer data.</p>
<p>A managed host can inspect service logs and run a controlled recovery outside the WordPress dashboard. On a self-managed server, that job falls to an administrator who knows its PHP, database and web-server setup.</p>
<p><img decoding="async" alt="Backup restoration scope" src="/img/Backup-restoration-scope.jpg"></p>
<p>Before choosing a restore point, check which files and database contents it includes and what happened on the site afterward. A backup taken before new orders, form submissions, posts or account changes restores an earlier database state. If you need that newer information, save or reconcile it first.</p>
<h2 id="verify-wordpress-recovery">Verify the repair and close the debug session</h2>
<p><img decoding="async" alt="WordPress recovery verification" src="/img/WordPress-recovery-verification-2.jpg"></p>
<p>A working homepage is only part of a recovery. Check the page that originally failed and the functions your visitors and administrators rely on.</p>
<ul>
<li><strong>Original symptom:</strong> Open the exact page, dashboard view or login URL that went blank.</li>
<li><strong>Public pages:</strong> Load the homepage and one other public URL.</li>
<li><strong>Administration:</strong> Confirm you can log in, reach <code>/wp-admin</code> and open the affected management screen.</li>
<li><strong>Different user contexts:</strong> Repeat any logged-in, logged-out, browser or device condition that gave a different result at the start.</li>
<li><strong>Essential functionality:</strong> Check the contact form, publishing, membership login or a test-mode checkout, whichever applies.</li>
<li><strong>Error recurrence:</strong> Read the private logs for new failures from the recovered request.</li>
</ul>
<p><img decoding="async" alt="WordPress incident cleanup" src="/img/WordPress-incident-cleanup.jpg"></p>
<p>Record which plugin, theme or setting stays changed. Return the debug constants to your intended production settings, confirm that PHP errors aren&#8217;t shown publicly, and either store the temporary logs securely or delete them, depending on what you need for the incident.</p>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Diagnose WordPress 500, 502, and 503 Errors</title>
		<link>https://noscript.info/wordpress/troubleshooting/500-502-503/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/troubleshooting/500-502-503</guid>

					<description><![CDATA[Diagnose WordPress 500, 502, and 503 errors by request, CDN or server layer, and logs. Find the next check, make a reversible fix, and verify recovery.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .urgency-now{ background: #fdecea; border-left: 4px solid #c0392b; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .urgency-soon{ background: #fff9e6; border-left: 4px solid #e0a800; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }.usefulmix-article blockquote{ background: #f6f4ee; border-left: 4px solid #8a8377; margin: 1.4em 0; padding: 0.9em 1.1em; }.usefulmix-article blockquote strong{ display: block; margin-bottom: 0.3em; }
</style>
<div class="usefulmix-article">
<div class="short-answer">
<p>When WordPress returns a 500, 502, or 503 error, find the failing request and the server layer that answered it, then use the matching log entry or maintenance evidence to pick one targeted, reversible fix. If you can&#8217;t get that evidence or don&#8217;t control the server, send your host the error, URL, time, and any diagnostic clues. Retest the original failing operation before calling the site recovered.</p>
</div>
<p>Your homepage can load fine while the dashboard, an AJAX request, or a WooCommerce operation fails. Start with the one request that broke and the server message logged for it.</p>
<aside class="callout" id="audit-navigator-pg109" aria-labelledby="audit-navigator-pg109-title" data-audit-widget="route">
<h3 id="audit-navigator-pg109-title">Choose the HTTP error</h3>
<p>Pick the error you see to open its section. The links lead to existing guidance and run no test.</p>
<p><label for="audit-navigator-pg109-choice">What do you need to check?</label><br />
<select id="audit-navigator-pg109-choice"><option value="">Select a task or symptom</option><option value="#http-500">HTTP 500</option><option value="#http-502">HTTP 502</option><option value="#http-503">HTTP 503</option><option value="#response-origin">Not sure whether the CDN, server or WordPress is failing</option><option value="#find-logs">Need to collect logs before changing anything</option><option value="#verify-recovery">Need to confirm that a repair held</option></select></p>
<p id="audit-navigator-pg109-result" aria-live="polite"><a href="#" hidden>Open the relevant section</a></p>
</aside>
<p><script>
(function() {
  'use strict';
  const widget = document.getElementById('audit-navigator-pg109');
  const choice = widget.querySelector('select');
  const link = widget.querySelector('#audit-navigator-pg109-result a');
  function update() {
    const selected = choice.options[choice.selectedIndex];
    if (!selected.value) { link.hidden = true; link.removeAttribute('href'); return; }
    const anchor = selected.value.slice(1);
    if (!document.getElementById(anchor)) { link.hidden = true; link.removeAttribute('href'); return; }
    link.href = selected.value;
    link.textContent = 'Open: ' + selected.textContent;
    link.hidden = false;
  }
  choice.addEventListener('change', update);
  update();
})();
</script></p>
<h2 id="http-codes">What 500, 502, and 503 mean</h2>
<p><img decoding="async" alt="WordPress HTTP errors" src="/img/WordPress-HTTP-errors.jpg"></p>
<p>Each code describes a different kind of failure. Separate 500, 502, and 503 at the first responding layer: the application, the proxy-to-upstream connection, or service availability can each require different log evidence.</p>
<table>
<thead>
<tr>
<th>Response</th>
<th>HTTP meaning</th>
<th>First useful clue</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>500 Internal Server Error</strong></td>
<td>The server hit an unexpected condition and couldn&#8217;t complete the request.</td>
<td>An application fatal error, a web-server configuration failure, or another server-side error entry.</td>
</tr>
<tr>
<td><strong>502 Bad Gateway</strong></td>
<td>A gateway or proxy got an invalid response from its upstream.</td>
<td>The upstream destination and the gateway&#8217;s matching error message.</td>
</tr>
<tr>
<td><strong>503 Service Unavailable</strong></td>
<td>The service can&#8217;t handle the request right now, for example during maintenance or overload.</td>
<td>A maintenance indicator or evidence that the service has no capacity.</td>
</tr>
</tbody>
</table>
<p>Note the scope along with the status. Does the error hit every public page, only <code>/wp-admin/</code>, or one endpoint such as <code>/wp-admin/admin-ajax.php</code>?</p>
<p><img decoding="async" alt="Affected WordPress endpoints" src="/img/Affected-WordPress-endpoints.jpg"></p>
<h2 id="incident-record">Capture the failure before changing settings</h2>
<p><img decoding="async" alt="Server incident record" src="/img/Server-incident-record.jpg"></p>
<p>Write down one failed request in enough detail that you can find it in a log.</p>
<p>If the page shows no HTTP status, open Chrome DevTools and select Network. With recording on, repeat the failing page load or action, then click the request to read its URL and Status. A browser label such as <code>(failed)</code> or a CORS error is not an HTTP 500, 502, or 503 response.</p>
<ul>
<li><strong>Request:</strong> The exact URL or endpoint, what you were doing, and whether you were signed in.</li>
<li><strong>Response:</strong> The HTTP status, the error text on screen, and any non-sensitive CDN or hosting identifiers in the response.</li>
<li><strong>Time:</strong> The date, clock time, and time zone, so a host can match it to server logs.</li>
<li><strong>Scope and recurrence:</strong> Which requests worked, which failed, and whether the failure was constant or intermittent.</li>
<li><strong>Recent change:</strong> A plugin, theme, PHP, <code>.htaccess</code>, migration, server, or CDN change made before the symptom appeared.</li>
<li><strong>Environment:</strong> Hosting provider, managed-hosting panel or VPS access, and CDN if you use one.</li>
</ul>
<p>An error that follows a configuration edit makes that edit worth checking first.</p>
<p><img decoding="async" alt="Failure evidence checklist" src="/img/Failure-evidence-checklist.jpg"></p>
<h2 id="response-origin">Find the failing layer: CDN, server, or WordPress</h2>
<p><img decoding="async" alt="Request processing layers" src="/img/Request-processing-layers.jpg"></p>
<p>A request can pass through a CDN, an origin proxy, a web server, PHP-FPM, and WordPress before a response comes back. For a 503, <a href="https://developers.cloudflare.com/support/troubleshooting/http-status-codes/cloudflare-5xx-errors/error-503/" target="_blank" rel="noopener">Cloudflare&#8217;s 503 guidance</a> treats <code>cloudflare</code> or <code>cloudflare-nginx</code> in the error HTML as the sign that Cloudflare generated the response. In that case, go to Cloudflare support. If the error HTML lacks that text, the origin generated the response, so check your host&#8217;s server logs. Custom error pages, extra proxies, and other CDNs need provider-specific evidence.</p>
<h2 id="find-logs">Find the useful logs even if wp-admin is down</h2>
<p><img decoding="async" alt="WordPress server logs" src="/img/WordPress-server-logs.jpg"></p>
<p>Start with whatever access you have left and find the error entry logged at the time of the failed request.</p>
<p>A GoDaddy/cPanel user wrote on r/Wordpress, “I edited my .htaccess file and now my site shows a 500 error, i failed to access my site using /wp-admin and now i am completely locked-out.” The host&#8217;s file manager or support channel still works when WordPress doesn&#8217;t.</p>
<table>
<thead>
<tr>
<th>Access available</th>
<th>Specific route</th>
<th>Evidence to obtain</th>
</tr>
</thead>
<tbody>
<tr>
<td>Managed-hosting panel</td>
<td>Open the site&#8217;s application or server error-log view, if provided.</td>
<td>The entry for the failing URL at the incident time.</td>
</tr>
<tr>
<td>File manager or SFTP</td>
<td>Inspect hosting-exposed logs or the site&#8217;s configured WordPress debug-log file.</td>
<td>A matching PHP or application error, or confirmation that the host exposes no log.</td>
</tr>
<tr>
<td>Authorized VPS access</td>
<td>Use the server&#8217;s configured web-server and PHP-FPM error-log locations.</td>
<td>A gateway, service, or runtime message that matches the request.</td>
</tr>
<tr>
<td>No technical access</td>
<td>Ask the hosting operator to retrieve the web or PHP error entry.</td>
<td>The failing service and its logged message, without guessing a filesystem path.</td>
</tr>
</tbody>
</table>
<p>On managed hosting, the panel can show an application log but not the PHP-FPM service underneath. On a VPS, the web server and the PHP runtime each record part of the same failure. The timestamp and request tell you which entry belongs to your failure and which is an unrelated warning.</p>
<p><img decoding="async" alt="Hosting error log access" src="/img/Hosting-error-log-access.jpg"></p>
<h3>When a WordPress debug log helps</h3>
<p>WordPress documents <code>WP_DEBUG</code>, <code>WP_DEBUG_LOG</code>, and <code>WP_DEBUG_DISPLAY</code> in its <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/" target="_blank" rel="noopener">debugging handbook</a>. The log and display settings take effect when <code>WP_DEBUG</code> is enabled. With <code>WP_DEBUG_LOG</code> on, errors go to <code>wp-content/debug.log</code> by default, though you can configure another path. This helps with off-screen AJAX and cron errors.</p>
<p>While you diagnose, <code>WP_DEBUG_DISPLAY=false</code> keeps WordPress debugging messages off the public page. If the request fails before WordPress runs, the debug log has no matching entry. Use the server or PHP-FPM logs for that layer.</p>
<blockquote><p><strong>Can a WordPress.org login restore access to a self-hosted site&#8217;s admin?</strong></p>
<p>Your WordPress.org account and the administrator account on a self-hosted WordPress site are separate. Recover access with the site&#8217;s own credentials or through your host&#8217;s account recovery.</p>
</blockquote>
<h2 id="http-500">For a 500 error, match the log to the change</h2>
<p><img decoding="async" alt="HTTP 500 diagnosis" src="/img/HTTP-500-diagnosis.jpg"></p>
<p>An Apache directive error, a PHP fatal, and a filesystem-access error can all break a WordPress request, and each needs a different fix. Start with the message logged for the failed operation.</p>
<p>Say an Apache-based site returns 500 after an <code>.htaccess</code> edit and the Apache error log names the directive you changed. Save a copy of the current file, then restore the known-good directive or your previous configuration. WordPress&#8217;s <a href="https://developer.wordpress.org/advanced-administration/server/web-server/httpd/" target="_blank" rel="noopener">Apache configuration documentation</a> describes the file&#8217;s role and the basic WordPress rules.</p>
<p>A standalone Nginx server ignores Apache <code>.htaccess</code> directives. Its routing rules live in the Nginx configuration. A setup with both Apache and Nginx can involve both configurations.</p>
<p><img decoding="async" alt="Apache WordPress directives" src="/img/Apache-WordPress-directives.jpg"></p>
<ul>
<li>If the log shows a PHP fatal pointing to a component, find the reported file or function and the code change made just before it, then follow the WordPress critical-error recovery for that component.</li>
<li>If the message is about server configuration, find the directive it names and the server that reads it. Leave unrelated configuration alone.</li>
<li>For a permission or ownership error, identify the failing path and the account running the operation before you change any access rights. Blanket permission changes create security risks.</li>
<li>If the error is database-related, follow the separate WordPress database troubleshooting procedure once the log points there.</li>
<li>If the log reports resource exhaustion, check which resource it names before changing PHP, process, or storage limits.</li>
</ul>
<h2 id="http-502">For a 502 error, inspect the upstream connection</h2>
<p><img decoding="async" alt="Nginx upstream errors" src="/img/Nginx-upstream-errors.jpg"></p>
<p>When Nginx is the gateway to PHP-FPM, its error log shows whether the configured upstream accepted the connection and whether it returned a valid response. The <code>fastcgi_pass</code> setting can point to a TCP address or a Unix socket, depending on the server configuration. For Nginx logs, PHP errors, and HTTP responses, see how to <a href="https://noscript.info/servers/operations/logs/#find-your-web-server-log">read logs after a website failure</a>.</p>
<table>
<thead>
<tr>
<th>Observed gateway message</th>
<th>What it means and what to check</th>
</tr>
</thead>
<tbody>
<tr>
<td>Connection refused to upstream</td>
<td>The connection attempt failed. Compare the <code>fastcgi_pass</code> destination with the PHP-FPM listener and service state.</td>
</tr>
<tr>
<td><code>upstream prematurely closed connection</code></td>
<td>The upstream closed the connection before the response finished. Match the request time with the PHP-FPM and application error records.</td>
</tr>
<tr>
<td>Invalid or empty upstream response/header</td>
<td>The gateway got no valid response. Check the FastCGI response and runtime logs for the affected request.</td>
</tr>
</tbody>
</table>
<p>A gateway that waits and never gets the upstream response is a timeout, which is a 504. A 502 means the upstream sent an invalid response.</p>
<p><img decoding="async" alt="PHP FPM upstream connection" src="/img/PHP-FPM-upstream-connection.jpg"></p>
<p>In r/woocommerce, a beginner using Nginx and Plesk wrote, “I keep getting an nginx 502 errors whenever different php endpoints are called, namely for example load-scripts.php or /wp-admin/admin-ajax.php.” The same thread included this recorded message:</p>
<p><code>2026-08-19 18:34:40 [error] upstream prematurely closed connection while reading response header from upstream</code></p>
<p>The failing request was <code>POST /wp-admin/admin-ajax.php HTTP/2.0</code>.</p>
<p>The log shows the connection broke. A PHP memory limit, a plugin fault, or a killed process can each cause that, and the PHP-FPM log from the same time shows which.</p>
<p><img decoding="async" alt="PHP request error diagnosis" src="/img/PHP-request-error-diagnosis.jpg"></p>
<h2 id="http-503">For a 503 error, separate maintenance from lost capacity</h2>
<p><img decoding="async" alt="WordPress maintenance response" src="/img/WordPress-maintenance-response.jpg"></p>
<p>First work out whether WordPress itself is in maintenance mode or the responding service is out of capacity.</p>
<div class="callout">
<p>During WordPress core maintenance, the default message is “Briefly unavailable for scheduled maintenance. Check back in a minute.” The core handler can send HTTP 503 with <code>Retry-After: 600</code>.</p>
</div>
<p>The header sets 600 seconds in that handler. WordPress can also use a custom <code>wp-content/maintenance.php</code> drop-in, and hosting systems can show different maintenance responses.</p>
<table>
<thead>
<tr>
<th>Observed evidence</th>
<th>What it suggests</th>
<th>Next investigation</th>
</tr>
</thead>
<tbody>
<tr>
<td>WordPress maintenance text during an update</td>
<td>Core maintenance is on.</td>
<td>Find out whether the update is still running or was interrupted.</td>
</tr>
<tr>
<td>503 with host or runtime resource warnings</td>
<td>The service lacks capacity.</td>
<td>Inspect the host&#8217;s resource observations and the PHP-FPM pool measurements.</td>
</tr>
<tr>
<td>503 on <code>/wp-admin/</code> while public pages work</td>
<td>The problem sits on an administrative path.</td>
<td>Compare the admin request with its runtime and application records.</td>
</tr>
</tbody>
</table>
<p>Don&#8217;t delete a maintenance marker just because it exists. Confirm the update&#8217;s state first, then use the maintenance-specific recovery.</p>
<p><img decoding="async" alt="PHP capacity measurements" src="/img/PHP-capacity-measurements.jpg"></p>
<h3>Reading PHP-FPM capacity evidence</h3>
<p>If the PHP-FPM status interface is enabled and secured, <a href="https://www.php.net/manual/en/fpm.status.php" target="_blank" rel="noopener">PHP&#8217;s FPM status documentation</a> describes <code>listen queue</code>, <code>active processes</code>, <code>idle processes</code>, <code>slow requests</code>, and <code>max children reached</code>. A nonzero listen queue means requests were waiting for a free process at the time you looked.</p>
<p>A <code>max children reached</code> value of <code>0</code> means the pool hasn&#8217;t hit that maximum in the recorded period. Any value of <code>1</code> or more means it has hit it at least once since the last restart. That is history. It doesn&#8217;t show the pool is saturated now, and it doesn&#8217;t give you a safe new value for <code>pm.max_children</code>.</p>
<h2 id="reversible-fix">Make one reversible fix, not five guesses</h2>
<p><img decoding="async" alt="Reversible WordPress changes" src="/img/Reversible-WordPress-changes.jpg"></p>
<p>Pick the smallest change the logs support. Prepare a rollback before touching a production site, especially if other functions must stay up. For systemd, systemctl, and journalctl, see how to <a href="https://noscript.info/servers/operations/systemctl/#verify-service">inspect systemd services and logs</a>.</p>
<p>On r/Wordpress, a managed WooCommerce operator facing persistent 503 errors wrote, “Honestly, I can&#8217;t risk breaking this more.” Bulk plugin deactivation can break checkout, payment, or login on an active store.</p>
<ul>
<li><strong>Match the fix to the log:</strong> Name the exact setting, code component, maintenance operation, or service fault the diagnosis points to.</li>
<li><strong>Keep the old version:</strong> Keep the previous configuration or component version and a way to restore it. If the change affects the database, you also need a usable database backup, not just the site files.</li>
<li><strong>One change:</strong> Apply one change and check its effect before making a second. If you combine a PHP upgrade, a plugin change, and a server restart, you can&#8217;t tell which one affected the response.</li>
<li><strong>Your host or admin:</strong> Ask your server administrator or managed-hosting provider to make service, socket, resource, and runtime changes that go beyond your account&#8217;s access.</li>
</ul>
<p><img decoding="async" alt="Production rollback checklist" src="/img/Production-rollback-checklist.jpg"></p>
<p>For a severe outage, a host-managed restore of a known-good state is an option, provided you understand its effects and the rollback.</p>
<h2 id="verify-recovery">Verify recovery and know when to call the host</h2>
<p><img decoding="async" alt="WordPress recovery testing" src="/img/WordPress-recovery-testing-2.jpg"></p>
<p>Repeat the failing URL or workflow in a safe test. Use the exact operation that failed, not a different page. If the next step involves WordPress, PHP errors, and recovery, see how to <a href="https://noscript.info/wordpress/troubleshooting/#recovery-test">troubleshoot WordPress errors by symptom</a>.</p>
<ul>
<li>Confirm the admin action, AJAX operation, or business process completes as expected. Don&#8217;t run test purchases that affect live customers.</li>
<li>Compare the new attempt with the same server or application log to see whether the failure continues.</li>
<li>For an intermittent failure, keep watching under the conditions where it recurred.</li>
</ul>
<p><img decoding="async" alt="Affected endpoint verification" src="/img/Affected-endpoint-verification.jpg"></p>
<h3>A useful hosting-support handoff</h3>
<p>If the failing system is beyond your access, send your host the domain, failing URL or endpoint, status and visible message, incident time and time zone, affected operations, hosting and CDN setup, a sanitized log extract if you have one, and any change you already tried. Say which public or logged-in functions still work. Remove cookies, authentication headers, credentials, and customer information from anything you share.</p>
<p>For a Cloudflare-generated 503, Cloudflare&#8217;s support procedure can also ask for the site&#8217;s <code>/cdn-cgi/trace</code> output. Send that privately.</p>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Fix “Error Establishing a Database Connection” in WordPress</title>
		<link>https://noscript.info/wordpress/troubleshooting/database-error/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/troubleshooting/database-error</guid>

					<description><![CDATA[Find the cause of a WordPress database connection error. Check credentials, MySQL errors, Docker readiness, and when to repair or restore.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .urgency-now{ background: #fdecea; border-left: 4px solid #c0392b; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .urgency-soon{ background: #fff9e6; border-left: 4px solid #e0a800; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }.usefulmix-article blockquote{ background: #f6f4ee; border-left: 4px solid #8a8377; margin: 1.4em 0; padding: 0.9em 1.1em; }.usefulmix-article blockquote strong{ display: block; margin-bottom: 0.3em; }
  </style>
<div class="usefulmix-article">
<div class="short-answer">
<p>To fix “Error establishing a database connection” in WordPress, confirm which database the site is configured to use, then test access to it before repairing tables or restoring a backup, because the error that test returns tells you which fix to apply. If a site that used to work fails now and then, check database availability, disk space, and connection limits before changing credentials. After the fix, test database-backed functions and watch for the error to return.</p>
</p></div>
<h2 id="what-error-establishing-a-database-connection-means">What “Error Establishing a Database Connection” means</h2>
<p>  <img decoding="async" alt="WordPress database error" src="/img/WordPress-database-error.jpg"></p>
<p>WordPress loads much of its site data, including posts and settings, from its database. This error means it can&#8217;t establish or use the configured connection. The message doesn&#8217;t tell you whether any content is lost. A different message, “One or more database tables are unavailable,” points to a table problem instead. “I really hope that i can get back all the edits that were made on the website last night. It took hours. :(” That&#8217;s what a poster in r/Wordpress wrote after a recently customized site stopped loading.</p>
<h2>Before you change anything, find out when and where it failed</h2>
<p>  <img decoding="async" alt="First failure triage" src="/img/First-failure-triage.jpg"></p>
<p>Answer three questions first. Did the installation ever work? Does every request fail? What access do you have to the hosting environment?</p>
<table>
<thead>
<tr>
<th>What you observe</th>
<th>Where to start</th>
<th>What to check</th>
</tr>
</thead>
<tbody>
<tr>
<td>New installation or recent migration</td>
<td>The database, account, and destination host you intended</td>
<td>Compare them with the active WordPress configuration</td>
</tr>
<tr>
<td>Previously working site, consistently unavailable</td>
<td>Recent changes and the database service status</td>
<td>Test the configured connection</td>
</tr>
<tr>
<td>Error comes and goes</td>
<td>Failure times and resource conditions</td>
<td>Check server health</td>
</tr>
<tr>
<td>Managed or shared hosting</td>
<td>Your provider&#8217;s database details and diagnostics</td>
<td>Use the hosting panel or contact provider support</td>
</tr>
<tr>
<td>Self-managed Linux VPS</td>
<td>Whether the database service is running</td>
<td>Read the logs and test database access on the server</td>
</tr>
<tr>
<td>Docker Compose deployment</td>
<td>Database readiness and the settings the containers run with</td>
<td>Work through the Docker Compose section</td>
</tr>
</tbody>
</table>
<p>“The issue turned out to be I was using 100% of available storage space on my digital ocean droplet,” an r/Wordpress poster wrote after investigating a website outage.</p>
<div class="callout">
      </div>
<h2>Check the database settings WordPress is actually using</h2>
<p>  <img decoding="async" alt="Database connection settings" src="/img/Database-connection-settings.jpg"></p>
<p>Start with the values WordPress actually uses, especially after a migration or deployment change.</p>
<p>The <a href="https://developer.wordpress.org/apis/wp-config-php/" target="_blank" rel="noopener">WordPress configuration reference</a> defines four central settings:</p>
<table>
<thead>
<tr>
<th>Setting</th>
<th>Purpose</th>
<th>What must match</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>DB_NAME</code></td>
<td>Names the selected database</td>
<td>The intended database on the selected server</td>
</tr>
<tr>
<td><code>DB_USER</code></td>
<td>Identifies the database account</td>
<td>The account this installation is allowed to use</td>
</tr>
<tr>
<td><code>DB_PASSWORD</code></td>
<td>Authenticates that account</td>
<td>The account&#8217;s current password</td>
</tr>
<tr>
<td><code>DB_HOST</code></td>
<td>Defines the connection endpoint</td>
<td>The correct hostname, plus the port or socket if one applies</td>
</tr>
</tbody>
</table>
<p>The database name and account name are different things. A valid account can still lack access to the database WordPress asks for.</p>
<p>On a conventional installation, read these values in <code>wp-config.php</code>. Some deployments generate their configuration from runtime environment variables. In those, an edited example file doesn&#8217;t control the running application&#8217;s settings.</p>
<p>  <img decoding="async" alt="WordPress host configuration" src="/img/WordPress-host-configuration.jpg"></p>
<p>Look closely at <code>DB_HOST</code>. WordPress accepts hostnames with port or Unix socket information when you need it. <code>localhost</code> and <code>127.0.0.1</code> can select different connection mechanisms.</p>
<p>Compare the active values with the database details from your host or deployment configuration. Fix any mismatch, and keep the previous configuration so you can roll back.</p>
<div class="callout">
<p><strong>Protect database credentials:</strong> Never put passwords in publicly accessible PHP diagnostic files, screenshots, support messages, or exposed command output.</p>
</p></div>
<h2>Test the connection and capture the actual database error</h2>
<p>  <img decoding="async" alt="MySQL connection test" src="/img/MySQL-connection-test.jpg"></p>
<p>Test the connection with the same details WordPress uses. The test shows whether your database account can reach and use the selected database.</p>
<ul>
<li><strong>Managed hosting:</strong> Use your provider&#8217;s database interface or diagnostic tool. Note which database and account you test.</li>
<li><strong>Linux VPS:</strong> Use a restricted database client from the server environment and keep its error message.</li>
<li><strong>WP-CLI:</strong> If WP-CLI and the database client tools are installed, run a read-only query using the site&#8217;s configuration.</li>
</ul>
<p>For WP-CLI, the <a href="https://developer.wordpress.org/cli/commands/db/query/" target="_blank" rel="noopener">WP-CLI database query command</a> includes an example that returns the selected default database:</p>
<pre><code>wp db query 'SELECT DATABASE();'</code></pre>
<p>Run it from the intended WordPress installation. If the result names your database, the connection works and can run the query against its selected database. An authentication, transport, or database-selection error tells you where to look next. The MySQL <code>DATABASE()</code> function returns <code>NULL</code> if the connection has no selected default database.</p>
<p><code>wp db check</code> is a separate command. It runs <code>mysqlcheck --check</code> with your WordPress configuration and checks tables, so use it for table integrity problems, not for this connection test.</p>
<p>  <img decoding="async" alt="Database connection results" src="/img/Database-connection-results.jpg"></p>
<p>Database login and database selection need a successful connection with the right account and target database. A MySQL client connected to another database instance can succeed while WordPress still can&#8217;t connect to its configured target. For work involving MySQL, database users, and permissions, follow the steps to <a href="https://noscript.info/servers/databases/mysql-users/#connect-as-the-account">check MySQL user credentials and grants</a>.</p>
<h2>Match a persistent connection error to its fix</h2>
<p>  <img decoding="async" alt="Database error codes" src="/img/Database-error-codes.jpg"></p>
<p>Login, access to a named database, and the connection itself are three separate stages, and the error code tells you which one failed.</p>
<p>The <a href="https://dev.mysql.com/doc/mysql-errors/8.4/en/server-error-reference.html" target="_blank" rel="noopener">MySQL 8.4 server error reference</a> lists errors the server reports. Its Client Error Message Reference covers connection errors that client libraries report:</p>
<table>
<thead>
<tr>
<th>Error</th>
<th>Meaning</th>
<th>Next action</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>1045</code> (Access denied)</td>
<td>The server rejected the account&#8217;s login, or the host you connect from isn&#8217;t permitted for that account</td>
<td>Compare the configured account, password, and allowed connecting host</td>
</tr>
<tr>
<td><code>1044</code> (Database access denied)</td>
<td>The account lacks access to the requested database</td>
<td>Check the account&#8217;s permissions on the named database</td>
</tr>
<tr>
<td><code>1049</code> (Unknown database)</td>
<td>The requested database name is not recognized on that server</td>
<td>Check the database name, the target instance, and whether the database exists</td>
</tr>
<tr>
<td><code>2002</code> or <code>2003</code> (Cannot connect)</td>
<td><code>2002</code> concerns a local socket connection, <code>2003</code> concerns a specified host and port</td>
<td>For <code>2002</code>, check the socket and the local service. For <code>2003</code>, check the host, port, service, and network path</td>
</tr>
<tr>
<td><code>1040</code> (Too many connections)</td>
<td>The database server has reached a connection-capacity limit</td>
<td>Check server load and connection limits</td>
</tr>
</tbody>
</table>
<p>Find the row for your error before changing any setting.</p>
<p>  <img decoding="async" alt="MySQL error diagnosis" src="/img/MySQL-error-diagnosis-2.jpg"></p>
<h3>If the account is rejected</h3>
<p>With <code>1045</code>, either the password is wrong or the account isn&#8217;t allowed to log in from that source host. Check the configured account and the hosts it can connect from before changing anything.</p>
<p>A client that logs in successfully can still hit a database-level privilege rejection, such as <code>1044</code>. Keep the two errors apart when you check account grants. For work involving WordPress, PHP errors, and recovery, follow the steps to <a href="https://noscript.info/wordpress/troubleshooting/#symptom-routes">troubleshoot WordPress errors by symptom</a>.</p>
<h3>If WordPress requests an unknown database</h3>
<p>With <code>1049</code>, confirm which database instance received the request and whether your database exists on it. After a migration, the active configuration can still point to a name from the previous host, or to a destination setup that isn&#8217;t finished.</p>
<h3>If the connection cannot reach the server</h3>
<p>A <code>2002</code> or <code>2003</code> puts the problem at the service or the connection path. The failing endpoint can be a local socket, a TCP hostname and port, or an address the application&#8217;s environment can&#8217;t reach.</p>
<p>After you fix the mismatch, repeat the test. If the error changes, a different stage is failing now.</p>
<h2>If the site was working or the error comes and goes, check server health</h2>
<p>  <img decoding="async" alt="Database service health" src="/img/Database-service-health.jpg"></p>
<p>For errors that come and go, look at the server while the failure happens. MySQL or MariaDB can become temporarily unavailable, run short of a resource, or reject connections once capacity runs out.</p>
<p>One poster in r/Wordpress running WordPress and MariaDB in Docker described the symptom: “However, after refreshing the page a few times sometimes the website will load again (live site, not cached).”</p>
<p>On a self-managed VPS, check the database service status and the error logs around the failed requests.</p>
<h3 id="what-to-look-for">What to look for</h3>
<ul>
<li><strong>Service availability:</strong> Was the database process accepting connections when WordPress failed?</li>
<li><strong>Database logs:</strong> Look for errors tied to the failed requests or to unexpected restarts.</li>
<li><strong>Disk space:</strong> Check free space on the filesystem the database and its operations use.</li>
<li><strong>Connection pressure:</strong> Compare rejected connections with the server&#8217;s limits during the incident.</li>
</ul>
<p>  <img decoding="async" alt="MySQL connection capacity" src="/img/MySQL-connection-capacity.jpg"></p>
<p>MySQL documents <code>1040</code>, “Too many connections,” for a server that has used up its client connection capacity.</p>
<p>If a restart brings the database back for a while, look at the errors and resource use before the restart to find what keeps causing the failure. For MySQL, SQL dumps, and database recovery, use the procedure to <a href="https://noscript.info/servers/databases/mysql-backup/#check-your-database-before-the-dump">back up and restore a MySQL database</a>.</p>
<p>On shared hosting, you can&#8217;t read privileged database logs or restart the service yourself. Ask your provider to check them.</p>
<h2>Docker Compose: check database readiness, service names, and persistent data</h2>
<p>  <img decoding="async" alt="Docker Compose readiness" src="/img/Docker-Compose-readiness.jpg"></p>
<p>A running Docker container can still be waiting for its database to become ready. WordPress also needs the right service address and the credentials of the database that&#8217;s already been initialized.</p>
<p>In r/selfhosted, a poster starting WordPress with Docker Compose put it this way: “I have waited as long as 24 hours trying to get it to launch but it never moves from that page.”</p>
<p>Docker Compose can wait for a dependency marked <code>service_healthy</code>, which means its configured health check passed. Read the database logs and look at what the check actually tests to judge readiness. A healthy result reflects that condition, so you still need to run the connection test for WordPress&#8217;s account and selected database.</p>
<h3>Match the service address to the Compose network</h3>
<p>When WordPress and its database run in separate containers, the database host must name the database&#8217;s endpoint on their network. Inside the WordPress container, <code>localhost</code> refers to that container&#8217;s own environment.</p>
<p>Compare the application&#8217;s database target with the database service defined in Compose. Check the database name and account the running installation uses.</p>
<p>  <img decoding="async" alt="Docker database persistence" src="/img/Docker-database-persistence.jpg"></p>
<h3>Keep the initialized database data intact</h3>
<p>Initialization environment variables don&#8217;t reconfigure a MySQL database that already sits in a populated data directory. A password you changed in an environment file therefore won&#8217;t match the credentials that remain in the existing database.</p>
<p>Find the persistent data volume attached to the active database service before modifying its configuration or storage.</p>
<div class="callout">
<p><strong>Preserve the database volume:</strong> Deleting or recreating a populated database volume can destroy WordPress content.</p>
</p></div>
<h2>When to repair, restore, or contact the host</h2>
<p>  <img decoding="async" alt="Repair restore decisions" src="/img/Repair-restore-decisions.jpg"></p>
<p>Repair modifies database tables. Restoration recovers data from an existing backup. Before doing either, check the connection result and see what stored data you can still read.</p>
<table>
<thead>
<tr>
<th>What you see</th>
<th>What to do</th>
<th>Rule</th>
</tr>
</thead>
<tbody>
<tr>
<td>Credentials, endpoint, or service connection fails</td>
<td>Fix access or bring the service back</td>
<td>Don&#8217;t repair tables for a connection failure</td>
</tr>
<tr>
<td>Database connects, but required tables are unavailable or damaged</td>
<td>Check table integrity, then repair only the affected tables</td>
<td>Save recoverable data first</td>
</tr>
<tr>
<td>Required data is missing or unusable, and a suitable backup exists</td>
<td>Consider restoring the backup</td>
<td>Check what the backup covers and what changed after it</td>
</tr>
<tr>
<td>Necessary server-side information is inaccessible</td>
<td>Escalate to hosting support or the server administrator</td>
<td>Send the exact error and the timeline</td>
</tr>
</tbody>
</table>
<p>  <img decoding="async" alt="Database repair prerequisites" src="/img/Database-repair-prerequisites.jpg"></p>
<h3>When WordPress database repair makes sense</h3>
<p>Before running repair, make sure you have a recoverable backup or preserved copy of the current database and site files. If database access blocks a safe backup, ask your host or server administrator about recovery options before altering tables.</p>
<p>WordPress has a repair facility controlled by <code>WP_ALLOW_REPAIR</code>, with its interface at <code>/wp-admin/maint/repair.php</code>. The <a href="https://developer.wordpress.org/advanced-administration/wordpress/wp-config/" target="_blank" rel="noopener">WordPress repair documentation</a> explains that the interface requires no logged-in user while repair mode is enabled.</p>
<p>Use this feature only to repair tables you&#8217;ve confirmed are damaged, and remove or disable <code>WP_ALLOW_REPAIR</code> as soon as you finish. Know which database and tables are affected before starting.</p>
<h3>Before restoring a backup</h3>
<p>A complete WordPress backup includes the site&#8217;s files and database.</p>
<p>Check the backup&#8217;s contents and recovery point before overwriting production data. Restoring an older database replaces any posts, settings, or other changes made after the backup was created.</p>
<p>  <img decoding="async" alt="Backup recovery options" src="/img/Backup-recovery-options.jpg"></p>
<h3>When to hand it to your hosting provider</h3>
<p>If you can&#8217;t reach service health, privileged logs, or database account settings, give your provider a short incident report:</p>
<ul>
<li><strong>Time and behavior:</strong> When the failure began, when the site last worked, and whether it comes and goes.</li>
<li><strong>Deployment:</strong> Whether it&#8217;s a new installation, a recent migration, or a site that worked before.</li>
<li><strong>Test result:</strong> The exact database error and how you ran the test.</li>
<li><strong>Changes made:</strong> The configuration edits or recovery attempts you&#8217;ve already tried.</li>
</ul>
<h2>Verify the site is back and that the error stays gone</h2>
<p>  <img decoding="async" alt="WordPress recovery checks" src="/img/WordPress-recovery-checks.jpg"></p>
<p>A cached public page can look normal while database-backed requests still fail, so check more than the front page.</p>
<p>Run these checks after your fix:</p>
<ul>
<li>Open a public page and the WordPress admin area. The page should behave as expected, and the admin area should retrieve site information.</li>
<li>Repeat the action that showed the error, and run one non-cached action that needs database access. If you ran a connection test, confirm it no longer fails.</li>
<li>For intermittent failures, compare later errors and service behavior with the original failure pattern.</li>
</ul>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>WordPress Not Sending Emails? Diagnose the Failure First</title>
		<link>https://noscript.info/wordpress/troubleshooting/email/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/troubleshooting/email</guid>

					<description><![CDATA[Trace missing WordPress emails from notification triggers to mailer logs and the recipient inbox. Fix the failed step and retest the original message.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .urgency-now{ background: #fdecea; border-left: 4px solid #c0392b; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .urgency-soon{ background: #fff9e6; border-left: 4px solid #e0a800; padding: 0.9em 1.1em; margin: 0.8em 0; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }.usefulmix-article blockquote{ background: #f6f4ee; border-left: 4px solid #8a8377; margin: 1.4em 0; padding: 0.9em 1.1em; }.usefulmix-article blockquote strong{ display: block; margin-bottom: 0.3em; }
</style>
<div class="usefulmix-article">
<div class="short-answer">
<p>To fix WordPress emails that don&#8217;t arrive, follow the original notification through its trigger, WordPress, the sending service, and the intended mailbox, fix the first stage that fails, then send that same notification again. If the receiving mail server already accepted the message, look at mailbox filtering or the recipient&#8217;s mail administrator before changing your WordPress mailer. Begin by working out whether the problem hits every message, one notification type, or one recipient.</p>
</div>
<h2 id="email-failure-pattern">Start with the pattern: which WordPress emails fail?</h2>
<p><img decoding="async" alt="WordPress email symptoms" src="/img/WordPress-email-symptoms.jpg"></p>
<p>A missing password-reset email and a missing contact-form notification look the same to the person waiting for them. They follow different paths. Before you touch your mail settings, pin down what stopped working. Trace one test message from the WordPress action through its mail transport, authentication and DNS records, then check the receiving mailbox.</p>
<p>Write down four things: the type of email, its recipient, when it last worked, and what changed around that time. A hosting move, a plugin update, or a new mail service narrows the search. Timing alone leaves the cause open.</p>
<table>
<thead>
<tr>
<th>What you observe</th>
<th>What it points to</th>
<th>Where to investigate</th>
</tr>
</thead>
<tbody>
<tr>
<td>Every WordPress email seems to fail</td>
<td>The shared sending path</td>
<td>WordPress mail attempt</td>
</tr>
<tr>
<td>A form submits, but no notice arrives</td>
<td>Form processing and email sending are separate steps</td>
<td>Form configuration</td>
</tr>
<tr>
<td>SMTP tests work, but form notifications fail</td>
<td>The test and the form use different application paths</td>
<td>Form notification settings</td>
</tr>
<tr>
<td>The mailer reports a connection or authentication error</td>
<td>Transport or provider submission failed</td>
<td>Exact mailer error</td>
</tr>
<tr>
<td>Sender authentication fails</td>
<td>Domain identity or authentication needs attention</td>
<td>From, SPF, DKIM, DMARC</td>
</tr>
<tr>
<td>Provider reports Delivered, but the inbox is empty</td>
<td>The receiving side handled the message</td>
<td>Recipient mailbox</td>
</tr>
<tr>
<td>Only one recipient misses messages</td>
<td>A problem specific to that destination</td>
<td>Recipient filtering</td>
</tr>
<tr>
<td>Email failed after a hosting migration</td>
<td>Website and mail responsibilities changed</td>
<td>Hosting and routing</td>
</tr>
<tr>
<td>Only order or password-reset messages fail</td>
<td>The notification trigger</td>
<td>Application notification</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="Email troubleshooting routes" src="/img/Email-troubleshooting-routes.jpg"></p>
<p>If WooCommerce order notifications arrive while your contact-form messages disappear, the problem sits in the form-specific path. If every type of WordPress message fails, look at the shared mail path.</p>
<h2 id="wordpress-mail-attempt">Find out whether WordPress tried to send the message</h2>
<p><img decoding="async" alt="WordPress mail handoff" src="/img/WordPress-mail-handoff.jpg"></p>
<p>A thank-you screen can appear even when the form created no email.</p>
<p>WordPress sends mail through <code>wp_mail()</code>, which uses PHPMailer underneath. The <a href="https://developer.wordpress.org/reference/functions/wp_mail/" target="_blank" rel="noopener">WordPress wp_mail() documentation</a> states that a successful return from the function doesn&#8217;t prove the recipient received the message.</p>
<p>WordPress also gives you two hooks:</p>
<ul>
<li><strong><code>wp_mail_failed</code>:</strong> Reports failures in the PHPMailer mail path.</li>
<li><strong><code>wp_mail_succeeded</code>:</strong> Reports success in that same path.</li>
</ul>
<h3>Track one original notification</h3>
<p>Trigger one identifiable instance of the notification that originally failed. Submit the affected contact form with test details, or start a password reset.</p>
<p><img decoding="async" alt="Mail event diagnostics" src="/img/Mail-event-diagnostics.jpg"></p>
<p>Look for that event in your WordPress mail log, plugin diagnostics, or application error output.</p>
<p>You&#8217;ll end up with one of three outcomes:</p>
<ul>
<li><strong>WordPress tried to send:</strong> WordPress or its mailer recorded an attempt to process the message.</li>
<li><strong>WordPress logged an error:</strong> An error identifies a failure during mail processing.</li>
<li><strong>The logs don&#8217;t say:</strong> Your diagnostic tools hold too little information about that event.</li>
</ul>
<p>The third outcome needs care. A missing entry in a logging plugin means WordPress skipped the send only if you know what the plugin captures and how it&#8217;s configured. If you have no record you can trust, turn on mail logging, trigger the notification again, and check the new entry.</p>
<h2 id="smtp-test-form-failure">When SMTP tests work but contact forms still fail</h2>
<p><img decoding="async" alt="Contact form settings" src="/img/Contact-form-settings.jpg"></p>
<p>An SMTP test can succeed while the real contact form stays broken. The test uses one mail path and one destination. The form has its own notification settings and its own trigger.</p>
<p>An Elementor administrator on r/elementor wrote: “I tried Wp-smtp using office settings, the plugin sent a successful email but the forms continue to not send.”</p>
<p>Next, check the form&#8217;s notification settings:</p>
<ul>
<li><strong>Notification enabled:</strong> Is the form set up to produce the email?</li>
<li><strong>Recipient:</strong> Does the notification go to the right mailbox?</li>
<li><strong>Sender and reply addresses:</strong> Are From and Reply-To set for their separate purposes?</li>
<li><strong>Suppression:</strong> Does the form plugin have a setting that blocks actual mail transmission?</li>
</ul>
<p>Contact Form 7 has two checks worth making in Additional Settings. With <code>demo_mode: on</code>, the form returns a successful response but skips the email. With <code>skip_mail: on</code>, sending is suppressed, but other form activity, including submission storage through Flamingo, can continue. Both are documented in the <a href="https://contactform7.com/additional-settings/" target="_blank" rel="noopener">Contact Form 7 additional settings guide</a>.</p>
<p><img decoding="async" alt="Form notification options" src="/img/Form-notification-options.jpg"></p>
<p>A form plugin can keep submitted entries even when its email notification fails.</p>
<p>Fix any mismatch you find in the form&#8217;s settings. Note the old value first so you can undo the change if the diagnosis turns out wrong. When WordPress, PHP errors, and recovery need a separate check, see how to <a href="https://noscript.info/wordpress/troubleshooting/#failure-scope">troubleshoot WordPress errors by symptom</a>.</p>
<h2 id="smtp-provider-errors">Read the SMTP or mail-provider error before changing settings</h2>
<p><img decoding="async" alt="SMTP provider errors" src="/img/SMTP-provider-errors.jpg"></p>
<p>When WordPress tried to send, the transport or provider can tell you what stopped it. A connection problem, rejected credentials, and an unauthorized sender each need a different fix.</p>
<p>Find the matching entry in your mailer&#8217;s error log or your sending provider&#8217;s activity records, and read the exact message.</p>
<table>
<thead>
<tr>
<th>Error or status</th>
<th>What it means</th>
<th>Fix</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>SMTP Error: connect() failed</code></td>
<td>The SMTP connection failed</td>
<td>Check the configured endpoint and your host&#8217;s restrictions</td>
</tr>
<tr>
<td><code>SMTP Error: Could not authenticate</code></td>
<td>The server was reached, but authentication failed</td>
<td>Review the service&#8217;s credentials or authentication setup</td>
</tr>
<tr>
<td><code>SMTP Error: Data not accepted</code></td>
<td>The SMTP server rejected the submitted message data</td>
<td>Read the provider&#8217;s rejection details and check sender or message restrictions</td>
</tr>
<tr>
<td>Sender rejected or unauthorized</td>
<td>The sending identity wasn&#8217;t authorized</td>
<td>Check the sender&#8217;s verification or authorization requirements</td>
</tr>
<tr>
<td>Accepted for processing</td>
<td>The provider accepted the message at the reported stage</td>
<td>Continue with the provider&#8217;s delivery events</td>
</tr>
<tr>
<td>Outcome unknown</td>
<td>The records don&#8217;t show whether submission succeeded</td>
<td>Use the selected service&#8217;s diagnostic documentation</td>
</tr>
</tbody>
</table>
<p>The first three error strings are examples from Gravity Forms troubleshooting. Their categories hold for other plugins too, but the wording differs by SMTP integration and provider.</p>
<p><img decoding="async" alt="Mailer error classification" src="/img/Mailer-error-classification.jpg"></p>
<div class="callout">
<p><strong>Hosting-specific example:</strong> WP Engine documents restrictions on outbound SMTP port 25.</p>
</div>
<p>Keep SMTP credentials, API keys, and sensitive logs out of public support posts.</p>
<h2 id="sender-authentication">Check the From address, SPF, DKIM and DMARC</h2>
<p><img decoding="async" alt="Email domain authentication" src="/img/Email-domain-authentication.jpg"></p>
<p>A message can reach the sending service and still run into sender-identity problems. Read the From address, the authenticated sending domain, and the recipient&#8217;s authentication checks together.</p>
<p>From shows the sender to the recipient. Reply-To tells the email client where replies go.</p>
<p>Say a visitor enters <code>visitor@otherdomain.example</code> in your contact form. If your site sends the notification with that address in From, your mail service is trying to send for a domain it isn&#8217;t authorized to use. Put a site-domain address in From and the visitor&#8217;s address in Reply-To. Replies still reach the visitor, and you aren&#8217;t impersonating them.</p>
<h3>What SPF, DKIM and DMARC do</h3>
<ul>
<li><strong>SPF:</strong> Lets a domain list its authorized sending systems in DNS.</li>
<li><strong>DKIM:</strong> Authenticates a message with a cryptographic signature from the signing domain.</li>
<li><strong>DMARC:</strong> Checks whether the domain in the visible From address aligns with a domain authenticated through SPF or DKIM, according to the domain&#8217;s DMARC rules.</li>
</ul>
<p>An SPF pass for one domain doesn&#8217;t mean the message passes DMARC alignment.</p>
<p><img decoding="async" alt="Sender identity alignment" src="/img/Sender-identity-alignment.jpg"></p>
<p>Google&#8217;s <a href="https://support.google.com/mail/answer/81126?hl=en" target="_blank" rel="noopener">Email Sender Guidelines</a> set different requirements by sender category. Every sender to Gmail needs SPF or DKIM. Senders that meet Google&#8217;s published bulk-sender threshold need SPF, DKIM, and DMARC.</p>
<h3>Compare your sending identity</h3>
<p>Compare the From domain you&#8217;ve configured with the domain your sending service authorizes and authenticates. Check the provider&#8217;s published DNS instructions against your SPF, DKIM, and DMARC records.</p>
<p>If a message arrives anywhere in a Gmail mailbox, Gmail&#8217;s Show original feature shows its authentication results in the headers.</p>
<p>Change DNS records only when your configuration and the provider&#8217;s requirements show a mismatch. Replacing unrelated entries adds new failure points and doesn&#8217;t explain the original problem.</p>
<h2 id="recipient-side-delivery">If the provider says “Delivered,” check the receiving side</h2>
<p><img decoding="async" alt="Recipient mailbox filtering" src="/img/Recipient-mailbox-filtering.jpg"></p>
<p>A sending provider&#8217;s Delivered status can mean the recipient&#8217;s mail server accepted the message. Final placement in the Inbox is a separate outcome. Postmark&#8217;s <a href="https://postmarkapp.com/support/article/1267-why-didn-t-this-recipient-receive-my-message" target="_blank" rel="noopener">delivery-status documentation</a> describes this distinction.</p>
<p>A poster on r/Wordpress posted an update about a nonprofit site&#8217;s missing notifications: “It seems that emails were coming through after all, but they had suddenly started going into spam.”</p>
<p><img decoding="async" alt="Receiving mailbox outcomes" src="/img/Receiving-mailbox-outcomes.jpg"></p>
<p>Check how the receiving side handled the message to that address:</p>
<ul>
<li><strong>Spam or junk:</strong> Filtering can move a message out of Inbox.</li>
<li><strong>Quarantine:</strong> Some organizations hold messages outside the recipient&#8217;s normal folders.</li>
<li><strong>Mailbox rules or forwarding:</strong> Automated rules can move or redirect incoming mail.</li>
<li><strong>Recipient-domain mail trace:</strong> A mailbox administrator can tell whether the organization&#8217;s mail system received, rejected, or handled the message.</li>
</ul>
<p>Compare what you find on the receiving side with the sending provider&#8217;s event for the same message.</p>
<h2 id="hosting-migration-email">If email broke after moving hosts, separate web hosting from email routing</h2>
<p><img decoding="async" alt="Hosting email routing" src="/img/Hosting-email-routing.jpg"></p>
<p>In an unresolved r/webhosting case involving GoDaddy domain and email services, a poster wrote: “After changing the website host from Cloudway(s) to SiteGround, our email is no longer working.”</p>
<p>The website, DNS zone, email mailboxes, and WordPress transactional sending service can each be managed by a different provider. Map out which service moved and which stayed. Then work out whether inbound mailbox delivery, outbound WordPress notifications, or both failed. Do that before changing MX records or local mail-routing settings.</p>
<h2 id="notification-triggers">Check the original notification: password resets and WooCommerce emails</h2>
<p><img decoding="async" alt="Order email notifications" src="/img/Order-email-notifications.jpg"></p>
<p>Some WordPress emails rely on a specific application event. A working mailbox or mailer says nothing about whether a given account or commerce notification was generated.</p>
<p>Password-reset requests and administrative email changes run through WordPress-specific workflows. When one of those messages is missing, ask whether the event actually happened and produced the expected notification.</p>
<p>WooCommerce works differently. Its email notifications follow the configured email type and the order event or status. An order in the dashboard can exist without every possible order email having been generated.</p>
<h3>Check the event and the notification</h3>
<p>For the missing account or WooCommerce message, check whether the notification is enabled and which event or order status triggers it.</p>
<p>WooCommerce introduced built-in transactional email logging in version 10.9. If your installation has the feature and it&#8217;s set to record the relevant events, open WooCommerce → Status → Logs and select the <code>transactional-emails</code> source. The records show one of four outcomes:</p>
<ul>
<li><strong>Sent:</strong> WooCommerce reports handing the email to its sending path. This isn&#8217;t an inbox-delivery confirmation.</li>
<li><strong>Failed:</strong> The email attempt hit a recorded error.</li>
<li><strong>Disabled:</strong> The notification was disabled.</li>
<li><strong>Skipped:</strong> WooCommerce skipped sending that notification.</li>
</ul>
<p>Your logging configuration sets log visibility and detail. These are WooCommerce transactional-email records, not a full history of WordPress password-reset or other core messages.</p>
<p><img decoding="async" alt="WooCommerce email triggers" src="/img/WooCommerce-email-triggers.jpg"></p>
<p>For an account-related message, focus on the operation you requested and the WordPress notification it should produce. Ordinary messages arriving through Google Workspace or another mailbox provider prove only that those messages arrived.</p>
<h2 id="verify-wordpress-email">Verify the fix with the same end-to-end notification</h2>
<p><img decoding="async" alt="Notification delivery verification" src="/img/Notification-delivery-verification.jpg"></p>
<p>A repaired setting needs a test that reproduces the original problem. Use the same application event and the same intended recipient.</p>
<p>A developer on r/Wordpress wrote: “Everything works for me. I get the emails. She doesn&#8217;t. What&#8217;s the deal?”</p>
<h3>What each successful result proves</h3>
<table>
<thead>
<tr>
<th>Evidence</th>
<th>What it proves</th>
<th>What it doesn&#8217;t cover</th>
</tr>
</thead>
<tbody>
<tr>
<td>Form reaches thank-you page</td>
<td>The form reached that UI state</td>
<td>Mail generation and delivery</td>
</tr>
<tr>
<td><code>wp_mail()</code> reports success</td>
<td>The WordPress/PHPMailer path reported success</td>
<td>Downstream acceptance and mailbox arrival</td>
</tr>
<tr>
<td>SMTP test reaches a test inbox</td>
<td>That specific test succeeded for its destination</td>
<td>The original notification and other recipients</td>
</tr>
<tr>
<td>Provider accepts or processes the message</td>
<td>Provider-side submission succeeded at the reported stage</td>
<td>Recipient-server and mailbox outcomes</td>
</tr>
<tr>
<td>Provider reports Delivered</td>
<td>Recipient-server acceptance, as the provider defines it</td>
<td>Inbox placement and reading</td>
</tr>
<tr>
<td>Intended recipient sees the original notification</td>
<td>That event reached the mailbox in this test</td>
<td>Future delivery to every address</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="Email success evidence" src="/img/Email-success-evidence.jpg"></p>
<p>After the fix, record the message type, test time, intended address, any event or log identifier, the provider&#8217;s delivery record for that notification, and the setting you changed. If you can&#8217;t check the final mailbox, report the highest stage you confirmed, such as provider acceptance or receiving-server acceptance.</p>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Fix Mixed Content in WordPress (Find the HTTP URL First)</title>
		<link>https://noscript.info/wordpress/troubleshooting/mixed-content/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/troubleshooting/mixed-content</guid>

					<description><![CDATA[Find the insecure URL in DevTools, then fix WordPress settings, stored links, Elementor assets, or proxy detection. Includes safe checks and verification.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }
</style>
<div class="usefulmix-article">
<div class="short-answer">
<p>To fix mixed content in WordPress, open the affected page in your browser&#8217;s developer tools to find the HTTP resource your HTTPS page requests, before installing another plugin or editing the database. Then correct whatever produces it: a WordPress setting, a stored URL, a generated asset, a plugin or theme reference, or the proxy configuration. Reload the page to confirm the resource loads and the page works, and if DevTools shows no mixed-content request, investigate the failure it does report.</p>
</div>
<p>An HTTPS page can look normal until a font vanishes, a video fails, or the browser reports an insecure request. The clue you need is the URL the page tried to load and how the browser responded.</p>
<h2>What a WordPress mixed-content warning means</h2>
<p><img decoding="async" alt="HTTPS resource behavior" src="/img/HTTPS-resource-behavior.jpg"></p>
<p>Mixed content happens when an HTTPS page requests a resource over HTTP. Say a post at <code>https://example.test/page/</code> references <code>http://example.test/wp-content/uploads/photo.jpg</code>. The page arrives securely, but the image URL uses an insecure scheme.</p>
<p>Browsers handle these requests differently by resource type and host.</p>
<table>
<thead>
<tr>
<th>HTTP resource on an HTTPS page</th>
<th>Browser treatment</th>
<th>Likely observation</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ordinary domain-hosted <code>&lt;img src&gt;</code></td>
<td>Auto-upgraded to HTTPS</td>
<td>Image loads if its HTTPS URL works, or fails if it does not</td>
</tr>
<tr>
<td>JavaScript file</td>
<td>Blockable</td>
<td>Page interaction can fail</td>
</tr>
<tr>
<td>Stylesheet or web font</td>
<td>Blockable</td>
<td>Styling or typography can disappear</td>
</tr>
<tr>
<td><code>&lt;iframe&gt;</code> or <code>fetch</code>/XHR request</td>
<td>Blockable</td>
<td>Embedded content or fetched data can fail</td>
</tr>
<tr>
<td>Responsive image in <code>&lt;img srcset&gt;</code> or <code>&lt;picture&gt;</code></td>
<td>Blockable</td>
<td>A responsive image can disappear</td>
</tr>
<tr>
<td>Otherwise-upgradable resource addressed by IP</td>
<td>Blocked</td>
<td>Browser refuses the insecure IP-hosted request</td>
</tr>
</tbody>
</table>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Mixed_content" target="_blank" rel="noopener">MDN&#8217;s mixed-content reference</a> documents these distinctions. An upgraded image can still carry an outdated <code>http://</code> reference in the page source.</p>
<p><img decoding="async" alt="Blocked insecure assets" src="/img/Blocked-insecure-assets.jpg"></p>
<p>A missing image alone does not mean mixed content. Certificate errors, 403 or 404 responses, CORS restrictions and redirect loops each need their own investigation. For WordPress, PHP errors, and recovery, see how to <a href="https://noscript.info/wordpress/troubleshooting/#failure-scope">troubleshoot WordPress errors by symptom</a>.</p>
<h2>Find the insecure request in Chrome before changing WordPress</h2>
<p><img decoding="async" alt="Chrome insecure requests" src="/img/Chrome-insecure-requests.jpg"></p>
<p>Inspect the affected WordPress page in Chrome DevTools. It shows the HTTP address, the resource type and what initiated the request.</p>
<ol>
<li><strong>Open the affected HTTPS page.</strong> Open Chrome DevTools and select Console and Network.</li>
<li><strong>Reload the page.</strong> Look for mixed-content warnings and requests to <code>http://</code> resources.</li>
<li><strong>Inspect the request.</strong> Record the full URL, hostname, path, resource type, response status and initiator if shown.</li>
<li><strong>Check what the browser did.</strong> It blocked the request, upgraded it automatically, or the request failed with an ordinary HTTP error.</li>
<li><strong>Pick the repair.</strong> The URL tells you where to look. The initiator and surrounding page content show who generated it.</li>
</ol>
<p>Chrome also offers a focused option under Privacy and security → Security → Non-secure origins → View requests in Network panel, as described in the <a href="https://developer.chrome.com/docs/devtools/security" target="_blank" rel="noopener">Chrome DevTools Security panel documentation</a>.</p>
<table>
<thead>
<tr>
<th>Insecure request or context</th>
<th>Possible origin</th>
<th>Repair section</th>
</tr>
</thead>
<tbody>
<tr>
<td>Own-domain CSS or JavaScript generated with HTTP</td>
<td>WordPress URL settings or HTTPS detection</td>
<td>WordPress addresses. Proxy configuration</td>
</tr>
<tr>
<td>Old media address inside a post or widget</td>
<td>Stored WordPress content</td>
<td>Database URL replacement</td>
</tr>
<tr>
<td>Generated font CSS under Elementor uploads</td>
<td>Page-builder data or generated assets</td>
<td>Elementor repair</td>
</tr>
<tr>
<td>Asset under a plugin directory</td>
<td>Plugin settings or URL generation</td>
<td>Plugin and theme references</td>
</tr>
<tr>
<td>Script or image from another hostname</td>
<td>External provider or CDN</td>
<td>Third-party resources</td>
</tr>
<tr>
<td>HTTP URLs appear after TLS termination upstream</td>
<td>Proxy scheme detection</td>
<td>Reverse proxy/CDN</td>
</tr>
<tr>
<td>Missing image with no mixed-content request</td>
<td>File access, incorrect path, or another resource error</td>
<td>Remaining-failure diagnosis</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="WordPress resource origins" src="/img/WordPress-resource-origins.jpg"></p>
<p>Suppose Network shows:</p>
<p><code>http://example.test/wp-content/uploads/2024/header.jpg</code></p>
<p>That looks like a media URL, but the path does not prove it came from a post&#8217;s database content. A page builder, template or plugin can have produced it.</p>
<p>Another request looks like this:</p>
<p><code>http://cdn.example.test/app.js</code></p>
<p>The external hostname means someone else controls the resource, and the <code>.js</code> extension marks a script, which the browser can block.</p>
<h2 id="check-wordpress-address-and-site-address-without-breaking-navigation">Check WordPress Address and Site Address without breaking navigation</h2>
<p><img decoding="async" alt="WordPress address settings" src="/img/WordPress-address-settings.jpg"></p>
<p>WordPress has two address settings with different jobs. On a standard single-site installation, open Settings → General and compare both against your HTTPS setup.</p>
<p>WordPress Address (URL) is where the WordPress core files live. Site Address (URL) is the public address of the website. On an HTTPS site, both use https. Their paths can differ.</p>
<p>For example, a site served from <code>https://example.test/</code> can keep its core files at <code>https://example.test/wordpress/</code>. WordPress documents this distinction in its migration guidance.</p>
<p>Some installations set these values through configuration or hosting tools, so you cannot edit them in the dashboard.</p>
<p>In a WordPress.org support thread about an insecure cookie-popup asset, the site owner wrote, “WP and Site addresses are both HTTPS”, so the next step is the resource that still uses HTTP.</p>
<p>If one address uses HTTP by mistake, correct that value and confirm the public page and admin navigation still work. If both fields are already correct, leave them alone and look at the component that emitted the insecure URL.</p>
<h2>Replace old HTTP URLs stored in WordPress safely</h2>
<p><img decoding="async" alt="WordPress database replacement" src="/img/WordPress-database-replacement.jpg"></p>
<p>Your address settings can be correct while old absolute HTTP links remain in posts, widgets, options or other stored content.</p>
<p>When the offending request comes from stored data, the replacement method matters. WordPress settings can contain PHP serialized values, and a raw string replacement can damage them.</p>
<h3>Back up first</h3>
<p>Before you change stored URLs, back up the WordPress database and site files. Then note the old address, the HTTPS address that replaces it, and the installation or tables the change covers. If the next step involves HTTPS, redirect rules, and TLS, see how to <a href="https://noscript.info/servers/web-stack/http-to-https/#apply-the-change-safely-and-keep-a-way-back">set HTTP-to-HTTPS redirects without loops</a>.</p>
<p>The <a href="https://developer.wordpress.org/cli/commands/search-replace/" target="_blank" rel="noopener">WP-CLI search-replace command reference</a> documents serialized-data handling and dry-run support. The command takes the old value first, then the new one. If the next step involves WP-CLI, serialized data, and URL replacement, see how to <a href="https://noscript.info/wordpress/maintenance/search-replace/#when-wp-cli-search-replace-is-the-right-tool">run a safe WP-CLI URL search-replace</a>.</p>
<p>For a single-site installation at <code>example.test</code>, run this first:</p>
<pre><code>wp search-replace 'http://example.test' 'https://example.test' \
  --skip-columns=guid --dry-run
</code></pre>
<p><code>--dry-run</code> reports the changes without saving them. Check that the matches belong to the right hostname, paths and tables.</p>
<p><code>--skip-columns=guid</code> protects the <code>guid</code> field. WordPress&#8217;s migration documentation cautions against changing <code>wp_posts.guid</code> during a site move because those values serve as feed identifiers.</p>
<p><img decoding="async" alt="WP CLI dry run" src="/img/WP-CLI-dry-run-2.jpg"></p>
<h3>Apply the replacement</h3>
<p>Once the dry run looks right and the affected resources work at their HTTPS URLs, run the same command without the dry-run flag:</p>
<pre><code>wp search-replace 'http://example.test' 'https://example.test' \
  --skip-columns=guid
</code></pre>
<p>If the site also uses <code>http://www.example.test</code>, handle that variant separately.</p>
<p>WordPress Multisite needs extra care. The command covers the selected site and its registered tables. Options such as <code>--url</code> and <code>--network</code> control which installation it targets.</p>
<p><img decoding="async" alt="Database plugin preview" src="/img/Database-plugin-preview.jpg"></p>
<h3>Without SSH: a database replacement plugin</h3>
<p>If you only have dashboard access, use a database search-and-replace plugin such as <a href="https://wordpress.org/plugins/better-search-replace/" target="_blank" rel="noopener">Better Search Replace on WordPress.org</a>. It lets you select database tables, handles serialized data and previews changes with a dry run.</p>
<p>Limit the replacement to your site and the addresses you are changing. In versions with a <code>Replace GUIDs</code> option, leave it unchecked on an established site.</p>
<h2 id="fix-elementor-plugin-theme-and-third-party-http-urls">Fix Elementor, plugin, theme and third-party HTTP URLs</h2>
<p><img decoding="async" alt="Elementor asset repair" src="/img/Elementor-asset-repair.jpg"></p>
<p>When the main address settings are correct, the insecure URL can come from a page builder, plugin, theme, widget, custom stylesheet or external service.</p>
<h3>Elementor-generated assets</h3>
<p>Elementor keeps settings and generated assets that can retain or reproduce old addresses.</p>
<p>Its documented workflow is WordPress Dashboard → Elementor → Editor → Tools → Replace URL, which changes stored addresses. The same Tools area has Clear Files &amp; Data, which regenerates Elementor&#8217;s generated files.</p>
<p>These menu labels follow Elementor&#8217;s documented interface from May 2026.</p>
<p>A WordPress.org forum user troubleshooting Elementor&#8217;s generated Google Fonts CSS asked, “Any ideas why this is happening or how to force Elementor to generate secure font URLs?”</p>
<p>The reported asset directory was:</p>
<p><code>/wp-content/uploads/elementor/google-fonts/css/</code></p>
<p>If the browser&#8217;s request points to that directory, start there. Replace URL handles stored content and Clear Files &amp; Data handles generated files, so fixing one can leave the other broken. If the warning survives a file regeneration, a stored or hardcoded reference is still producing it.</p>
<p><img decoding="async" alt="Elementor generated fonts" src="/img/Elementor-generated-fonts.jpg"></p>
<h3>Hardcoded plugin and theme resources</h3>
<p>An HTTP address can also sit in a plugin setting, custom CSS, a template or a widget. Find the setting or code that produces it and correct that reference.</p>
<p>A cookie-banner asset is a clear example. An HTTPS WordPress page can reference a file under:</p>
<p><code>/wp-content/plugins/cookie-law-info/lite/frontend/images/close.svg</code></p>
<p>The plugin can output HTTP even when both address fields are correct.</p>
<p>With an external stylesheet, script or embed, the remote provider controls whether HTTPS is available. Your options are a secure URL from that provider, a replacement asset, or removing the obsolete integration.</p>
<h2>Check HTTPS detection behind a reverse proxy or CDN</h2>
<p><img decoding="async" alt="Trusted proxy forwarding" src="/img/Trusted-proxy-forwarding.jpg"></p>
<p>When a reverse proxy or CDN terminates HTTPS before the request reaches WordPress, the backend sees plain HTTP unless the original scheme is passed along. WordPress then generates insecure URLs. One WordPress operator using HAProxy, WireGuard and Nginx wrote on r/Wordpress, “I can get the page to load with Mixed content errors.”</p>
<p>If you run a similar chain, check where TLS terminates. Then check whether a trusted proxy sends <code>X-Forwarded-Proto</code>. With that header, WordPress detects HTTPS and avoids an admin redirect loop. Never trust forwarding headers supplied by the client, because they can be spoofed.</p>
<h2>Choose a source repair, rewriting plugin or CSP</h2>
<p><img decoding="async" alt="Mixed content remedies" src="/img/Mixed-content-remedies.jpg"></p>
<p>Correct a bad URL where it originates whenever you can. A source fix stays fixed without any rewrite on later responses. If the database is the source, use a serialized-aware replacement. Reach for output rewriting or a browser policy only when you cannot edit the origin yet.</p>
<table>
<thead>
<tr>
<th>Method</th>
<th>Suitable situation</th>
<th>What changes</th>
<th>Limitation</th>
</tr>
</thead>
<tbody>
<tr>
<td>Edit source URL or setting</td>
<td>Known incorrect reference</td>
<td>Stored value or component configuration</td>
<td>Requires access to the source</td>
</tr>
<tr>
<td>WP-CLI replacement</td>
<td>Confirmed legacy database addresses with command-line access</td>
<td>Targeted stored data</td>
<td>Covers only the selected site and registered tables unless you target more</td>
</tr>
<tr>
<td>Dashboard database replacement plugin</td>
<td>Confirmed stored HTTP values without SSH access</td>
<td>Targeted stored data</td>
<td>Depends on correct table scope</td>
</tr>
<tr>
<td>Elementor URL and file tools</td>
<td>Builder-owned addresses or generated assets</td>
<td>Elementor data or generated files</td>
<td>Other components can still emit HTTP</td>
</tr>
<tr>
<td>Mixed-content rewriting plugin</td>
<td>Source cannot readily be corrected</td>
<td>Generated output or requests during runtime</td>
<td>Adds an ongoing dependency</td>
</tr>
<tr>
<td>CSP <code>upgrade-insecure-requests</code></td>
<td>Browser-level upgrading fits the deployment</td>
<td>Browser request behavior</td>
<td>Does not edit WordPress data</td>
</tr>
<tr>
<td>Cloudflare HTTPS rewriting</td>
<td>Supported CDN-managed deployment</td>
<td>Edge URL handling</td>
<td>Depends on edge configuration and available HTTPS resources</td>
</tr>
</tbody>
</table>
<div class="callout">
<p>SSL Insecure Content Fixer offers targeted settings and broader Capture modes. WPBeginner warns that extensive capture can slow the site.</p>
</div>
<p><img decoding="async" alt="HTTP rewrite tradeoffs" src="/img/HTTP-rewrite-tradeoffs.jpg"></p>
<p>The <code>Content-Security-Policy: upgrade-insecure-requests</code> directive changes how the browser makes insecure resource requests. It leaves your WordPress records unchanged.</p>
<p>Before changing an asset reference from <code>http://</code> to <code>https://</code>, open the exact HTTPS URL and confirm it serves the file you need. If it fails, use a secure replacement or remove the obsolete reference. CSP, rewriting plugins and CDN rewrites do not create an HTTPS endpoint at the destination.</p>
<h2>Verify the repair and investigate what remains broken</h2>
<p><img decoding="async" alt="WordPress repair verification" src="/img/WordPress-repair-verification-2.jpg"></p>
<p>A source repair removes the insecure reference. A browser or CDN rewrite loads the resource securely but leaves the stored HTTP URL as it is. Cached output can keep older references, so test a fresh response after the change.</p>
<p>After the fix, check the page like this:</p>
<ol>
<li><strong>Clear caches.</strong> Clear every layer your site uses, such as WordPress page caching, generated builder assets, hosting or CDN caching, and browser cache.</li>
<li><strong>Reload the affected page with DevTools.</strong> Compare the original insecure request with the new Network and Console entries.</li>
<li><strong>Inspect the result.</strong> Confirm the resource loads securely and no mixed-content violation remains.</li>
<li><strong>Test the original feature.</strong> Check the image, typography, stylesheet, embedded content or script behavior that first exposed the fault.</li>
<li><strong>Sample related pages.</strong> Check other templates and routes, and test logged in if the original issue depended on it.</li>
</ol>
<h3>When the warning is gone but something still fails</h3>
<table>
<thead>
<tr>
<th>Remaining observation</th>
<th>What to investigate</th>
</tr>
</thead>
<tbody>
<tr>
<td>Image URL now uses HTTPS but returns 404</td>
<td>File existence and requested path</td>
</tr>
<tr>
<td>Resource returns 403</td>
<td>Permissions, server rules or access restrictions</td>
</tr>
<tr>
<td>External script remains unavailable</td>
<td>Provider&#8217;s HTTPS resource and URL</td>
</tr>
<tr>
<td>Plugin asset still uses HTTP</td>
<td>Plugin-specific settings or URL generation</td>
</tr>
<tr>
<td>Old URL reappears after a stored-data edit</td>
<td>Generated assets, templates or cached output</td>
</tr>
<tr>
<td>Admin login enters a redirect loop</td>
<td>HTTPS forwarding and redirect configuration</td>
</tr>
</tbody>
</table>
<p><img decoding="async" alt="Remaining WordPress failures" src="/img/Remaining-WordPress-failures.jpg"></p>
<p>In one r/Wordpress report after a security-plugin change, a WordPress Multisite maintainer wrote, “Deactivating it again doesn&#8217;t bring them back.”</p>
<p>The same discussion involved upload-directory <code>.htaccess</code> rules. A request that fails because of access controls needs a different repair from a browser refusing an HTTP subresource.</p>
<p>If a change causes new damage, restore from the backup or the configuration you recorded before the change. Do not make a second broad change while the first failure is unexplained.</p>
</div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Why Is WordPress Slow? Find the Bottleneck Before You Fix It</title>
		<link>https://noscript.info/wordpress/performance/slow-site/</link>
		
		<dc:creator><![CDATA[NoScript Team]]></dc:creator>
		<pubDate>Thu, 29 Oct 2026 16:21:43 +0000</pubDate>
				<category><![CDATA[Performance]]></category>
		<guid isPermaLink="false">https://noscript.info/wordpress/performance/slow-site</guid>

					<description><![CDATA[Find out why WordPress pages, admin screens, or WooCommerce actions are slow. Follow browser timings, cache evidence, and request traces to a safe fix.]]></description>
										<content:encoded><![CDATA[<style>.usefulmix-article{ font-family: Georgia, 'Times New Roman', serif; max-width: 760px; margin: 0 auto; padding: 40px 20px; line-height: 1.65; color: #1a1a1a; background: #fdfdfb; }.usefulmix-article h1{ font-size: 1.9em; line-height: 1.25; margin-bottom: 0.3em; }.usefulmix-article h2{ font-size: 1.35em; margin-top: 2em; border-bottom: 2px solid #c0392b; padding-bottom: 0.2em; }.usefulmix-article h3{ font-size: 1.05em; margin-top: 1.3em; color: #333; }.usefulmix-article .short-answer{ background: #fff6f0; border-left: 4px solid #c0392b; padding: 1em 1.2em; margin: 1.2em 0; }.usefulmix-article table{ border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 0.95em; }.usefulmix-article th, .usefulmix-article td{ border: 1px solid #ddd; padding: 8px 10px; text-align: left; vertical-align: top; }.usefulmix-article th{ background: #f4f0ea; }.usefulmix-article .callout{ background: #eef3f7; border-left: 4px solid #3a6ea5; padding: 0.9em 1.1em; margin: 1.2em 0; font-size: 0.95em; }.usefulmix-article ul{ padding-left: 1.3em; }.usefulmix-article img{ max-width: 100%; height: auto; }
</style>
<div class="usefulmix-article">
<div class="short-answer">
<p>Find the delayed request before choosing a fix. Once your tests point to an expensive component, change that one component in a way you can undo, then test the same task again. If the cause stays unclear, give your host or developer the measured request and the conditions it ran under.</p>
</div>
<p>A homepage can appear instantly while the WordPress editor takes several seconds to open. Another site can send its HTML promptly, then spend the next few seconds loading scripts and images. The two call for different investigations.</p>
<h2>Start with the exact thing that&#8217;s slow</h2>
<p><img decoding="async" alt="WordPress slowdown symptoms" src="/img/WordPress-slowdown-symptoms.jpg"></p>
<p>Pick the page, screen or action that&#8217;s delayed and name it by URL or operation.</p>
<table>
<thead>
<tr>
<th>What feels slow</th>
<th>Request to isolate</th>
<th>Where to look</th>
</tr>
</thead>
<tbody>
<tr>
<td>Public page loads slowly</td>
<td>Open the affected public URL</td>
<td>Initial response and browser loading</td>
</tr>
<tr>
<td>Dashboard or editor lags</td>
<td>Open or save a specific <code>/wp-admin/</code> screen</td>
<td>Logged-in WordPress processing</td>
</tr>
<tr>
<td>Product search or checkout stalls</td>
<td>The affected search, cart or order action</td>
<td>Dynamic request processing</td>
</tr>
<tr>
<td>Slowdowns come and go</td>
<td>A named action during a slow period</td>
<td>Incident timing and host activity</td>
</tr>
</tbody>
</table>
<p>A public product page and an admin product lookup are different operations, even for the same product.</p>
<p>Write down the URL or action, your login state, device and browser, the approximate time and time zone, and any visible error. If the problem is intermittent, note when it happened even if the delay vanishes before it can be reproduced. Keep guesses about plugins out of it.</p>
<p><img decoding="async" alt="Affected request record" src="/img/Affected-request-record.jpg"></p>
<h2>Get a baseline measurement</h2>
<p><img decoding="async" alt="WordPress speed metrics" src="/img/WordPress-speed-metrics.jpg"></p>
<p>A performance score can go up while one user action stays painfully slow. Google PageSpeed Insights gives you a lab assessment and, when enough observations exist, real-user data from the Chrome User Experience Report (CrUX).</p>
<p>CrUX data in PageSpeed Insights covers the previous 28 days, and Google&#8217;s field classification uses the 75th percentile of recorded experiences. A fresh lab run and the aggregated field data can disagree. The <a href="https://developers.google.com/speed/docs/insights/v5/about" target="_blank" rel="noopener">Google PageSpeed Insights documentation</a> explains both.</p>
<table>
<thead>
<tr>
<th>Metric</th>
<th>What it describes</th>
<th>Good</th>
<th>Poor</th>
</tr>
</thead>
<tbody>
<tr>
<td>TTFB</td>
<td>Time to First Byte: initial response timing</td>
<td>≤ 800 ms</td>
<td>&gt; 1,800 ms</td>
</tr>
<tr>
<td>LCP</td>
<td>Largest Contentful Paint: largest relevant visible content</td>
<td>≤ 2.5 s</td>
<td>&gt; 4.0 s</td>
</tr>
<tr>
<td>INP</td>
<td>Interaction to Next Paint: response to user interaction</td>
<td>≤ 200 ms</td>
<td>&gt; 500 ms</td>
</tr>
<tr>
<td>CLS</td>
<td>Cumulative Layout Shift: visual stability</td>
<td>≤ 0.1</td>
<td>&gt; 0.25</td>
</tr>
</tbody>
</table>
<p>CLS has no time unit, since it measures layout movement. Use the thresholds to pick which metric to investigate.</p>
<div class="callout">
<p>A Hostinger user discussing WP Rocket, Perfmatters, and other optimizations wrote on r/Wordpress on July 11, 2026: “However, my website still takes time to load. and it frustrates me.”</p>
</div>
<p>Take a baseline for the operation you chose in the first section. Run the test more than once, with the same page, login state, device and cache state each time, and save every result. If PageSpeed Insights has no CrUX data for your URL, keep the lab measurement and label it as lab data.</p>
<p><img decoding="async" alt="Comparable speed baseline" src="/img/Comparable-speed-baseline.jpg"></p>
<h2>Pick diagnostic tools that match your access</h2>
<p><img decoding="async" alt="WordPress diagnostic access" src="/img/WordPress-diagnostic-access.jpg"></p>
<p>Start with what you can reach. A browser shows request and rendering behavior, WordPress diagnostics add application detail, and server access exposes the processes behind a slow response. For CPU, memory, and disk usage, see how to <a href="https://noscript.info/servers/operations/monitoring/#check-your-linux-server-s-resources-without-changing-anything">measure Linux server resource usage</a>.</p>
<table>
<thead>
<tr>
<th>Access</th>
<th>What you get</th>
<th>Use it to</th>
</tr>
</thead>
<tbody>
<tr>
<td>Browser only</td>
<td>Network waterfall, request timing, browser performance, PageSpeed Insights</td>
<td>Locate the slow request or rendering phase</td>
</tr>
<tr>
<td>WordPress administrator</td>
<td>Tools → Site Health; Query Monitor</td>
<td>Check environment details, queries and WordPress operations</td>
</tr>
<tr>
<td>Host, developer or server administrator</td>
<td>Application performance monitoring (APM), server logs, PHP and database/resource telemetry</td>
<td>Trace the costly parts of a slow transaction and see server conditions during the incident</td>
</tr>
</tbody>
</table>
<p>In WordPress, Tools → Site Health has Status and Info views that list configuration details and potential problems. An administrator can also use the Query Monitor plugin to inspect queries, HTTP API activity and component timings.</p>
<p>The browser can show that a response arrived late. It can&#8217;t show how much of the delay came from PHP, a database query or an external service the server called. Your provider and account permissions set APM and log access, so on managed hosting your host can be the one to pull those details for you.</p>
<p><img decoding="async" alt="Site Health diagnostics" src="/img/Site-Health-diagnostics.jpg"></p>
<h2>Find out whether the delay happens before or after the HTML arrives</h2>
<p><img decoding="async" alt="Browser request timing" src="/img/Browser-request-timing.jpg"></p>
<p>Your browser shows whether the HTML itself starts late, or arrives promptly and the page is slow afterward.</p>
<p>In Chrome, open DevTools → Network, reload the slow public page, select its main document request and open the Timing tab. The <a href="https://developer.chrome.com/docs/devtools/network/reference" target="_blank" rel="noopener">Chrome DevTools Network reference</a> describes phases such as DNS lookup, connection, Waiting (TTFB) and Content Download.</p>
<p>The Timing tab&#8217;s Waiting (TTFB) phase covers the wait inside that one request. TTFB for the whole page navigation can also include earlier redirects and connection time.</p>
<h3>If the document response begins late</h3>
<p>Check the connection and wait phases. A long wait on the HTML request points to network conditions, cache behavior or backend execution. A server or application trace can then separate PHP work, database operations and remote calls the server makes.</p>
<h3>If the HTML arrives promptly but the page remains slow</h3>
<p>Read the waterfall below the document request and find the LCP element or the delayed interaction. Large images, blocking scripts, styles, fonts and third-party resources loaded by the browser are the first things to check. A slow LCP and a slow INP are different problems, so go by the action that felt slow.</p>
<p><img decoding="async" alt="HTTP waterfall phases" src="/img/HTTP-waterfall-phases.jpg"></p>
<h2>Why a fast homepage can hide a slow dashboard</h2>
<p><img decoding="async" alt="WordPress cache comparison" src="/img/WordPress-cache-comparison.jpg"></p>
<p>The public homepage and a logged-in dashboard take different paths. A full-page cache can return HTML it generated earlier for an eligible public request, which skips most of the work WordPress would otherwise repeat.</p>
<table>
<thead>
<tr>
<th>Request or cache layer</th>
<th>What gets reused</th>
<th>What it tells you</th>
</tr>
</thead>
<tbody>
<tr>
<td>Anonymous HTML cache hit</td>
<td>Generated page output</td>
<td>A fast hit says nothing about uncached PHP and database speed</td>
</tr>
<tr>
<td>Authenticated admin or personalized action</td>
<td>Depends on the route and your cache configuration</td>
<td>Can run fresh PHP, queries and plugin code</td>
</tr>
<tr>
<td>Persistent object cache</td>
<td>Reusable application data</td>
<td>Cuts repeated data work without serving a whole cached page</td>
</tr>
</tbody>
</table>
<p>The <a href="https://developer.wordpress.org/advanced-administration/performance/cache/" target="_blank" rel="noopener">WordPress caching documentation</a> separates page caching from object caching. Personalized routes can be excluded from full-page caching on purpose.</p>
<p>On December 28, 2025, a nonprofit administrator using DreamHost shared hosting and Cloudflare posted this on r/Wordpress: “However, the backend, the WP admin dashboard, runs super slow&#8211;not always, but most of the time.”</p>
<p>Load the public page as an anonymous visitor, then compare it with the slow logged-in or dynamic action. Check whether your cache or host reports a status on the response. A hit means the page came from cache. A miss means it didn&#8217;t. If nothing is reported, you can&#8217;t tell.</p>
<p><img decoding="async" alt="Anonymous authenticated requests" src="/img/Anonymous-authenticated-requests.jpg"></p>
<h2>Trace slow WordPress admin screens and recent changes</h2>
<p><img decoding="async" alt="WordPress admin profiling" src="/img/WordPress-admin-profiling.jpg"></p>
<p>Profile a lagging editor or dashboard as its own logged-in operation. Admin requests run plugin and theme hooks, load metadata, query MySQL or MariaDB and call remote services that a cached public page never needs.</p>
<p>In an August 24, 2026 r/Wordpress thread about structured content built with Advanced Custom Fields (ACF), a poster wrote: “My WordPress admin, however, is absurdly slow.” The same thread mentioned a recent HTTPS change.</p>
<p>Open the slow admin screen or repeat the same save while a trace is running, either in WordPress or from your host. Query Monitor groups database queries by the responsible component, flags slow operations and shows WordPress HTTP API request timing. A provider&#8217;s APM shows costly PHP transaction segments. The <a href="https://wordpress.org/plugins/query-monitor/" target="_blank" rel="noopener">Query Monitor plugin page</a> describes its views.</p>
<p>Look for a query, callback or HTTP call that takes a large share of the time during the slow action, and note which plugin or theme it belongs to. Repeat the action. If the same one is slow again, it&#8217;s your lead. Many short queries can cost less than one long wait, so plugin count and query count don&#8217;t point to a culprit.</p>
<p>If the slowdown began after a plugin, theme, PHP or configuration change, add that change to your record.</p>
<p><img decoding="async" alt="Query Monitor component timing" src="/img/Query-Monitor-component-timing.jpg"></p>
<h2>Trace slow AJAX requests, database work, and outside services</h2>
<p><img decoding="async" alt="WordPress dynamic request" src="/img/WordPress-dynamic-request.jpg"></p>
<p>A stalled product lookup or order action can be waiting on one dynamic request while the rest of the page responds. WordPress interactions can go through admin-ajax.php, a REST API route or an application-specific endpoint. When page cache, Redis, and PHP OPcache need a separate check, see how to <a href="https://noscript.info/wordpress/performance/cache-layers/#affected-request">choose the right WordPress cache layer</a>.</p>
<p>A poster on r/Wordpress asked this on September 4, 2026, in a discussion about a B2B WooCommerce workflow: “Any ideas that I can look into to improve loading speed and improve ajax lookup speed”</p>
<p>Trigger the slow action with the browser&#8217;s Network panel open and find the matching request by its timing and action. If you have access, line that same request up with WordPress query, PHP, database and HTTP-call diagnostics. Sort the delay into one of these:</p>
<ul>
<li><strong>WordPress/PHP processing:</strong> A handler, hook or callback takes measurable time to run.</li>
<li><strong>Database work:</strong> A query or database wait takes time during the slow action. Look at its measured duration and whether something blocks it.</li>
<li><strong>Remote call from the server:</strong> PHP waits on another service through WordPress HTTP handling or a related application request.</li>
<li><strong>Browser-side resources:</strong> JavaScript execution or a third-party resource delays the displayed result after the server responds.</li>
<li><strong>Unresolved:</strong> Your tools show a slow request but can&#8217;t split up its internal cost.</li>
</ul>
<p>A wait on an API call made from PHP shows up in the application trace. A third-party script loaded by the browser shows up in the browser waterfall. Judge a database query by its behavior and measured time. Never change or delete rows based on table size.</p>
<p><img decoding="async" alt="AJAX database service timing" src="/img/AJAX-database-service-timing.jpg"></p>
<p>WordPress Site Health warns when autoloaded options exceed a configurable default of 800,000 bytes. Background activity from WP-Cron or Action Scheduler is another candidate if its timing matches the slow operation.</p>
<h2>Investigate intermittent slowdowns and hosting limits</h2>
<p><img decoding="async" alt="Hosting activity correlation" src="/img/Hosting-activity-correlation.jpg"></p>
<p>When slowness comes and goes, line up the times it happens with resource graphs, PHP worker activity, scheduled jobs, database events and error logs.</p>
<p>A publisher with about 3,000 articles wrote on r/Wordpress on October 23, 2026: “When we move our website to another host then it is fixed for about 2-3 years.”</p>
<p>A move changes the PHP environment, caching, database setup and resource limits all at once, so the improvement doesn&#8217;t tell you which one mattered. Match the slow periods against your host&#8217;s telemetry and configuration history. If you can&#8217;t see those records, ask your host for them.</p>
<h2 id="test-one-suspected-cause-safely">Test one suspected cause safely</h2>
<p><img decoding="async" alt="Safe WordPress change" src="/img/Safe-WordPress-change.jpg"></p>
<p>Once your trace points to an expensive component, test by changing one condition you can restore afterward. If you change a caching setting, a plugin configuration and the PHP environment at once, you can&#8217;t tell which one made the difference.</p>
<p>Use staging or a planned maintenance window. Back up the site and keep the original configuration so you can reverse the change.</p>
<div class="callout">
<p><strong>Protect the live site.</strong> Isolating plugins, changing the database or editing PHP settings can interrupt production workflows. Debugging and profiling add overhead and can expose sensitive information. Limit temporary access and logging, protect what you collect, and turn off diagnostic tools when the test ends.</p>
</div>
<p>Write the test down in three lines:</p>
<ul>
<li><strong>Suspect:</strong> The query, component or external call the trace pointed to.</li>
<li><strong>Change:</strong> One setting you can revert, or one component you isolate.</li>
<li><strong>Must still work:</strong> The action that has to keep working, and the failure that triggers a rollback.</li>
</ul>
<p>For a slow editor save, the save has to keep working while you isolate the expensive operation from its trace.</p>
<p><img decoding="async" alt="Reversible test checklist" src="/img/Reversible-test-checklist.jpg"></p>
<h2>Verify the fix or give your host an actionable report</h2>
<p><img decoding="async" alt="Before after WordPress" src="/img/Before-after-WordPress.jpg"></p>
<p>A change worked if the original slow operation got faster and still does its job. Repeat your baseline test on the same URL or action.</p>
<p>Check function as well as speed. A faster editor that can&#8217;t save, or a checkout that won&#8217;t complete, is a broken workflow. One fast run doesn&#8217;t prove an intermittent problem is gone.</p>
<p><img decoding="async" alt="Performance retest results" src="/img/Performance-retest-results.jpg"></p>
<ul>
<li><strong>Improved and functional:</strong> Timings improve and the action still works. Keep the change.</li>
<li><strong>Unchanged or broken:</strong> The action got no faster or stopped working. Roll back to the saved state.</li>
<li><strong>Unresolved:</strong> You still can&#8217;t identify the expensive component. Escalate the specific incident.</li>
</ul>
<p>When you escalate, send your host or developer the record you started in the first section, plus the cache state, measured delay, browser timings, the changes you made and any PHP, database or application trace you have.</p>
</div>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
