“There has been a critical error on this website” after a PHP update: find the cause and fix it

By CompatNav · Published · Last reviewed · 9 min read

Short answer

If the message appeared right after a PHP update, switch your site back to the PHP version it used before, in your hosting control panel. If the update caused the error, the site works again straight away. Then find the plugin or theme behind it: WordPress emails the site administrator with its name, and the error message shows its folder. Update, replace or fix it, and only then upgrade PHP again.

First, get your site back

WordPress shows “There has been a critical error on this website.” when PHP stops with a fatal error while building a page. Since WordPress 5.2 it catches these errors, shows an error message instead of a blank page, and emails the site administrator (make.wordpress.org).

If the message appeared right after a PHP update, undo the update first and investigate afterwards:

  1. Open your hosting control panel and find the PHP version setting. It is often called “PHP version”, “PHP Selector” or “MultiPHP Manager”.
  2. Choose the version your site used before and save.
  3. Reload your site. If the PHP update caused the error, the site works again.

Can’t change it yourself? Ask your host’s support to switch your site back; it’s a routine request. Going back is a pause, not a solution: PHP versions reach their end of life (see PHP 8.2 reaches end of life on 31 December 2026), so the cause has to be fixed.

Find the plugin or theme that stopped

The email WordPress sends you

When the error happens, WordPress emails the site’s administration email address. The subject contains “Your Site is Experiencing a Technical Issue”, and the email names the culprit: “In this case, WordPress caught an error with one of your plugins, …” or “… with your theme, …”. It also contains the technical error message and a link to recovery mode (WordPress 7.1.2 source).

On the admin and login pages of a single site, the error message itself reminds you: “Please check your site admin email inbox for instructions.”

Recovery mode

The link in the email logs you in while the plugin or theme that caused the error is paused. The admin area tells you which extensions are paused and what the errors are, so you can deactivate the plugin or switch the theme. You leave recovery mode with the button in the admin bar (make.wordpress.org).

No email? Find the error message

Your host usually keeps a PHP error log; its control panel or support can show it to you. If you aren’t comfortable editing your site’s files, this is the way to go: ask your host’s support for the PHP error log from the time the error appeared.

WordPress can also write errors to a log file. For that you edit wp-config.php, usually in the main folder of your WordPress site, with your host’s File Manager or an FTP program: set WP_DEBUG and WP_DEBUG_LOG to true and WP_DEBUG_DISPLAY to false. The WordPress documentation says these debug tools are “not recommended” on live sites, and by default the log is written to wp-content/debug.log (developer.wordpress.org). If you use it on a live site, point WP_DEBUG_LOG to a file outside the public web folder, as the documentation allows, and switch it off again when you’re done.

Reading the error message

A fatal error message tells you what went wrong, and where. This is the real message PHP 8.0 gives for a plugin that still uses create_function():

Output on PHP 8.0.30the script stopped

Fatal error: Uncaught Error: 1Call to undefined function create_function() in /var/www/html/2wp-content/plugins/old-slider/old-slider.php:3
Stack trace:
#0 {main}
  thrown in /var/www/html/wp-content/plugins/old-slider/3old-slider.php on line 3
  1. What went wrong: PHP can’t find the function create_function(), because PHP 8.0 removed it.
  2. Which plugin: the folder after wp-content/plugins/ (or wp-content/themes/) names the plugin (or theme): here, old-slider.
  3. Where exactly: the file and line, for whoever fixes the code.

Why a PHP update causes fatal errors

Each PHP version removes things that were announced as deprecated earlier, and changes how some code behaves. PHP 8.0, for example, removed several features that PHP 7 had already deprecated. Old plugin code runs into such changes in three ways.

A function that no longer exists

create_function() was deprecated in PHP 7.2 “given the security issues of this function (being a thin wrapper around eval())” (php.net). PHP 8.0 removed it, along with each(): “create_function() has been removed. Anonymous functions may be used instead.” and “each() has been removed. foreach or ArrayIterator should be used instead.” (php.net).

On PHP 7.4 the code still runs and only logs a deprecation notice. On PHP 8.0 and later the call is a fatal error.

Code: create_function() and each(), before and after

wp-content/plugins/old-slider/old-slider.php

<?php
$slides = [['title' => 'Team', 'order' => 2], ['title' => 'Welcome', 'order' => 1]];
$by_order = create_function('$a, $b', 'return $a["order"] - $b["order"];');
usort($slides, $by_order);
echo 'First slide: ', $slides[0]['title'], "\n";

Output on PHP 7.4.33

Deprecated: Function create_function() is deprecated in /var/www/html/wp-content/plugins/old-slider/old-slider.php on line 3
First slide: Welcome

Output on PHP 8.0.30the script stopped

Fatal error: Uncaught Error: Call to undefined function create_function() in /var/www/html/wp-content/plugins/old-slider/old-slider.php:3
Stack trace:
#0 {main}
  thrown in /var/www/html/wp-content/plugins/old-slider/old-slider.php on line 3

An anonymous function does the same job on every PHP version:

wp-content/plugins/old-slider/old-slider.php

<?php
$slides = [['title' => 'Team', 'order' => 2], ['title' => 'Welcome', 'order' => 1]];
$by_order = function ($a, $b) {
    return $a['order'] - $b['order'];
};
usort($slides, $by_order);
echo 'First slide: ', $slides[0]['title'], "\n";

Output on PHP 8.0.30

First slide: Welcome

Output on PHP 8.5.11

First slide: Welcome

each() goes the same way; foreach replaces it:

wp-content/themes/old-theme/functions.php

<?php
$options = ['color' => 'blue', 'layout' => 'wide'];
while (list($key, $value) = each($options)) {
    echo $key, ' = ', $value, "\n";
}

Output on PHP 7.4.33

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /var/www/html/wp-content/themes/old-theme/functions.php on line 3
color = blue
layout = wide

Output on PHP 8.0.30the script stopped

Fatal error: Uncaught Error: Call to undefined function each() in /var/www/html/wp-content/themes/old-theme/functions.php:3
Stack trace:
#0 {main}
  thrown in /var/www/html/wp-content/themes/old-theme/functions.php on line 3

wp-content/themes/old-theme/functions.php

<?php
$options = ['color' => 'blue', 'layout' => 'wide'];
foreach ($options as $key => $value) {
    echo $key, ' = ', $value, "\n";
}

Output on PHP 8.0.30

color = blue
layout = wide

Code the new version refuses to compile

Some code isn’t even loaded any more. PHP 8.0: “Nested ternaries now require explicit parentheses.” (php.net) A line like $a ? 'x' : $b ? 'y' : 'z' without brackets stops the whole file from compiling, so every page that loads it fails.

Code: a nested ternary, before and after

wp-content/plugins/old-gallery/old-gallery.php

<?php
$count = 0;
$label = $count == 0 ? 'no photos' : $count == 1 ? 'one photo' : 'photos';
echo $label, "\n";

Output on PHP 7.4.33

Deprecated: Unparenthesized `a ? b : c ? d : e` is deprecated. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)` in /var/www/html/wp-content/plugins/old-gallery/old-gallery.php on line 3
one photo

Output on PHP 8.0.30the script stopped

Fatal error: Unparenthesized `a ? b : c ? d : e` is not supported. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)` in /var/www/html/wp-content/plugins/old-gallery/old-gallery.php on line 3

On PHP 7.4 this line already gave the wrong answer: with zero photos it prints “one photo”, because old PHP read the chain from left to right. Brackets make the intended order explicit:

wp-content/plugins/old-gallery/old-gallery.php

<?php
$count = 0;
$label = $count == 0 ? 'no photos' : ($count == 1 ? 'one photo' : 'photos');
echo $label, "\n";

Output on PHP 8.0.30

no photos

Code that silently changes meaning

The trickiest case produces no error where the problem is. Very old PHP code creates objects with a method that has the same name as its class, instead of __construct(). PHP 8.0: “Methods with the same name as the class are no longer interpreted as constructors.” (php.net)

On PHP 8.0 that method simply isn’t run when the object is created. There is no error at that line: the object stays uninitialised, and the page fails later, wherever the missing data is used. The error message then points to that later line, not to the real cause.

Code: an old-style constructor, before and after

wp-content/plugins/old-slider/includes/class-slider.php

<?php
class Slider {
    private $slides;

    public function Slider() {
        $this->slides = ['welcome.jpg', 'team.jpg'];
    }

    public function count_slides() {
        return count($this->slides);
    }
}

$slider = new Slider();
echo 'Slides: ', $slider->count_slides(), "\n";

Output on PHP 7.4.33

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; Slider has a deprecated constructor in /var/www/html/wp-content/plugins/old-slider/includes/class-slider.php on line 2
Slides: 2

Output on PHP 8.0.30the script stopped

Slides:
Fatal error: Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given in /var/www/html/wp-content/plugins/old-slider/includes/class-slider.php:10
Stack trace:
#0 /var/www/html/wp-content/plugins/old-slider/includes/class-slider.php(15): Slider->count_slides()
#1 {main}
  thrown in /var/www/html/wp-content/plugins/old-slider/includes/class-slider.php on line 10

On PHP 8.0 the error is reported at count() on line 10, called from line 15. The cause is on line 5, where Slider() is no longer treated as the constructor. Renaming it to __construct() fixes it on every version:

wp-content/plugins/old-slider/includes/class-slider.php

<?php
class Slider {
    private $slides;

    public function __construct() {
        $this->slides = ['welcome.jpg', 'team.jpg'];
    }

    public function count_slides() {
        return count($this->slides);
    }
}

$slider = new Slider();
echo 'Slides: ', $slider->count_slides(), "\n";

Output on PHP 8.0.30

Slides: 2

Reading the code, rather than waiting for the error, finds the cause directly. This is how a check reports this plugin before the upgrade:

Fix it

  • Update the plugin or theme (Dashboard → Updates). If an update is available, install it first: it may already contain the fix.
  • Already on the latest version, or no updates for years? Contact its developer, or replace it with a maintained alternative.
  • Code written for your site? Give the error message to whoever maintains it.
  • Don’t edit the plugin’s or theme’s files yourself: your changes are lost with the next update.

Not ready yet: what to do explains each option in more detail.

Upgrade PHP again, safely

  1. Make a backup of your site.
  2. Check all plugins and your theme for the PHP version you want, not only the one that failed: another plugin may have the same problem. A CompatNav scan, for example, lists every place that will break or only show notices, per plugin and theme.
  3. Fix what will break, as above.
  4. Switch PHP, then visit your important pages and forms, and look at your error log over the next few days.

What a scan can’t catch

A check that reads code finds removed functions, code PHP refuses to compile, and patterns like old-style constructors before you switch. It can’t see problems that depend on the values a plugin works with while it runs. For example, PHP 8.0 turned “a number of warnings” into errors, such as arithmetic on a value that isn’t a number (php.net): whether that happens depends on the data. That’s why the last step, checking the site after switching, always matters.

For the PHP 8.5 changes specifically, see WordPress and PHP 8.5: what breaks, what only shows notices.

Key takeaways

  • First get the site back: switch to the previous PHP version in your hosting panel, or ask your host to.
  • WordPress emails the site administrator: the subject contains “Your Site is Experiencing a Technical Issue”, and the email names the plugin or theme and links to recovery mode.
  • In the error message, the folder after wp-content/plugins/ or wp-content/themes/ tells you which plugin or theme stopped.
  • PHP updates break code in three ways: a function that no longer exists, code the new version refuses to compile, and code that silently changes meaning, like old-style constructors, which fail later and elsewhere.
  • Fix it by updating, replacing or asking the developer; check everything before you switch PHP again; a check can’t see problems that depend on values at run time.

Frequently asked questions

Will I lose my content?

No. Posts, pages and settings are stored in the database. A fatal error stops PHP from building the page; it doesn’t delete anything. Switching the PHP version back doesn’t touch your content either.

Why is my admin area broken too?

The plugin or theme also loads in the admin area, so the same error stops it there. The link in WordPress’s email opens recovery mode, where you can log in with that plugin or theme paused.

How do I switch PHP back?

In your hosting control panel, look for a setting called something like “PHP version”, “PHP Selector” or “MultiPHP Manager”, and choose the version your site used before. If you can’t find it, ask your host’s support: it’s a routine request.

I didn’t get the email. Where is it?

WordPress sends it to the Administration Email Address under Settings → General (or to the address in the RECOVERY_MODE_EMAIL setting, if your site defines it), and by default at most once a day. Check your spam folder.

Can a theme cause it too?

Yes. The email then says “WordPress caught an error with your theme”, and the error message points to a folder under wp-content/themes/.

Check your own site before you upgrade

CompatNav is a free WordPress plugin. It reads the code of your plugins and themes on your own server and tells you, in plain words, what will break and what will only show notices on the PHP version you choose. It never changes your code. It can’t see problems that only appear while code runs with real data, so a quick check of your site after the upgrade still matters.

Get CompatNav on wordpress.org How it works

Sources

About the code examples: each output is the real output of the code shown, run with the official PHP builds, without a php.ini, with all errors reported and displayed. Only the file path was replaced by a neutral server path.