2026年11月13日
2026年11月13日
Send WordPress Errors to Slack with an Incoming Webhook and mu-plugin
This article is a localized edition of the Japanese original. Read the Japanese original
When a plugin or theme causes a PHP fatal error in WordPress, the screen shows "There has been a critical error on this website", and instructions for recovery mode are sent to the administrator's email address. Because that email can be noticed late, this article shows how to send a notification to a Slack channel at the same moment.
All you need is a Slack Incoming Webhook and a single WordPress mu-plugin file (a plugin that is always loaded without being activated). No extra plugins are required. The steps were checked against Slack's developer documentation and the WordPress source code as of November 2026.
How it works
- When you create an Incoming Webhook in Slack, you get a dedicated URL for posting messages to a channel
- At the end of each request, a function registered with PHP's
register_shutdown_function()runs and checks the last error witherror_get_last() - If it was a fatal error, the details are sent to the webhook URL with
wp_remote_post()
WordPress core also checks for errors at the end of the request and shows the "critical error" screen. That screen is displayed with a setting that does not stop processing ('exit' => false passed to wp_die()), so your function still runs afterwards.
1. Create an Incoming Webhook in Slack
- Open the Slack API app management page and choose "Create New App" → "From scratch"
- Enter an app name (for example,
WordPress Alerts), choose the workspace to notify, and create the app - Open "Incoming Webhooks" in the left menu and turn on "Activate Incoming Webhooks"
- Click "Add New Webhook to Workspace", choose the channel to post to, and click "Authorize"
- Copy the URL shown under "Webhook URLs for Your Workspace"
The URL looks like this:
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
To post to a private channel, you must already be a member of that channel.
First, check from a terminal on your computer that messages arrive.
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Test notification from WordPress"}' \
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
If it works, ok is printed and the message is posted to the channel.
Handling the webhook URL
Anyone who knows this URL can post to the channel.
- Don't put it in theme files or in a public Git repository
- If it leaks, delete that webhook on the Incoming Webhooks screen of the Slack app settings and create a new one
Slack may revoke webhook URLs that it finds in public places.
With an Incoming Webhook, you cannot change the channel, display name or icon when sending. The ones set in the app configuration are used.
2. Add the URL to wp-config.php
Add the following line to wp-config.php above the line /* That's all, stop editing! */.
<?php
define( 'WPDR_SLACK_WEBHOOK_URL', 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX' );
For working with wp-config.php, see also How to add constants to wp-config.php. If you want staging and production to notify different channels, put a different URL in each site's wp-config.php.
3. Add the mu-plugin
Create the wp-content/mu-plugins/ folder (if it doesn't exist) and put the following file in it as 0-slack-error-notify.php. Files in the mu-plugins folder are loaded without activation in the admin, and before regular plugins. Files in that folder are loaded in name order, so the name starts with 0-.
<?php
/**
* Plugin Name: Slack Error Notify
* Description: Sends PHP fatal errors to a Slack Incoming Webhook.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Send a message to Slack. Returns true on success.
*/
function wpdr_slack_send( $text ) {
if ( ! defined( 'WPDR_SLACK_WEBHOOK_URL' ) || '' === WPDR_SLACK_WEBHOOK_URL ) {
return false;
}
if ( ! function_exists( 'wp_remote_post' ) ) {
return false;
}
$response = wp_remote_post(
WPDR_SLACK_WEBHOOK_URL,
array(
'timeout' => 5,
'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ),
'body' => wp_json_encode( array( 'text' => $text ) ),
)
);
return ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response );
}
register_shutdown_function(
function () {
$error = error_get_last();
if ( null === $error ) {
return;
}
$fatal_types = array( E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR );
if ( ! in_array( $error['type'], $fatal_types, true ) ) {
return;
}
// Send the same error at most once every 10 minutes.
$key = 'wpdr_slack_' . md5( $error['message'] . $error['file'] . $error['line'] );
if ( function_exists( 'get_transient' ) ) {
if ( get_transient( $key ) ) {
return;
}
set_transient( $key, 1, 10 * MINUTE_IN_SECONDS );
}
$path = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '(CLI / cron)';
$text = sprintf(
"PHP fatal error: %s\nPath: %s\nFile: %s:%d\nMessage: %s",
wp_parse_url( home_url(), PHP_URL_HOST ),
$path,
$error['file'],
$error['line'],
mb_substr( $error['message'], 0, 1000 )
);
wpdr_slack_send( $text );
}
);
Key points of the code:
- Only fatal errors (errors that stop processing) are sent. Warnings and deprecation notices are not.
- If the same error keeps happening, a notification would arrive on every request, so the same message is sent at most once every 10 minutes (recorded in a WordPress transient).
- The request to Slack times out after 5 seconds, so that pages don't hang for long when Slack can't be reached.
- The notification includes the file and line where the error occurred. Server paths are sent to Slack, so send notifications to a channel for the people involved only.
4. Test it
If you have SSH and WP-CLI, call the send function directly to check that WordPress can reach Slack.
wp eval 'var_dump( wpdr_slack_send( "Test notification from WordPress" ) );'
If bool(true) is printed and the message is posted to the channel, it works. If you get bool(false), check the constant name and URL in wp-config.php, and that the server is allowed to make outbound HTTPS connections.
To test the fatal error notification itself, do it on a staging site, not in production: temporarily add an mu-plugin that just calls a function that doesn't exist, and open a page.
<?php
// Delete this file as soon as the test is done.
if ( isset( $_GET['slack_test'] ) ) {
wpdr_undefined_function_for_test();
}
Save this file as wp-content/mu-plugins/zz-slack-test.php and open https://your-staging-site/?slack_test=1. The "critical error" screen appears and a notification arrives in Slack. Delete the file when you're done.
What is not notified
This method has limits.
- Errors before the mu-plugin is loaded: A typo in
wp-config.phpor an error while WordPress core is loading is not notified, because this mu-plugin has not been loaded yet. - When the database can't be reached: "Error establishing a database connection" is not a PHP fatal error, so it is not notified.
- When the server itself is down: PHP isn't running, so nothing can be sent.
To cover these, combine this with an uptime monitoring service that checks your site from outside at regular intervals. Many monitoring services can notify Slack.
Finding the cause of the error
When you get a notification, the file path in the error message (such as wp-content/plugins/plugin-name/…) tells you which plugin or theme caused it. If you can't get into the admin, log in through the recovery mode link sent to the administrator's email and deactivate the plugin that caused it. For details, see How to use WordPress recovery mode, and for keeping a log of errors, see How to enable WordPress debug mode.
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)