Skip to content

Commit 97f024c

Browse files
Copilotswissspidy
andcommitted
Add --skip-locale-check flag to wp core download for fallback locale version
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
1 parent 871a308 commit 97f024c

2 files changed

Lines changed: 134 additions & 4 deletions

File tree

features/core-download.feature

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,74 @@ Feature: Download WordPress
5151
Then the wp-settings.php file should exist
5252
And the {SUITE_CACHE_DIR}/core/wordpress-{VERSION}-de_DE.tar.gz file should exist
5353

54+
Scenario: Error when requested locale is not available for the latest version
55+
Given an empty directory
56+
And an empty cache
57+
And that HTTP requests to https://api.wordpress.org/core/version-check/1.7/ will respond with:
58+
"""
59+
HTTP/1.1 200 OK
60+
Content-Type: application/json
61+
62+
{"offers":[{"response":"upgrade","download":"https://downloads.wordpress.org/release/wordpress-6.9.4.zip","locale":"en_US","packages":{"full":"https://downloads.wordpress.org/release/wordpress-6.9.4.zip","no_content":"https://downloads.wordpress.org/release/wordpress-6.9.4-no-content.zip","new_bundled":"https://downloads.wordpress.org/release/wordpress-6.9.4-new-bundled.zip","partial":false,"rollback":false},"current":"6.9.4","version":"6.9.4","php_version":"7.2.24","mysql_version":"5.5.5","new_bundled":"6.7","partial_version":false}]}
63+
"""
64+
65+
When I try `wp core download --locale=de_DE`
66+
Then the return code should be 1
67+
And STDERR should contain:
68+
"""
69+
Error: The requested locale (de_DE) was not found.
70+
"""
71+
72+
Scenario: Download older locale version when latest is not yet available using --skip-locale-check
73+
Given an empty directory
74+
And an empty cache
75+
And that HTTP requests to https://api.wordpress.org/core/version-check/1.7/ will respond with:
76+
"""
77+
HTTP/1.1 200 OK
78+
Content-Type: application/json
79+
80+
{"offers":[{"response":"upgrade","download":"https://downloads.wordpress.org/release/wordpress-6.9.4.zip","locale":"en_US","packages":{"full":"https://downloads.wordpress.org/release/wordpress-6.9.4.zip","no_content":"https://downloads.wordpress.org/release/wordpress-6.9.4-no-content.zip","new_bundled":"https://downloads.wordpress.org/release/wordpress-6.9.4-new-bundled.zip","partial":false,"rollback":false},"current":"6.9.4","version":"6.9.4","php_version":"7.2.24","mysql_version":"5.5.5","new_bundled":"6.7","partial_version":false}]}
81+
"""
82+
And that HTTP requests to https://api.wordpress.org/translations/core/1.0/ will respond with:
83+
"""
84+
HTTP/1.1 200 OK
85+
Content-Type: application/json
86+
87+
{"translations":[{"language":"de_DE","version":"4.4.2","updated":"2024-01-01 00:00:00","english_name":"German","native_name":"Deutsch","package":"https://downloads.wordpress.org/translation/core/4.4.2/de_DE.zip"}]}
88+
"""
89+
90+
When I run `wp core download --locale=de_DE --skip-locale-check`
91+
Then the wp-settings.php file should exist
92+
And STDERR should contain:
93+
"""
94+
Warning: The latest WordPress version is not yet available in the de_DE locale. Downloading version 4.4.2 instead.
95+
"""
96+
97+
Scenario: Error when --skip-locale-check is set but no translation exists for locale
98+
Given an empty directory
99+
And an empty cache
100+
And that HTTP requests to https://api.wordpress.org/core/version-check/1.7/ will respond with:
101+
"""
102+
HTTP/1.1 200 OK
103+
Content-Type: application/json
104+
105+
{"offers":[{"response":"upgrade","download":"https://downloads.wordpress.org/release/wordpress-6.9.4.zip","locale":"en_US","packages":{"full":"https://downloads.wordpress.org/release/wordpress-6.9.4.zip","no_content":"https://downloads.wordpress.org/release/wordpress-6.9.4-no-content.zip","new_bundled":"https://downloads.wordpress.org/release/wordpress-6.9.4-new-bundled.zip","partial":false,"rollback":false},"current":"6.9.4","version":"6.9.4","php_version":"7.2.24","mysql_version":"5.5.5","new_bundled":"6.7","partial_version":false}]}
106+
"""
107+
And that HTTP requests to https://api.wordpress.org/translations/core/1.0/ will respond with:
108+
"""
109+
HTTP/1.1 200 OK
110+
Content-Type: application/json
111+
112+
{"translations":[]}
113+
"""
114+
115+
When I try `wp core download --locale=de_DE --skip-locale-check`
116+
Then the return code should be 1
117+
And STDERR should contain:
118+
"""
119+
Error: The requested locale (de_DE) was not found.
120+
"""
121+
54122
Scenario: Catch download of non-existent WP version
55123
Given an empty directory
56124

src/Core_Command.php

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ public function check_update( $args, $assoc_args ) {
149149
* [--extract]
150150
* : Whether to extract the downloaded file. Defaults to true.
151151
*
152+
* [--skip-locale-check]
153+
* : If specified, allows downloading an older version of WordPress when the requested locale is not available for the latest release.
154+
*
152155
* ## EXAMPLES
153156
*
154157
* $ wp core download --locale=nl_NL
@@ -160,7 +163,7 @@ public function check_update( $args, $assoc_args ) {
160163
* @when before_wp_load
161164
*
162165
* @param array{0?: string} $args Positional arguments.
163-
* @param array{path?: string, locale?: string, version?: string, 'skip-content'?: bool, force?: bool, insecure?: bool, extract?: bool} $assoc_args Associative arguments.
166+
* @param array{path?: string, locale?: string, version?: string, 'skip-content'?: bool, force?: bool, insecure?: bool, extract?: bool, 'skip-locale-check'?: bool} $assoc_args Associative arguments.
164167
*/
165168
public function download( $args, $assoc_args ) {
166169
/**
@@ -233,14 +236,22 @@ public function download( $args, $assoc_args ) {
233236

234237
$download_url = $this->get_download_url( $version, $locale, $extension );
235238
} else {
239+
$wp_org_api = new WpOrgApi( [ 'insecure' => $insecure ] );
236240
try {
237-
$offer = ( new WpOrgApi( [ 'insecure' => $insecure ] ) )
238-
->get_core_download_offer( $locale );
241+
$offer = $wp_org_api->get_core_download_offer( $locale );
239242
} catch ( Exception $exception ) {
240243
WP_CLI::error( $exception );
241244
}
242245
if ( ! $offer ) {
243-
WP_CLI::error( "The requested locale ({$locale}) was not found." );
246+
if ( Utils\get_flag_value( $assoc_args, 'skip-locale-check', false ) ) {
247+
$offer = $this->find_latest_offer_for_locale( $locale, $insecure );
248+
if ( is_array( $offer ) ) {
249+
WP_CLI::warning( "The latest WordPress version is not yet available in the {$locale} locale. Downloading version {$offer['current']} instead." );
250+
}
251+
}
252+
if ( ! $offer ) {
253+
WP_CLI::error( "The requested locale ({$locale}) was not found." );
254+
}
244255
}
245256
$version = $offer['current'];
246257
$download_url = $offer['download'];
@@ -1671,6 +1682,57 @@ private function get_download_url( $version, $locale = 'en_US', $file_type = 'zi
16711682
return "https://{$locale_subdomain}wordpress.org/wordpress-{$version}{$locale_suffix}.{$file_type}";
16721683
}
16731684

1685+
/**
1686+
* Finds the latest available WordPress download offer for a given locale by consulting
1687+
* the WordPress.org translations API.
1688+
*
1689+
* Used as a fallback when the primary version-check API does not return an offer for
1690+
* the requested locale (e.g., when a new WordPress release hasn't been translated yet).
1691+
*
1692+
* @param string $locale Locale to find an offer for.
1693+
* @param bool $insecure Whether to disable SSL verification.
1694+
* @return array{current: string, download: string}|false Offer array on success, false on failure.
1695+
*/
1696+
private function find_latest_offer_for_locale( $locale, $insecure ) {
1697+
$headers = [ 'Accept' => 'application/json' ];
1698+
$options = [
1699+
'timeout' => 30,
1700+
'insecure' => $insecure,
1701+
];
1702+
1703+
try {
1704+
/** @var \WpOrg\Requests\Response $response */
1705+
$response = Utils\http_request( 'GET', 'https://api.wordpress.org/translations/core/1.0/', null, $headers, $options );
1706+
} catch ( Exception $exception ) {
1707+
return false;
1708+
}
1709+
1710+
if ( $response->status_code < 200 || $response->status_code >= 300 ) {
1711+
return false;
1712+
}
1713+
1714+
/** @var array{translations: array<int, array{language: string, version: string}>}|null $body */
1715+
$body = json_decode( $response->body, true );
1716+
1717+
if ( ! is_array( $body ) || empty( $body['translations'] ) ) {
1718+
return false;
1719+
}
1720+
1721+
foreach ( $body['translations'] as $translation ) {
1722+
if (
1723+
isset( $translation['language'], $translation['version'] )
1724+
&& $locale === $translation['language']
1725+
) {
1726+
return [
1727+
'current' => $translation['version'],
1728+
'download' => $this->get_download_url( $translation['version'], $locale, 'zip' ),
1729+
];
1730+
}
1731+
}
1732+
1733+
return false;
1734+
}
1735+
16741736
/**
16751737
* Returns update information.
16761738
*

0 commit comments

Comments
 (0)