Skip to content

Commit

Permalink
Start of GA implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
thijsoo committed Jan 21, 2025
1 parent a9c394e commit 104daee
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Yoast\WP\SEO\Dashboard\Application\Sessions;

Check warning on line 3 in src/dashboard/application/sessions/organic-sessions-data-provider.php

View workflow job for this annotation

GitHub Actions / Check code style

A namespace name should be no more than 2 levels deep (excluding the prefix). Level depth found: 3 in Yoast\WP\SEO\Dashboard\Application\Sessions

use Yoast\WP\SEO\Dashboard\Domain\Data_Provider\Data_Container;
use Yoast\WP\SEO\Dashboard\Domain\Data_Provider\Data_Provider_Interface;
use Yoast\WP\SEO\Dashboard\Domain\Data_Provider\Parameters;
use Yoast\WP\SEO\Dashboard\Infrastructure\Google_Analytics\Site_Kit_Google_Analytics_Adapter;
use Yoast\WP\SEO\Dashboard\Infrastructure\Search_Rankings\Organic_Sessions_Parser;

class Organic_Sessions_Data_Provider implements Data_Provider_Interface {

Check failure on line 11 in src/dashboard/application/sessions/organic-sessions-data-provider.php

View workflow job for this annotation

GitHub Actions / Check code style

Missing doc comment for class Organic_Sessions_Data_Provider

Check failure on line 11 in src/dashboard/application/sessions/organic-sessions-data-provider.php

View workflow job for this annotation

GitHub Actions / Check code style

Expected 1 space before opening brace; found 2

/**
* The adapter.
*
* @var Site_Kit_Google_Analytics_Adapter $site_kit_google_analytics_adapter
*/
private $site_kit_google_analytics_adapter;

/**
* The parser.
* @var Organic_Sessions_Parser $organic_sessions_parser

Check failure on line 22 in src/dashboard/application/sessions/organic-sessions-data-provider.php

View workflow job for this annotation

GitHub Actions / Check code style

There must be exactly one blank line before the tags in a doc comment
*/
private $organic_sessions_parser;


/**
* The constructor.
*
* @param Site_Kit_Google_Analytics_Adapter $site_kit_google_analytics_adapter The adapter.
* @param Organic_Sessions_Parser $organic_sessions_parser The parser.
*/
public function __construct( Site_Kit_Google_Analytics_Adapter $site_kit_google_analytics_adapter,Organic_Sessions_Parser $organic_sessions_parser ) {

Check failure on line 33 in src/dashboard/application/sessions/organic-sessions-data-provider.php

View workflow job for this annotation

GitHub Actions / Check code style

Expected 1 blank line before function; 2 found

Check failure on line 33 in src/dashboard/application/sessions/organic-sessions-data-provider.php

View workflow job for this annotation

GitHub Actions / Check code style

Expected 1 space between comma and type hint "Organic_Sessions_Parser"; 0 found
$this->site_kit_google_analytics_adapter = $site_kit_google_analytics_adapter;
$this->organic_sessions_parser = $organic_sessions_parser;

Check failure on line 35 in src/dashboard/application/sessions/organic-sessions-data-provider.php

View workflow job for this annotation

GitHub Actions / Check code style

Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space
}

/**
* 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 {

$results = $this->site_kit_google_analytics_adapter->get_data( $parameters );
return $this->organic_sessions_parser->parse( $results );
}
}
15 changes: 7 additions & 8 deletions src/dashboard/domain/search-rankings/search-data.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@ class Search_Data implements Data_Interface {
private $position;

/**
* An array representation of the different `keys`.
* In the context of this domain object keys can represent a `URI` or a `search term`
* In the context of this domain object the subject can represent a `URI` or a `search term`
*
* @var string[]
* @var string
*/
private $keys = [];
private $subject;

/**
* The seo score.
Expand All @@ -59,14 +58,14 @@ class Search_Data implements Data_Interface {
* @param float $ctr The ctr.
* @param int $impressions The impressions.
* @param float $position The position.
* @param string[] $keys The clicks.
* @param string $subject The clicks.
*/
public function __construct( int $clicks, float $ctr, int $impressions, float $position, array $keys ) {
public function __construct( int $clicks, float $ctr, int $impressions, float $position, string $subject ) {
$this->clicks = $clicks;
$this->ctr = $ctr;
$this->impressions = $impressions;
$this->position = $position;
$this->keys = $keys;
$this->subject = $subject;
$this->seo_score = 0;
}

Expand All @@ -81,7 +80,7 @@ public function to_array(): array {
'ctr' => $this->ctr,
'impressions' => $this->impressions,
'position' => $this->position,
'keys' => $this->keys,
'subject' => $this->subject,
'seoScore' => $this->seo_score,
];
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
namespace Yoast\WP\SEO\Dashboard\Infrastructure\Google_Analytics;

use Yoast\WP\SEO\Dashboard\Domain\Data_Provider\Parameters;

/**
* Domain object to add search console specific data to the parameters.
*/
class Google_Analytics_Parameters extends Parameters {

/**
* The search dimension_filters to query.
*
* @var string[] $dimension_filters
*/
private $dimension_filters;
/**
* The search metrics to query.
*
* @var string[] $metrics
*/
private $metrics;

Check failure on line 23 in src/dashboard/infrastructure/google-analytics/google-analytics-parameters.php

View workflow job for this annotation

GitHub Actions / Check code style

Expected 1 blank line(s) before member var; 0 found

/**
* The constructor.
*
* @param string[] $dimension_filters The search dimensionFilters to query.
* @param string[] $metrics The search metrics to query.

Check failure on line 29 in src/dashboard/infrastructure/google-analytics/google-analytics-parameters.php

View workflow job for this annotation

GitHub Actions / Check code style

Expected 11 spaces after parameter name; 1 found
*/
public function __construct( array $dimension_filters,array $metrics ) {

Check failure on line 31 in src/dashboard/infrastructure/google-analytics/google-analytics-parameters.php

View workflow job for this annotation

GitHub Actions / Check code style

Expected 1 space between comma and type hint "array"; 0 found
$this->dimension_filters = $dimension_filters;
$this->metrics = $metrics;

Check failure on line 33 in src/dashboard/infrastructure/google-analytics/google-analytics-parameters.php

View workflow job for this annotation

GitHub Actions / Check code style

Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space
}

/**
* Getter for the dimension_filters.
*
* @return string[]
*/
public function get_dimension_filters(): array {
return $this->dimension_filters;
}

/**
* Getter for the metrics parameters.
*
* @return string[]
*/
public function get_metrics(): array {
return $this->metrics;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong
// phpcs:disable Yoast.NamingConventions.NamespaceName.MaxExceeded
namespace Yoast\WP\SEO\Dashboard\Infrastructure\Google_Analytics;

use Google\Site_Kit\Core\Modules\Module;
use Google\Site_Kit\Core\Modules\Modules;
use Google\Site_Kit\Modules\Search_Console;
use Google\Site_Kit\Plugin;
use Google\Site_Kit_Dependencies\Google\Service\SearchConsole\ApiDataRow;
use WP_Error;

/**
* The site API adapter to make calls via the Site_Kit plugin.
*/
class Site_Kit_Google_Analytics_Adapter {

/**
* The search console module class from Site kit.
*
* @var Module
*/
private static $search_console_module;

/**
* The register method that sets the instance in the adapter.
*
* @return void
*/
public function __construct() {
if ( \class_exists( 'Google\Site_Kit\Plugin' ) ) {
$site_kit_plugin = Plugin::instance();
$modules = new Modules( $site_kit_plugin->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 Google_Analytics_Parameters $parameters The parameters.
*
* @return ApiDataRow[]|WP_Error Data on success, or WP_Error on failure.
*/
public function get_data( Google_Analytics_Parameters $parameters ) {
$api_parameters = [
'slug' => "analytics-4",
'datapoint' => 'report',
'startDate' => $parameters->get_start_date(),
'endDate' => $parameters->get_end_date(),
'limit' => $parameters->get_limit(),
'dimensionFilters' => $parameters->get_dimension_filters(),
'metrics' => [ $parameters->get_metrics() ],
];

return self::$search_console_module->get_data( 'report', $api_parameters );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Search_Rankings_Parser {
public function parse( array $results ): Data_Container {
$search_data_container = new Data_Container();
foreach ( $results as $ranking ) {
$search_data_container->add_data( new Search_Data( $ranking->clicks, $ranking->ctr, $ranking->impressions, $ranking->position, $ranking->keys ) );
$search_data_container->add_data( new Search_Data( $ranking->clicks, $ranking->ctr, $ranking->impressions, $ranking->position, $ranking->keys[0] ) );
}

return $search_data_container;
Expand Down
30 changes: 30 additions & 0 deletions src/dashboard/infrastructure/sessions/organic-sessions-parser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong
// phpcs:disable Yoast.NamingConventions.NamespaceName.MaxExceeded
namespace Yoast\WP\SEO\Dashboard\Infrastructure\Search_Rankings;

use Google\Site_Kit_Dependencies\Google\Service\SearchConsole\ApiDataRow;
use Yoast\WP\SEO\Dashboard\Domain\Data_Provider\Data_Container;
use Yoast\WP\SEO\Dashboard\Domain\Search_Rankings\Search_Data;

/**
* This class contains all logic to parse the raw API response to usable domain objects for the rest of the system.
*/
class Organic_Sessions_Parser {

/**
* Parses the raw API response to a Search Data object containing the API response and SEO score.
*
* @param ApiDataRow[] $results The raw results.
*
* @return Data_Container The parsed data.
*/
public function parse( array $results ): Data_Container {
$search_data_container = new Data_Container();
foreach ( $results 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;
}
}
120 changes: 120 additions & 0 deletions src/dashboard/user-interface/sessions/organic-sessions-route.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
namespace Yoast\WP\SEO\Dashboard\User_Interface\Search_Rankings;

use Exception;
use WP_REST_Request;
use WP_REST_Response;
use WPSEO_Capability_Utils;
use Yoast\WP\SEO\Conditionals\No_Conditionals;
use Yoast\WP\SEO\Dashboard\Application\Sessions\Organic_Sessions_Data_Provider;
use Yoast\WP\SEO\Dashboard\Infrastructure\Google_Analytics\Google_Analytics_Parameters;
use Yoast\WP\SEO\Main;
use Yoast\WP\SEO\Routes\Route_Interface;

/**
* organic sessions route.
*/
class Organic_Sessions_Route implements Route_Interface {

use No_Conditionals;

/**
* The namespace of the rout.
*
* @var string
*/
public const ROUTE_NAMESPACE = Main::API_V1_NAMESPACE;
/**
* The prefix of the rout.
*
* @var string
*/
public const ROUTE_PREFIX = '/organic_sessions';

/**
* The data provider.
*
* @var Organic_Sessions_Data_Provider $organic_sessions_data_provider
*/
private $organic_sessions_data_provider;

/**
* The constructor.
*
* @param Organic_Sessions_Data_Provider $organic_sessions_data_provider The data provider.
*/
public function __construct( Organic_Sessions_Data_Provider $organic_sessions_data_provider ) {
$this->organic_sessions_data_provider = $organic_sessions_data_provider;
}

/**
* Registers routes for scores.
*
* @return void
*/
public function register_routes() {
\register_rest_route(
self::ROUTE_NAMESPACE,
self::ROUTE_PREFIX,
[
[
'methods' => 'GET',
'callback' => [ $this, 'get_sessions' ],
//'permission_callback' => [ $this, 'permission_manage_options' ],

Check warning on line 64 in src/dashboard/user-interface/sessions/organic-sessions-route.php

View workflow job for this annotation

GitHub Actions / Check code style

This comment is 62% valid code; is this commented out code?
'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_sessions( WP_REST_Request $request ): WP_REST_Response {
try {
$request_parameters = new Google_Analytics_Parameters( ["sessionDefaultChannelGrouping" => "Organic Search"], [
'name' => 'sessions',
]);

$request_parameters->set_limit( $request->get_param( 'limit' ) );
$request_parameters->set_start_date( '2024-01-01' );
$request_parameters->set_end_date( '2025-01-01' );

$search_data_container = $this->organic_sessions_data_provider->get_data( $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' );
}
}

0 comments on commit 104daee

Please sign in to comment.