# jetpack/16.3-a.5/jetpack_vendor/automattic/jetpack-stats-admin/src/class-wpcom-client.php

Jetpack – WP Security, Backup, Speed, &amp; Growth, version 16.3-a.5. 164 lines.

- Page: https://pluginprobe.com/plugins/jetpack/16.3-a.5/code/jetpack_vendor/automattic/jetpack-stats-admin/src/class-wpcom-client.php
- Raw: https://pluginprobe.com/plugins/jetpack/16.3-a.5/raw/jetpack_vendor/automattic/jetpack-stats-admin/src/class-wpcom-client.php
- Modified: 2026-09-08T18:39:34+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/jetpack/16.3-a.5/code/jetpack_vendor/automattic/jetpack-stats-admin/src/class-wpcom-client.php#L10-L20`.

```php
<?php
/**
 * A class that wraps `Automattic\Jetpack\Connection\Client` and handles cache and errors.
 *
 * @package automattic/jetpack-stats-admin
 */

namespace Automattic\Jetpack\Stats_Admin;

use Automattic\Jetpack\Connection\Client;
use WP_Error;

/**
 * A class that wraps `Automattic\Jetpack\Connection\Client` and handles cache and errors.
 *
 * @package Automattic\Jetpack\Stats_Admin
 */
class WPCOM_Client {
	/**
	 * Transient prefix for caching REST API responses.
	 *
	 * @var string
	 */
	const CACHE_TRANSIENT_PREFIX = 'STATS_REST_RESP_';

	/**
	 * Query the WordPress.com REST API using the blog token cached.
	 *
	 * @param String $path The API endpoint relative path.
	 * @param String $version The API version.
	 * @param array  $args Request arguments.
	 * @param String $body Request body.
	 * @param String $base_api_path (optional) the API base path override, defaults to 'rest'.
	 * @param bool   $use_cache (optional) default to true.
	 * @param string $cache_key (optional) default to null meaning the function auto generates cache key.
	 * @return array|WP_Error $response Data.
	 */
	public static function request_as_blog_cached( $path, $version = '1.1', $args = array(), $body = null, $base_api_path = 'rest', $use_cache = true, $cache_key = null ) {
		// Only allow caching GET requests.
		$use_cache = $use_cache && ! ( isset( $args['method'] ) && strtoupper( $args['method'] ) !== 'GET' ) && ! static::should_bypass_cache();

		// Arrays are serialized without considering the order of objects, but it's okay atm.
		$cache_key ??= self::CACHE_TRANSIENT_PREFIX . md5( implode( '|', array( $path, $version, wp_json_encode( $args, JSON_UNESCAPED_SLASHES ), wp_json_encode( $body, JSON_UNESCAPED_SLASHES ), $base_api_path ) ) );

		if ( $use_cache ) {
			$response_body_content = get_transient( $cache_key );
			if ( false !== $response_body_content ) {
				return json_decode( $response_body_content, true );
			}
		}

		$response_body = static::request_as_blog( $path, $version, $args, $body, $base_api_path );

		if ( is_wp_error( $response_body ) ) {
			return $response_body;
		}

		// Cache the response for 5 minutes.
		set_transient( $cache_key, wp_json_encode( $response_body, JSON_UNESCAPED_SLASHES ), 5 * MINUTE_IN_SECONDS );

		return $response_body;
	}

	/**
	 * Query the WordPress.com REST API using the blog token
	 *
	 * @param String $path The API endpoint relative path.
	 * @param String $version The API version.
	 * @param array  $args Request arguments.
	 * @param String $body Request body.
	 * @param String $base_api_path (optional) the API base path override, defaults to 'rest'.
	 * @return array|WP_Error $response Data.
	 */
	public static function request_as_blog( $path, $version = '1.1', $args = array(), $body = null, $base_api_path = 'rest' ) {
		$response = Client::wpcom_json_api_request_as_blog(
			$path,
			$version,
			$args,
			$body,
			$base_api_path
		);

		if ( is_wp_error( $response ) ) {
			// `Client` fails before sending anything when the site holds no blog token, and that
			// error carries no status, which the REST API renders as a 500. Say what actually
			// happened so callers can tell an unconnected site from a broken one. Newer connection
			// packages name the reason (`no_possible_tokens`); older ones return `missing_token`.
			// `malformed_token` means the stored token has no secret half and cannot sign anything.
			if ( in_array( $response->get_error_code(), array( 'missing_token', 'no_possible_tokens', 'malformed_token' ), true ) ) {
				return new WP_Error(
					'site_not_connected',
					__( 'This site is not connected to WordPress.com.', 'jetpack-stats-admin' ),
					array( 'status' => 400 )
				);
			}

			return $response;
		}

		$response_code         = wp_remote_retrieve_response_code( $response );
		$response_body_content = wp_remote_retrieve_body( $response );
		$response_body         = json_decode( $response_body_content, true );

		$error = static::get_wp_error( $response_body, (int) $response_code );
		if ( is_wp_error( $error ) ) {
			// Unknown token keys and incorrect secrets also mean the site cannot authenticate.
			// Expose these rejections like a missing token so callers can identify the broken connection.
			if ( in_array( $error->get_error_code(), array( 'invalid_token', 'unknown_token', 'signature_mismatch' ), true ) ) {
				return new WP_Error(
					'site_not_connected',
					__( 'This site is not connected to WordPress.com.', 'jetpack-stats-admin' ),
					array( 'status' => 400 )
				);
			}
			return $error;
		}

		return $response_body;
	}

	/**
	 * Build error object from remote response body and status code.
	 *
	 * @param array $response_body Remote response body.
	 * @param int   $response_code Http response code.
	 * @return WP_Error
	 */
	protected static function get_wp_error( $response_body, $response_code = 200 ) {
		$error_code = null;
		foreach ( array( 'code', 'error' ) as $error_code_key ) {
			if ( isset( $response_body[ $error_code_key ] ) ) {
				$error_code = $response_body[ $error_code_key ];
				break;
			}
		}

		// Sometimes the response code could be 200 but the response body still contains an error.
		if ( $error_code !== null || $response_code !== 200 ) {
			return new WP_Error(
				$error_code,
				$response_body['message'] ?? 'unknown remote error',
				array( 'status' => $response_code )
			);
		}

		// No error.
		return null;
	}

	/**
	 * Check if the cache should be bypassed.
	 *
	 * @return bool
	 */
	protected static function should_bypass_cache() {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return isset( $_GET['force_refresh'] ) || isset( $_GET['statsPurchaseSuccess'] ) ||
			// phpcs:ignore WordPress.Arrays.ArrayKeySpacingRestrictions.SpacesAroundArrayKeys, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			( isset( $_SERVER[ 'HTTP_REFERER' ] ) && false !== strpos( $_SERVER[ 'HTTP_REFERER' ], 'force_refresh' ) ) ||
			// phpcs:ignore WordPress.Arrays.ArrayKeySpacingRestrictions.SpacesAroundArrayKeys, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			( isset( $_SERVER[ 'HTTP_REFERER' ] ) && false !== strpos( $_SERVER[ 'HTTP_REFERER' ], 'statsPurchaseSuccess' ) );
	}
}

```
