Skip to content

Commit 31b0176

Browse files
authored
Merge pull request #303 from wp-cli/copilot/fix-wp-core-check-update-issue
2 parents 2b1add2 + 5d8c693 commit 31b0176

File tree

2 files changed

+125
-1
lines changed

2 files changed

+125
-1
lines changed

features/core-check-update.feature

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,19 @@ Feature: Check for more recent versions
7070
"""
7171
---
7272
"""
73+
74+
Scenario: Check update shows warning when version check API fails
75+
Given a WP install
76+
And that HTTP requests to https://api.wordpress.org/core/version-check/1.7/ will respond with:
77+
"""
78+
HTTP/1.1 500 Internal Server Error
79+
Content-Type: text/plain
80+
81+
<Error body>
82+
"""
83+
84+
When I try `wp core check-update --force-check`
85+
Then STDERR should contain:
86+
"""
87+
Warning: Failed to check for updates
88+
"""

src/Core_Command.php

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@
3131
*/
3232
class Core_Command extends WP_CLI_Command {
3333

34+
/**
35+
* Stores HTTP API errors encountered during version check.
36+
*
37+
* @var \WP_Error|null
38+
*/
39+
private $version_check_error = null;
40+
3441
/**
3542
* Checks for WordPress updates via Version Check API.
3643
*
@@ -92,6 +99,14 @@ public function check_update( $args, $assoc_args ) {
9299
[ 'version', 'update_type', 'package_url' ]
93100
);
94101
$formatter->display_items( $updates );
102+
} elseif ( $this->version_check_error ) {
103+
// If there was an HTTP error during version check, show a warning
104+
WP_CLI::warning(
105+
sprintf(
106+
'Failed to check for updates: %s',
107+
$this->version_check_error->get_error_message()
108+
)
109+
);
95110
} else {
96111
WP_CLI::success( 'WordPress is at the latest version.' );
97112
}
@@ -1453,7 +1468,25 @@ private function get_download_url( $version, $locale = 'en_US', $file_type = 'zi
14531468
*/
14541469
private function get_updates( $assoc_args ) {
14551470
$force_check = Utils\get_flag_value( $assoc_args, 'force-check' );
1456-
wp_version_check( [], $force_check );
1471+
1472+
// Reset error tracking
1473+
$this->version_check_error = null;
1474+
1475+
// Hook into pre_http_request with max priority to capture errors during version check
1476+
// This is necessary because tests and plugins may use pre_http_request to mock responses
1477+
add_filter( 'pre_http_request', [ $this, 'capture_version_check_error' ], PHP_INT_MAX, 3 );
1478+
1479+
// Also hook into http_api_debug to capture errors from real HTTP requests
1480+
// This fires when pre_http_request doesn't short-circuit the request
1481+
add_action( 'http_api_debug', [ $this, 'capture_version_check_error_from_response' ], 10, 5 );
1482+
1483+
try {
1484+
wp_version_check( [], $force_check );
1485+
} finally {
1486+
// Ensure the hooks are always removed, even if wp_version_check() throws an exception
1487+
remove_filter( 'pre_http_request', [ $this, 'capture_version_check_error' ], PHP_INT_MAX );
1488+
remove_action( 'http_api_debug', [ $this, 'capture_version_check_error_from_response' ], 10 );
1489+
}
14571490

14581491
/**
14591492
* @var object{updates: array<object{version: string, locale: string, packages: object{partial?: string, full: string}}>}|false $from_api
@@ -1510,6 +1543,81 @@ private function get_updates( $assoc_args ) {
15101543
return array_values( $updates );
15111544
}
15121545

1546+
/**
1547+
* Sets or clears the version check error property based on an HTTP response.
1548+
*
1549+
* @param mixed $response The HTTP response (WP_Error, array, or other).
1550+
*/
1551+
private function set_version_check_error( $response ) {
1552+
if ( is_wp_error( $response ) ) {
1553+
$this->version_check_error = $response;
1554+
} elseif ( is_array( $response ) && isset( $response['response']['code'] ) && $response['response']['code'] >= 400 ) {
1555+
// HTTP error status code (4xx or 5xx) - convert to WP_Error for consistency
1556+
$this->version_check_error = new \WP_Error(
1557+
'http_request_failed',
1558+
sprintf(
1559+
'HTTP request failed with status %d: %s',
1560+
$response['response']['code'],
1561+
isset( $response['response']['message'] ) ? $response['response']['message'] : 'Unknown error'
1562+
)
1563+
);
1564+
} else {
1565+
// Clear any previous error if we got a successful response.
1566+
$this->version_check_error = null;
1567+
}
1568+
}
1569+
1570+
/**
1571+
* Handles the pre_http_request filter to capture HTTP errors during version check.
1572+
*
1573+
* This method signature matches the pre_http_request filter signature.
1574+
* Uses PHP_INT_MAX priority to run after test mocking and plugin modifications.
1575+
*
1576+
* @param false|array|WP_Error $response A preemptive return value of an HTTP request.
1577+
* @param array $args HTTP request arguments.
1578+
* @param string $url The request URL.
1579+
* @return false|array|WP_Error The response, unmodified.
1580+
*/
1581+
public function capture_version_check_error( $response, $args, $url ) {
1582+
if ( false === strpos( $url, 'api.wordpress.org/core/version-check' ) ) {
1583+
return $response;
1584+
}
1585+
1586+
// A `false` response means the request is not being preempted.
1587+
// In this case, we don't want to change the error status, as the subsequent
1588+
// `http_api_debug` hook will handle the actual response.
1589+
if ( false !== $response ) {
1590+
$this->set_version_check_error( $response );
1591+
}
1592+
1593+
return $response;
1594+
}
1595+
1596+
/**
1597+
* Handles the http_api_debug action to capture HTTP errors from real requests.
1598+
*
1599+
* This fires when pre_http_request doesn't short-circuit the request.
1600+
* Uses the http_api_debug action hook signature.
1601+
*
1602+
* @param array|WP_Error $response HTTP response or WP_Error object.
1603+
* @param string $context Context of the HTTP request.
1604+
* @param string $_class HTTP transport class name (unused).
1605+
* @param array $_args HTTP request arguments (unused).
1606+
* @param string $url URL being requested.
1607+
*/
1608+
public function capture_version_check_error_from_response( $response, $context, $_class, $_args, $url ) {
1609+
if ( false === strpos( $url, 'api.wordpress.org/core/version-check' ) ) {
1610+
return;
1611+
}
1612+
1613+
// Only capture on response, not pre_response
1614+
if ( 'response' !== $context ) {
1615+
return;
1616+
}
1617+
1618+
$this->set_version_check_error( $response );
1619+
}
1620+
15131621
/**
15141622
* Clean up extra files.
15151623
*

0 commit comments

Comments
 (0)