← All articles

Security

How to Recover from a Fatal PHP Error in a WordPress Snippet

A bad snippet can white-screen wp-admin. Here is how to get the site back, disable only the offending code, and stop the next fatal from taking everything down.

June 24, 2026 4 min read Mark Ashton

  • wordpress
  • security
  • php
  • workflow
Abstract cover artwork for How to Recover from a Fatal PHP Error in a WordPress Snippet

A fatal PHP error in a snippet is a different incident than a fatal in a theme template. The template usually takes down one view. A snippet that runs on plugins_loaded or init takes down every view, including wp-admin and WP-CLI HTTP contexts. That is the white screen of death, and it is why "just paste this into a snippet" is not a complete instruction.

This is the recovery path we use, then the setup that makes the next one boring.

Confirm it is a snippet

If the site died immediately after you saved or activated a snippet, it is the snippet. If you are not sure, check wp-content/debug.log (with WP_DEBUG_LOG true) or the host error log. Fatals name a file. Database-stored plugins often show a runtime-generated path; file-based plugins show a real file under wp-content.

Other usual suspects: a plugin update, a PHP version bump (7.0 / PHP 8.4 is producing a lot of these this summer), or a mu-plugin. Do not start by restoring the entire database.

Recovery if you can still reach admin

Some snippet plugins catch the fatal on the next request and disable the offender. If you can log in:

  1. Open the snippet list. Look for an auto-deactivated item or a last-modified timestamp that matches the outage.
  2. Leave it inactive. Do not re-enable to "see if it still breaks."
  3. Fix on staging, or fix in the editor while inactive, then activate once.

If the admin loads but every page is a fatal after header output, switch to a default theme only after you have ruled out snippets. Theme switch is a slower diagnostic.

Recovery if admin is a white screen

Work from the host, not the browser.

Safe mode / query flags. Some plugins document a URL flag that skips snippet execution. Use it if you have one. Load wp-login.php with that flag, deactivate the snippet, remove the flag.

File-based storage (the good case). If snippets are files — SnipVault, FluentSnippets, or Code Snippets in file-execution mode — SFTP or SSH to the storage directory and rename the newest .php file to .php.off. Reload. If the site returns, you found it. That is a two-minute fix and the strongest argument for not storing executable PHP in wp_options.

Database-only storage. You need either:

  • wp plugin deactivate plugin-slug over SSH, then fix or truncate the snippet row, then reactivate
  • A host phpMyAdmin pass at the plugin's table (search for the last edited snippet name)
  • A backup from *before* the save

This is why we keep SnipVault file-based and why FluentSnippets took the same side. SQL-as-incident-response is a bad workflow.

WP-CLI. wp plugin list and wp plugin deactivate still work when HTTP is dead, as long as PHP can bootstrap. If the fatal happens so early that WP-CLI dies too, you are back to renaming files.

Fix the snippet, do not just delete it

Once the site is up, treat the code as a failed deploy:

  • Reproduce on staging with WP_DEBUG on
  • Read the line the log named. 8.4 fatals are often typed properties and nullables, not "PHP is broken"
  • Add the missing guard: existence checks, function_exists, a capability check, a prepared query
  • Run a security audit if the snippet was pasted from a gist. Fatals and vulnerabilities travel together.

If you used an AI to generate the snippet, the failure mode is usually a hook that fires before a function is loaded, or a class that relies on dynamic properties. The Snippet Engineer sandbox probe exists specifically so that fatal happens on a probe request, not on production init.

Stop the next one from taking the site down

Isolation is a product feature, not a vibe.

  • Sandbox before publish. A probe request that fatals should refuse deploy. Catching the error *after* activation is better than nothing; catching it before is better.
  • Per-snippet disable. One file, one toggle. A combined "utilities.php" snippet is a single point of failure.
  • HMAC / integrity. If the file on disk does not match what you saved, you have a different incident (tamper), not a typo.
  • Git. GitHub sync gives you git revert instead of "does anyone have the old version in email?"
  • PHP version parity. Staging on 8.2 and production on 8.4 is how you get fatals that "passed QA."

We wrote the longer philosophy in how to safely manage WordPress code snippets. The incident version is: if recovery requires a database editor, the architecture is wrong.

A note on "safe mode" folklore

Search results still say "add ini_set('display_errors', 1) to wp-config" or "delete the plugin folder." Displaying errors on a production store shows stack traces to customers. Deleting the plugin folder disables *every* snippet, including the ones keeping checkout alive.

Prefer: skip or rename one snippet, keep the plugin, keep the rest of the library. That is only possible if the plugin isolates execution and you can identify the file.

After-action

Write down which snippet failed, which hook it ran on, and whether it should have been conditionally loaded. A fatal in a snippet that only needed to run on /checkout should never have been registered on init for the whole site.

Then decide if that snippet should still exist. A surprising number of white screens come from code nobody can explain. Deleting it is a valid fix.

Fatals will still happen. The difference between a five-minute rename and a two-hour restore is whether your snippets are files with a kill switch — or rows in a table you cannot reach because the table is what is crashing PHP.

Next

Ready to upgrade your snippet workflow?

GitHub sync, the Snippet Engineer, and security auditing — in one WordPress plugin.