Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions includes/Core/Modules/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -502,14 +502,7 @@ final public function get_client() {
* @return OAuth_Client OAuth_Client instance.
*/
private function get_oauth_client_for_datapoint( Datapoint $datapoint ) {
if (
$this instanceof Module_With_Owner
&& $this->is_shareable()
&& $datapoint->is_shareable()
&& $this->get_owner_id() !== get_current_user_id()
&& ! $this->is_recoverable()
&& current_user_can( Permissions::READ_SHARED_MODULE_DATA, $this->slug )
) {
if ( $this instanceof Module_With_Owner && $this->is_shared_datapoint_request( $datapoint ) ) {
$oauth_client = $this->get_owner_oauth_client();

try {
Expand Down Expand Up @@ -753,14 +746,26 @@ function ( $item ) {
* @return bool TRUE if the request is for shared data, otherwise FALSE.
*/
protected function is_shared_data_request( Data_Request $data ) {
$datapoint = $this->get_datapoint_definition( "{$data->method}:{$data->datapoint}" );
$oauth_client = $this->get_oauth_client_for_datapoint( $datapoint );
$datapoint = $this->get_datapoint_definition( "{$data->method}:{$data->datapoint}" );

if ( $this->authentication->get_oauth_client() !== $oauth_client ) {
return true;
}
return $this->is_shared_datapoint_request( $datapoint );
}

return false;
/**
* Determines whether the current datapoint request is for shared data.
*
* @since n.e.x.t
*
* @param Datapoint $datapoint Datapoint instance.
* @return bool TRUE if the request is for shared data, otherwise FALSE.
*/
protected function is_shared_datapoint_request( Datapoint $datapoint ) {
return $this instanceof Module_With_Owner
&& $this->is_shareable()
&& $datapoint->is_shareable()
&& $this->get_owner_id() !== get_current_user_id()
&& ! $this->is_recoverable()
&& current_user_can( Permissions::READ_SHARED_MODULE_DATA, $this->slug );
}

/**
Expand Down
113 changes: 29 additions & 84 deletions includes/Modules/Analytics_4.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,16 @@
use Google\Site_Kit\Modules\Analytics_4\Datapoints\Get_Enhanced_Measurement_Settings;
use Google\Site_Kit\Modules\Analytics_4\Datapoints\Get_Webdatastreams;
use Google\Site_Kit\Modules\Analytics_4\Datapoints\Get_Webdatastreams_Batch;
use Google\Site_Kit\Modules\Analytics_4\Datapoints\Get_Report;
use Google\Site_Kit\Modules\Analytics_4\Datapoints\Get_Key_Events;
use Google\Site_Kit\Modules\Analytics_4\Datapoints\Get_Has_Property_Access;
use Google\Site_Kit\Modules\Analytics_4\Datapoints\Save_Custom_Dimension_Data_Available;
use Google\Site_Kit\Modules\Analytics_4\Datapoints\Sync_Custom_Dimensions;
use Google\Site_Kit\Modules\Analytics_4\Datapoints\Update_Enhanced_Measurement_Settings;
use Google\Site_Kit\Modules\Analytics_4\Synchronize_Property;
use Google\Site_Kit\Modules\Analytics_4\Synchronize_AdSenseLinked;
use Google\Site_Kit\Modules\Analytics_4\GoogleAnalyticsAdmin\AccountProvisioningService;
use Google\Site_Kit\Modules\Analytics_4\Report\Request as Analytics_4_Report_Request;
use Google\Site_Kit\Modules\Analytics_4\Report\Response as Analytics_4_Report_Response;
use Google\Site_Kit\Modules\Analytics_4\Resource_Data_Availability_Date;
use Google\Site_Kit\Modules\Analytics_4\Settings;
use Google\Site_Kit\Modules\Analytics_4\Synchronize_AdsLinked;
Expand All @@ -85,10 +87,6 @@
use Google\Site_Kit\Modules\Analytics_4\Web_Tag;
use Google\Site_Kit_Dependencies\Google\Model as Google_Model;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData as Google_Service_AnalyticsData;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData\RunReportRequest as Google_Service_AnalyticsData_RunReportRequest;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData\DateRange as Google_Service_AnalyticsData_DateRange;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData\Dimension as Google_Service_AnalyticsData_Dimension;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData\Metric as Google_Service_AnalyticsData_Metric;
use Google\Site_Kit_Dependencies\Google\Service\GoogleAnalyticsAdmin as Google_Service_GoogleAnalyticsAdmin;
use Google\Site_Kit_Dependencies\Google\Service\GoogleAnalyticsAdmin\GoogleAnalyticsAdminV1betaDataStream;
use Google\Site_Kit_Dependencies\Google\Service\GoogleAnalyticsAdmin\GoogleAnalyticsAdminV1betaDataStreamWebStreamData;
Expand All @@ -108,6 +106,7 @@
use Google\Site_Kit\Modules\Analytics_4\Conversion_Reporting\Conversion_Reporting_New_Badge_Events_Sync;
use Google\Site_Kit\Modules\Analytics_4\Conversion_Reporting\Conversion_Reporting_Provider;
use Google\Site_Kit\Modules\Analytics_4\Reset_Audiences;
use Google\Site_Kit\Core\Modules\Datapoint;
use stdClass;
use WP_Error;
use WP_Post;
Expand Down Expand Up @@ -700,9 +699,13 @@ protected function get_datapoint_definitions() {
'https://www.googleapis.com/auth/tagmanager.readonly',
),
),
'GET:key-events' => array(
'service' => 'analyticsadmin',
'shareable' => true,
'GET:key-events' => new Get_Key_Events(
array(
'service' => function () {
return $this->get_service( 'analyticsadmin' );
},
'settings' => $this->get_settings(),
)
),
'POST:create-account-ticket' => new Create_Account_Ticket(
array(
Expand Down Expand Up @@ -743,10 +746,24 @@ protected function get_datapoint_definitions() {
),
'GET:properties' => array( 'service' => 'analyticsadmin' ),
'GET:property' => array( 'service' => 'analyticsadmin' ),
'GET:has-property-access' => array( 'service' => 'analyticsdata' ),
'GET:report' => array(
'service' => 'analyticsdata',
'shareable' => true,
'GET:has-property-access' => new Get_Has_Property_Access(
array(
'service' => function () {
return $this->get_service( 'analyticsdata' );
},
)
),
'GET:report' => new Get_Report(
array(
'service' => function () {
return $this->get_service( 'analyticsdata' );
},
'settings' => $this->get_settings(),
'context' => $this->context,
'is_shared_request' => function ( Datapoint $datapoint ) {
return $this->is_shared_datapoint_request( $datapoint );
},
),
),
'GET:batch-report' => array(
'service' => 'analyticsdata',
Expand Down Expand Up @@ -1303,58 +1320,6 @@ protected function create_data_request( Data_Request $data ) {
}

return $this->get_service( 'analyticsadmin' )->properties->get( self::normalize_property_id( $data['propertyID'] ) );
case 'GET:has-property-access':
if ( ! isset( $data['propertyID'] ) ) {
throw new Missing_Required_Param_Exception( 'propertyID' );
}

// A simple way to check for property access is to attempt a minimal report request.
// If the user does not have access, this will return a 403 error.
$request = new Google_Service_AnalyticsData_RunReportRequest();
$request->setDimensions( array( new Google_Service_AnalyticsData_Dimension( array( 'name' => 'date' ) ) ) );
$request->setMetrics( array( new Google_Service_AnalyticsData_Metric( array( 'name' => 'sessions' ) ) ) );
$request->setDateRanges(
array(
new Google_Service_AnalyticsData_DateRange(
array(
'start_date' => 'yesterday',
'end_date' => 'today',
)
),
)
);
$request->setLimit( 0 );

return $this->get_analyticsdata_service()->properties->runReport( $data['propertyID'], $request );
case 'GET:report':
if ( empty( $data['metrics'] ) ) {
return new WP_Error(
'missing_required_param',
/* translators: %s: Missing parameter name */
sprintf( __( 'Request parameter is empty: %s.', 'google-site-kit' ), 'metrics' ),
array( 'status' => 400 )
);
}

$settings = $this->get_settings()->get();
if ( empty( $settings['propertyID'] ) ) {
return new WP_Error(
'missing_required_setting',
__( 'No connected Google Analytics property ID.', 'google-site-kit' ),
array( 'status' => 500 )
);
}

$report = new Analytics_4_Report_Request( $this->context );
$request = $report->create_request( $data, $this->is_shared_data_request( $data ) );
if ( is_wp_error( $request ) ) {
return $request;
}

$property_id = self::normalize_property_id( $settings['propertyID'] );
$request->setProperty( $property_id );

return $this->get_analyticsdata_service()->properties->runReport( $property_id, $request );

case 'GET:batch-report':
if ( empty( $data['requests'] ) ) {
Expand Down Expand Up @@ -1538,22 +1503,7 @@ protected function create_data_request( Data_Request $data ) {
}

return $this->get_tagmanager_service()->accounts_containers->lookup( array( 'destinationId' => $data['measurementID'] ) );
case 'GET:key-events':
$settings = $this->get_settings()->get();
if ( empty( $settings['propertyID'] ) ) {
return new WP_Error(
'missing_required_setting',
__( 'No connected Google Analytics property ID.', 'google-site-kit' ),
array( 'status' => 500 )
);
}

$analyticsadmin = $this->get_service( 'analyticsadmin' );
$property_id = self::normalize_property_id( $settings['propertyID'] );

return $analyticsadmin
->properties_keyEvents // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
->listPropertiesKeyEvents( $property_id );
case 'POST:set-google-tag-id-mismatch':
if ( ! isset( $data['hasMismatchedTag'] ) ) {
throw new Missing_Required_Param_Exception( 'hasMismatchedTag' );
Expand Down Expand Up @@ -1624,11 +1574,6 @@ protected function parse_data_response( Data_Request $data, $response ) {
return (array) $response->getDestination();
case 'GET:google-tag-settings':
return $this->get_google_tag_settings_for_measurement_id( $response, $data['measurementID'] );
case 'GET:key-events':
return (array) $response->getKeyEvents();
case 'GET:report':
$report = new Analytics_4_Report_Response( $this->context );
return $report->parse_response( $data, $response );
case 'POST:sync-audiences':
$audiences = $this->audience_utilities->set_available_audiences( $response->getAudiences() );
return $audiences;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
/**
* Class Google\Site_Kit\Modules\Analytics_4\Datapoints\Get_Has_Property_Access
*
* @package Google\Site_Kit\Modules\Analytics_4\Datapoints
* @copyright 2026 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/

namespace Google\Site_Kit\Modules\Analytics_4\Datapoints;

use Google\Site_Kit\Core\Modules\Datapoint;
use Google\Site_Kit\Core\Modules\Executable_Datapoint;
use Google\Site_Kit\Core\REST_API\Data_Request;
use Google\Site_Kit\Core\REST_API\Exception\Missing_Required_Param_Exception;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData\RunReportRequest as Google_Service_AnalyticsData_RunReportRequest;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData\DateRange as Google_Service_AnalyticsData_DateRange;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData\Dimension as Google_Service_AnalyticsData_Dimension;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData\Metric as Google_Service_AnalyticsData_Metric;

/**
* Has property access datapoint.
*
* @since n.e.x.t
* @access private
* @ignore
*/
class Get_Has_Property_Access extends Datapoint implements Executable_Datapoint {

/**
* Creates a request object.
*
* @since n.e.x.t
*
* @param Data_Request $data Data request object.
* @return mixed Request object on success, or WP_Error on failure.
* @throws Missing_Required_Param_Exception Thrown if a required parameter is missing.
*/
public function create_request( Data_Request $data ) {
if ( ! isset( $data['propertyID'] ) ) {
throw new Missing_Required_Param_Exception( 'propertyID' );
}

// A simple way to check for property access is to attempt a minimal report request.
// If the user does not have access, this will return a 403 error.
$request = new Google_Service_AnalyticsData_RunReportRequest();
$request->setDimensions( array( new Google_Service_AnalyticsData_Dimension( array( 'name' => 'date' ) ) ) );
$request->setMetrics( array( new Google_Service_AnalyticsData_Metric( array( 'name' => 'sessions' ) ) ) );
$request->setDateRanges(
array(
new Google_Service_AnalyticsData_DateRange(
array(
'start_date' => 'yesterday',
'end_date' => 'today',
)
),
)
);
$request->setLimit( 0 );

return $this->get_service()->properties->runReport( $data['propertyID'], $request );
}

/**
* Parses a response.
*
* @since n.e.x.t
*
* @param mixed $response Request response.
* @param Data_Request $data Data request object.
* @return mixed The original response without any modifications.
*/
public function parse_response( $response, Data_Request $data ) {
return $response;
}
}
88 changes: 88 additions & 0 deletions includes/Modules/Analytics_4/Datapoints/Get_Key_Events.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php
/**
* Class Google\Site_Kit\Modules\Analytics_4\Datapoints\Get_Key_Events
*
* @package Google\Site_Kit\Modules\Analytics_4\Datapoints
* @copyright 2026 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://sitekit.withgoogle.com
*/

namespace Google\Site_Kit\Modules\Analytics_4\Datapoints;

use Google\Site_Kit\Core\Modules\Executable_Datapoint;
use Google\Site_Kit\Core\Modules\Shareable_Datapoint;
use Google\Site_Kit\Core\REST_API\Data_Request;
use Google\Site_Kit\Modules\Analytics_4;
use Google\Site_Kit_Dependencies\Google\Service\GoogleAnalyticsAdmin\GoogleAnalyticsAdminV1betaKeyEvent;
use Google\Site_Kit\Modules\Analytics_4\Settings;
use WP_Error;

/**
* Get key events datapoint class.
*
* @since n.e.x.t
* @access private
* @ignore
*/
class Get_Key_Events extends Shareable_Datapoint implements Executable_Datapoint {

/**
* Module settings instance.
*
* @since n.e.x.t
* @var Settings
*/
private $settings;

/**
* Constructor.
*
* @since n.e.x.t
*
* @param array $definition Definition fields.
*/
public function __construct( array $definition ) {
parent::__construct( $definition );
$this->settings = $definition['settings'];
}

/**
* Creates a request object.
*
* @since n.e.x.t
*
* @param Data_Request $data Data request object.
* @return mixed Request object on success, or WP_Error on failure.
*/
public function create_request( Data_Request $data ) {
$settings = $this->settings->get();

if ( empty( $settings['propertyID'] ) ) {
return new WP_Error(
'missing_required_setting',
__( 'No connected Google Analytics property ID.', 'google-site-kit' ),
array( 'status' => 500 )
);
}

$property_id = Analytics_4::normalize_property_id( $settings['propertyID'] );

return $this->get_service()
->properties_keyEvents // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
->listPropertiesKeyEvents( $property_id );
}

/**
* Parses a response.
*
* @since n.e.x.t
*
* @param mixed $response Request response.
* @param Data_Request $data Data request object.
* @return GoogleAnalyticsAdminV1betaKeyEvent[] Array of key events.
*/
public function parse_response( $response, Data_Request $data ) {
return (array) $response->getKeyEvents();
}
}
Loading
Loading