: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Don't show this message if there is a newer version available.
* Potential for confusion, and also not useful for them to know at this point.
if ( 'fail' === $type && ! $newer_version_available ) {
$body .= __( 'An attempt was made, but your site could not be updated automatically.' ) . ' ';
$body .= __( 'Updating is easy and only takes a few moments:' );
$body .= "\n" . network_admin_url( 'update-core.php' );
if ( $newer_version_available ) {
/* translators: 1: Home URL, 2: WordPress version. */
__( 'Your site at %1$s experienced a critical failure while trying to update WordPress to version %2$s.' ),
/* translators: 1: Home URL, 2: WordPress latest version. */
__( 'Your site at %1$s experienced a critical failure while trying to update to the latest version of WordPress, %2$s.' ),
$body .= "\n\n" . __( "This means your site may be offline or broken. Don't panic; this can be fixed." );
$body .= "\n\n" . __( "Please check out your site now. It's possible that everything is working. If it says you need to update, you should do so:" );
$body .= "\n" . network_admin_url( 'update-core.php' );
$critical_support = 'critical' === $type && ! empty( $core_update->support_email );
if ( $critical_support ) {
// Support offer if available.
$body .= "\n\n" . sprintf(
/* translators: %s: Support email address. */
__( 'The WordPress team is willing to help you. Forward this email to %s and the team will work with you to make sure your site is working.' ),
$core_update->support_email
// Add a note about the support forums.
$body .= "\n\n" . __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' );
$body .= "\n" . __( 'https://wordpress.org/support/forums/' );
// Updates are important!
if ( 'success' !== $type || $newer_version_available ) {
$body .= "\n\n" . __( 'Keeping your site updated is important for security. It also makes the internet a safer place for you and your readers.' );
if ( $critical_support ) {
$body .= ' ' . __( "Reach out to WordPress Core developers to ensure you'll never have this problem again." );
// If things are successful and we're now on the latest, mention plugins and themes if any are out of date.
if ( 'success' === $type && ! $newer_version_available && ( get_plugin_updates() || get_theme_updates() ) ) {
$body .= "\n\n" . __( 'You also have some plugins or themes with updates available. Update them now:' );
$body .= "\n" . network_admin_url();
$body .= "\n\n" . __( 'The WordPress Team' ) . "\n";
if ( 'critical' === $type && is_wp_error( $result ) ) {
/* translators: %s: WordPress version. */
$body .= sprintf( __( 'Your site was running version %s.' ), get_bloginfo( 'version' ) );
$body .= ' ' . __( 'Some data that describes the error your site encountered has been put together.' );
$body .= ' ' . __( 'Your hosting company, support forum volunteers, or a friendly developer may be able to use this information to help you:' );
* If we had a rollback and we're still critical, then the rollback failed too.
* Loop through all errors (the main WP_Error, the update result, the rollback result) for code, data, etc.
if ( 'rollback_was_required' === $result->get_error_code() ) {
$errors = array( $result, $result->get_error_data()->update, $result->get_error_data()->rollback );
$errors = array( $result );
foreach ( $errors as $error ) {
if ( ! is_wp_error( $error ) ) {
$error_code = $error->get_error_code();
/* translators: %s: Error code. */
$body .= "\n\n" . sprintf( __( 'Error code: %s' ), $error_code );
if ( 'rollback_was_required' === $error_code ) {
if ( $error->get_error_message() ) {
$body .= "\n" . $error->get_error_message();
$error_data = $error->get_error_data();
$body .= "\n" . implode( ', ', (array) $error_data );
$to = get_site_option( 'admin_email' );
$email = compact( 'to', 'subject', 'body', 'headers' );
* Filters the email sent following an automatic background core update.
* Array of email arguments that will be passed to wp_mail().
* @type string $to The email recipient. An array of emails
* can be returned, as handled by wp_mail().
* @type string $subject The email's subject.
* @type string $body The email message body.
* @type string $headers Any email headers, defaults to no headers.
* @param string $type The type of email being sent. Can be one of
* 'success', 'fail', 'manual', 'critical'.
* @param object $core_update The update offer that was attempted.
* @param mixed $result The result for the core update. Can be WP_Error.
$email = apply_filters( 'auto_core_update_email', $email, $type, $core_update, $result );
wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] );
* Checks whether an email should be sent after attempting plugin or theme updates.
* @param array $update_results The results of update tasks.
protected function after_plugin_theme_update( $update_results ) {
$successful_updates = array();
$failed_updates = array();
if ( ! empty( $update_results['plugin'] ) ) {
* Filters whether to send an email following an automatic background plugin update.
* @since 5.5.1 Added the `$update_results` parameter.
* @param bool $enabled True if plugin update notifications are enabled, false otherwise.
* @param array $update_results The results of plugins update tasks.
$notifications_enabled = apply_filters( 'auto_plugin_update_send_email', true, $update_results['plugin'] );
if ( $notifications_enabled ) {
foreach ( $update_results['plugin'] as $update_result ) {
if ( true === $update_result->result ) {
$successful_updates['plugin'][] = $update_result;
$failed_updates['plugin'][] = $update_result;
if ( ! empty( $update_results['theme'] ) ) {
* Filters whether to send an email following an automatic background theme update.
* @since 5.5.1 Added the `$update_results` parameter.
* @param bool $enabled True if theme update notifications are enabled, false otherwise.
* @param array $update_results The results of theme update tasks.
$notifications_enabled = apply_filters( 'auto_theme_update_send_email', true, $update_results['theme'] );
if ( $notifications_enabled ) {
foreach ( $update_results['theme'] as $update_result ) {
if ( true === $update_result->result ) {
$successful_updates['theme'][] = $update_result;
$failed_updates['theme'][] = $update_result;
if ( empty( $successful_updates ) && empty( $failed_updates ) ) {
if ( empty( $failed_updates ) ) {
$this->send_plugin_theme_email( 'success', $successful_updates, $failed_updates );
} elseif ( empty( $successful_updates ) ) {
$this->send_plugin_theme_email( 'fail', $successful_updates, $failed_updates );
$this->send_plugin_theme_email( 'mixed', $successful_updates, $failed_updates );
* Sends an email upon the completion or failure of a plugin or theme background update.
* @param string $type The type of email to send. Can be one of 'success', 'fail', 'mixed'.
* @param array $successful_updates A list of updates that succeeded.
* @param array $failed_updates A list of updates that failed.
protected function send_plugin_theme_email( $type, $successful_updates, $failed_updates ) {
// No updates were attempted.
if ( empty( $successful_updates ) && empty( $failed_updates ) ) {
$unique_failures = false;
$past_failure_emails = get_option( 'auto_plugin_theme_update_emails', array() );
* When only failures have occurred, an email should only be sent if there are unique failures.
* A failure is considered unique if an email has not been sent for an update attempt failure
* to a plugin or theme with the same new_version.
if ( 'fail' === $type ) {
foreach ( $failed_updates as $update_type => $failures ) {
foreach ( $failures as $failed_update ) {
if ( ! isset( $past_failure_emails[ $failed_update->item->{$update_type} ] ) ) {
// Check that the failure represents a new failure based on the new_version.
if ( version_compare( $past_failure_emails[ $failed_update->item->{$update_type} ], $failed_update->item->new_version, '<' ) ) {
if ( ! $unique_failures ) {
$successful_plugins = ( ! empty( $successful_updates['plugin'] ) );
$successful_themes = ( ! empty( $successful_updates['theme'] ) );
$failed_plugins = ( ! empty( $failed_updates['plugin'] ) );
$failed_themes = ( ! empty( $failed_updates['theme'] ) );
if ( $successful_plugins && $successful_themes ) {
/* translators: %s: Site title. */
$subject = __( '[%s] Some plugins and themes have automatically updated' );
/* translators: %s: Home URL. */
__( 'Howdy! Some plugins and themes have automatically updated to their latest versions on your site at %s. No further action is needed on your part.' ),
} elseif ( $successful_plugins ) {
/* translators: %s: Site title. */
$subject = __( '[%s] Some plugins were automatically updated' );
/* translators: %s: Home URL. */
__( 'Howdy! Some plugins have automatically updated to their latest versions on your site at %s. No further action is needed on your part.' ),
/* translators: %s: Site title. */
$subject = __( '[%s] Some themes were automatically updated' );
/* translators: %s: Home URL. */
__( 'Howdy! Some themes have automatically updated to their latest versions on your site at %s. No further action is needed on your part.' ),
if ( $failed_plugins && $failed_themes ) {
/* translators: %s: Site title. */
$subject = __( '[%s] Some plugins and themes have failed to update' );
/* translators: %s: Home URL. */
__( 'Howdy! Plugins and themes failed to update on your site at %s.' ),
} elseif ( $failed_plugins ) {
/* translators: %s: Site title. */
$subject = __( '[%s] Some plugins have failed to update' );
/* translators: %s: Home URL. */
__( 'Howdy! Plugins failed to update on your site at %s.' ),
/* translators: %s: Site title. */
$subject = __( '[%s] Some themes have failed to update' );
/* translators: %s: Home URL. */
__( 'Howdy! Themes failed to update on your site at %s.' ),
if ( in_array( $type, array( 'fail', 'mixed' ), true ) ) {
$body[] = __( 'Please check your site now. It’s possible that everything is working. If there are updates available, you should update.' );
// List failed plugin updates.
if ( ! empty( $failed_updates['plugin'] ) ) {
$body[] = __( 'The following plugins failed to update. If there was a fatal error in the update, the previously installed version has been restored.' );
foreach ( $failed_updates['plugin'] as $item ) {
if ( ! empty( $item->item->url ) ) {
$item_url = ' : ' . esc_url( $item->item->url );
if ( $item->item->current_version ) {
$body_message .= sprintf(
/* translators: 1: Plugin name, 2: Current version number, 3: New version number, 4: Plugin URL. */
__( '- %1$s (from version %2$s to %3$s)%4$s' ),
html_entity_decode( $item->name ),
$item->item->current_version,
$item->item->new_version,
$body_message .= sprintf(
/* translators: 1: Plugin name, 2: Version number, 3: Plugin URL. */
__( '- %1$s version %2$s%3$s' ),
html_entity_decode( $item->name ),
$item->item->new_version,
$past_failure_emails[ $item->item->plugin ] = $item->item->new_version;
// List failed theme updates.
if ( ! empty( $failed_updates['theme'] ) ) {
$body[] = __( 'These themes failed to update:' );
foreach ( $failed_updates['theme'] as $item ) {
if ( $item->item->current_version ) {
/* translators: 1: Theme name, 2: Current version number, 3: New version number. */
__( '- %1$s (from version %2$s to %3$s)' ),
html_entity_decode( $item->name ),
$item->item->current_version,
/* translators: 1: Theme name, 2: Version number. */
__( '- %1$s version %2$s' ),
html_entity_decode( $item->name ),
$past_failure_emails[ $item->item->theme ] = $item->item->new_version;
// List successful updates.
if ( in_array( $type, array( 'success', 'mixed' ), true ) ) {
// List successful plugin updates.
if ( ! empty( $successful_updates['plugin'] ) ) {
$body[] = __( 'These plugins are now up to date:' );
foreach ( $successful_updates['plugin'] as $item ) {
if ( ! empty( $item->item->url ) ) {
$item_url = ' : ' . esc_url( $item->item->url );
if ( $item->item->current_version ) {
$body_message .= sprintf(
/* translators: 1: Plugin name, 2: Current version number, 3: New version number, 4: Plugin URL. */
__( '- %1$s (from version %2$s to %3$s)%4$s' ),
html_entity_decode( $item->name ),
$item->item->current_version,
$item->item->new_version,
$body_message .= sprintf(
/* translators: 1: Plugin name, 2: Version number, 3: Plugin URL. */
__( '- %1$s version %2$s%3$s' ),
html_entity_decode( $item->name ),
$item->item->new_version,
unset( $past_failure_emails[ $item->item->plugin ] );
// List successful theme updates.
if ( ! empty( $successful_updates['theme'] ) ) {
$body[] = __( 'These themes are now up to date:' );
foreach ( $successful_updates['theme'] as $item ) {
if ( $item->item->current_version ) {
/* translators: 1: Theme name, 2: Current version number, 3: New version number. */
__( '- %1$s (from version %2$s to %3$s)' ),
html_entity_decode( $item->name ),
$item->item->current_version,
/* translators: 1: Theme name, 2: Version number. */
__( '- %1$s version %2$s' ),
html_entity_decode( $item->name ),
unset( $past_failure_emails[ $item->item->theme ] );
/* translators: %s: Plugins screen URL. */
__( 'To manage plugins on your site, visit the Plugins page: %s' ),
admin_url( 'plugins.php' )
/* translators: %s: Themes screen URL. */
__( 'To manage themes on your site, visit the Themes page: %s' ),
admin_url( 'themes.php' )
// Add a note about the support forums.
$body[] = __( 'If you experience any issues or need support, the volunteers in the WordPress.org support forums may be able to help.' );
$body[] = __( 'https://wordpress.org/support/forums/' );
$body[] = "\n" . __( 'The WordPress Team' );
if ( '' !== get_option( 'blogname' ) ) {
$site_title = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
$site_title = parse_url( home_url(), PHP_URL_HOST );
$body = implode( "\n", $body );
$to = get_site_option( 'admin_email' );
$subject = sprintf( $subject, $site_title );