diff --git a/plugins/optimization-detective/site-health.php b/plugins/optimization-detective/site-health.php index f70ed72553..26a4405b59 100644 --- a/plugins/optimization-detective/site-health.php +++ b/plugins/optimization-detective/site-health.php @@ -127,6 +127,10 @@ function od_compose_site_health_result( $response ): array { $message = wp_remote_retrieve_response_message( $response ); $body = wp_remote_retrieve_body( $response ); $data = json_decode( $body, true ); + $header = wp_remote_retrieve_header( $response, 'content-type' ); + if ( is_array( $header ) ) { + $header = array_pop( $header ); + } $is_expected = ( 400 === $code && @@ -156,7 +160,18 @@ function od_compose_site_health_result( $response ): array { $result['description'] .= '
' . esc_html( $data['message'] ) . '
'; } - $result['description'] .= '
' . esc_html__( 'Raw response:', 'optimization-detective' ) . '
' . esc_html( $body ) . '
'; + if ( '' !== $body ) { + $result['description'] .= '
'; + $result['description'] .= '' . esc_html__( 'Raw response:', 'optimization-detective' ) . ''; + + if ( is_string( $header ) && str_contains( $header, 'html' ) ) { + $escaped_content = htmlspecialchars( $body, ENT_QUOTES, 'UTF-8' ); + $result['description'] .= ''; + } else { + $result['description'] .= '
' . esc_html( $body ) . '
'; + } + $result['description'] .= '
'; + } } } return $result; @@ -238,7 +253,7 @@ function od_maybe_render_rest_api_health_check_admin_notice( bool $in_plugin_row $message = "
$message
"; } - wp_admin_notice( + $notice = wp_get_admin_notice( $message, array( 'type' => 'warning', @@ -246,6 +261,16 @@ function od_maybe_render_rest_api_health_check_admin_notice( bool $in_plugin_row 'paragraph_wrap' => false, ) ); + + echo wp_kses( + $notice, + array_merge( + wp_kses_allowed_html( 'post' ), + array( + 'iframe' => array_fill_keys( array( 'srcdoc', 'sandbox', 'width', 'height' ), true ), + ) + ) + ); } /** diff --git a/plugins/optimization-detective/tests/test-site-health.php b/plugins/optimization-detective/tests/test-site-health.php index 8ca97fd51f..bc195135aa 100644 --- a/plugins/optimization-detective/tests/test-site-health.php +++ b/plugins/optimization-detective/tests/test-site-health.php @@ -120,12 +120,33 @@ public function data_provider_test_rest_api_availability(): array { 'code' => 403, 'message' => 'Forbidden', ), + 'headers' => array( + 'content-type' => 'text/html', + ), 'body' => "\n403 Forbidden\n\n

403 Forbidden

\n
nginx
\n\n", ), 'expected_option' => '1', 'expected_status' => 'recommended', 'expected_unavailable' => true, ), + 'other_forbidden' => array( + 'mocked_response' => array( + 'response' => array( + 'code' => 403, + 'message' => 'Forbidden', + ), + 'headers' => array( + 'content-type' => array( + 'text/html; charset=utf-8', + 'application/xhtml+xml', + ), + ), + 'body' => '403 Forbidden

Forbidden

You don\'t have permission to access this resource.

', + ), + 'expected_option' => '1', + 'expected_status' => 'recommended', + 'expected_unavailable' => true, + ), 'error' => array( 'mocked_response' => new WP_Error( 'bad', 'Something terrible has happened' ), 'expected_option' => '1', @@ -142,6 +163,8 @@ public function data_provider_test_rest_api_availability(): array { * @covers ::od_compose_site_health_result * @covers ::od_get_rest_api_health_check_response * @covers ::od_is_rest_api_unavailable + * @covers ::od_render_rest_api_health_check_admin_notice_in_plugin_row + * @covers ::od_maybe_render_rest_api_health_check_admin_notice * * @dataProvider data_provider_test_rest_api_availability * @@ -151,6 +174,24 @@ public function test_rest_api_availability( $mocked_response, string $expected_o $this->filter_rest_api_response( $mocked_response ); $result = od_test_rest_api_availability(); + $notice = get_echo( 'od_render_rest_api_health_check_admin_notice_in_plugin_row', array( 'optimization-detective/load.php' ) ); + if ( $expected_unavailable ) { + $this->assertStringContainsString( '', $notice ); + if ( is_array( $mocked_response ) ) { + if ( isset( $mocked_response['headers']['content-type'] ) && str_contains( join( '', (array) $mocked_response['headers']['content-type'] ), 'html' ) ) { + $this->assertStringContainsString( '', $notice ); + $this->assertStringNotContainsString( '', $notice ); + } else { + $this->assertStringContainsString( '', $notice ); + $this->assertStringNotContainsString( '', $notice ); + } + } else { + $this->assertStringNotContainsString( '', $notice ); + $this->assertStringNotContainsString( '', $notice ); + } + } else { + $this->assertSame( '', $notice ); + } $this->assertArrayHasKey( 'label', $result ); $this->assertArrayHasKey( 'status', $result ); $this->assertArrayHasKey( 'badge', $result ); @@ -392,7 +433,7 @@ static function ( $pre, array $args, string $url ) use ( $mocked_response, $obse } /** - * Build a mock response. + * Build a mock JSON response. * * @param int $status_code HTTP status code. * @param string $message HTTP status message. @@ -406,6 +447,9 @@ protected function build_mock_response( int $status_code, string $message, array 'message' => $message, ), 'body' => wp_json_encode( $body ), + 'headers' => array( + 'content-type' => 'application/json', + ), ); } }