diff --git a/features/plugin-install.feature b/features/plugin-install.feature index 8f828329..6275c93b 100644 --- a/features/plugin-install.feature +++ b/features/plugin-install.feature @@ -472,3 +472,29 @@ Feature: Install WordPress plugins """ active-network """ + + Scenario: Install plugin from a zip file with a custom --slug + Given a WP install + + When I run `wp plugin install https://github.com/wp-cli-test/generic-example-plugin/archive/refs/heads/master.zip --slug=my-custom-plugin` + Then STDOUT should contain: + """ + Renamed 'generic-example-plugin-master' to 'my-custom-plugin'. + """ + And STDOUT should contain: + """ + Plugin installed successfully. + """ + And the wp-content/plugins/my-custom-plugin directory should exist + And the wp-content/plugins/generic-example-plugin-master directory should not exist + And the return code should be 0 + + Scenario: Error when --slug is used with multiple plugins + Given a WP install + + When I try `wp plugin install hello-dolly akismet --slug=my-plugin` + Then STDERR should contain: + """ + Error: The --slug option can only be used when installing a single item. + """ + And the return code should be 1 diff --git a/features/theme-install.feature b/features/theme-install.feature index 52373006..a5406cc6 100644 --- a/features/theme-install.feature +++ b/features/theme-install.feature @@ -186,3 +186,29 @@ Feature: Install WordPress themes """ active """ + + Scenario: Install theme from a zip file with a custom --slug + Given a WP install + + When I run `wp theme install https://github.com/wp-cli-test/generic-example-theme/archive/refs/heads/master.zip --slug=my-custom-theme` + Then STDOUT should contain: + """ + Renamed 'generic-example-theme-master' to 'my-custom-theme'. + """ + And STDOUT should contain: + """ + Theme installed successfully. + """ + And the wp-content/themes/my-custom-theme directory should exist + And the wp-content/themes/generic-example-theme-master directory should not exist + And the return code should be 0 + + Scenario: Error when --slug is used with multiple themes + Given a WP install + + When I try `wp theme install twentytwelve twentyeleven --slug=my-theme` + Then STDERR should contain: + """ + Error: The --slug option can only be used when installing a single item. + """ + And the return code should be 1 diff --git a/src/Plugin_Command.php b/src/Plugin_Command.php index 1c3ac3a2..0fb12a8c 100644 --- a/src/Plugin_Command.php +++ b/src/Plugin_Command.php @@ -1165,6 +1165,9 @@ protected function filter_item_list( $items, $args ) { * [--with-dependencies] * : If set, the command will also install all required dependencies of the plugin as specified in the 'Requires Plugins' header. * + * [--slug=] + * : Use this as the target directory name when installing from a zip file. Cannot be used when installing multiple plugins. + * * ## EXAMPLES * * # Install the latest version from wordpress.org and activate diff --git a/src/Theme_Command.php b/src/Theme_Command.php index 00dfe3da..7ea769c1 100644 --- a/src/Theme_Command.php +++ b/src/Theme_Command.php @@ -612,6 +612,9 @@ protected function filter_item_list( $items, $args ) { * [--insecure] * : Retry downloads without certificate validation if TLS handshake fails. Note: This makes the request vulnerable to a MITM attack. * + * [--slug=] + * : Use this as the target directory name when installing from a zip file. Cannot be used when installing multiple themes. + * * ## EXAMPLES * * # Install the latest version from wordpress.org and activate diff --git a/src/WP_CLI/CommandWithUpgrade.php b/src/WP_CLI/CommandWithUpgrade.php index d1623c97..4ee663db 100755 --- a/src/WP_CLI/CommandWithUpgrade.php +++ b/src/WP_CLI/CommandWithUpgrade.php @@ -185,8 +185,14 @@ private function show_legend( $items ) { } public function install( $args, $assoc_args ) { - $successes = 0; - $errors = 0; + $successes = 0; + $errors = 0; + $custom_slug = Utils\get_flag_value( $assoc_args, 'slug', false ); + + if ( $custom_slug && count( $args ) > 1 ) { + WP_CLI::error( 'The --slug option can only be used when installing a single item.' ); + } + foreach ( $args as $slug ) { if ( empty( $slug ) ) { @@ -263,10 +269,32 @@ public function install( $args, $assoc_args ) { $file_upgrader = $this->get_upgrader( $assoc_args ); $filter = false; - // If a GitHub URL, do some guessing as to the correct plugin/theme directory. - if ( $is_remote && 'github.com' === Utils\parse_url( $slug, PHP_URL_HOST ) + if ( $custom_slug ) { + // If --slug is specified, rename the extracted directory to the provided slug. + $filter = function ( $source ) use ( $custom_slug ) { + /** + * @var \WP_Filesystem_Base $wp_filesystem + */ + global $wp_filesystem; + + $source_dir = Utils\basename( $source ); // `$source` is trailing-slashed path to the unzipped archive directory. + if ( $source_dir === $custom_slug ) { + return $source; + } + $new_path = substr_replace( $source, $custom_slug, (int) strrpos( $source, $source_dir ), strlen( $source_dir ) ); + + if ( $wp_filesystem->move( $source, $new_path ) ) { + WP_CLI::log( sprintf( "Renamed '%s' to '%s'.", $source_dir, $custom_slug ) ); + return $new_path; + } + + return new WP_Error( 'wpcli_install_slug', "Couldn't rename to '{$custom_slug}'." ); + }; + add_filter( 'upgrader_source_selection', $filter, 10 ); + } elseif ( $is_remote && 'github.com' === Utils\parse_url( $slug, PHP_URL_HOST ) // Don't attempt to rename ZIPs uploaded to the releases page or coming from a raw source. && ! preg_match( '#github\.com/[^/]+/[^/]+/(?:releases/download|raw)/#', $slug ) ) { + // If a GitHub URL, do some guessing as to the correct plugin/theme directory. $filter = function ( $source ) use ( $slug ) { /**