diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f67077..df6961e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Gateway status probes (Site Health test, status REST route, settings connection test, `wp pinch status`) fall back to OpenClaw 2.0's `/v1/status` when the legacy `/api/v1/status` path returns 404. OpenClaw 2.0 removed the `/api` route prefix, which made every probe report the gateway unreachable while chat kept working. + ## [3.1.2] - 2026-03-28 Why this matters: Dependabot security and maintenance bumps (wp-env, PHPStan, XML stack) land in one release, and local PHPUnit runs without hand-wiring polyfill paths. diff --git a/includes/CLI/Status_Command.php b/includes/CLI/Status_Command.php index 90910ff..2ac65a2 100644 --- a/includes/CLI/Status_Command.php +++ b/includes/CLI/Status_Command.php @@ -53,8 +53,8 @@ public static function run( array $args, array $assoc_args ): void { $error_msg = ''; if ( ! empty( $gateway_url ) && ! empty( $api_token ) ) { - $response = wp_remote_get( - trailingslashit( $gateway_url ) . 'api/v1/status', + $response = \WP_Pinch\Rest\Helpers::gateway_status_request( + $gateway_url, array( 'timeout' => 10, 'headers' => array( diff --git a/includes/Rest/Helpers.php b/includes/Rest/Helpers.php index 497f412..045db4c 100644 --- a/includes/Rest/Helpers.php +++ b/includes/Rest/Helpers.php @@ -392,4 +392,29 @@ public static function process_sse_buffer( string $buffer ): array { $out = implode( "\n", $output ); return array( '' !== $out ? $out . "\n" : '', $carry ?? '' ); } + + /** + * GET the gateway status endpoint, tolerating both path generations. + * + * OpenClaw 1.x serves the status probe at /api/v1/status; OpenClaw 2.0 + * removed the /api route prefix and serves /v1/status. Probe the legacy + * path first (no behavior change for 1.x gateways) and retry the 2.0 + * path only on a 404. + * + * @param string $gateway_url Gateway base URL. + * @param array $args Request args (timeout, auth header). + * @param bool $safe Use wp_safe_remote_get() (SSRF-hardened) instead + * of wp_remote_get(); matches each caller's + * previous transport. + * @return array|\WP_Error HTTP response array or WP_Error. + */ + public static function gateway_status_request( string $gateway_url, array $args, bool $safe = false ) { + $base = trailingslashit( $gateway_url ); + $get = $safe ? 'wp_safe_remote_get' : 'wp_remote_get'; + $response = $get( $base . 'api/v1/status', $args ); + if ( ! is_wp_error( $response ) && 404 === (int) wp_remote_retrieve_response_code( $response ) ) { + $response = $get( $base . 'v1/status', $args ); + } + return $response; + } } diff --git a/includes/Rest/Status.php b/includes/Rest/Status.php index 0961b04..581c906 100644 --- a/includes/Rest/Status.php +++ b/includes/Rest/Status.php @@ -68,12 +68,13 @@ public static function handle_status( \WP_REST_Request $request ): \WP_REST_Resp if ( $result['configured'] ) { $status_url = trailingslashit( $gateway_url ) . 'api/v1/status'; if ( wp_http_validate_url( $status_url ) ) { - $response = wp_safe_remote_get( - $status_url, + $response = Helpers::gateway_status_request( + $gateway_url, array( 'timeout' => 5, 'headers' => array( 'Authorization' => 'Bearer ' . $api_token ), - ) + ), + true ); } else { $response = new \WP_Error( 'invalid_gateway', __( 'Gateway URL failed security validation.', 'wp-pinch' ) ); diff --git a/includes/Settings/Settings_Admin_Pages_Trait.php b/includes/Settings/Settings_Admin_Pages_Trait.php index 5a462a4..4f4c79d 100644 --- a/includes/Settings/Settings_Admin_Pages_Trait.php +++ b/includes/Settings/Settings_Admin_Pages_Trait.php @@ -138,14 +138,15 @@ public static function ajax_test_connection(): void { wp_send_json_error( __( 'Gateway URL failed security validation. Use a public HTTP or HTTPS URL.', 'wp-pinch' ) ); } - $response = wp_safe_remote_get( - $status_url, + $response = Rest\Helpers::gateway_status_request( + $url, array( 'timeout' => 10, 'headers' => array( 'Authorization' => 'Bearer ' . $token, ), - ) + ), + true ); if ( is_wp_error( $response ) ) { diff --git a/includes/class-site-health.php b/includes/class-site-health.php index 51c2589..f8a4c97 100644 --- a/includes/class-site-health.php +++ b/includes/class-site-health.php @@ -217,8 +217,8 @@ public static function test_gateway_connectivity(): array { return $result; } - $response = wp_remote_get( - trailingslashit( $gateway_url ) . 'api/v1/status', + $response = Rest\Helpers::gateway_status_request( + $gateway_url, array( 'timeout' => 10, 'headers' => array(