From 730da5dda4a6ad876462c181dc05e8bb716e7e8f Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Sun, 22 Dec 2024 13:30:25 -0500 Subject: [PATCH 01/12] Support requires and requires_php in plugin/theme list and update commands This introduces a new update sate of 'unavailable' which is when there is a new version of a theme/plugin upstream but the local WordPress / PHP requirements do not meet the requirements set by the authors. --- features/plugin.feature | 55 +++++++++++++++++ features/theme.feature | 28 +++++++++ src/Plugin_Command.php | 94 ++++++++++++++++++++++++------ src/WP_CLI/CommandWithUpgrade.php | 29 ++++++--- src/WP_CLI/ParseThemeNameInput.php | 69 +++++++++++++++++----- 5 files changed, 235 insertions(+), 40 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index b513af6c..8fb751a3 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -810,3 +810,58 @@ Feature: Manage WordPress plugins """ 5.5 """ + + @require-php-7 + Scenario: Show plugin update as unavailable if it doesn't meet WordPress requirements + Given a WP install + + When I run `wp core download --version=6.4 --force` + And I run `rm -r wp-content/themes/*` + And I run `wp plugin install wp-super-cache --version=1.9.4` + + When I run `wp plugin list --name=wp-super-cache --field=update_version` + And save STDOUT as {UPDATE_VERSION} + + When I run `wp plugin list --name=wp-super-cache --field=requires` + And save STDOUT as {REQUIRES} + + When I run `wp plugin list --name=wp-super-cache --field=requires_php` + And save STDOUT as {REQUIRES_PHP} + + And I run `wp plugin list` + Then STDOUT should be a table containing rows: + | name | status | update | version | update_version | auto_update | requires | requires_php | + | wp-super-cache | inactive | unavailable | 1.9.4 | {UPDATE_VERSION} | off | {REQUIRES} | {REQUIRES_PHP} | + + When I try `wp plugin update wp-super-cache` + Then STDERR should contain: + """ + Warning: wp-super-cache: Requires a newer version of WordPress + """ + + @less-than-php-8.0 @require-wp-5.6 + Scenario: Show plugin update as unavailable if it doesn't meet PHP requirements + Given a WP install + + And I run `wp plugin install edit-flow --version=0.9.8` + + When I run `wp plugin list --name=edit-flow --field=update_version` + And save STDOUT as {UPDATE_VERSION} + + When I run `wp plugin list --name=edit-flow --field=requires` + And save STDOUT as {REQUIRES} + + When I run `wp plugin list --name=edit-flow --field=requires_php` + And save STDOUT as {REQUIRES_PHP} + + And I run `wp plugin list` + Then STDOUT should be a table containing rows: + | name | status | update | version | update_version | auto_update | requires | requires_php | + | edit-flow | inactive | unavailable | 0.9.8 | {UPDATE_VERSION} | off | {REQUIRES} | {REQUIRES_PHP} | + + When I try `wp plugin update edit-flow` + Then STDERR should contain: + """ + Warning: edit-flow: Requires a newer version of PHP + """ + diff --git a/features/theme.feature b/features/theme.feature index fa15a95c..dae20816 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -620,3 +620,31 @@ Feature: Manage WordPress themes Then STDOUT should be a table containing rows: | auto_update | | on | + + @require-php-7 + Scenario: Show theme update as unavailable if it doesn't meet WordPress requirements + Given a WP install + + When I run `wp core download --version=6.2 --force` + And I run `rm -r wp-content/themes/*` + And I run `wp theme install kadence --version=1.1.1` + + When I run `wp theme list --name=kadence --field=update_version` + And save STDOUT as {UPDATE_VERSION} + + When I run `wp theme list --name=kadence --field=requires` + And save STDOUT as {REQUIRES} + + When I run `wp theme list --name=kadence --field=requires_php` + And save STDOUT as {REQUIRES_PHP} + + And I run `wp theme list` + Then STDOUT should be a table containing rows: + | name | status | update | version | update_version | auto_update | requires | requires_php | + | kadence | inactive | unavailable | 1.1.1 | {UPDATE_VERSION} | off | {REQUIRES} | {REQUIRES_PHP} | + + When I try `wp theme update kadence` + Then STDERR should contain: + """ + Warning: kadence: Requires a newer version of WordPress + """ diff --git a/src/Plugin_Command.php b/src/Plugin_Command.php index 55adf856..8c0b5bcc 100644 --- a/src/Plugin_Command.php +++ b/src/Plugin_Command.php @@ -271,6 +271,8 @@ protected function get_all_items() { 'file' => $file, 'auto_update' => false, 'tested_up_to' => '', + 'requires' => '', + 'requires_php' => '', 'wporg_status' => $wporg_info['status'], 'wporg_last_updated' => $wporg_info['last_updated'], ); @@ -293,6 +295,8 @@ protected function get_all_items() { 'auto_update' => false, 'author' => $item_data['Author'], 'tested_up_to' => '', + 'requires' => '', + 'requires_php' => '', 'wporg_status' => '', 'wporg_last_updated' => '', ]; @@ -740,6 +744,8 @@ public function update( $args, $assoc_args ) { } protected function get_item_list() { + global $wp_version; + $items = []; $duplicate_names = []; @@ -760,29 +766,62 @@ protected function get_item_list() { $update_info = ( isset( $all_update_info->response[ $file ] ) && null !== $all_update_info->response[ $file ] ) ? (array) $all_update_info->response[ $file ] : null; $name = Utils\get_plugin_name( $file ); $wporg_info = $this->get_wporg_data( $name ); + $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $file, false, false ); if ( ! isset( $duplicate_names[ $name ] ) ) { $duplicate_names[ $name ] = array(); } + $php_version = PHP_VERSION; + + $requires = isset( $update_info ) && isset( $update_info['requires'] ) ? $update_info['requires'] : null; + $requires_php = isset( $update_info ) && isset( $update_info['requires_php'] ) ? $update_info['requires_php'] : null; + + // If an update has requires_php set, check to see if the local version of PHP meets that requirement + // The plugins update API already filters out plugins that don't meet WordPress requirements, but does not + // filter out plugins based on PHP requirements -- so we must do that here + $compatible_php = empty( $requires_php ) || version_compare( PHP_VERSION, $requires_php, '>=' ); + + if ( ! $compatible_php ) { + $update = 'unavailable'; + $update_unavailable_reason = "Requires a newer version of PHP [$requires_php] than available [$php_version]"; + } else { + $update = $update_info ? 'available' : 'none'; + } + + // requires and requires_php are only provided by the plugins update API in the case of an update available. + // For display consistency, get these values from the current plugin file if they aren't in this response + if ( null === $requires ) { + $requires = ! empty( $plugin_data['RequiresWP'] ) ? $plugin_data['RequiresWP'] : ''; + } + + if ( null === $requires_php ) { + $requires_php = ! empty( $plugin_data['RequiresPHP'] ) ? $plugin_data['RequiresPHP'] : ''; + } + $duplicate_names[ $name ][] = $file; $items[ $file ] = [ - 'name' => $name, - 'status' => $this->get_status( $file ), - 'update' => (bool) $update_info, - 'update_version' => isset( $update_info ) && isset( $update_info['new_version'] ) ? $update_info['new_version'] : null, - 'update_package' => isset( $update_info ) && isset( $update_info['package'] ) ? $update_info['package'] : null, - 'version' => $details['Version'], - 'update_id' => $file, - 'title' => $details['Name'], - 'description' => wordwrap( $details['Description'] ), - 'file' => $file, - 'auto_update' => in_array( $file, $auto_updates, true ), - 'author' => $details['Author'], - 'tested_up_to' => '', - 'wporg_status' => $wporg_info['status'], - 'wporg_last_updated' => $wporg_info['last_updated'], - 'recently_active' => in_array( $file, array_keys( $recently_active ), true ), + 'name' => $name, + 'status' => $this->get_status( $file ), + 'update' => $update, + 'update_version' => isset( $update_info ) && isset( $update_info['new_version'] ) ? $update_info['new_version'] : null, + 'update_package' => isset( $update_info ) && isset( $update_info['package'] ) ? $update_info['package'] : null, + 'version' => $details['Version'], + 'update_id' => $file, + 'title' => $details['Name'], + 'description' => wordwrap( $details['Description'] ), + 'file' => $file, + 'auto_update' => in_array( $file, $auto_updates, true ), + 'author' => $details['Author'], + 'tested_up_to' => '', + 'requires' => $requires, + 'requires_php' => $requires_php, + 'wporg_status' => $wporg_info['status'], + 'wporg_last_updated' => $wporg_info['last_updated'], + + 'recently_active' => in_array( $file, array_keys( $recently_active ), true ), + + 'update_unavailable_reason' => isset( $update_unavailable_reason ) ? $update_unavailable_reason : '', ]; if ( $this->check_headers['tested_up_to'] ) { @@ -817,9 +856,25 @@ protected function get_item_list() { // Get info for all plugins that don't have an update. $plugin_update_info = isset( $all_update_info->no_update[ $file ] ) ? $all_update_info->no_update[ $file ] : null; - // Compare version and update information in plugin list. + // Check if local version is newer than what is listed upstream. if ( null !== $plugin_update_info && version_compare( $details['Version'], $plugin_update_info->new_version, '>' ) ) { - $items[ $file ]['update'] = static::INVALID_VERSION_MESSAGE; + $items[ $file ]['update'] = static::INVALID_VERSION_MESSAGE; + $items[ $file ]['requires'] = isset( $plugin_update_info->requires ) ? $plugin_update_info->requires : null; + $items[ $file ]['requires_php'] = isset( $plugin_update_info->requires_php ) ? $plugin_update_info->requires_php : null; + } + + // If there is a plugin in no_update with a newer version than the local copy, it is because the plugins update api + // has already filtered it because the local WordPress version is too low + if ( null !== $plugin_update_info && version_compare( $details['Version'], $plugin_update_info->new_version, '<' ) ) { + $items[ $file ]['update'] = 'unavailable'; + $items[ $file ]['update_version'] = $plugin_update_info->new_version; + $items[ $file ]['requires'] = isset( $plugin_update_info->requires ) ? $plugin_update_info->requires : null; + $items[ $file ]['requires_php'] = isset( $plugin_update_info->requires_php ) ? $plugin_update_info->requires_php : null; + + $reason = "Requires a newer version of WordPress [$plugin_update_info->requires] than installed [$wp_version]"; + + $items[ $file ]['update_unavailable_reason'] = $reason; + } } } @@ -1397,6 +1452,8 @@ public function delete( $args, $assoc_args = array() ) { * * file * * author * * tested_up_to + * * requires + * * requires_php * * wporg_status * * wporg_last_updated * @@ -1488,7 +1545,6 @@ protected function get_status( $file ) { if ( is_plugin_active_for_network( $file ) ) { return 'active-network'; } - if ( is_plugin_active( $file ) ) { return 'active'; } diff --git a/src/WP_CLI/CommandWithUpgrade.php b/src/WP_CLI/CommandWithUpgrade.php index d925aeb2..78919ca1 100755 --- a/src/WP_CLI/CommandWithUpgrade.php +++ b/src/WP_CLI/CommandWithUpgrade.php @@ -103,7 +103,7 @@ private function status_all() { $padding = $this->get_padding( $items ); foreach ( $items as $file => $details ) { - if ( $details['update'] ) { + if ( 'available' === $details['update'] ) { $line = ' %yU%n'; } else { $line = ' '; @@ -150,8 +150,7 @@ private function show_legend( $items ) { $this->map['long'][ $status ] ); } - - if ( in_array( true, wp_list_pluck( $items, 'update' ), true ) ) { + if ( in_array( 'available', wp_list_pluck( $items, 'update' ), true ) ) { $legend_line[] = '%yU = Update Available%n'; } @@ -375,7 +374,12 @@ protected function update_many( $args, $assoc_args ) { $errors = count( $args ) - count( $items ); } - $items_to_update = wp_list_filter( $items, [ 'update' => true ] ); + $items_to_update = array_filter( + $items, + function ( $item ) { + return isset( $item['update'] ) && $item['update'] !== 'none'; + } + ); $minor = (bool) Utils\get_flag_value( $assoc_args, 'minor', false ); $patch = (bool) Utils\get_flag_value( $assoc_args, 'patch', false ); @@ -417,6 +421,11 @@ protected function update_many( $args, $assoc_args ) { ++$skipped; unset( $items_to_update[ $item_key ] ); } + if ( 'unavailable' === $item_info['update'] ) { + WP_CLI::warning( "{$item_info['name']}: {$item_info['update_unavailable_reason']}" ); + ++$skipped; + unset( $items_to_update[ $item_key ] ); + } } if ( Utils\get_flag_value( $assoc_args, 'dry-run' ) ) { @@ -564,10 +573,14 @@ function ( $value ) { foreach ( $item as $field => &$value ) { if ( 'update' === $field ) { - if ( true === $value ) { - $value = 'available'; - } elseif ( false === $value ) { - $value = 'none'; + // If an update is unavailable, make sure to also show these fields which will explain why + if ( 'unavailable' === $value ) { + if ( ! in_array( 'requires', $this->obj_fields, true ) ) { + array_push( $this->obj_fields, 'requires' ); + } + if ( ! in_array( 'requires_php', $this->obj_fields, true ) ) { + array_push( $this->obj_fields, 'requires_php' ); + } } } elseif ( 'auto_update' === $field ) { if ( true === $value ) { diff --git a/src/WP_CLI/ParseThemeNameInput.php b/src/WP_CLI/ParseThemeNameInput.php index 6a30a386..7f59c360 100644 --- a/src/WP_CLI/ParseThemeNameInput.php +++ b/src/WP_CLI/ParseThemeNameInput.php @@ -45,6 +45,11 @@ protected function check_optional_args_and_all( $args, $all, $verb = 'install' ) * @return array */ private function get_all_themes() { + global $wp_version; + // Extract the major WordPress version (e.g., "6.3") from the full version string + list($wp_core_version) = explode( '-', $wp_version ); + $wp_core_version = implode( '.', array_slice( explode( '.', $wp_core_version ), 0, 2 ) ); + $items = array(); $theme_version_info = array(); @@ -76,22 +81,60 @@ private function get_all_themes() { } foreach ( wp_get_themes() as $key => $theme ) { - $stylesheet = $theme->get_stylesheet(); - + $stylesheet = $theme->get_stylesheet(); $update_info = ( isset( $all_update_info->response[ $stylesheet ] ) && null !== $all_update_info->response[ $theme->get_stylesheet() ] ) ? (array) $all_update_info->response[ $theme->get_stylesheet() ] : null; + // Unlike plugin update responses, the wordpress.org API does not seem to check and filter themes that don't meet + // WordPress version requirements into a separate no_updates array + // Also unlike plugin update responses, the wordpress.org API seems to always include requires AND requires_php + $requires = isset( $update_info ) && isset( $update_info['requires'] ) ? $update_info['requires'] : null; + $requires_php = isset( $update_info ) && isset( $update_info['requires_php'] ) ? $update_info['requires_php'] : null; + + $compatible_php = empty( $requires_php ) || version_compare( PHP_VERSION, $requires_php, '>=' ); + $compatible_wp = empty( $requires ) || version_compare( $wp_version, $requires, '>=' ); + + if ( ! $compatible_php ) { + $update = 'unavailable'; + $update_unavailable_reason = sprintf( + 'Requires a newer version of PHP [%s] than installed [%s]', + $requires_php, + PHP_VERSION + ); + } else { + $update = $update_info ? 'available' : 'none'; + } + + if ( ! $compatible_wp ) { + $update = 'unavailable'; + $update_unavailable_reason = "Requires a newer version of WordPress [$requires] than installed [$wp_version]"; + } else { + $update = $update_info ? 'available' : 'none'; + } + + // For display consistency, get these values from the current plugin file if they aren't in this response + if ( null === $requires ) { + $requires = ! empty( $theme->get( 'RequiresWP' ) ) ? $theme->get( 'RequiresWP' ) : ''; + } + + if ( null === $requires_php ) { + $requires_php = ! empty( $theme->get( 'RequiresPHP' ) ) ? $theme->get( 'RequiresPHP' ) : ''; + } + $items[ $stylesheet ] = [ - 'name' => $key, - 'status' => $this->get_status( $theme ), - 'update' => (bool) $update_info, - 'update_version' => isset( $update_info['new_version'] ) ? $update_info['new_version'] : null, - 'update_package' => isset( $update_info['package'] ) ? $update_info['package'] : null, - 'version' => $theme->get( 'Version' ), - 'update_id' => $stylesheet, - 'title' => $theme->get( 'Name' ), - 'description' => wordwrap( $theme->get( 'Description' ) ), - 'author' => $theme->get( 'Author' ), - 'auto_update' => in_array( $stylesheet, $auto_updates, true ), + 'name' => $key, + 'status' => $this->get_status( $theme ), + 'update' => $update, + 'update_version' => isset( $update_info['new_version'] ) ? $update_info['new_version'] : null, + 'update_package' => isset( $update_info['package'] ) ? $update_info['package'] : null, + 'version' => $theme->get( 'Version' ), + 'update_id' => $stylesheet, + 'title' => $theme->get( 'Name' ), + 'description' => wordwrap( $theme->get( 'Description' ) ), + 'author' => $theme->get( 'Author' ), + 'auto_update' => in_array( $stylesheet, $auto_updates, true ), + 'requires' => $requires, + 'requires_php' => $requires_php, + 'update_unavailable_reason' => isset( $update_unavailable_reason ) ? $update_unavailable_reason : '', ]; // Compare version and update information in theme list. From f2153c8f1060cd8eabdff10c2a624f9e73d51d41 Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Tue, 24 Dec 2024 11:37:35 -0500 Subject: [PATCH 02/12] Fix phpcs --- src/WP_CLI/CommandWithUpgrade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WP_CLI/CommandWithUpgrade.php b/src/WP_CLI/CommandWithUpgrade.php index 78919ca1..a1953eab 100755 --- a/src/WP_CLI/CommandWithUpgrade.php +++ b/src/WP_CLI/CommandWithUpgrade.php @@ -377,7 +377,7 @@ protected function update_many( $args, $assoc_args ) { $items_to_update = array_filter( $items, function ( $item ) { - return isset( $item['update'] ) && $item['update'] !== 'none'; + return isset( $item['update'] ) && 'none' !== $item['update']; } ); From 91f68a7e3bbbc5f08a3f2840da8dfd0129eb840a Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Fri, 27 Dec 2024 10:26:50 -0500 Subject: [PATCH 03/12] Adjust warning text --- features/plugin.feature | 4 ++-- features/theme.feature | 2 +- src/Plugin_Command.php | 15 ++++++++------- src/WP_CLI/ParseThemeNameInput.php | 10 ++++++---- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/features/plugin.feature b/features/plugin.feature index 8fb751a3..79cacb31 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -836,7 +836,7 @@ Feature: Manage WordPress plugins When I try `wp plugin update wp-super-cache` Then STDERR should contain: """ - Warning: wp-super-cache: Requires a newer version of WordPress + Warning: wp-super-cache: This update requires WordPress version """ @less-than-php-8.0 @require-wp-5.6 @@ -862,6 +862,6 @@ Feature: Manage WordPress plugins When I try `wp plugin update edit-flow` Then STDERR should contain: """ - Warning: edit-flow: Requires a newer version of PHP + Warning: edit-flow: This update requires PHP version """ diff --git a/features/theme.feature b/features/theme.feature index dae20816..169901b0 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -646,5 +646,5 @@ Feature: Manage WordPress themes When I try `wp theme update kadence` Then STDERR should contain: """ - Warning: kadence: Requires a newer version of WordPress + Warning: kadence: This update requires WordPress version """ diff --git a/src/Plugin_Command.php b/src/Plugin_Command.php index 8c0b5bcc..58ceaec7 100644 --- a/src/Plugin_Command.php +++ b/src/Plugin_Command.php @@ -772,8 +772,6 @@ protected function get_item_list() { $duplicate_names[ $name ] = array(); } - $php_version = PHP_VERSION; - $requires = isset( $update_info ) && isset( $update_info['requires'] ) ? $update_info['requires'] : null; $requires_php = isset( $update_info ) && isset( $update_info['requires_php'] ) ? $update_info['requires_php'] : null; @@ -783,8 +781,13 @@ protected function get_item_list() { $compatible_php = empty( $requires_php ) || version_compare( PHP_VERSION, $requires_php, '>=' ); if ( ! $compatible_php ) { - $update = 'unavailable'; - $update_unavailable_reason = "Requires a newer version of PHP [$requires_php] than available [$php_version]"; + $update = 'unavailable'; + + $update_unavailable_reason = sprintf( + 'This update requires PHP version %s, but the version installed is %s.', + $requires_php, + PHP_VERSION + ); } else { $update = $update_info ? 'available' : 'none'; } @@ -818,9 +821,7 @@ protected function get_item_list() { 'requires_php' => $requires_php, 'wporg_status' => $wporg_info['status'], 'wporg_last_updated' => $wporg_info['last_updated'], - 'recently_active' => in_array( $file, array_keys( $recently_active ), true ), - 'update_unavailable_reason' => isset( $update_unavailable_reason ) ? $update_unavailable_reason : '', ]; @@ -871,7 +872,7 @@ protected function get_item_list() { $items[ $file ]['requires'] = isset( $plugin_update_info->requires ) ? $plugin_update_info->requires : null; $items[ $file ]['requires_php'] = isset( $plugin_update_info->requires_php ) ? $plugin_update_info->requires_php : null; - $reason = "Requires a newer version of WordPress [$plugin_update_info->requires] than installed [$wp_version]"; + $reason = "This update requires WordPress version $plugin_update_info->requires, but the version installed is $wp_version."; $items[ $file ]['update_unavailable_reason'] = $reason; diff --git a/src/WP_CLI/ParseThemeNameInput.php b/src/WP_CLI/ParseThemeNameInput.php index 7f59c360..84017f4b 100644 --- a/src/WP_CLI/ParseThemeNameInput.php +++ b/src/WP_CLI/ParseThemeNameInput.php @@ -94,9 +94,10 @@ private function get_all_themes() { $compatible_wp = empty( $requires ) || version_compare( $wp_version, $requires, '>=' ); if ( ! $compatible_php ) { - $update = 'unavailable'; + $update = 'unavailable'; + $update_unavailable_reason = sprintf( - 'Requires a newer version of PHP [%s] than installed [%s]', + 'This update requires PHP version %s, but the version installed is %s.', $requires_php, PHP_VERSION ); @@ -105,8 +106,9 @@ private function get_all_themes() { } if ( ! $compatible_wp ) { - $update = 'unavailable'; - $update_unavailable_reason = "Requires a newer version of WordPress [$requires] than installed [$wp_version]"; + $update = 'unavailable'; + + $update_unavailable_reason = "This update requires WordPress version $requires, but the version installed is $wp_version."; } else { $update = $update_info ? 'available' : 'none'; } From 0cd790d2c9ed912226d4228dba19f81e18afee3c Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Sun, 29 Dec 2024 13:11:59 -0500 Subject: [PATCH 04/12] Update test requirements to match moina minimum WordPress version --- features/theme-update.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/theme-update.feature b/features/theme-update.feature index c5bf42ed..d9fda895 100644 --- a/features/theme-update.feature +++ b/features/theme-update.feature @@ -32,6 +32,7 @@ Feature: Update WordPress themes | name | version | | twentytwelve | 4.0 | + @require-wp-4.5 Scenario: Not giving a slug on update should throw an error unless --all given Given a WP install And I run `wp theme path` From e4d0dd9d15ffcba45de017a21bb51ed754b3fc4a Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Thu, 13 Feb 2025 16:45:08 -0500 Subject: [PATCH 05/12] Use a specific elseif to avoid errors in logic --- src/WP_CLI/ParseThemeNameInput.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/WP_CLI/ParseThemeNameInput.php b/src/WP_CLI/ParseThemeNameInput.php index 84017f4b..fabb2dad 100644 --- a/src/WP_CLI/ParseThemeNameInput.php +++ b/src/WP_CLI/ParseThemeNameInput.php @@ -101,14 +101,14 @@ private function get_all_themes() { $requires_php, PHP_VERSION ); - } else { - $update = $update_info ? 'available' : 'none'; - } - - if ( ! $compatible_wp ) { + } elseif ( ! $compatible_wp ) { $update = 'unavailable'; - $update_unavailable_reason = "This update requires WordPress version $requires, but the version installed is $wp_version."; + $update_unavailable_reason = sprintf( + 'This update requires WordPress version %s, but the version installed is %s.', + $requires, + $wp_version + ); } else { $update = $update_info ? 'available' : 'none'; } From a4021e2ff346887824b8a0aad5d3c4af5e115f14 Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Thu, 13 Feb 2025 16:50:05 -0500 Subject: [PATCH 06/12] Use new HTTP mock feature to more reliably test --- composer.json | 2 +- features/plugin.feature | 102 +++++++++++++++++++++++++++------------- features/theme.feature | 87 +++++++++++++++++++++++++++++----- 3 files changed, 145 insertions(+), 46 deletions(-) diff --git a/composer.json b/composer.json index 399f62bd..31d45d68 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "wp-cli/entity-command": "^1.3 || ^2", "wp-cli/language-command": "^2.0", "wp-cli/scaffold-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^4" + "wp-cli/wp-cli-tests": "^4.3.7" }, "config": { "process-timeout": 7200, diff --git a/features/plugin.feature b/features/plugin.feature index 79cacb31..dcecf1c1 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -811,57 +811,95 @@ Feature: Manage WordPress plugins 5.5 """ - @require-php-7 Scenario: Show plugin update as unavailable if it doesn't meet WordPress requirements Given a WP install - - When I run `wp core download --version=6.4 --force` - And I run `rm -r wp-content/themes/*` - And I run `wp plugin install wp-super-cache --version=1.9.4` - - When I run `wp plugin list --name=wp-super-cache --field=update_version` - And save STDOUT as {UPDATE_VERSION} - - When I run `wp plugin list --name=wp-super-cache --field=requires` - And save STDOUT as {REQUIRES} - - When I run `wp plugin list --name=wp-super-cache --field=requires_php` - And save STDOUT as {REQUIRES_PHP} + And a wp-content/plugins/example/example.php file: + """ + Date: Fri, 14 Feb 2025 12:35:24 -0500 Subject: [PATCH 07/12] Require wp 4.0 for plugins update test The plugins update-check api doesn't actually work with older versions of WordPress, for two reasons: The first is that the no_updates field wasn't added til 4.0 The second is that the request that WP itself makes to the plugins update API is missing &all=true which causes the API to always return an empty response in my testing. Both of these were added in 4.0 here: https://github.com/WordPress/wordpress-develop/commit/b00097b75832adebe5682723ea8eb2a9816db55c --- features/plugin.feature | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/plugin.feature b/features/plugin.feature index dcecf1c1..21041ec2 100644 --- a/features/plugin.feature +++ b/features/plugin.feature @@ -811,6 +811,7 @@ Feature: Manage WordPress plugins 5.5 """ + @require-wp-4.0 Scenario: Show plugin update as unavailable if it doesn't meet WordPress requirements Given a WP install And a wp-content/plugins/example/example.php file: @@ -857,6 +858,7 @@ Feature: Manage WordPress plugins Warning: example: This update requires WordPress version 100 """ + @require-wp-4.0 Scenario: Show plugin update as unavailable if it doesn't meet PHP requirements Given a WP install And a wp-content/plugins/example/example.php file: From 130dcd69ae3cc2d689d1c386f345cc1bfbd2243d Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Fri, 14 Feb 2025 12:44:56 -0500 Subject: [PATCH 08/12] Use twentythirteen for this test Astra requires at least WordPress 5.3 so this test no longer applies since we flag the update as unavailable. Switch to twentythirteen which has lower WP requriements and is better to use for testing old versions --- features/theme.feature | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index f0db902a..824ef61b 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -210,7 +210,7 @@ Feature: Manage WordPress themes Scenario: Flag `--skip-update-check` skips update check when running `wp theme list` Given a WP install - When I run `wp theme install astra --version=1.0.0` + When I run `wp theme install twentythirteen --version=1.1` Then STDOUT should contain: """ Theme installed successfully. @@ -218,8 +218,8 @@ Feature: Manage WordPress themes When I run `wp theme list --fields=name,status,update` Then STDOUT should be a table containing rows: - | name | status | update | - | astra | inactive | available | + | name | status | update | + | twentythirteen | inactive | available | When I run `wp transient delete update_themes --network` Then STDOUT should be: @@ -229,8 +229,8 @@ Feature: Manage WordPress themes When I run `wp theme list --fields=name,status,update --skip-update-check` Then STDOUT should be a table containing rows: - | name | status | update | - | astra | inactive | none | + | name | status | update | + | twentythirteen | inactive | none | Scenario: Install a theme when the theme directory doesn't yet exist Given a WP install From 1f9609ccf1e7960bcb9439f003cd3f07abb230c5 Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Fri, 14 Feb 2025 12:57:59 -0500 Subject: [PATCH 09/12] use --force Older versions of WordPress already have this installed (!) We want to force this older version since we know there will be updates. --- features/theme.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 824ef61b..6ef18ce2 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -210,10 +210,10 @@ Feature: Manage WordPress themes Scenario: Flag `--skip-update-check` skips update check when running `wp theme list` Given a WP install - When I run `wp theme install twentythirteen --version=1.1` + When I run `wp theme install twentythirteen --version=1.1 --force` Then STDOUT should contain: """ - Theme installed successfully. + Installed 1 of 1 themes """ When I run `wp theme list --fields=name,status,update` From 36ec8f651f842ca09edce5aa0118090532100108 Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Fri, 14 Feb 2025 13:13:54 -0500 Subject: [PATCH 10/12] Update test to work across any WordPress version This is going to have different results across different versions of WordPress now, because output depends on the upstream requirements of what we are testing. Update test so that the update status is variable and we specify the fields otherwise it would sometimes show additional fields explaining the reason an update is unavailable --- features/upgradables.feature | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/features/upgradables.feature b/features/upgradables.feature index 64685c0f..fcfbf659 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -55,10 +55,14 @@ Feature: Manage WordPress themes and plugins Then STDOUT should not be empty And save STDOUT as {UPDATE_VERSION} - When I run `wp list` + When I run `wp list --name= --field=update` + Then STDOUT should not be empty + And save STDOUT as {UPDATE} + + When I run `wp list --fields=name,status,update,version,update_version,auto_update` Then STDOUT should be a table containing rows: - | name | status | update | version | update_version | auto_update | - | | inactive | available | | {UPDATE_VERSION} | off | + | name | status | update | version | update_version | auto_update | + | | inactive | {UPDATE} | | {UPDATE_VERSION} | off | When I run `wp list --field=name` Then STDOUT should contain: From 38409d0a22953ffff4dcd0cba342c064a8d91e69 Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Tue, 18 Feb 2025 15:48:47 -0500 Subject: [PATCH 11/12] More changes for PHP 5.6 / WP 3.7 tests to skip or pass --- features/theme.feature | 17 ++++++++++------- features/upgradables.feature | 12 ++++-------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 6ef18ce2..49e5c8ba 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -210,7 +210,7 @@ Feature: Manage WordPress themes Scenario: Flag `--skip-update-check` skips update check when running `wp theme list` Given a WP install - When I run `wp theme install twentythirteen --version=1.1 --force` + When I run `wp theme install twentyten --version=4.0` Then STDOUT should contain: """ Installed 1 of 1 themes @@ -218,8 +218,8 @@ Feature: Manage WordPress themes When I run `wp theme list --fields=name,status,update` Then STDOUT should be a table containing rows: - | name | status | update | - | twentythirteen | inactive | available | + | name | status | update | + | twentyten | inactive | available | When I run `wp transient delete update_themes --network` Then STDOUT should be: @@ -229,8 +229,8 @@ Feature: Manage WordPress themes When I run `wp theme list --fields=name,status,update --skip-update-check` Then STDOUT should be a table containing rows: - | name | status | update | - | twentythirteen | inactive | none | + | name | status | update | + | twentyten | inactive | none | Scenario: Install a theme when the theme directory doesn't yet exist Given a WP install @@ -284,6 +284,7 @@ Feature: Manage WordPress themes Theme updated successfully. """ + @require-wp-5.7 Scenario: Enabling and disabling a theme Given a WP multisite install And I run `wp theme install moina` @@ -379,6 +380,7 @@ Feature: Manage WordPress themes And STDOUT should be empty And the return code should be 1 + @require-wp-5.7 Scenario: Install and attempt to activate a child theme without its parent Given a WP install And I run `wp theme install moina-blog` @@ -392,6 +394,7 @@ Feature: Manage WordPress themes And STDOUT should be empty And the return code should be 1 + @require-wp-5.7 Scenario: List an active theme with its parent Given a WP install And I run `wp theme install moina` @@ -470,6 +473,7 @@ Feature: Manage WordPress themes twentytwelve,1.0,{UPDATE_VERSION},Updated """ + @require-wp-5.7 Scenario: Automatically install parent theme for a child theme Given a WP install @@ -579,7 +583,7 @@ Feature: Manage WordPress themes Error: Parameter errors: Invalid value specified for 'status' (Filter the output by theme status.) """ - + @require-wp-5.7 Scenario: Parent theme is active when its child is active Given a WP install And I run `wp theme delete --all --force` @@ -621,7 +625,6 @@ Feature: Manage WordPress themes | auto_update | | on | - @require-php-7 Scenario: Show theme update as unavailable if it doesn't meet WordPress requirements Given a WP install And a wp-content/themes/example/style.css file: diff --git a/features/upgradables.feature b/features/upgradables.feature index fcfbf659..69f436d4 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -55,14 +55,10 @@ Feature: Manage WordPress themes and plugins Then STDOUT should not be empty And save STDOUT as {UPDATE_VERSION} - When I run `wp list --name= --field=update` - Then STDOUT should not be empty - And save STDOUT as {UPDATE} - - When I run `wp list --fields=name,status,update,version,update_version,auto_update` + When I run `wp list` Then STDOUT should be a table containing rows: - | name | status | update | version | update_version | auto_update | - | | inactive | {UPDATE} | | {UPDATE_VERSION} | off | + | name | status | update | version | update_version | auto_update | + | | inactive | available | | {UPDATE_VERSION} | off | When I run `wp list --field=name` Then STDOUT should contain: @@ -212,5 +208,5 @@ Feature: Manage WordPress themes and plugins Examples: | type | type_name | item | item_title | version | zip_file | file_to_check | - | theme | Theme | moina | Moina | 1.1.2 | https://wordpress.org/themes/download/moina.1.1.2.zip | {CONTENT_DIR}/moina/style.css | + | theme | Theme | twentyten | Twenty Ten | 4.0 | https://wordpress.org/themes/download/twentyten.4.0.zip | {CONTENT_DIR}/twentyten/style.css | | plugin | Plugin | category-checklist-tree | Category Checklist Tree | 1.2 | https://downloads.wordpress.org/plugin/category-checklist-tree.1.2.zip | {CONTENT_DIR}/category-checklist-tree/category-checklist-tree.php | From 47b062e92e50f03369864608181ba8919c4b4e20 Mon Sep 17 00:00:00 2001 From: Isla Waters Date: Tue, 18 Feb 2025 16:17:47 -0500 Subject: [PATCH 12/12] Revert use of twentyten WordPress Trunk actually includes all of these past default themes so the output is different. Put behind a version guard instead --- features/theme.feature | 9 +++++---- features/upgradables.feature | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/features/theme.feature b/features/theme.feature index 49e5c8ba..a42717fc 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -207,19 +207,20 @@ Feature: Manage WordPress themes And STDOUT should be empty And the return code should be 0 + @require-wp-5.3 Scenario: Flag `--skip-update-check` skips update check when running `wp theme list` Given a WP install - When I run `wp theme install twentyten --version=4.0` + When I run `wp theme install astra --version=1.0.0` Then STDOUT should contain: """ - Installed 1 of 1 themes + Theme installed successfully. """ When I run `wp theme list --fields=name,status,update` Then STDOUT should be a table containing rows: | name | status | update | - | twentyten | inactive | available | + | astra | inactive | available | When I run `wp transient delete update_themes --network` Then STDOUT should be: @@ -230,7 +231,7 @@ Feature: Manage WordPress themes When I run `wp theme list --fields=name,status,update --skip-update-check` Then STDOUT should be a table containing rows: | name | status | update | - | twentyten | inactive | none | + | astra | inactive | none | Scenario: Install a theme when the theme directory doesn't yet exist Given a WP install diff --git a/features/upgradables.feature b/features/upgradables.feature index 69f436d4..dee3a627 100644 --- a/features/upgradables.feature +++ b/features/upgradables.feature @@ -3,6 +3,7 @@ Feature: Manage WordPress themes and plugins Background: Given an empty cache + @require-wp-4.5 Scenario Outline: Installing, upgrading and deleting a theme or plugin Given a WP install And I run `wp path` @@ -208,5 +209,5 @@ Feature: Manage WordPress themes and plugins Examples: | type | type_name | item | item_title | version | zip_file | file_to_check | - | theme | Theme | twentyten | Twenty Ten | 4.0 | https://wordpress.org/themes/download/twentyten.4.0.zip | {CONTENT_DIR}/twentyten/style.css | + | theme | Theme | moina | Moina | 1.1.2 | https://wordpress.org/themes/download/moina.1.1.2.zip | {CONTENT_DIR}/moina/style.css | | plugin | Plugin | category-checklist-tree | Category Checklist Tree | 1.2 | https://downloads.wordpress.org/plugin/category-checklist-tree.1.2.zip | {CONTENT_DIR}/category-checklist-tree/category-checklist-tree.php |