diff --git a/src/js/_enqueues/wp/updates.js b/src/js/_enqueues/wp/updates.js index ef4b47e66093e..f0b865eed28a2 100644 --- a/src/js/_enqueues/wp/updates.js +++ b/src/js/_enqueues/wp/updates.js @@ -2715,7 +2715,13 @@ var $pluginRow = $( event.target ).parents( 'tr' ), confirmMessage; - if ( $pluginRow.hasClass( 'is-uninstallable' ) ) { + if ( $pluginRow.hasClass( 'active' ) ) { + confirmMessage = sprintf( + /* translators: %s: Plugin name. */ + __( 'You are about to delete %s.\n\nThis plugin is active and will be deactivated before deletion.\n\nAre you sure you want to proceed?' ), + $pluginRow.find( '.plugin-title strong' ).text() + ); + } else if ( $pluginRow.hasClass( 'is-uninstallable' ) ) { confirmMessage = sprintf( /* translators: %s: Plugin name. */ __( 'Are you sure you want to delete %s and its data?' ), @@ -2842,9 +2848,22 @@ break; case 'delete-selected': - var confirmMessage = 'plugin' === type ? - __( 'Are you sure you want to delete the selected plugins and their data?' ) : - __( 'Caution: These themes may be active on other sites in the network. Are you sure you want to proceed?' ); + var confirmMessage; + if ( 'plugin' === type ) { + var hasActivePlugins = false; + $bulkActionForm.find( 'input[name="checked[]"]:checked' ).each( function() { + if ( $( this ).parents( 'tr' ).hasClass( 'active' ) ) { + hasActivePlugins = true; + } + } ); + + confirmMessage = __( 'Are you sure you want to delete the selected plugins and their data?' ); + if ( hasActivePlugins ) { + confirmMessage += '\n\n' + __( 'Note: Active plugins will be deactivated before deletion.' ); + } + } else { + confirmMessage = __( 'Caution: These themes may be active on other sites in the network. Are you sure you want to proceed?' ); + } if ( ! window.confirm( confirmMessage ) ) { event.preventDefault(); diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php index 2af08fba70af9..4031e090b4d0d 100644 --- a/src/wp-admin/includes/ajax-actions.php +++ b/src/wp-admin/includes/ajax-actions.php @@ -4752,9 +4752,8 @@ function wp_ajax_delete_plugin() { $status['plugin'] = $plugin; $status['pluginName'] = $plugin_data['Name']; - if ( is_plugin_active( $plugin ) ) { - $status['errorMessage'] = __( 'You cannot delete a plugin while it is active on the main site.' ); - wp_send_json_error( $status ); + if ( is_network_admin() ? is_plugin_active_for_network( $plugin ) : is_plugin_active( $plugin ) ) { + deactivate_plugins( $plugin, false, is_network_admin() ); } // Check filesystem credentials. `delete_plugins()` will bail otherwise. diff --git a/src/wp-admin/includes/class-wp-plugins-list-table.php b/src/wp-admin/includes/class-wp-plugins-list-table.php index 08b2e982e702f..f7b123eb342b7 100644 --- a/src/wp-admin/includes/class-wp-plugins-list-table.php +++ b/src/wp-admin/includes/class-wp-plugins-list-table.php @@ -680,7 +680,7 @@ protected function get_bulk_actions() { $actions['update-selected'] = __( 'Update' ); } - if ( current_user_can( 'delete_plugins' ) && ( 'active' !== $status ) ) { + if ( current_user_can( 'delete_plugins' ) ) { $actions['delete-selected'] = __( 'Delete' ); } @@ -942,29 +942,29 @@ public function single_row( $item ) { ); } } + } - if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) { - if ( $has_dependents && ! $has_circular_dependency ) { - $actions['delete'] = __( 'Delete' ) . - '' . - __( 'You cannot delete this plugin as other plugins require it.' ) . - ''; - } else { - $delete_url = 'plugins.php?action=delete-selected' . - '&checked[]=' . urlencode( $plugin_file ) . - '&plugin_status=' . $context . - '&paged=' . $page . - '&s=' . $s; + if ( current_user_can( 'delete_plugins' ) ) { + if ( $has_dependents && ! $has_circular_dependency ) { + $actions['delete'] = __( 'Delete' ) . + '' . + __( 'You cannot delete this plugin as other plugins require it.' ) . + ''; + } else { + $delete_url = 'plugins.php?action=delete-selected' . + '&checked[]=' . urlencode( $plugin_file ) . + '&plugin_status=' . $context . + '&paged=' . $page . + '&s=' . $s; - $actions['delete'] = sprintf( - '%s', - wp_nonce_url( $delete_url, 'bulk-plugins' ), - esc_attr( $plugin_id_attr ), - /* translators: %s: Plugin name. */ - esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ), - __( 'Delete' ) - ); - } + $actions['delete'] = sprintf( + '%s', + wp_nonce_url( $delete_url, 'bulk-plugins' ), + esc_attr( $plugin_id_attr ), + /* translators: %s: Plugin name. */ + esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ), + __( 'Delete' ) + ); } } } else { @@ -1048,31 +1048,31 @@ public function single_row( $item ) { ); } } + } // End if $is_active. - if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) { - if ( $has_dependents && ! $has_circular_dependency ) { - $actions['delete'] = __( 'Delete' ) . - '' . - __( 'You cannot delete this plugin as other plugins require it.' ) . - ''; - } else { - $delete_url = 'plugins.php?action=delete-selected' . - '&checked[]=' . urlencode( $plugin_file ) . - '&plugin_status=' . $context . - '&paged=' . $page . - '&s=' . $s; + if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) { + if ( $has_dependents && ! $has_circular_dependency ) { + $actions['delete'] = __( 'Delete' ) . + '' . + __( 'You cannot delete this plugin as other plugins require it.' ) . + ''; + } else { + $delete_url = 'plugins.php?action=delete-selected' . + '&checked[]=' . urlencode( $plugin_file ) . + '&plugin_status=' . $context . + '&paged=' . $page . + '&s=' . $s; - $actions['delete'] = sprintf( - '%s', - wp_nonce_url( $delete_url, 'bulk-plugins' ), - esc_attr( $plugin_id_attr ), - /* translators: %s: Plugin name. */ - esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ), - __( 'Delete' ) - ); - } + $actions['delete'] = sprintf( + '%s', + wp_nonce_url( $delete_url, 'bulk-plugins' ), + esc_attr( $plugin_id_attr ), + /* translators: %s: Plugin name. */ + esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ), + __( 'Delete' ) + ); } - } // End if $is_active. + } } // End if $screen->in_admin( 'network' ). } // End if $context. diff --git a/src/wp-admin/plugins.php b/src/wp-admin/plugins.php index 6a359c822fac1..ff14e87b4102f 100644 --- a/src/wp-admin/plugins.php +++ b/src/wp-admin/plugins.php @@ -280,12 +280,6 @@ exit; } - $plugins = array_filter( $plugins, 'is_plugin_inactive' ); // Do not allow to delete activated plugins. - if ( empty( $plugins ) ) { - wp_redirect( self_admin_url( "plugins.php?error=true&main=true&plugin_status=$status&paged=$page&s=$s" ) ); - exit; - } - // Bail on all if any paths are invalid. // validate_file() returns truthy for invalid files. $invalid_plugin_files = array_filter( $plugins, 'validate_file' ); @@ -373,14 +367,21 @@ $data_to_delete = false; - foreach ( $plugin_info as $plugin ) { + foreach ( $plugin_info as $plugin_file => $plugin ) { + $is_active = is_network_admin() ? is_plugin_active_for_network( $plugin_file ) : is_plugin_active( $plugin_file ); + + $active_notice = ''; + if ( $is_active ) { + $active_notice = ' ' . __( '(is active and will be deactivated)' ) . ''; + } + if ( $plugin['is_uninstallable'] ) { /* translators: 1: Plugin name, 2: Plugin author. */ - echo '
  • ', sprintf( __( '%1$s by %2$s (will also delete its data)' ), '' . $plugin['Name'] . '', '' . $plugin['AuthorName'] . '' ), '
  • '; + echo '
  • ', sprintf( __( '%1$s by %2$s (will also delete its data)' ), '' . $plugin['Name'] . '', '' . $plugin['AuthorName'] . '' ), $active_notice, '
  • '; $data_to_delete = true; } else { /* translators: 1: Plugin name, 2: Plugin author. */ - echo '
  • ', sprintf( _x( '%1$s by %2$s', 'plugin' ), '' . $plugin['Name'] . '', '' . $plugin['AuthorName'] ) . '', '
  • '; + echo '
  • ', sprintf( _x( '%1$s by %2$s', 'plugin' ), '' . $plugin['Name'] . '', '' . $plugin['AuthorName'] ) . '', $active_notice, '
  • '; } } @@ -427,6 +428,18 @@ $plugins_to_delete = count( $plugins ); } // End if verify-delete. + // Deactivate active plugins before deleting them. + $active_plugins = array(); + foreach ( $plugins as $plugin ) { + if ( is_network_admin() ? is_plugin_active_for_network( $plugin ) : is_plugin_active( $plugin ) ) { + $active_plugins[] = $plugin; + } + } + + if ( ! empty( $active_plugins ) ) { + deactivate_plugins( $active_plugins, false, is_network_admin() ); + } + $delete_result = delete_plugins( $plugins ); // Store the result in an option rather than a URL param due to object type & length.