Title: WP_Automatic_Updater::send_plugin_theme_email
Published: August 11, 2020
Last modified: April 28, 2025

---

# WP_Automatic_Updater::send_plugin_theme_email( string $type, array $successful_updates, array $failed_updates )

## In this article

 * [Parameters](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#parameters)
 * [Source](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#source)
 * [Hooks](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#hooks)
 * [Related](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#changelog)

[ Back to top](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#wp--skip-link--target)

Sends an email upon the completion or failure of a plugin or theme background update.

## 󠀁[Parameters](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#parameters)󠁿

 `$type`stringrequired

The type of email to send. Can be one of `'success'`, `'fail'`, `'mixed'`.

`$successful_updates`arrayrequired

A list of updates that succeeded.

`$failed_updates`arrayrequired

A list of updates that failed.

## 󠀁[Source](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#source)󠁿

    ```php
    protected function send_plugin_theme_email( $type, $successful_updates, $failed_updates ) {
    	// No updates were attempted.
    	if ( empty( $successful_updates ) && empty( $failed_updates ) ) {
    		return;
    	}

    	$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} ] ) ) {
    					$unique_failures = true;
    					continue;
    				}

    				// 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, '<' ) ) {
    					$unique_failures = true;
    				}
    			}
    		}

    		if ( ! $unique_failures ) {
    			return;
    		}
    	}

    	$admin_user = get_user_by( 'email', get_site_option( 'admin_email' ) );

    	if ( $admin_user ) {
    		$switched_locale = switch_to_user_locale( $admin_user->ID );
    	} else {
    		$switched_locale = switch_to_locale( get_locale() );
    	}

    	$body               = array();
    	$successful_plugins = ( ! empty( $successful_updates['plugin'] ) );
    	$successful_themes  = ( ! empty( $successful_updates['theme'] ) );
    	$failed_plugins     = ( ! empty( $failed_updates['plugin'] ) );
    	$failed_themes      = ( ! empty( $failed_updates['theme'] ) );

    	switch ( $type ) {
    		case 'success':
    			if ( $successful_plugins && $successful_themes ) {
    				/* translators: %s: Site title. */
    				$subject = __( '[%s] Some plugins and themes have automatically updated' );
    				$body[]  = sprintf(
    					/* 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.' ),
    					home_url()
    				);
    			} elseif ( $successful_plugins ) {
    				/* translators: %s: Site title. */
    				$subject = __( '[%s] Some plugins were automatically updated' );
    				$body[]  = sprintf(
    					/* 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.' ),
    					home_url()
    				);
    			} else {
    				/* translators: %s: Site title. */
    				$subject = __( '[%s] Some themes were automatically updated' );
    				$body[]  = sprintf(
    					/* 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.' ),
    					home_url()
    				);
    			}

    			break;
    		case 'fail':
    		case 'mixed':
    			if ( $failed_plugins && $failed_themes ) {
    				/* translators: %s: Site title. */
    				$subject = __( '[%s] Some plugins and themes have failed to update' );
    				$body[]  = sprintf(
    					/* translators: %s: Home URL. */
    					__( 'Howdy! Plugins and themes failed to update on your site at %s.' ),
    					home_url()
    				);
    			} elseif ( $failed_plugins ) {
    				/* translators: %s: Site title. */
    				$subject = __( '[%s] Some plugins have failed to update' );
    				$body[]  = sprintf(
    					/* translators: %s: Home URL. */
    					__( 'Howdy! Plugins failed to update on your site at %s.' ),
    					home_url()
    				);
    			} else {
    				/* translators: %s: Site title. */
    				$subject = __( '[%s] Some themes have failed to update' );
    				$body[]  = sprintf(
    					/* translators: %s: Home URL. */
    					__( 'Howdy! Themes failed to update on your site at %s.' ),
    					home_url()
    				);
    			}

    			break;
    	}

    	if ( in_array( $type, array( 'fail', 'mixed' ), true ) ) {
    		$body[] = "\n";
    		$body[] = __( 'Please check your site now. It’s possible that everything is working. If there are updates available, you should update.' );
    		$body[] = "\n";

    		// 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 ) {
    				$body_message = '';
    				$item_url     = '';

    				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,
    						$item_url
    					);
    				} else {
    					$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,
    						$item_url
    					);
    				}

    				$body[] = $body_message;

    				$past_failure_emails[ $item->item->plugin ] = $item->item->new_version;
    			}

    			$body[] = "\n";
    		}

    		// 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 ) {
    					$body[] = sprintf(
    						/* 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,
    						$item->item->new_version
    					);
    				} else {
    					$body[] = sprintf(
    						/* translators: 1: Theme name, 2: Version number. */
    						__( '- %1$s version %2$s' ),
    						html_entity_decode( $item->name ),
    						$item->item->new_version
    					);
    				}

    				$past_failure_emails[ $item->item->theme ] = $item->item->new_version;
    			}

    			$body[] = "\n";
    		}
    	}

    	// List successful updates.
    	if ( in_array( $type, array( 'success', 'mixed' ), true ) ) {
    		$body[] = "\n";

    		// List successful plugin updates.
    		if ( ! empty( $successful_updates['plugin'] ) ) {
    			$body[] = __( 'These plugins are now up to date:' );

    			foreach ( $successful_updates['plugin'] as $item ) {
    				$body_message = '';
    				$item_url     = '';

    				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,
    						$item_url
    					);
    				} else {
    					$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,
    						$item_url
    					);
    				}
    				$body[] = $body_message;

    				unset( $past_failure_emails[ $item->item->plugin ] );
    			}

    			$body[] = "\n";
    		}

    		// 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 ) {
    					$body[] = sprintf(
    						/* 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,
    						$item->item->new_version
    					);
    				} else {
    					$body[] = sprintf(
    						/* translators: 1: Theme name, 2: Version number. */
    						__( '- %1$s version %2$s' ),
    						html_entity_decode( $item->name ),
    						$item->item->new_version
    					);
    				}

    				unset( $past_failure_emails[ $item->item->theme ] );
    			}

    			$body[] = "\n";
    		}
    	}

    	if ( $failed_plugins ) {
    		$body[] = sprintf(
    			/* translators: %s: Plugins screen URL. */
    			__( 'To manage plugins on your site, visit the Plugins page: %s' ),
    			admin_url( 'plugins.php' )
    		);
    		$body[] = "\n";
    	}

    	if ( $failed_themes ) {
    		$body[] = sprintf(
    			/* translators: %s: Themes screen URL. */
    			__( 'To manage themes on your site, visit the Themes page: %s' ),
    			admin_url( 'themes.php' )
    		);
    		$body[] = "\n";
    	}

    	// 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 );
    	} else {
    		$site_title = parse_url( home_url(), PHP_URL_HOST );
    	}

    	$body    = implode( "\n", $body );
    	$to      = get_site_option( 'admin_email' );
    	$subject = sprintf( $subject, $site_title );
    	$headers = '';

    	$email = compact( 'to', 'subject', 'body', 'headers' );

    	/**
    	 * Filters the email sent following an automatic background update for plugins and themes.
    	 *
    	 * @since 5.5.0
    	 *
    	 * @param array  $email {
    	 *     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', 'mixed'.
    	 * @param array  $successful_updates A list of updates that succeeded.
    	 * @param array  $failed_updates     A list of updates that failed.
    	 */
    	$email = apply_filters( 'auto_plugin_theme_update_email', $email, $type, $successful_updates, $failed_updates );

    	$result = wp_mail( $email['to'], wp_specialchars_decode( $email['subject'] ), $email['body'], $email['headers'] );

    	if ( $result ) {
    		update_option( 'auto_plugin_theme_update_emails', $past_failure_emails );
    	}

    	if ( $switched_locale ) {
    		restore_previous_locale();
    	}
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-admin/includes/class-wp-automatic-updater.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/6.9.4/src/wp-admin/includes/class-wp-automatic-updater.php#L1235)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/6.9.4/src/wp-admin/includes/class-wp-automatic-updater.php#L1235-L1552)

## 󠀁[Hooks](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#hooks)󠁿

 [apply_filters( ‘auto_plugin_theme_update_email’, array $email, string $type, array $successful_updates, array $failed_updates )](https://developer.wordpress.org/reference/hooks/auto_plugin_theme_update_email/)

Filters the email sent following an automatic background update for plugins and 
themes.

## 󠀁[Related](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#related)󠁿

| Uses | Description | 
| [switch_to_user_locale()](https://developer.wordpress.org/reference/functions/switch_to_user_locale/)`wp-includes/l10n.php` |

Switches the translations according to the given user’s locale.

  | 
| [restore_previous_locale()](https://developer.wordpress.org/reference/functions/restore_previous_locale/)`wp-includes/l10n.php` |

Restores the translations according to the previous locale.

  | 
| [switch_to_locale()](https://developer.wordpress.org/reference/functions/switch_to_locale/)`wp-includes/l10n.php` |

Switches the translations according to the given locale.

  | 
| [get_locale()](https://developer.wordpress.org/reference/functions/get_locale/)`wp-includes/l10n.php` |

Retrieves the current locale.

  | 
| [wp_specialchars_decode()](https://developer.wordpress.org/reference/functions/wp_specialchars_decode/)`wp-includes/formatting.php` |

Converts a number of HTML entities into their special characters.

  | 
| [get_user_by()](https://developer.wordpress.org/reference/functions/get_user_by/)`wp-includes/pluggable.php` |

Retrieves user info by a given field.

  | 
| [wp_mail()](https://developer.wordpress.org/reference/functions/wp_mail/)`wp-includes/pluggable.php` |

Sends an email, similar to PHP’s mail function.

  | 
| [__()](https://developer.wordpress.org/reference/functions/__/)`wp-includes/l10n.php` |

Retrieves the translation of $text.

  | 
| [esc_url()](https://developer.wordpress.org/reference/functions/esc_url/)`wp-includes/formatting.php` |

Checks and cleans a URL.

  | 
| [admin_url()](https://developer.wordpress.org/reference/functions/admin_url/)`wp-includes/link-template.php` |

Retrieves the URL to the admin area for the current site.

  | 
| [home_url()](https://developer.wordpress.org/reference/functions/home_url/)`wp-includes/link-template.php` |

Retrieves the URL for the current site where the front end is accessible.

  | 
| [apply_filters()](https://developer.wordpress.org/reference/functions/apply_filters/)`wp-includes/plugin.php` |

Calls the callback functions that have been added to a filter hook.

  | 
| [get_site_option()](https://developer.wordpress.org/reference/functions/get_site_option/)`wp-includes/option.php` |

Retrieve an option value for the current network based on name of option.

  | 
| [update_option()](https://developer.wordpress.org/reference/functions/update_option/)`wp-includes/option.php` |

Updates the value of an option that was already added.

  | 
| [get_option()](https://developer.wordpress.org/reference/functions/get_option/)`wp-includes/option.php` |

Retrieves an option value based on an option name.

  |

[Show 10 more](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#)

| Used by | Description | 
| [WP_Automatic_Updater::after_plugin_theme_update()](https://developer.wordpress.org/reference/classes/wp_automatic_updater/after_plugin_theme_update/)`wp-admin/includes/class-wp-automatic-updater.php` |

Checks whether an email should be sent after attempting plugin or theme updates.

  |

## 󠀁[Changelog](https://developer.wordpress.org/reference/classes/wp_automatic_updater/send_plugin_theme_email/?output_format=md#changelog)󠁿

| Version | Description | 
| [5.5.0](https://developer.wordpress.org/reference/since/5.5.0/) | Introduced. |

## User Contributed Notes

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Fclasses%2Fwp_automatic_updater%2Fsend_plugin_theme_email%2F)
before being able to contribute a note or feedback.