Add warning in `wp plugin is-active` for missing plugin files still in active_plugins
Description
When a plugin directory is manually removed (not via WP-CLI), the plugin remains in WordPress's active_plugins option. This orphaned entry can break dependency checks and compatibility features in other plugins and core. wp plugin is-active previously returned "not active" without indicating this inconsistent state.
Changes
-
Modified
Plugin_Command::is_active()to checkactive_plugins/active_sitewide_pluginsoptions when plugin file is not found - Uses WordPress's
validate_plugin()to confirm file absence - Emits warning:
Plugin 'X' is marked as active but the plugin file does not exist. - Returns exit code 1 (not active) as before - no behavioral change
- Handles both single-site and multisite scenarios
Example behavior:
$ wp plugin activate akismet
Success: Activated 1 of 1 plugins.
$ rm -rf wp-content/plugins/akismet
$ wp plugin is-active akismet
Warning: Plugin 'akismet' is marked as active but the plugin file does not exist.
$ echo $?
1
Tests
- Added
features/plugin-is-active.featurewith scenarios covering active, inactive, missing, and orphaned plugins - Includes test for network-activated plugins with missing files to verify
--networkflag behavior - Fixed test scenario to properly activate plugin before deactivating to ensure consistent test behavior
Checklist
- [x] Functional tests included
- [x] Follows WP-CLI coding standards (lint, phpcs, phpstan pass)
- [x] Documentation updated (method docblock)
Original prompt
This section details on the original issue you should resolve
<issue_title>is-active/deactivate should also check the "active_plugins" option</issue_title> <issue_description>## Bug Report
- [x] Yes, I reviewed the contribution guidelines.
- [x] Yes, more specifically, I reviewed the guidelines on how to write clear bug reports.
Describe the current, buggy behavior
When a plugin file/directory is removed by the user (and not by WP), the "active_plugins" option will still contain that plugin. Various plugins (and WP core?) use this "active_plugins" option for dependency checks, loading of compatibitility data,...
However
wp plugin is-activeandwp plugin deactivatewill report that the plugin isn't active/the plugin could not be found.WP core has a function https://developer.wordpress.org/reference/functions/validate_active_plugins/ to update this option (and deactivate all those not found ones), however it will deactivate ALL of those plugins, not necessarily only the one passed to CLI. However it's trivial copy and port that to CLI.
Describe how other contributors can replicate this bug
wp plugin activate whatever rm -rf wp-content/plugins/whatever wp plugin deactivate whatever wp eval "echo array_values( preg_grep( '#^whatever#', get_option( 'active_plugins' ) ) )[0];"Describe what you would expect as the correct outcome
is-active and deactivate should deactivate the plugin if it's still in active_plugins but the directory does not exist.
Provide a possible solution
See validate_active_plugins()</issue_description>
<agent_instructions>
wp plugin is-activeshould emit a warning if the plugin does not exist but is still in the active_plugins option. This can be done by using thevalidate_pluginoption provided by WordPress</agent_instructions>Comments on the Issue (you are @copilot in this section)
@swissspidy Updating `wp plugin deactivate` sounds reasonable at first glance, but we shouldn't change `is-active` to make destructive actions. That sounds very unexpected when you just want to check the status.@swissspidy What about `wp plugin is-active` emitting a warning if the plugin does not exist but is still in the `active_plugins` option?
- Fixes wp-cli/extension-command#458
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.
@copilot One failing test:
001 Scenario: Check if an inactive plugin is not active # features/plugin-is-active.feature:16
When I run `wp plugin deactivate akismet` # features/plugin-is-active.feature:17
$ wp plugin deactivate akismet
Success: Plugin already deactivated.
Warning: Plugin 'akismet' isn't active.
@copilot One failing test:
...
Fixed in commit 76ee8dc. The test scenario now activates the plugin before deactivating it, since each scenario starts with a fresh WP install where akismet is inactive by default.
Codecov Report
:x: Patch coverage is 88.88889% with 3 lines in your changes missing coverage. Please review.
| Files with missing lines | Patch % | Lines |
|---|---|---|
| src/Plugin_Command.php | 88.88% | 3 Missing :warning: |
:loudspeaker: Thoughts on this report? Let us know!
/gemini review
@copilot These ! empty( $input_name ) checks appear to be redundant. The <plugin> argument is required for this command, so $input_name (from $args[0]) should always be a non-empty string. Removing these checks will simplify the condition.
On a related note, this logic for finding a plugin by name is duplicated from WP_CLI\Fetchers\Plugin::get(). For future refactoring, it would be beneficial to extract this into a shared helper to improve maintainability.
"$input_name.php" === $plugin_file ||
$plugin_file === $input_name ||
( dirname( $plugin_file ) === $input_name && '.' !== $input_name )
@copilot These
! empty( $input_name )checks appear to be redundant. The<plugin>argument is required for this command, so$input_name(from$args[0]) should always be a non-empty string. Rem...
Removed the redundant ! empty( $input_name ) checks in commit 0ed14ea. Since <plugin> is a required argument, $input_name will always be set.