'advanced-cache.php' => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
'db.php' => array( __( 'Custom database class.' ), true ), // Auto on load.
'db-error.php' => array( __( 'Custom database error message.' ), true ), // Auto on error.
'install.php' => array( __( 'Custom installation script.' ), true ), // Auto on installation.
'maintenance.php' => array( __( 'Custom maintenance message.' ), true ), // Auto on maintenance.
'object-cache.php' => array( __( 'External object cache.' ), true ), // Auto on load.
'php-error.php' => array( __( 'Custom PHP error message.' ), true ), // Auto on error.
'fatal-error-handler.php' => array( __( 'Custom PHP fatal error handler.' ), true ), // Auto on error.
$dropins['sunrise.php'] = array( __( 'Executed before Multisite is loaded.' ), 'SUNRISE' ); // SUNRISE
$dropins['blog-deleted.php'] = array( __( 'Custom site deleted message.' ), true ); // Auto on deleted blog.
$dropins['blog-inactive.php'] = array( __( 'Custom site inactive message.' ), true ); // Auto on inactive blog.
$dropins['blog-suspended.php'] = array( __( 'Custom site suspended message.' ), true ); // Auto on archived or spammed blog.
* Determines whether a plugin is active.
* Only plugins installed in the plugins/ folder can be active.
* Plugins in the mu-plugins/ folder can't be "activated," so this function will
* return false for those plugins.
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @return bool True, if in the active plugins list. False, not in the list.
function is_plugin_active( $plugin ) {
return in_array( $plugin, (array) get_option( 'active_plugins', array() ), true ) || is_plugin_active_for_network( $plugin );
* Determines whether the plugin is inactive.
* Reverse of is_plugin_active(). Used as a callback.
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
* @see is_plugin_active()
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @return bool True if inactive. False if active.
function is_plugin_inactive( $plugin ) {
return ! is_plugin_active( $plugin );
* Determines whether the plugin is active for the entire network.
* Only plugins installed in the plugins/ folder can be active.
* Plugins in the mu-plugins/ folder can't be "activated," so this function will
* return false for those plugins.
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @return bool True if active for the network, otherwise false.
function is_plugin_active_for_network( $plugin ) {
if ( ! is_multisite() ) {
$plugins = get_site_option( 'active_sitewide_plugins' );
if ( isset( $plugins[ $plugin ] ) ) {
* Checks for "Network: true" in the plugin header to see if this should
* be activated only as a network wide plugin. The plugin would also work
* when Multisite is not enabled.
* Checks for "Site Wide Only: true" for backward compatibility.
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @return bool True if plugin is network only, false otherwise.
function is_network_only_plugin( $plugin ) {
$plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
return $plugin_data['Network'];
* Attempts activation of plugin in a "sandbox" and redirects on success.
* A plugin that is already activated will not attempt to be activated again.
* The way it works is by setting the redirection to the error before trying to
* include the plugin file. If the plugin fails, then the redirection will not
* be overwritten with the success message. Also, the options will not be
* updated and the activation hook will not be called on plugin error.
* It should be noted that in no way the below code will actually prevent errors
* within the file. The code should not be used elsewhere to replicate the
* "sandbox", which uses redirection to work.
* If any errors are found or text is outputted, then it will be captured to
* ensure that the success redirection will update the error redirection.
* @since 5.2.0 Test for WordPress version and PHP version compatibility.
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @param string $redirect Optional. URL to redirect to.
* @param bool $network_wide Optional. Whether to enable the plugin for all sites in the network
* or just the current site. Multisite only. Default false.
* @param bool $silent Optional. Whether to prevent calling activation hooks. Default false.
* @return null|WP_Error Null on success, WP_Error on invalid file.
function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silent = false ) {
$plugin = plugin_basename( trim( $plugin ) );
if ( is_multisite() && ( $network_wide || is_network_only_plugin( $plugin ) ) ) {
$current = get_site_option( 'active_sitewide_plugins', array() );
$_GET['networkwide'] = 1; // Back compat for plugins looking for this value.
$current = get_option( 'active_plugins', array() );
$valid = validate_plugin( $plugin );
if ( is_wp_error( $valid ) ) {
$requirements = validate_plugin_requirements( $plugin );
if ( is_wp_error( $requirements ) ) {
if ( $network_wide && ! isset( $current[ $plugin ] )
|| ! $network_wide && ! in_array( $plugin, $current, true )
if ( ! empty( $redirect ) ) {
// We'll override this later if the plugin can be included without fatal error.
wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) );
// Load the plugin to test whether it throws any errors.
plugin_sandbox_scrape( $plugin );
* Fires before a plugin is activated.
* If a plugin is silently activated (such as during an update),
* this hook does not fire.
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @param bool $network_wide Whether to enable the plugin for all sites in the network
* or just the current site. Multisite only. Default false.
do_action( 'activate_plugin', $plugin, $network_wide );
* Fires as a specific plugin is being activated.
* This hook is the "activation" hook used internally by register_activation_hook().
* The dynamic portion of the hook name, `$plugin`, refers to the plugin basename.
* If a plugin is silently activated (such as during an update), this hook does not fire.
* @param bool $network_wide Whether to enable the plugin for all sites in the network
* or just the current site. Multisite only. Default false.
do_action( "activate_{$plugin}", $network_wide );
$current = get_site_option( 'active_sitewide_plugins', array() );
$current[ $plugin ] = time();
update_site_option( 'active_sitewide_plugins', $current );
$current = get_option( 'active_plugins', array() );
update_option( 'active_plugins', $current );
* Fires after a plugin has been activated.
* If a plugin is silently activated (such as during an update),
* this hook does not fire.
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @param bool $network_wide Whether to enable the plugin for all sites in the network
* or just the current site. Multisite only. Default false.
do_action( 'activated_plugin', $plugin, $network_wide );
if ( ob_get_length() > 0 ) {
$output = ob_get_clean();
return new WP_Error( 'unexpected_output', __( 'The plugin generated unexpected output.' ), $output );
* Deactivates a single plugin or multiple plugins.
* The deactivation hook is disabled by the plugin upgrader by using the $silent
* @param string|string[] $plugins Single plugin or list of plugins to deactivate.
* @param bool $silent Prevent calling deactivation hooks. Default false.
* @param bool|null $network_wide Whether to deactivate the plugin for all sites in the network.
* A value of null will deactivate plugins for both the network
* and the current site. Multisite only. Default null.
function deactivate_plugins( $plugins, $silent = false, $network_wide = null ) {
$network_current = get_site_option( 'active_sitewide_plugins', array() );
$current = get_option( 'active_plugins', array() );
foreach ( (array) $plugins as $plugin ) {
$plugin = plugin_basename( trim( $plugin ) );
if ( ! is_plugin_active( $plugin ) ) {
$network_deactivating = ( false !== $network_wide ) && is_plugin_active_for_network( $plugin );
* Fires before a plugin is deactivated.
* If a plugin is silently deactivated (such as during an update),
* this hook does not fire.
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network
* or just the current site. Multisite only. Default false.
do_action( 'deactivate_plugin', $plugin, $network_deactivating );
if ( false !== $network_wide ) {
if ( is_plugin_active_for_network( $plugin ) ) {
unset( $network_current[ $plugin ] );
} elseif ( $network_wide ) {
if ( true !== $network_wide ) {
$key = array_search( $plugin, $current, true );
unset( $current[ $key ] );
if ( $do_blog && wp_is_recovery_mode() ) {
list( $extension ) = explode( '/', $plugin );
wp_paused_plugins()->delete( $extension );
* Fires as a specific plugin is being deactivated.
* This hook is the "deactivation" hook used internally by register_deactivation_hook().
* The dynamic portion of the hook name, `$plugin`, refers to the plugin basename.
* If a plugin is silently deactivated (such as during an update), this hook does not fire.
* @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network
* or just the current site. Multisite only. Default false.
do_action( "deactivate_{$plugin}", $network_deactivating );
* Fires after a plugin is deactivated.
* If a plugin is silently deactivated (such as during an update),
* this hook does not fire.
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network
* or just the current site. Multisite only. Default false.
do_action( 'deactivated_plugin', $plugin, $network_deactivating );
update_option( 'active_plugins', $current );
update_site_option( 'active_sitewide_plugins', $network_current );
* Activates multiple plugins.
* When WP_Error is returned, it does not mean that one of the plugins had
* errors. It means that one or more of the plugin file paths were invalid.
* The execution will be halted as soon as one of the plugins has an error.
* @param string|string[] $plugins Single plugin or list of plugins to activate.
* @param string $redirect Redirect to page after successful activation.
* @param bool $network_wide Whether to enable the plugin for all sites in the network.
* @param bool $silent Prevent calling activation hooks. Default false.
* @return true|WP_Error True when finished or WP_Error if there were errors during a plugin activation.
function activate_plugins( $plugins, $redirect = '', $network_wide = false, $silent = false ) {
if ( ! is_array( $plugins ) ) {
$plugins = array( $plugins );
foreach ( $plugins as $plugin ) {
if ( ! empty( $redirect ) ) {
$redirect = add_query_arg( 'plugin', $plugin, $redirect );
$result = activate_plugin( $plugin, $redirect, $network_wide, $silent );
if ( is_wp_error( $result ) ) {
$errors[ $plugin ] = $result;
if ( ! empty( $errors ) ) {
return new WP_Error( 'plugins_invalid', __( 'One of the plugins is invalid.' ), $errors );
* Removes directory and files of a plugin for a list of plugins.
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
* @param string[] $plugins List of plugin paths to delete, relative to the plugins directory.
* @param string $deprecated Not used.
* @return bool|null|WP_Error True on success, false if `$plugins` is empty, `WP_Error` on failure.
* `null` if filesystem credentials are required to proceed.
function delete_plugins( $plugins, $deprecated = '' ) {
if ( empty( $plugins ) ) {
foreach ( $plugins as $plugin ) {
$checked[] = 'checked[]=' . $plugin;
$url = wp_nonce_url( 'plugins.php?action=delete-selected&verify-delete=1&' . implode( '&', $checked ), 'bulk-plugins' );
$credentials = request_filesystem_credentials( $url );
if ( false === $credentials ) {
if ( ! empty( $data ) ) {
require_once ABSPATH . 'wp-admin/admin-header.php';
require_once ABSPATH . 'wp-admin/admin-footer.php';
if ( ! WP_Filesystem( $credentials ) ) {
// Failed to connect. Error and request again.
request_filesystem_credentials( $url, '', true );
if ( ! empty( $data ) ) {
require_once ABSPATH . 'wp-admin/admin-header.php';
require_once ABSPATH . 'wp-admin/admin-footer.php';
if ( ! is_object( $wp_filesystem ) ) {
return new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) );
if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
return new WP_Error( 'fs_error', __( 'Filesystem error.' ), $wp_filesystem->errors );
// Get the base plugin folder.
$plugins_dir = $wp_filesystem->wp_plugins_dir();
if ( empty( $plugins_dir ) ) {
return new WP_Error( 'fs_no_plugins_dir', __( 'Unable to locate WordPress plugin directory.' ) );
$plugins_dir = trailingslashit( $plugins_dir );
$plugin_translations = wp_get_installed_translations( 'plugins' );
foreach ( $plugins as $plugin_file ) {
if ( is_uninstallable_plugin( $plugin_file ) ) {
uninstall_plugin( $plugin_file );
* Fires immediately before a plugin deletion attempt.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
do_action( 'delete_plugin', $plugin_file );
$this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin_file ) );
* If plugin is in its own directory, recursively delete the directory.
* Base check on if plugin includes directory separator AND that it's not the root plugin folder.
if ( strpos( $plugin_file, '/' ) && $this_plugin_dir !== $plugins_dir ) {
$deleted = $wp_filesystem->delete( $this_plugin_dir, true );
$deleted = $wp_filesystem->delete( $plugins_dir . $plugin_file );
* Fires immediately after a plugin deletion attempt.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
* @param bool $deleted Whether the plugin deletion was successful.