From 55ec7f3910480f59172de00c22f471132aa57332 Mon Sep 17 00:00:00 2001 From: Austin Ginder Date: Thu, 17 Sep 2026 19:14:22 -0400 Subject: [PATCH 1/3] Download update packages side by side before running the bulk upgrader `update --all` (and any multi-item update) whitelists each package with the HTTP cache manager, then lets the upgrader download them one at a time. With WpHttpCacheManager::prefetch() available, the packages are now fetched concurrently into the cache first, so the upgrader finds every one of them on disk. On an 11-plugin update the wall time drops by a third on a fast connection and by half on a slow one; the install phase is unchanged. The call is guarded with method_exists() so the package keeps working with a WP-CLI that does not have prefetch() yet. --- features/plugin-update.feature | 61 +++++++++++++++++++++++++++++++ features/theme-update.feature | 25 +++++++++++++ src/WP_CLI/CommandWithUpgrade.php | 4 ++ 3 files changed, 90 insertions(+) diff --git a/features/plugin-update.feature b/features/plugin-update.feature index 46513e14..7e79117f 100644 --- a/features/plugin-update.feature +++ b/features/plugin-update.feature @@ -371,6 +371,67 @@ Feature: Update WordPress plugins Success: Updated 2 of 2 plugins. """ + @require-wp-5.2 + Scenario: Updating several plugins downloads their packages side by side + Given a WP install + And an empty cache + And I run `wp plugin delete akismet` + + When I run `wp plugin install health-check --version=1.5.0` + Then STDOUT should not be empty + + When I run `wp plugin install wordpress-importer --version=0.5` + Then STDOUT should not be empty + + When I run `wp plugin update --all` + Then STDOUT should contain: + """ + Downloading 2 packages... + """ + And STDOUT should contain: + """ + Using cached file + """ + And STDOUT should contain: + """ + Success: Updated 2 of 2 plugins. + """ + + When I run `wp plugin install health-check --version=1.5.0 --force` + And I run `wp plugin install wordpress-importer --version=0.5 --force` + And I run `wp plugin update --all` + Then STDOUT should not contain: + """ + Downloading 2 packages... + """ + And STDOUT should contain: + """ + Success: Updated 2 of 2 plugins. + """ + + @require-wp-5.2 + Scenario: Updating a single plugin downloads its package on its own + Given a WP install + And an empty cache + And I run `wp plugin delete akismet` + + When I run `wp plugin install wordpress-importer --version=0.5` + Then STDOUT should not be empty + + When I run `wp plugin update --all` + Then STDOUT should not contain: + """ + Downloading 1 packages... + """ + And STDOUT should not contain: + """ + Using cached file + """ + And STDOUT should contain: + """ + Success: Updated 1 of 1 plugins. + """ + @require-wp-5.2 @skip-windows Scenario: Failed plugin update keeps JSON output parseable Given a WP install diff --git a/features/theme-update.feature b/features/theme-update.feature index c93d9377..defc3e64 100644 --- a/features/theme-update.feature +++ b/features/theme-update.feature @@ -258,6 +258,31 @@ Feature: Update WordPress themes Success: Updated 2 of 2 themes. """ + Scenario: Updating several themes downloads their packages side by side + Given a WP install + And an empty cache + And I run `wp theme delete --all --force` + + When I run `wp theme install storefront --version=1.0.0` + Then STDOUT should not be empty + + When I run `wp theme install twentytwelve --version=1.0` + Then STDOUT should not be empty + + When I run `wp theme update --all` + Then STDOUT should contain: + """ + Downloading 2 packages... + """ + And STDOUT should contain: + """ + Using cached file + """ + And STDOUT should contain: + """ + Success: Updated 2 of 2 themes. + """ + Scenario: Skip theme update when theme directory is a VCS checkout Given a WP install And I run `wp theme install twentytwelve --version=3.0 --force` diff --git a/src/WP_CLI/CommandWithUpgrade.php b/src/WP_CLI/CommandWithUpgrade.php index 4ad5032b..b7260c72 100755 --- a/src/WP_CLI/CommandWithUpgrade.php +++ b/src/WP_CLI/CommandWithUpgrade.php @@ -807,6 +807,10 @@ function ( $item ) { foreach ( $items_to_update as $item ) { $cache_manager->whitelist_package( $item['update_package'], $this->item_type, $item['name'], $item['update_version'] ); } + // Fetch the packages side by side before the upgrader asks for them one at a time. + if ( method_exists( $cache_manager, 'prefetch' ) ) { + $cache_manager->prefetch( wp_list_pluck( $items_to_update, 'update_package' ) ); + } $upgrader = $this->get_upgrader( $assoc_args ); // Ensure the upgrader uses the download offer present in each item. $transient_filter = function ( $transient ) use ( $items_to_update ) { From 661a57ee7b894144ada832056f6821734d48e7f5 Mon Sep 17 00:00:00 2001 From: Austin Ginder Date: Fri, 18 Sep 2026 05:19:45 -0400 Subject: [PATCH 2/3] Use `I try` for the update steps of the prefetch scenarios `I run` fails on any STDERR output as well as on a non-zero exit, and the neighbouring `update --all` scenarios use `I try` for that reason. The theme scenario is tagged @require-wp-4.5 like the one before it. --- features/plugin-update.feature | 6 +++--- features/theme-update.feature | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/features/plugin-update.feature b/features/plugin-update.feature index 7e79117f..2eb77c10 100644 --- a/features/plugin-update.feature +++ b/features/plugin-update.feature @@ -383,7 +383,7 @@ Feature: Update WordPress plugins When I run `wp plugin install wordpress-importer --version=0.5` Then STDOUT should not be empty - When I run `wp plugin update --all` + When I try `wp plugin update --all` Then STDOUT should contain: """ Downloading 2 packages... @@ -399,7 +399,7 @@ Feature: Update WordPress plugins When I run `wp plugin install health-check --version=1.5.0 --force` And I run `wp plugin install wordpress-importer --version=0.5 --force` - And I run `wp plugin update --all` + And I try `wp plugin update --all` Then STDOUT should not contain: """ Downloading 2 packages... @@ -418,7 +418,7 @@ Feature: Update WordPress plugins When I run `wp plugin install wordpress-importer --version=0.5` Then STDOUT should not be empty - When I run `wp plugin update --all` + When I try `wp plugin update --all` Then STDOUT should not contain: """ Downloading 1 packages... diff --git a/features/theme-update.feature b/features/theme-update.feature index defc3e64..a5c5ab91 100644 --- a/features/theme-update.feature +++ b/features/theme-update.feature @@ -258,6 +258,7 @@ Feature: Update WordPress themes Success: Updated 2 of 2 themes. """ + @require-wp-4.5 Scenario: Updating several themes downloads their packages side by side Given a WP install And an empty cache @@ -269,7 +270,7 @@ Feature: Update WordPress themes When I run `wp theme install twentytwelve --version=1.0` Then STDOUT should not be empty - When I run `wp theme update --all` + When I try `wp theme update --all` Then STDOUT should contain: """ Downloading 2 packages... From fc7b6c549ba257355d631f718c3337328561f8fc Mon Sep 17 00:00:00 2001 From: Austin Ginder Date: Fri, 18 Sep 2026 06:59:01 -0400 Subject: [PATCH 3/3] Assert the single-plugin update prints no prefetch line in either number The negative assertion matched only "Downloading 1 packages...", so a singular wording would have slipped past it. --- features/plugin-update.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/plugin-update.feature b/features/plugin-update.feature index 2eb77c10..4567d938 100644 --- a/features/plugin-update.feature +++ b/features/plugin-update.feature @@ -421,7 +421,7 @@ Feature: Update WordPress plugins When I try `wp plugin update --all` Then STDOUT should not contain: """ - Downloading 1 packages... + Downloading 1 package """ And STDOUT should not contain: """