Bali, Indonesia
Insights

Why WordPress Throws a Critical Error Right After Switching to PHP 8

October 28, 2026
0:00
You changed the PHP version from 7.4 to 8.x in the control panel, reloaded the site, and got 'There has been a critical error on this website.' Switching back fixes it immediately, so the obvious conclusion is that PHP 8 is broken or that WordPress isn't ready for it. Usually neither is true. Something specific in your site stopped working on the new version, and the server already wrote down exactly what it was. This article walks through that situation as a post-mortem: what the impact looks like, how the investigation usually goes, where the real answer shows up, how to get the site back without being stuck on old PHP, and what to change so the next switch is uneventful.
The symptom is sharp and easy to reproduce. Front end and wp-admin both show the same generic message, sometimes with a line about checking the site admin email. Rolling back the PHP version restores everything within seconds. That message comes from WordPress itself, not from the web server. Since WordPress 5.2, core catches PHP fatal errors (errors that stop the script entirely) and shows a friendly page instead of a stack trace or a blank screen. It also tries to email the admin address with a recovery mode link, a special login that pauses the offending plugin or theme so you can get into the dashboard. If that email arrived, it often names the plugin directly. Many people never see it because the admin address is old or the site's outgoing mail doesn't work. The important detail is the word 'fatal'. Warnings and deprecation notices don't produce this screen. Something threw an error that PHP refused to continue past.
The rollback test proves one thing: the failure depends on the PHP version. It doesn't tell you which file, plugin, or setting is responsible. This is where support conversations often stall, because 'it works on 7.4' feels like a complete diagnosis. When a support engineer picks up one of these, the first question is not 'which plugins do you have' but 'what does the error log say'. Guessing by disabling plugins one at a time works eventually, but on a site with dozens of plugins it's slow and you learn nothing about whether the theme or a missing extension is also involved. In practice the cause almost always falls into one of three buckets:
  1. Code that uses something PHP 8 removed or made stricter. Functions like create_function() and each() were deprecated years ago and removed in PHP 8.0. Old sliders, page builders, and abandoned themes still call them. PHP 8 also turned many former warnings into thrown errors, so code like calling count() on something that isn't an array now stops execution instead of logging a notice.
  2. A PHP extension that exists on the old version but not the new one. Most panels install extensions per version, so enabling PHP 8.x doesn't copy over intl, imagick, mbstring, or an ionCube Loader you added to 7.4 at some point.
  3. Different limits. Each PHP version typically has its own php.ini (on cPanel EasyApache 4, for example, under /opt/cpanel/ea-php80/root/etc/php.ini for 8.0). If you raised memory_limit or max_execution_time on the old version, the new one may be running with defaults.
The log tells you which bucket you're in.
Where the log lives depends on the setup. On many cPanel servers PHP writes an error_log file into the directory of the script that failed, often the document root. If WP_DEBUG_LOG is enabled in wp-config.php, WordPress writes to wp-content/debug.log. PHP-FPM setups may log to a pool-specific file instead. If you have WP_DEBUG on but still see nothing, that's a separate problem covered elsewhere; the server-side log is usually the more reliable place to start. Switch to PHP 8 again, load the page once to trigger the error, switch back, then read the log:
BASH
# Run from the site's document root; file names and locations depend on the server setup
tail -n 50 error_log
grep -n 'PHP Fatal' error_log | tail -n 20
grep -n 'PHP Fatal' wp-content/debug.log | tail -n 20
You're looking for a line like this:
TEXT
# Illustrative output format (paths and names are placeholders)
[date] PHP Fatal error:  Uncaught Error: Call to undefined function create_function() in /home/user/public_html/wp-content/plugins/old-slider/includes/widget.php:42
[date] PHP Fatal error:  Uncaught Error: Call to undefined function mb_strlen() in /home/user/public_html/wp-content/themes/old-theme/functions.php:118
[date] PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /home/user/public_html/wp-includes/class-wpdb.php on line 2187
Each of those lines points to a different bucket, and the file path does most of the work for you. The first is removed-function code. The path sits under wp-content/plugins/old-slider/, so that plugin is the culprit, and the function name tells you why. The fix is an update or a replacement, not a server change. The second looks similar, but mb_strlen() is a normal, current function. When a function that should exist is 'undefined', the extension providing it is missing on the new version. Here that's mbstring. The code is fine; the PHP build isn't. The third is a limit. The file named in a memory error is just where PHP happened to run out, often in core, so don't blame class-wpdb.php. Compare memory_limit between the two versions. One trap worth knowing: running php -v or php -m over SSH shows the CLI binary, which may not be the version your site uses on the web. To check extensions for the version the site actually runs, use the panel's per-version extension list, or a temporary phpinfo() page that you delete right after.
Rolling back is a valid first move. It restores service, and nothing is lost. The risk is that rollback becomes the permanent state, and the site keeps running on an unsupported PHP branch that no longer gets security fixes. Once you know the cause, there are better short-term options. For a broken plugin, you can deactivate just that plugin and keep PHP 8. If you have WP-CLI, the flags below load WordPress without plugins or themes, which matters because a fatal error would otherwise stop WP-CLI too:
BASH
# Deactivate only the plugin named in the fatal error, then confirm what is still active
wp plugin deactivate old-slider --skip-plugins --skip-themes
wp plugin list --status=active --skip-plugins --skip-themes
Without SSH, renaming the plugin's folder in File Manager or over FTP (for example old-slider to old-slider.off) has the same effect: WordPress can't find it and deactivates it. Theme errors are harder, because the site needs a theme to render; switching to a default theme is the usual stopgap. For a missing extension, enable it for the new PHP version in your panel, then switch again. For limits, copy the values you deliberately changed into the new version's settings. In both cases, recheck the log after the switch. Fixing one fatal error often reveals the next one that was hiding behind it. Deactivating a plugin isn't free, so check what it did first. If it's a slider, the homepage looks different. If it handles payments, forms, or redirects, you're trading one outage for a quieter one.
The deeper problem is that changing PHP versions is usually treated as a dropdown setting, when it actually changes the runtime for every line of code on the site. A few habits make the next switch boring. Test on a staging copy first. Clone the site, switch staging to the target version, browse the pages that matter (checkout, forms, login, any custom templates), and read the log. Many fatal errors only fire on specific pages, so a working homepage proves little. Scan code before you switch. PHP_CodeSniffer with the PHPCompatibilityWP ruleset can flag removed functions and changed behavior across plugins and themes, using something like phpcs -p wp-content/plugins/ --standard=PHPCompatibilityWP --runtime-set testVersion 8.0-. It requires installing those tools and produces some false positives, but it finds the create_function() class of problem before visitors do. Match the environment, not just the version. Before switching, write down which extensions and php.ini overrides the current version has, and apply the same ones to the new version. This catches the second and third buckets with no debugging at all. Retire abandoned code. A plugin that calls functions removed in PHP 8.0 hasn't been maintained for a long time, and that usually means it also hasn't had security fixes. Replacing it is more work than renaming a folder, but it removes the blocker for good. The same applies to WordPress core: older core releases predate PHP 8 support, so update core before the PHP switch, not after. If the symptom you saw was a blank white page instead of the critical error message, the causes overlap heavily; that variant is covered in Kenapa WordPress Jadi Blank Putih Setelah Upgrade ke PHP 8.x. The practical takeaway is simple. When PHP 8 breaks a WordPress site, don't treat rollback as the answer. Trigger the error once, read the 'PHP Fatal' line, and let the file path and error type tell you whether you're dealing with old code, a missing extension, or a missing limit. Fix that on staging, carry your extensions and php.ini settings across, and the next switch should be a non-event.