diff --git a/features/plugin-install.feature b/features/plugin-install.feature
index 319c0787..7eae2b28 100644
--- a/features/plugin-install.feature
+++ b/features/plugin-install.feature
@@ -305,3 +305,77 @@ Feature: Install WordPress plugins
"""
active
"""
+
+ Scenario: Install with --activate on already-active plugin should keep it activated
+ Given a WP install
+
+ When I run `wp plugin install hello-dolly --activate`
+ Then STDOUT should contain:
+ """
+ Plugin 'hello-dolly' activated.
+ """
+ And the return code should be 0
+
+ When I run `wp plugin list --name=hello-dolly --field=status`
+ Then STDOUT should be:
+ """
+ active
+ """
+
+ When I try `wp plugin install hello-dolly --activate`
+ Then STDERR should contain:
+ """
+ Warning: hello-dolly: Plugin already installed.
+ """
+ And STDOUT should contain:
+ """
+ Activating 'hello-dolly'...
+ """
+ And STDOUT should contain:
+ """
+ Plugin 'hello-dolly' activated.
+ """
+ And the return code should be 0
+
+ When I run `wp plugin list --name=hello-dolly --field=status`
+ Then STDOUT should be:
+ """
+ active
+ """
+
+ Scenario: Install with --activate-network on already-network-active plugin should keep it activated
+ Given a WP multisite install
+
+ When I run `wp plugin install hello-dolly --activate-network`
+ Then STDOUT should contain:
+ """
+ Plugin 'hello-dolly' network activated.
+ """
+ And the return code should be 0
+
+ When I run `wp plugin list --name=hello-dolly --field=status`
+ Then STDOUT should be:
+ """
+ active-network
+ """
+
+ When I try `wp plugin install hello-dolly --activate-network`
+ Then STDERR should contain:
+ """
+ Warning: hello-dolly: Plugin already installed.
+ """
+ And STDOUT should contain:
+ """
+ Network-activating 'hello-dolly'...
+ """
+ And STDOUT should contain:
+ """
+ Plugin 'hello-dolly' network activated.
+ """
+ And the return code should be 0
+
+ When I run `wp plugin list --name=hello-dolly --field=status`
+ Then STDOUT should be:
+ """
+ active-network
+ """
diff --git a/src/Plugin_Command.php b/src/Plugin_Command.php
index 06875d73..68cb819b 100644
--- a/src/Plugin_Command.php
+++ b/src/Plugin_Command.php
@@ -391,7 +391,8 @@ public function activate( $args, $assoc_args = [] ) {
// If force flag is set, deactivate and reactivate to run activation hooks.
if ( $force ) {
deactivate_plugins( $plugin->file, false, true );
- } else {
+ } elseif ( ! $this->chained_command ) {
+ // Only skip if not part of a chained command.
WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." );
continue;
}
@@ -401,7 +402,8 @@ public function activate( $args, $assoc_args = [] ) {
// If force flag is set, deactivate and reactivate to run activation hooks.
if ( $force ) {
deactivate_plugins( $plugin->file, false, false );
- } else {
+ } elseif ( ! $this->chained_command ) {
+ // Only skip if not part of a chained command.
WP_CLI::warning( "Plugin '{$plugin->name}' is already active." );
continue;
}
@@ -415,22 +417,30 @@ public function activate( $args, $assoc_args = [] ) {
$result = activate_plugin( $plugin->file, '', $network_wide );
if ( is_wp_error( $result ) ) {
- $message = $result->get_error_message();
- $message = (string) preg_replace( '/]+>.*<\/a>/im', '', $message );
- $message = wp_strip_all_tags( $message );
- $message = str_replace( 'Error: ', '', $message );
- WP_CLI::warning( "Failed to activate plugin. {$message}" );
- // If the error is due to unexpected output, display it for debugging
- if ( 'unexpected_output' === $result->get_error_code() ) {
- /**
- * @var string $output
- */
- $output = $result->get_error_data();
- if ( ! empty( $output ) ) {
- WP_CLI::debug( "Unexpected output: {$output}", 'plugin' );
+ // When called from a chained command, treat 'already_active' as success.
+ // This handles race conditions where WordPress may have preserved activation
+ // status during the install process.
+ if ( $this->chained_command && 'plugin_already_active' === $result->get_error_code() ) {
+ $this->active_output( $plugin->name, $plugin->file, $network_wide, 'activate' );
+ ++$successes;
+ } else {
+ $message = $result->get_error_message();
+ $message = (string) preg_replace( '/]+>.*<\/a>/im', '', $message );
+ $message = wp_strip_all_tags( $message );
+ $message = str_replace( 'Error: ', '', $message );
+ WP_CLI::warning( "Failed to activate plugin. {$message}" );
+ // If the error is due to unexpected output, display it for debugging
+ if ( 'unexpected_output' === $result->get_error_code() ) {
+ /**
+ * @var string $output
+ */
+ $output = $result->get_error_data();
+ if ( ! empty( $output ) ) {
+ WP_CLI::debug( "Unexpected output: {$output}", 'plugin' );
+ }
}
+ ++$errors;
}
- ++$errors;
} else {
$this->active_output( $plugin->name, $plugin->file, $network_wide, 'activate' );
++$successes;