diff --git a/src/dashboard/application/search-rankings/top-page-repository.php b/src/dashboard/application/search-rankings/top-page-repository.php new file mode 100644 index 00000000000..7083bb66042 --- /dev/null +++ b/src/dashboard/application/search-rankings/top-page-repository.php @@ -0,0 +1,42 @@ +site_kit_search_console_adapter = $site_kit_search_console_adapter; + } + + /** + * Method to get search related data from a provider. + * + * @param Parameters $parameters The parameter to get the search data for. + * + * @return Data_Container + */ + public function get_data( Parameters $parameters ): Data_Container { + + return $this->site_kit_search_console_adapter->get_data( $parameters ); + } +} diff --git a/src/dashboard/application/search-rankings/top-query-repository.php b/src/dashboard/application/search-rankings/top-query-repository.php new file mode 100644 index 00000000000..ee9c05a63d1 --- /dev/null +++ b/src/dashboard/application/search-rankings/top-query-repository.php @@ -0,0 +1,42 @@ +site_kit_search_console_adapter = $site_kit_search_console_adapter; + } + + /** + * Method to get search related data from a provider. + * + * @param Parameters $parameters The parameter to get the search data for. + * + * @return Data_Container + */ + public function get_data( Parameters $parameters ): Data_Container { + + return $this->site_kit_search_console_adapter->get_data( $parameters ); + } +} diff --git a/src/dashboard/domain/data-provider/dashboard-repository-interface.php b/src/dashboard/domain/data-provider/dashboard-repository-interface.php new file mode 100644 index 00000000000..9a24f78923d --- /dev/null +++ b/src/dashboard/domain/data-provider/dashboard-repository-interface.php @@ -0,0 +1,18 @@ + $data_container + */ + private $data_container; + + /** + * The constructor + */ + public function __construct() { + $this->data_container = []; + } + + /** + * Method to add data. + * + * @param Data_Interface $data The data. + * + * @return void + */ + public function add_data( Data_Interface $data ) { + $this->data_container[] = $data; + } + + /** + * Converts the list to an array. + * + * @return array The array of endpoints. + */ + public function to_array(): array { + $result = []; + foreach ( $this->data_container as $data ) { + $result[] = $data->to_array(); + } + + return $result; + } +} diff --git a/src/dashboard/domain/data-provider/data-interface.php b/src/dashboard/domain/data-provider/data-interface.php new file mode 100644 index 00000000000..4f9693bc77f --- /dev/null +++ b/src/dashboard/domain/data-provider/data-interface.php @@ -0,0 +1,16 @@ + + */ + public function to_array(): array; +} diff --git a/src/dashboard/domain/data-provider/parameters.php b/src/dashboard/domain/data-provider/parameters.php new file mode 100644 index 00000000000..f555e5c4e64 --- /dev/null +++ b/src/dashboard/domain/data-provider/parameters.php @@ -0,0 +1,90 @@ +start_date; + } + + /** + * Getter for the end date. + * The date format should be Y-M-D. + * + * @return string + */ + public function get_end_date(): string { + return $this->end_date; + } + + /** + * Getter for the result limit. + * + * @return int + */ + public function get_limit(): int { + return $this->limit; + } + + /** + * The start date setter. + * + * @param string $start_date The start date. + * + * @return void + */ + public function set_start_date( string $start_date ): void { + $this->start_date = $start_date; + } + + /** + * The end date setter. + * + * @param string $end_date The end date. + * + * @return void + */ + public function set_end_date( string $end_date ): void { + $this->end_date = $end_date; + } + + /** + * The result limit. + * + * @param int $limit The result limit. + * @return void + */ + public function set_limit( int $limit ): void { + $this->limit = $limit; + } +} diff --git a/src/dashboard/domain/search-rankings/search-data.php b/src/dashboard/domain/search-rankings/search-data.php new file mode 100644 index 00000000000..46e0136e4cf --- /dev/null +++ b/src/dashboard/domain/search-rankings/search-data.php @@ -0,0 +1,87 @@ +clicks = $clicks; + $this->ctr = $ctr; + $this->impressions = $impressions; + $this->position = $position; + $this->subject = $subject; + $this->seo_score = 0; + } + + /** + * The array representation of this domain object. + * + * @return array + */ + public function to_array(): array { + return [ + 'clicks' => $this->clicks, + 'ctr' => $this->ctr, + 'impressions' => $this->impressions, + 'position' => $this->position, + 'subject' => $this->subject, + 'seoScore' => $this->seo_score, + ]; + } +} diff --git a/src/dashboard/infrastructure/endpoints/search-rankings/top-page-endpoint.php b/src/dashboard/infrastructure/endpoints/search-rankings/top-page-endpoint.php new file mode 100644 index 00000000000..ed1c0bfdf68 --- /dev/null +++ b/src/dashboard/infrastructure/endpoints/search-rankings/top-page-endpoint.php @@ -0,0 +1,52 @@ +get_namespace() . $this->get_route() ); + } +} diff --git a/src/dashboard/infrastructure/endpoints/search-rankings/top-query-endpoint.php b/src/dashboard/infrastructure/endpoints/search-rankings/top-query-endpoint.php new file mode 100644 index 00000000000..96011d6b4a1 --- /dev/null +++ b/src/dashboard/infrastructure/endpoints/search-rankings/top-query-endpoint.php @@ -0,0 +1,52 @@ +get_namespace() . $this->get_route() ); + } +} diff --git a/src/dashboard/infrastructure/search-console/search-console-parameters.php b/src/dashboard/infrastructure/search-console/search-console-parameters.php new file mode 100644 index 00000000000..2acc51e15ab --- /dev/null +++ b/src/dashboard/infrastructure/search-console/search-console-parameters.php @@ -0,0 +1,36 @@ +dimensions = $dimensions; + } + + /** + * Getter for the dimensions. + * + * @return string[] + */ + public function get_dimensions(): array { + return $this->dimensions; + } +} diff --git a/src/dashboard/infrastructure/search-console/site-kit-search-console-adapter.php b/src/dashboard/infrastructure/search-console/site-kit-search-console-adapter.php new file mode 100644 index 00000000000..3e49c9ee0af --- /dev/null +++ b/src/dashboard/infrastructure/search-console/site-kit-search-console-adapter.php @@ -0,0 +1,65 @@ +context() ); + self::$search_console_module = $modules->get_module( Search_Console::MODULE_SLUG ); + } + } + + /** + * The wrapper method to add our parameters to a Site Kit API request. + * + * @param Search_Console_Parameters $parameters The parameters. + * + * @return Data_Container|WP_Error Data on success, or WP_Error on failure. + */ + public function get_data( Search_Console_Parameters $parameters ): Data_Container { + $api_parameters = [ + 'slug' => 'search-console', + 'datapoint' => 'searchanalytics', + 'startDate' => $parameters->get_start_date(), + 'endDate' => $parameters->get_end_date(), + 'limit' => $parameters->get_limit(), + 'dimensions' => $parameters->get_dimensions(), + ]; + + $data_rows = self::$search_console_module->get_data( 'searchanalytics', $api_parameters ); + + $search_data_container = new Data_Container(); + foreach ( $data_rows as $ranking ) { + $search_data_container->add_data( new Search_Data( $ranking->clicks, $ranking->ctr, $ranking->impressions, $ranking->position, $ranking->keys[0] ) ); + } + + return $search_data_container; + } +} diff --git a/src/dashboard/user-interface/search-rankings/abstract-ranking-route.php b/src/dashboard/user-interface/search-rankings/abstract-ranking-route.php new file mode 100644 index 00000000000..90b10b5aebe --- /dev/null +++ b/src/dashboard/user-interface/search-rankings/abstract-ranking-route.php @@ -0,0 +1,166 @@ + The conditionals that must be met to load this. + */ + public static function get_conditionals(): array { + return [ Google_Site_Kit_Feature_Conditional::class ]; + } + + /** + * The constructor. + * + * @param Dashboard_Repository_Interface $search_rankings_repository The data provider. + */ + public function __construct( Dashboard_Repository_Interface $search_rankings_repository ) { + $this->search_rankings_repository = $search_rankings_repository; + } + + /** + * Sets the request parameters. + * + * @param Search_Console_Parameters $request_parameters The API request parameters. + * + * @return void + */ + public function set_request_parameters( + Search_Console_Parameters $request_parameters + ) { + $this->request_parameters = $request_parameters; + } + + /** + * Returns the route prefix. + * + * @throws Exception If the ROUTE_PREFIX constant is not set in the child class. + * @return string The route prefix. + */ + public static function get_route_prefix() { + $class = static::class; + $prefix = $class::ROUTE_PREFIX; + + if ( $prefix === null ) { + throw new Exception( 'Ranking route without explicit prefix' ); + } + + return $prefix; + } + + /** + * Registers routes for scores. + * + * @return void + */ + public function register_routes() { + \register_rest_route( + self::ROUTE_NAMESPACE, + $this->get_route_prefix(), + [ + [ + 'methods' => 'GET', + 'callback' => [ $this, 'get_rankings' ], + 'permission_callback' => [ $this, 'permission_manage_options' ], + 'args' => [ + 'limit' => [ + 'required' => true, + 'type' => 'int', + 'sanitize_callback' => 'sanitize_text_field', + 'default' => 5, + ], + + ], + ], + ] + ); + } + + /** + * Gets the rankings of a specific amount of pages. + * + * @param WP_REST_Request $request The request object. + * + * @return WP_REST_Response The success or failure response. + */ + public function get_rankings( WP_REST_Request $request ): WP_REST_Response { + try { + $this->request_parameters->set_limit( $request->get_param( 'limit' ) ); + $date = new DateTime( 'now', new DateTimeZone( 'UTC' ) ); + $date->modify( '-28 days' ); + + $this->request_parameters->set_start_date( $date->format( 'Y-m-d' ) ); + $this->request_parameters->set_end_date( ( new DateTime( 'now', new DateTimeZone( 'UTC' ) ) )->format( 'Y-m-d' ) ); + + $search_data_container = $this->search_rankings_repository->get_data( $this->request_parameters ); + + } catch ( Exception $exception ) { + return new WP_REST_Response( + [ + 'error' => $exception->getMessage(), + ], + $exception->getCode() + ); + } + + return new WP_REST_Response( + $search_data_container->to_array(), + 200 + ); + } + + /** + * Permission callback. + * + * @return bool True when user has the 'wpseo_manage_options' capability. + */ + public function permission_manage_options() { + return WPSEO_Capability_Utils::current_user_can( 'wpseo_manage_options' ); + } +} diff --git a/src/dashboard/user-interface/search-rankings/top-page-route.php b/src/dashboard/user-interface/search-rankings/top-page-route.php new file mode 100644 index 00000000000..6c0a443fc1e --- /dev/null +++ b/src/dashboard/user-interface/search-rankings/top-page-route.php @@ -0,0 +1,30 @@ +set_request_parameters( new Search_Console_Parameters( [ 'page' ] ) ); + + parent::__construct( $top_page_repository ); + } +} diff --git a/src/dashboard/user-interface/search-rankings/top-query-route.php b/src/dashboard/user-interface/search-rankings/top-query-route.php new file mode 100644 index 00000000000..126dae619b0 --- /dev/null +++ b/src/dashboard/user-interface/search-rankings/top-query-route.php @@ -0,0 +1,30 @@ +set_request_parameters( new Search_Console_Parameters( [ 'query' ] ) ); + + parent::__construct( $top_query_repository ); + } +}