Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions features/plugin-install.feature
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,53 @@ Feature: Install WordPress plugins
"""
And the return code should be 1

Scenario: Installed plugin is detected even without available update information
Given a WP install
# `install_plugin_install_status()` falls back to an "install" status if the
# WordPress.org API does not offer an update for an outdated plugin.
And a wp-content/mu-plugins/no-plugin-updates.php file:
"""
<?php
/**
* Plugin Name: Hide Plugin Updates
* Description: Simulates the WordPress.org API not offering any plugin updates
* Author: WP-CLI tests
*/
add_filter(
'site_transient_update_plugins',
function ( $updates ) {
if ( is_object( $updates ) ) {
$updates->response = array();
}
return $updates;
},
PHP_INT_MAX
);
"""
And a wp-content/plugins/debug-bar/debug-bar.php file:
"""
<?php
/**
* Plugin Name: Debug Bar
* Version: 0.1
*/
"""

When I try `wp plugin install debug-bar`
Then STDOUT should be:
"""
Success: Plugin already installed.
"""
And STDERR should be:
"""
Warning: debug-bar: Plugin already installed.
"""
And STDERR should not contain:
"""
Destination folder already exists
"""
And the return code should be 0

Scenario: Paths aren't backslashed when destination folder already exists
Given a WP install

Expand Down
36 changes: 33 additions & 3 deletions src/Plugin_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -778,9 +778,15 @@ protected function install_from_repo( $slug, $assoc_args ) {

$status = install_plugin_install_status( $api );

if ( ! Utils\get_flag_value( $assoc_args, 'force' ) && 'install' !== $status['status'] ) {
// We know this will fail, so avoid a needless download of the package.
return new WP_Error( 'already_installed', 'Plugin already installed.' );
if ( ! Utils\get_flag_value( $assoc_args, 'force' ) ) {
$is_installed = 'install' !== $status['status']
|| $this->is_plugin_installed( $slug )
|| $this->is_plugin_installed( $api->slug );

if ( $is_installed ) {
// We know this will fail, so avoid a needless download of the package.
return new WP_Error( 'already_installed', 'Plugin already installed.' );
}
}

WP_CLI::log( sprintf( 'Installing %s (%s)', html_entity_decode( $api->name, ENT_QUOTES ), $api->version ) );
Expand All @@ -798,6 +804,30 @@ protected function install_from_repo( $slug, $assoc_args ) {
return $result;
}

/**
* Checks whether a plugin with the given slug is already installed.
*
* `install_plugin_install_status()` reports an 'install' status for a plugin
* that is already installed when the WordPress.org API does not provide any
* update information for the installed version. This happens for example for
* the Akismet plugin that is bundled with WordPress, whenever the bundled
* version is outdated but no update is being offered for it.
*
* Checking the file system as well makes sure such a plugin is reported as
* being already installed instead of the installation failing with a
* "Destination folder already exists" error.
*
* @param string $slug Plugin slug.
* @return bool Whether the plugin folder holds an installed plugin.
*/
private function is_plugin_installed( $slug ) {
if ( ! is_dir( WP_PLUGIN_DIR . '/' . $slug ) ) {
return false;
}

return count( get_plugins( '/' . $slug ) ) > 0;
}

/**
* Updates one or more plugins.
*
Expand Down
Loading