$args wp_remote_request() args (method, body, headers…). * @return array|null A WP HTTP response array, or null. */ public static function respond( string $url, array $args ): ?array { $host = (string) wp_parse_url( $url, PHP_URL_HOST ); if ( '' === $host ) { return null; } $relay_host = (string) wp_parse_url( Plugin::relay_url(), PHP_URL_HOST ); if ( 'oauth2.googleapis.com' === $host || ( '' !== $relay_host && 0 === strcasecmp( $host, $relay_host ) ) ) { return self::auth( $url ); } if ( 'analyticsadmin.googleapis.com' === $host ) { return self::admin( $url ); } if ( 'analyticsdata.googleapis.com' === $host ) { return self::data( $url, $args ); } if ( 'searchconsole.googleapis.com' === $host ) { return self::gsc( $url, $args ); } return null; } /** * Token/refresh/revoke. * * @param string $url Request URL. * @return array */ private static function auth( string $url ): array { if ( false !== strpos( $url, '/revoke' ) ) { return self::ok( array() ); } return self::ok( array( 'access_token' => 'demo-token', 'expires_in' => 3600, 'scope' => 'openid email https://www.googleapis.com/auth/analytics.readonly https://www.googleapis.com/auth/webmasters.readonly', ) ); } /** * Account summaries and web data streams. * * @param string $url Request URL. * @return array */ private static function admin( string $url ): array { if ( false !== strpos( $url, 'dataStreams' ) ) { return self::ok( array( 'dataStreams' => array( array( 'name' => self::PROPERTY_ID . '/dataStreams/1', 'type' => 'WEB_DATA_STREAM', 'displayName' => 'Demo Site', 'webStreamData' => array( 'measurementId' => self::MEASUREMENT_ID, 'defaultUri' => home_url(), ), ), ), ) ); } return self::ok( array( 'accountSummaries' => array( array( 'account' => 'accounts/1000000001', 'displayName' => 'Demo Account', 'propertySummaries' => array( array( 'property' => self::PROPERTY_ID, 'displayName' => 'Demo Site', ), ), ), ), ) ); } /** * Runs runReport, batchRunReports or runRealtimeReport. * * @param string $url Request URL. * @param array $args Request args. * @return array */ private static function data( string $url, array $args ): array { $body = self::decode_body( $args ); if ( false !== strpos( $url, ':batchRunReports' ) ) { $requests = array_values( (array) ( $body['requests'] ?? array() ) ); return self::ok( array( 'reports' => array_map( static fn( $request ): array => FakeReports::report( is_array( $request ) ? $request : array(), false ), $requests ), ) ); } $is_realtime = false !== strpos( $url, ':runRealtimeReport' ); return self::ok( FakeReports::report( $body, $is_realtime ) ); } /** * Verified sites and searchAnalytics.query. * * @param string $url Request URL. * @param array $args Request args. * @return array */ private static function gsc( string $url, array $args ): array { if ( false !== strpos( $url, '/searchAnalytics/query' ) ) { return self::ok( FakeSearchConsole::query( self::decode_body( $args ) ) ); } return self::ok( array( 'siteEntry' => array_map( static fn( string $site_url ): array => array( 'siteUrl' => $site_url, 'permissionLevel' => 'siteOwner', ), self::search_console_sites() ), ) ); } /** * The Search Console properties of the demo's Google account: a * `sc-domain:` property when the site's host is a real-looking domain, * and the URL-prefix property for the site (with a trailing slash, as * Search Console lists it). The demo seeds one of these as gsc_site * (tagsmith_demo_gsc_site() in tagsmith-demo.php), so the Health * tab finds the site it selected. A bare IP or a host with a port, such * as Playground's `127.0.0.1:9400`, only has the URL-prefix property. * * @return string[] */ private static function search_console_sites(): array { $home = home_url(); $host = (string) wp_parse_url( $home, PHP_URL_HOST ); $sites = array(); if ( 1 === preg_match( '/^[a-z0-9.-]+\.[a-z]{2,}$/i', $host ) ) { $sites[] = 'sc-domain:' . strtolower( $host ); } $sites[] = rtrim( $home, '/' ) . '/'; return $sites; } /** * Decodes a request's JSON body. * * @param array $args wp_remote_request() args. * @return array */ private static function decode_body( array $args ): array { $raw = $args['body'] ?? null; if ( is_array( $raw ) ) { return $raw; } if ( ! is_string( $raw ) || '' === $raw ) { return array(); } $decoded = json_decode( $raw, true ); return is_array( $decoded ) ? $decoded : array(); } /** * Wraps a decoded body into a WP HTTP response array. * * @param array $body Response body. * @return array */ private static function ok( array $body ): array { return array( 'headers' => array(), 'body' => (string) wp_json_encode( $body ), 'response' => array( 'code' => 200, 'message' => 'OK', ), 'cookies' => array(), 'filename' => null, ); } }