WP_Fatal_Error_Handler
Default shutdown handler for fatal PHP errors.
Source: wp-includes/class-wp-fatal-error-handler.php
Since: 5.2.0
Description
WP_Fatal_Error_Handler handles fatal PHP errors that would normally cause a "white screen of death" (WSOD). It provides user-friendly error messages and integrates with WordPress Recovery Mode.
A drop-in fatal-error-handler.php in wp-content/ can provide a custom handler class.
Class Attributes
#[AllowDynamicProperties]
class WP_Fatal_Error_Handler
How It Works
- Registered via
register_shutdown_function()during WordPress bootstrap - When PHP encounters a fatal error, the shutdown function runs
- Handler detects the error, checks if it should be handled
- Attempts Recovery Mode for protected endpoints
- Displays appropriate error template
Methods
handle()
Runs the shutdown handler. Registered via register_shutdown_function().
public function handle(): void
Flow:
- Exit early if
WP_SANDBOX_SCRAPINGis defined - Exit early if in maintenance mode
- Detect error via
detect_error() - Load text domain if needed
- Attempt Recovery Mode handling (single site, initialized)
- Display error template if admin or headers not sent
Example registration:
// Done automatically by wp_register_fatal_error_handler()
register_shutdown_function( array( $handler, 'handle' ) );
detect_error() (protected)
Detects the error causing the crash.
protected function detect_error(): ?array
Returns: Error array from error_get_last(), or null if no error or error shouldn’t be handled.
Error array structure:
array(
'type' => E_ERROR, // Error type constant
'message' => 'Error message', // Error description
'file' => '/path/to/file.php',
'line' => 123,
)
should_handle_error() (protected)
Determines whether WordPress should handle the error.
protected function should_handle_error( array $error ): bool
| Parameter | Type | Required | Description |
|---|---|---|---|
$error |
array | Yes | Error from error_get_last() |
Returns: true if WordPress should handle the error.
Handled error types:
| Constant | Value | Description |
|---|---|---|
E_ERROR |
1 | Fatal run-time error |
E_PARSE |
4 | Compile-time parse error |
E_USER_ERROR |
256 | User-generated fatal error |
E_COMPILE_ERROR |
64 | Fatal compile-time error |
E_RECOVERABLE_ERROR |
4096 | Catchable fatal error |
Additional errors can be included via the wp_should_handle_php_error filter.
display_error_template() (protected)
Displays the PHP error template.
protected function display_error_template( array $error, true|WP_Error $handled ): void
| Parameter | Type | Required | Description |
|---|---|---|---|
$error |
array | Yes | Error from error_get_last() |
$handled |
true|WP_Error | Yes | Whether Recovery Mode handled the error |
Template priority:
- Custom drop-in:
wp-content/php-error.php - Default template via
display_default_error_template()
display_default_error_template() (protected)
Displays the default PHP error template using wp_die().
protected function display_default_error_template( array $error, true|WP_Error $handled ): void
| Parameter | Type | Required | Description |
|---|---|---|---|
$error |
array | Yes | Error from error_get_last() |
$handled |
true|WP_Error | Yes | Whether Recovery Mode handled the error |
Messages by context:
| Context | Message |
|---|---|
| Recovery Mode active | "…putting it in recovery mode. Please check Themes and Plugins…" |
| Protected endpoint (multisite) | "…reach out to your site administrator…" |
| Protected endpoint (single) | "…check your site admin email inbox…" |
| Other | "There has been a critical error on this website." |
Customization
Custom Fatal Error Handler (Drop-in)
Create wp-content/fatal-error-handler.php:
<?php
class My_Fatal_Error_Handler extends WP_Fatal_Error_Handler {
protected function display_default_error_template( $error, $handled ) {
// Custom error display
http_response_code( 500 );
echo '<h1>Site Temporarily Unavailable</h1>';
echo '<p>We are experiencing technical difficulties.</p>';
// Log the actual error
error_log( sprintf(
'Fatal error: %s in %s on line %d',
$error['message'],
$error['file'],
$error['line']
) );
}
}
return new My_Fatal_Error_Handler();
Custom PHP Error Template (Drop-in)
Create wp-content/php-error.php:
<?php
/**
* Custom PHP error template.
*
* Variables available:
* - $error: Error array from error_get_last()
* - $handled: Whether Recovery Mode handled the error
*/
http_response_code( 500 );
?>
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
</head>
<body>
<h1>Something went wrong</h1>
<p>Please try again later.</p>
</body>
</html>
Disabling the Handler
Via constant in wp-config.php:
define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true );
Via filter (must be defined before WordPress loads):
$GLOBALS['wp_filter'] = array(
'wp_fatal_error_handler_enabled' => array(
10 => array(
array(
'accepted_args' => 0,
'function' => function() {
return false;
},
),
),
),
);
Integration with Recovery Mode
When a fatal error occurs on a protected endpoint:
- Error is detected by
WP_Fatal_Error_Handler wp_recovery_mode()->handle_error()is called- Recovery Mode:
- Logs the error
- Identifies the problematic extension
- Pauses the extension
- Sends recovery email to admin
- Admin can access site via recovery link
- Admin can fix or deactivate the extension
Protected endpoints:
- Admin pages (
/wp-admin/) - Login page (
wp-login.php) - REST API (selected routes)
Error Handling Flow
PHP Fatal Error
│
▼
register_shutdown_function() triggers
│
▼
WP_Fatal_Error_Handler::handle()
│
├── WP_SANDBOX_SCRAPING? → exit
├── Maintenance mode? → exit
│
▼
detect_error()
│
├── No error? → exit
├── should_handle_error() = false? → exit
│
▼
Recovery Mode initialized?
│
├── Yes → wp_recovery_mode()->handle_error()
│ └── Pause extension, send email
│
▼
display_error_template()
│
├── php-error.php drop-in exists?
│ └── Yes → require php-error.php
│
└── No → display_default_error_template()
└── wp_die() with error message