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
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:
- Open the snippet list. Look for an auto-deactivated item or a last-modified timestamp that matches the outage.
- Leave it inactive. Do not re-enable to "see if it still breaks."
- 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-slugover 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_DEBUGon - 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, aprepared 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 revertinstead 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.