From 6558cacfd8f68b702b549857ced45b686810fdd0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 22:43:24 +0000 Subject: [PATCH 1/6] Initial plan From 1cd40e6e0c22b3d9ebaddb1c61aae63dd0f41a46 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 22:48:21 +0000 Subject: [PATCH 2/6] Fix: Always activate plugin when --activate flag is used with install When using `wp plugin install --force --activate`, the plugin should always be activated even if it appears to be already active. This fixes an edge case where WordPress might deactivate a plugin during the installation process (when plugin files are temporarily deleted), leaving the plugin deactivated after the update completes. The fix modifies the activate() method to skip the "already active" check when called from the install command (chained_command = true), ensuring that explicit activation requests are always honored. Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/plugin-install.feature | 33 +++++++++++++++++++++++++++++++++ src/Plugin_Command.php | 4 +++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/features/plugin-install.feature b/features/plugin-install.feature index 319c0787a..716926f4b 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -305,3 +305,36 @@ Feature: Install WordPress plugins """ active """ + + Scenario: Force update an active plugin with --activate flag 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 run `wp plugin install hello-dolly --force --activate` + Then STDOUT should contain: + """ + Plugin updated successfully + """ + And STDOUT should contain: + """ + Success: Installed 1 of 1 plugins. + """ + And the return code should be 0 + + When I run `wp plugin list --name=hello-dolly --field=status` + Then STDOUT should be: + """ + active + """ diff --git a/src/Plugin_Command.php b/src/Plugin_Command.php index 5ce246aca..073f1c55c 100644 --- a/src/Plugin_Command.php +++ b/src/Plugin_Command.php @@ -383,7 +383,9 @@ public function activate( $args, $assoc_args = [] ) { continue; } // Don't reactivate active plugins, but do let them become network-active. - if ( ! $network_wide && 'active' === $status ) { + // However, when called from install command (chained_command), always attempt activation + // to handle edge cases where the plugin may have been deactivated during the install process. + if ( ! $network_wide && 'active' === $status && ! $this->chained_command ) { WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); continue; } From 5305959244a9180af007bea199c3d603b0e0f7e1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 22:49:34 +0000 Subject: [PATCH 3/6] Add tests for plugin activation with --force flag Add comprehensive tests to verify that plugins remain activated when using --force with --activate or --activate-network flags. These tests cover both single-site and multisite scenarios. Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/plugin-install.feature | 33 +++++++++++++++++++++++++++++++++ src/Plugin_Command.php | 4 +++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/features/plugin-install.feature b/features/plugin-install.feature index 716926f4b..accd09f12 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -338,3 +338,36 @@ Feature: Install WordPress plugins """ active """ + + Scenario: Force update a network-active plugin with --activate-network flag should keep it network-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 run `wp plugin install hello-dolly --force --activate-network` + Then STDOUT should contain: + """ + Plugin updated successfully + """ + And STDOUT should contain: + """ + Success: Installed 1 of 1 plugins. + """ + 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 073f1c55c..d66247d2a 100644 --- a/src/Plugin_Command.php +++ b/src/Plugin_Command.php @@ -378,7 +378,9 @@ public function activate( $args, $assoc_args = [] ) { continue; } // Network-active is the highest level of activation status. - if ( 'active-network' === $status ) { + // However, when called from install command (chained_command), always attempt activation + // to handle edge cases where the plugin may have been deactivated during the install process. + if ( 'active-network' === $status && ! $this->chained_command ) { WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); continue; } From 1b639da63c8bb4c3f18370703e509fdf10d38267 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:01:54 +0000 Subject: [PATCH 4/6] Fix activation error handling when called from install When activate() is called from install command and the plugin is already active, activate_plugin() returns WP_Error('plugin_already_active'). This should be treated as success, not failure, since the desired end state (active plugin) is achieved. Changes: - Restructure activation checks to always run force deactivation first - When chained_command is true and plugin is already active without force, fall through to activate_plugin() and handle 'plugin_already_active' error - Treat 'plugin_already_active' as success when called from install command Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Plugin_Command.php | 50 +++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/Plugin_Command.php b/src/Plugin_Command.php index 428ebc651..9f6ced786 100644 --- a/src/Plugin_Command.php +++ b/src/Plugin_Command.php @@ -387,25 +387,23 @@ public function activate( $args, $assoc_args = [] ) { continue; } // Network-active is the highest level of activation status. - // However, when called from install command (chained_command), always attempt activation - // to handle edge cases where the plugin may have been deactivated during the install process. - if ( 'active-network' === $status && ! $this->chained_command ) { + if ( 'active-network' === $status ) { // 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 called from install command. WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); continue; } } // Don't reactivate active plugins, but do let them become network-active. - // However, when called from install command (chained_command), always attempt activation - // to handle edge cases where the plugin may have been deactivated during the install process. - if ( ! $network_wide && 'active' === $status && ! $this->chained_command ) { + if ( ! $network_wide && 'active' === $status ) { // 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 called from install command. WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); continue; } @@ -419,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 install 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; From c13bbd5e941a3a857baa1ebc14bf8ee920d90adc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:03:15 +0000 Subject: [PATCH 5/6] Update tests to exercise the actual fix Replace --force tests with tests that actually exercise the code path where activate_plugin() returns 'plugin_already_active'. These tests verify that installing an already-active plugin with --activate (without --force) correctly treats the 'plugin_already_active' error as success. Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/plugin-install.feature | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/features/plugin-install.feature b/features/plugin-install.feature index accd09f12..7eae2b28f 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -306,7 +306,7 @@ Feature: Install WordPress plugins active """ - Scenario: Force update an active plugin with --activate flag should keep it activated + 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` @@ -322,14 +322,18 @@ Feature: Install WordPress plugins active """ - When I run `wp plugin install hello-dolly --force --activate` - Then STDOUT should contain: + When I try `wp plugin install hello-dolly --activate` + Then STDERR should contain: + """ + Warning: hello-dolly: Plugin already installed. """ - Plugin updated successfully + And STDOUT should contain: + """ + Activating 'hello-dolly'... """ And STDOUT should contain: """ - Success: Installed 1 of 1 plugins. + Plugin 'hello-dolly' activated. """ And the return code should be 0 @@ -339,7 +343,7 @@ Feature: Install WordPress plugins active """ - Scenario: Force update a network-active plugin with --activate-network flag should keep it network-activated + 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` @@ -355,14 +359,18 @@ Feature: Install WordPress plugins active-network """ - When I run `wp plugin install hello-dolly --force --activate-network` - Then STDOUT should contain: + When I try `wp plugin install hello-dolly --activate-network` + Then STDERR should contain: + """ + Warning: hello-dolly: Plugin already installed. """ - Plugin updated successfully + And STDOUT should contain: + """ + Network-activating 'hello-dolly'... """ And STDOUT should contain: """ - Success: Installed 1 of 1 plugins. + Plugin 'hello-dolly' network activated. """ And the return code should be 0 From 6a597e472df141cdf412778d4c8d82eaa9e600b7 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 17 Feb 2026 15:16:12 +0100 Subject: [PATCH 6/6] Apply suggestions from code review --- src/Plugin_Command.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Plugin_Command.php b/src/Plugin_Command.php index 9f6ced786..68cb819b1 100644 --- a/src/Plugin_Command.php +++ b/src/Plugin_Command.php @@ -392,7 +392,7 @@ public function activate( $args, $assoc_args = [] ) { if ( $force ) { deactivate_plugins( $plugin->file, false, true ); } elseif ( ! $this->chained_command ) { - // Only skip if not called from install command. + // Only skip if not part of a chained command. WP_CLI::warning( "Plugin '{$plugin->name}' is already network active." ); continue; } @@ -403,7 +403,7 @@ public function activate( $args, $assoc_args = [] ) { if ( $force ) { deactivate_plugins( $plugin->file, false, false ); } elseif ( ! $this->chained_command ) { - // Only skip if not called from install command. + // Only skip if not part of a chained command. WP_CLI::warning( "Plugin '{$plugin->name}' is already active." ); continue; } @@ -417,7 +417,7 @@ public function activate( $args, $assoc_args = [] ) { $result = activate_plugin( $plugin->file, '', $network_wide ); if ( is_wp_error( $result ) ) { - // When called from install command, treat 'already_active' as success. + // 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() ) {