wordpress-seo
/
src
/
dashboard
/
infrastructure
/
search-console
/
site-kit-search-console-adapter.php
site-kit-search-console-adapter.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.6, at src/dashboard/infrastructure/search-console/site-kit-search-console-adapter.php
| 1 | <?php |
| 2 | |
| 3 | // phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong |
| 4 | // phpcs:disable Yoast.NamingConventions.NamespaceName.MaxExceeded |
| 5 | namespace Yoast\WP\SEO\Dashboard\Infrastructure\Search_Console; |
| 6 | |
| 7 | use Google\Site_Kit_Dependencies\Google\Service\SearchConsole\ApiDataRow; |
| 8 | use WP_REST_Response; |
| 9 | use Yoast\WP\SEO\Dashboard\Domain\Data_Provider\Data_Container; |
| 10 | use Yoast\WP\SEO\Dashboard\Domain\Search_Console\Failed_Request_Exception; |
| 11 | use Yoast\WP\SEO\Dashboard\Domain\Search_Console\Unexpected_Response_Exception; |
| 12 | use Yoast\WP\SEO\Dashboard\Domain\Search_Rankings\Comparison_Search_Ranking_Data; |
| 13 | use Yoast\WP\SEO\Dashboard\Domain\Search_Rankings\Search_Ranking_Data; |
| 14 | |
| 15 | /** |
| 16 | * The site API adapter to make calls to the Search Console API, via the Site_Kit plugin. |
| 17 | */ |
| 18 | class Site_Kit_Search_Console_Adapter { |
| 19 | |
| 20 | /** |
| 21 | * Holds the api call class. |
| 22 | * |
| 23 | * @var Site_Kit_Search_Console_Api_Call $site_kit_search_console_api_call |
| 24 | */ |
| 25 | private $site_kit_search_console_api_call; |
| 26 | |
| 27 | /** |
| 28 | * The constructor. |
| 29 | * |
| 30 | * @param Site_Kit_Search_Console_Api_Call $site_kit_search_console_api_call The api call class. |
| 31 | */ |
| 32 | public function __construct( Site_Kit_Search_Console_Api_Call $site_kit_search_console_api_call ) { |
| 33 | $this->site_kit_search_console_api_call = $site_kit_search_console_api_call; |
| 34 | } |
| 35 | |
| 36 | /** |
| 37 | * The wrapper method to do a Site Kit API request for Search Console. |
| 38 | * |
| 39 | * @param Search_Console_Parameters $parameters The parameters. |
| 40 | * |
| 41 | * @throws Failed_Request_Exception When the request responds with an error from Site Kit. |
| 42 | * @throws Unexpected_Response_Exception When the request responds with an unexpected format. |
| 43 | * @return Data_Container The Site Kit API response. |
| 44 | */ |
| 45 | public function get_data( Search_Console_Parameters $parameters ): Data_Container { |
| 46 | $api_parameters = $this->build_parameters( $parameters ); |
| 47 | |
| 48 | $response = $this->site_kit_search_console_api_call->do_request( $api_parameters ); |
| 49 | |
| 50 | $this->validate_response( $response ); |
| 51 | |
| 52 | return $this->parse_response( $response->get_data() ); |
| 53 | } |
| 54 | |
| 55 | /** |
| 56 | * The wrapper method to do a comparison Site Kit API request for Search Console. |
| 57 | * |
| 58 | * @param Search_Console_Parameters $parameters The parameters. |
| 59 | * |
| 60 | * @throws Failed_Request_Exception When the request responds with an error from Site Kit. |
| 61 | * @throws Unexpected_Response_Exception When the request responds with an unexpected format. |
| 62 | * @return Data_Container The Site Kit API response. |
| 63 | */ |
| 64 | public function get_comparison_data( Search_Console_Parameters $parameters ): Data_Container { |
| 65 | $api_parameters = $this->build_parameters( $parameters ); |
| 66 | |
| 67 | // Since we're doing a comparison request, we need to increase the date range to the start of the previous period. We'll later split the data into two periods. |
| 68 | $api_parameters['startDate'] = $parameters->get_compare_start_date(); |
| 69 | |
| 70 | $response = $this->site_kit_search_console_api_call->do_request( $api_parameters ); |
| 71 | |
| 72 | $this->validate_response( $response ); |
| 73 | |
| 74 | return $this->parse_comparison_response( $response->get_data(), $parameters->get_compare_end_date() ); |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * Builds the parameters to be used in the Site Kit API request. |
| 79 | * |
| 80 | * @param Search_Console_Parameters $parameters The parameters. |
| 81 | * |
| 82 | * @return array<string, array<string, string>> The Site Kit API parameters. |
| 83 | */ |
| 84 | private function build_parameters( Search_Console_Parameters $parameters ): array { |
| 85 | $api_parameters = [ |
| 86 | 'startDate' => $parameters->get_start_date(), |
| 87 | 'endDate' => $parameters->get_end_date(), |
| 88 | 'dimensions' => $parameters->get_dimensions(), |
| 89 | ]; |
| 90 | |
| 91 | if ( $parameters->get_limit() !== 0 ) { |
| 92 | $api_parameters['limit'] = $parameters->get_limit(); |
| 93 | } |
| 94 | |
| 95 | return $api_parameters; |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Parses a response for a comparison Site Kit API request for Search Analytics. |
| 100 | * |
| 101 | * @param ApiDataRow[] $response The response to parse. |
| 102 | * @param string $compare_end_date The compare end date. |
| 103 | * |
| 104 | * @throws Unexpected_Response_Exception When the comparison request responds with an unexpected format. |
| 105 | * @return Data_Container The parsed comparison Site Kit API response. |
| 106 | */ |
| 107 | private function parse_comparison_response( array $response, ?string $compare_end_date ): Data_Container { |
| 108 | $data_container = new Data_Container(); |
| 109 | $comparison_search_ranking_data = new Comparison_Search_Ranking_Data(); |
| 110 | |
| 111 | foreach ( $response as $ranking_date ) { |
| 112 | |
| 113 | if ( ! \is_a( $ranking_date, ApiDataRow::class ) ) { |
| 114 | throw new Unexpected_Response_Exception(); |
| 115 | } |
| 116 | |
| 117 | $ranking_data = new Search_Ranking_Data( $ranking_date->getClicks(), $ranking_date->getCtr(), $ranking_date->getImpressions(), $ranking_date->getPosition(), $ranking_date->getKeys()[0] ); |
| 118 | |
| 119 | // Now split the data into two periods. |
| 120 | if ( $ranking_date->getKeys()[0] <= $compare_end_date ) { |
| 121 | $comparison_search_ranking_data->add_previous_traffic_data( $ranking_data ); |
| 122 | } |
| 123 | else { |
| 124 | $comparison_search_ranking_data->add_current_traffic_data( $ranking_data ); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | $data_container->add_data( $comparison_search_ranking_data ); |
| 129 | |
| 130 | return $data_container; |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * Parses a response for a Site Kit API request for Search Analytics. |
| 135 | * |
| 136 | * @param ApiDataRow[] $response The response to parse. |
| 137 | * |
| 138 | * @throws Unexpected_Response_Exception When the request responds with an unexpected format. |
| 139 | * @return Data_Container The parsed Site Kit API response. |
| 140 | */ |
| 141 | private function parse_response( array $response ): Data_Container { |
| 142 | $search_ranking_data_container = new Data_Container(); |
| 143 | |
| 144 | foreach ( $response as $ranking ) { |
| 145 | |
| 146 | if ( ! \is_a( $ranking, ApiDataRow::class ) ) { |
| 147 | throw new Unexpected_Response_Exception(); |
| 148 | } |
| 149 | |
| 150 | /** |
| 151 | * Filter: 'wpseo_transform_dashboard_subject_for_testing' - Allows overriding subjects like URLs for the dashboard, to facilitate testing in local environments. |
| 152 | * |
| 153 | * @param string $url The subject to be transformed. |
| 154 | * |
| 155 | * @internal |
| 156 | */ |
| 157 | $subject = \apply_filters( 'wpseo_transform_dashboard_subject_for_testing', $ranking->getKeys()[0] ); |
| 158 | |
| 159 | $search_ranking_data_container->add_data( new Search_Ranking_Data( $ranking->getClicks(), $ranking->getCtr(), $ranking->getImpressions(), $ranking->getPosition(), $subject ) ); |
| 160 | } |
| 161 | |
| 162 | return $search_ranking_data_container; |
| 163 | } |
| 164 | |
| 165 | /** |
| 166 | * Validates the response coming from Search Console. |
| 167 | * |
| 168 | * @param WP_REST_Response $response The response we want to validate. |
| 169 | * |
| 170 | * @return void. |
| 171 | * |
| 172 | * @throws Failed_Request_Exception When the request responds with an error from Site Kit. |
| 173 | * @throws Unexpected_Response_Exception When the request responds with an unexpected format. |
| 174 | */ |
| 175 | private function validate_response( WP_REST_Response $response ): void { |
| 176 | if ( $response->is_error() ) { |
| 177 | $error_data = $response->as_error()->get_error_data(); |
| 178 | $error_status_code = ( $error_data['status'] ?? 500 ); |
| 179 | throw new Failed_Request_Exception( |
| 180 | \wp_kses_post( |
| 181 | $response->as_error() |
| 182 | ->get_error_message(), |
| 183 | ), |
| 184 | (int) $error_status_code, |
| 185 | ); |
| 186 | } |
| 187 | |
| 188 | if ( ! \is_array( $response->get_data() ) ) { |
| 189 | throw new Unexpected_Response_Exception(); |
| 190 | } |
| 191 | } |
| 192 | } |
| 193 |