Skip to content

Commit

Permalink
Single site: deactivate and skip loading
Browse files Browse the repository at this point in the history
  • Loading branch information
hellofromtonya committed Jan 10, 2024
1 parent 18cacc0 commit c8e80a0
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/wp-admin/includes/admin-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@

add_action( 'admin_notices', 'update_nag', 3 );
add_action( 'admin_notices', 'deactivated_plugins_notice', 5 );
add_action( 'admin_notices', '_render_notice_for_deactivated_incompatible_plugins', 5 );
add_action( 'admin_notices', 'paused_plugins_notice', 5 );
add_action( 'admin_notices', 'paused_themes_notice', 5 );
add_action( 'admin_notices', 'maintenance_nag', 10 );
Expand Down
78 changes: 78 additions & 0 deletions src/wp-admin/includes/plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -2595,3 +2595,81 @@ function deactivated_plugins_notice() {
update_site_option( 'wp_force_deactivated_plugins', array() );
}
}

/**
* Renders an admin notice for each incompatible plugin.
*
* Displays an admin notice in case a plugin was deactivated during the
* loading of WordPress due to incompatibility with the current version
* of WordPress.
*
* @since 6.5.0
* @access private
*
* @global string $wp_version The WordPress version string.
*/
function _render_notice_for_deactivated_incompatible_plugins() {

if ( ! current_user_can( 'activate_plugins' ) ) {
return;
}

$blog_deactivated_plugins = get_option( 'wp_force_deactivation_incompatible_plugins' );
$site_deactivated_plugins = array();

if ( false === $blog_deactivated_plugins ) {
// Option not in database, add an empty array to avoid extra DB queries on subsequent loads.
update_option( 'wp_force_deactivation_incompatible_plugins', array() );
}

if ( is_multisite() ) {
$site_deactivated_plugins = get_site_option( 'wp_force_deactivation_incompatible_plugins' );
if ( false === $site_deactivated_plugins ) {
// Option not in database, add an empty array to avoid extra DB queries on subsequent loads.
update_site_option( 'wp_force_deactivation_incompatible_plugins', array() );
}
}

if ( empty( $blog_deactivated_plugins ) && empty( $site_deactivated_plugins ) ) {
// No deactivated plugins.
return;
}

$deactivated_plugins = array_merge( $blog_deactivated_plugins, $site_deactivated_plugins );

foreach ( $deactivated_plugins as $plugin ) {
if ( ! empty( $plugin['version_compatible'] ) && ! empty( $plugin['version_deactivated'] ) ) {
$explanation = sprintf(
/* translators: 1: Name of deactivated plugin, 2: Plugin version deactivated, 3: Current WP version, 4: Compatible plugin version. */
__( '%1$s %2$s was deactivated due to incompatibility with WordPress %3$s, please upgrade to %1$s %4$s or later.' ),
$plugin['plugin_name'],
$plugin['version_deactivated'],
$GLOBALS['wp_version'],
$plugin['version_compatible']
);
} else {
$explanation = sprintf(
/* translators: 1: Name of deactivated plugin, 2: Plugin version deactivated, 3: Current WP version. */
__( '%1$s %2$s was deactivated due to incompatibility with WordPress %3$s.' ),
$plugin['plugin_name'],
! empty( $plugin['version_deactivated'] ) ? $plugin['version_deactivated'] : '',
$GLOBALS['wp_version'],
$plugin['version_compatible']
);
}

$message = sprintf(
'%s</p><p><a href="%s">%s</a>',
$explanation,
esc_url( admin_url( 'plugins.php?plugin_status=inactive' ) ),
__( 'Go to the Plugins screen' )
);
wp_admin_notice( $message, array( 'type' => 'warning' ) );
}

// Empty the options.
update_option( 'wp_force_deactivation_incompatible_plugins', array() );
if ( is_multisite() ) {
update_site_option( 'wp_force_deactivation_incompatible_plugins', array() );
}
}
148 changes: 148 additions & 0 deletions src/wp-includes/class-wp-incompatible-plugins-handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php
/**
* WordPress incompatible "for Core" plugins handler class.
*
* @package WordPress
* @since 6.5.0
*/

/**
* Incompatibility "fore Core" plugins handler.
*
* @since 6.5.0
*/
class WP_Incompatible_Plugins_Handler {

const PLUGINS = array(
'gutenberg/gutenberg.php' => array(
'name' => 'Gutenberg',
'minimum_compatible_version' => '16.5',
),
);

/**
* Plugins for compatibility checks.
*
* @var array
*/
private static $plugins_for_compat_check = array();

public static function reset() {
static::$plugins_for_compat_check = array();
}

/**
* Flags the plugin for compatibility check if it's in the PLUGINS list.
*
* @since 6.5.0
*
* @param string $plugin The plugin to check.
* @param string $plugin_file The plugin's file.
* @param array $plugins The list of active and valid plugins to be loaded.
*/
public static function maybe_flag_for_compat_check( $plugin, $plugin_file, $plugins ) {
if ( ! isset( static::PLUGINS[ $plugin ] ) ) {
return;
}

// Get the last index value, as this is where this plugin is stored in the $plugins array.
end( $plugins );
$plugins_index = key( $plugins );

static::$plugins_for_compat_check[ $plugin ] = array(
'file' => $plugin_file,
'deactivated_version' => '',
'index_plugins_to_load' => $plugins_index,
);
}

/**
* On WordPress load, deactivate the incompatible plugins.
*
* Also removes the incompatible plugins from the given $plugins_to_load to
* prevent these plugins from loading.
*
* @since 6.5.0
*
* @param array $plugins_to_load Activate and valid plugins to load. (Passed by reference.)
*/
public static function deactivate_on_wp_load( &$plugins_to_load ) {
// Bail out if there are no active plugins for compatibility check.
if ( empty( static::$plugins_for_compat_check ) || empty( $plugins_to_load ) ) {
return;
}

$active_plugins = (array) get_option( 'active_plugins', array() );
$active_plugins_by_plugin = array_flip( $active_plugins );
$found_incompatibles = array();

/*
* Loop through the plugins to do the compatibility check.
* Deactivate each incompatible plugin.
*/
foreach ( static::$plugins_for_compat_check as $plugin => $plugin_info ) {

$index_plugins_to_load = $plugin_info['index_plugins_to_load'];

if ( ! isset( $plugins_to_load[ $index_plugins_to_load ] ) ) {
return;
}

// Get the Name and Version from the plugin's header.
$plugin_data = get_file_data(
$plugins_to_load[ $index_plugins_to_load ],
array(
'Name' => 'Plugin Name',
'Version' => 'Version',
),
'plugin'
);

// Whoops, something went wrong. Bail out.
if ( ! ( isset( $plugin_data['Version'] ) && isset( $plugin_data['Name'] ) ) ) {
return;
}

// Check if compatible. If yes, bail out.
$min_compat_version = static::PLUGINS[ $plugin ]['minimum_compatible_version'];
if ( version_compare( $plugin_data['Version'], $min_compat_version, '>=' ) ) {
return;
}

// Add the plugin to found incompatibles.
$found_incompatibles[ $plugin ] = array(
'plugin_name' => $plugin_data['Name'],
'version_deactivated' => $plugin_data['Version'],
'version_compatible' => $min_compat_version,
);

// Remove it from the 'active_plugins' option.
unset( $active_plugins[ $active_plugins_by_plugin[ $plugin ] ] );

// Remove it from the plugins to be loaded.
unset( $plugins_to_load[ $index_plugins_to_load ] );
}

if ( empty( $found_incompatibles ) ) {
return;
}

// Update the 'active plugins' option, which no longer includes the incompatible plugins.
update_option( 'active_plugins', $active_plugins );

// Update the list of incompatible plugins to notify user in the admin.
$incompatible_plugins = (array) get_option( 'wp_force_deactivation_incompatible_plugins', array() );
$incompatible_plugins = array_merge( $incompatible_plugins, $found_incompatibles );
update_option( 'wp_force_deactivation_incompatible_plugins', $incompatible_plugins );
}

/**
* During Core's update, handles deactivate incompatible plugins.
*
* @since 6.5.0
*/
public static function deactivate_on_core_upgrade() {
// the code currently exists _upgrade_core_deactivate_incompatible_plugins().
// Consider either moving to here or modifying the function to use this class.
}
}
4 changes: 3 additions & 1 deletion src/wp-includes/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,9 @@ function wp_get_active_and_valid_plugins() {
// Not already included as a network plugin.
&& ( ! $network_plugins || ! in_array( WP_PLUGIN_DIR . '/' . $plugin, $network_plugins, true ) )
) {
$plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
$plugin_file = WP_PLUGIN_DIR . '/' . $plugin;
$plugins[] = $plugin_file;
WP_Incompatible_Plugins_Handler::maybe_flag_for_compat_check( $plugin, $plugin_file, $plugins );
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/wp-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@
require ABSPATH . WPINC . '/fonts/class-wp-font-face-resolver.php';
require ABSPATH . WPINC . '/fonts/class-wp-font-face.php';
require ABSPATH . WPINC . '/fonts.php';
require ABSPATH . WPINC . '/class-wp-incompatible-plugins-handler.php';

$GLOBALS['wp_embed'] = new WP_Embed();

Expand Down Expand Up @@ -466,7 +467,10 @@
}

// Load active plugins.
foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
$_active_and_valid_plugins_to_load = wp_get_active_and_valid_plugins();
WP_Incompatible_Plugins_Handler::deactivate_on_wp_load( $_active_and_valid_plugins_to_load );

foreach ( $_active_and_valid_plugins_to_load as $plugin ) {
wp_register_plugin_realpath( $plugin );

$_wp_plugin_file = $plugin;
Expand All @@ -482,7 +486,8 @@
*/
do_action( 'plugin_loaded', $plugin );
}
unset( $plugin, $_wp_plugin_file );
unset( $plugin, $_wp_plugin_file, $_active_and_valid_plugins_to_load );
WP_Incompatible_Plugins_Handler::reset();

// Load pluggable functions.
require ABSPATH . WPINC . '/pluggable.php';
Expand Down

0 comments on commit c8e80a0

Please sign in to comment.