← All case studies

Post-Mortem: White Screen After a Forced PHP 8.2 Upgrade

Environment
Managed LAMP hosting · Apache 2.4 · PHP 8.2 · WordPress · custom child theme
Symptom
Completely blank page on every URL, including wp-admin
Resolution
90 minutes from access to full restoration
Published

Incident Overview

A small-business site went down overnight with no deployment, no update clicked, and no one logged in. Every URL — front end and /wp-admin — returned a blank white page with HTTP 500 and zero bytes of HTML. The trigger: the host’s fleet-wide, mandatory migration from PHP 7.4 (end-of-life) to PHP 8.2, applied automatically at 02:00.

The blank screen is the defining trait of a fatal PHP error with display suppressed: the process died before emitting any output. The page is empty, but the error log is not.

Raw Diagnostic Logs

display_errors off (correct for production), so the evidence lives in the log:

$ tail -3 /home/account/logs/error_log
[26-Jul-2026 02:04:11 UTC] PHP Fatal error:  Uncaught Error: Call to undefined
  function create_function() in /home/account/public_html/wp-content/themes/
  legacy-biz-child/inc/widgets.php:214
Stack trace:
#0 /home/account/public_html/wp-settings.php(675): include()

One line tells the whole story: file, line, and the removed API. create_function() was deprecated in PHP 7.2 and removed in PHP 8.0 — the theme had been shipping a time bomb for years, armed the moment the host pulled 7.4.

A quick sweep for the same pattern before fixing anything, so the site doesn’t crash again one file later:

$ grep -rn "create_function\|each(" wp-content/themes/legacy-biz-child/ \
    wp-content/plugins/ --include="*.php" | grep -v vendor | cut -d: -f1 | sort -u
wp-content/themes/legacy-biz-child/inc/widgets.php
wp-content/themes/legacy-biz-child/inc/customizer.php

Two files, five call sites total — small enough to patch properly rather than abandoning the theme.

Forensic Root Cause Analysis

The failure chain:

  1. Host removes PHP 7.4 (EOL) and force-migrates all accounts to 8.2 — legitimate and announced, but announced to an inbox nobody monitored.
  2. The active child theme registers widgets via create_function(), an API removed in PHP 8.0.
  3. WordPress loads the theme on every request, including admin requests — so the fatal error also locked the owner out of the dashboard that could have switched themes.
  4. WordPress’s built-in recovery mode emails went to a defunct address, so the “site is having technical difficulties” lifeline was never seen.

Root cause: unmaintained theme code using a removed API, with the upgrade risk invisible because no compatibility scan had ever run against the site.

Remediation & Command Log

Backup, then restore service in the safest order — WP-CLI works even when the site’s pages don’t:

tar -czf /home/account/pre-fix-$(date +%F).tar.gz public_html/
mariadb-dump --single-transaction site_db | gzip > /home/account/pre-fix-db.sql.gz

# Confirm the failure is theme-scoped: switch to a bundled default theme
wp theme activate twentytwentyfour
curl -s -o /dev/null -w "%{http_code}\n" https://example-site.com/
# 200 — site is back on a fallback theme within minutes

With the site up, patch the five call sites offline. Representative diff:

// Before — removed in PHP 8.0
add_action('widgets_init', create_function('', 'register_widget("Legacy_CTA_Widget");'));

// After — anonymous function, PHP 8.x-safe
add_action('widgets_init', function () {
    register_widget('Legacy_CTA_Widget');
});

Lint every changed file against the new runtime before reactivating:

for f in inc/widgets.php inc/customizer.php; do php -l "wp-content/themes/legacy-biz-child/$f"; done
wp theme activate legacy-biz-child
curl -s -o /dev/null -w "%{http_code}\n" https://example-site.com/
# 200 — original theme restored, look and feel unchanged

Preventative Hardening

  • Ran the full codebase through PHPCompatibility (PHP_CodeSniffer ruleset) targeting PHP 8.2; patched every remaining deprecation warning, not just the fatals.
  • Fixed the recovery-mode email so the next fatal error reaches a monitored inbox:
// wp-config.php
define('RECOVERY_MODE_EMAIL', 'ops@client-domain.com');
  • Registered the hosting account’s notification address to a shared, monitored mailbox — the migration notice had gone unread for six weeks.
  • Left the client a one-page upgrade-readiness checklist: how to spin up the host’s staging clone and run the compatibility scan before any future PHP version bump.

Details in this post-mortem are anonymized and composited from recurring incidents of the same failure class. The logs and commands are representative of the actual diagnostic path. Staring at a blank page right now? Our white screen recovery service starts with your error log, not guesswork.

Facing the same failure right now?

This is the exact process a repair follows — start with the matching recovery service.

Fix My Site Now