Files
SIGE-WEB-snapshot/wp-content/plugins/google-analytics-for-wordpress/includes/api/class-monsterinsights-api-overview.php

285 lines
7.8 KiB
PHP

<?php
/**
* Overview Report API Client class for MonsterInsights.
*
* Fetches campaign, page, and device data with TotalUsers, PageViews, and BounceRate.
* Uses the same reporting relay API endpoint as the Custom Dashboard, but is exposed
* as a standalone API client that extends the base MonsterInsights_API_Client.
*
* @package MonsterInsights
*/
defined( 'ABSPATH' ) || exit;
class MonsterInsights_API_Overview extends MonsterInsights_API_Client {
/**
* Overview report query ID.
*
* This ID is used by the remote reporting service to key the response.
*/
const QUERY_ID = 'overview';
/**
* Default dimensions for the overview report.
*
* Maps to GA4 Data API dimension names:
* - date: Date (YYYYMMDD)
* - sessionCampaignName: Campaign - Name
* - sessionSource: Campaign - Source
* - sessionMedium: Campaign - Medium
* - firstUserManualTerm: Campaign - Term
* - landingPage: Page - Landing Page
* - pageTitle: Page - Title
* - deviceCategory: Device
*
* @var array
*/
protected static $dimensions = array(
'date',
'sessionCampaignName',
'sessionSource',
'sessionMedium',
'firstUserManualTerm',
'landingPage',
'pageTitle',
'deviceCategory',
);
/**
* Default metrics for the overview report.
*
* Maps to GA4 Data API metric names:
* - totalUsers: Total Users
* - screenPageViews: Page Views
* - bounceRate: Bounce Rate
*
* @var array
*/
protected static $metrics = array(
'totalUsers',
'screenPageViews',
'sessions',
'bounceRate',
'ecommercePurchases',
'averagePurchaseRevenue',
'newUsers',
'engagementRate',
'totalRevenue',
);
/**
* Build the overview API query payload (without date range).
*
* @return array Query parameters for the reporting API.
*/
public static function build_query() {
return array(
'id' => self::QUERY_ID,
'dimensions' => self::$dimensions,
'metrics' => self::$metrics,
'compare' => false,
'limit' => 100,
'groupBy' => 'date',
);
}
/**
* Normalize an input date range array using MonsterInsights_Report logic.
*
* Ensures we always have a valid start/end range and that the end date is not in the future.
*
* @param array $date_range {
* Optional. Raw date range input.
*
* @type string $start Start date (Y-m-d).
* @type string $end End date (Y-m-d).
* }
*
* @return array Normalized date range with 'start' and 'end' keys.
*/
public function normalize_date_range( $date_range = array() ) {
if ( empty( $date_range['start'] ) || empty( $date_range['end'] ) ) {
// Fallback to last 30 days when dates are missing.
$date_range = $this->get_default_date_range( 30 );
} else {
// Ensure end date is not in the future.
$end_date = strtotime( $date_range['end'] );
$today = strtotime( 'today' );
if ( $end_date > $today ) {
$date_range['end'] = date( 'Y-m-d', $today );
}
}
return $date_range;
}
/**
* Build a default date range when none is provided.
*
* @param int $days Number of days to include (inclusive of today).
*
* @return array {
* @type string $start Start date (Y-m-d).
* @type string $end End date (Y-m-d).
* }
*/
private function get_default_date_range( $days = 30 ) {
$days = max( 1, (int) $days );
$end_ts = strtotime( 'today' );
$start_ts = strtotime( '-' . ( $days - 1 ) . ' days', $end_ts );
return array(
'start' => date( 'Y-m-d', $start_ts ),
'end' => date( 'Y-m-d', $end_ts ),
);
}
/**
* Parse and normalize the date range coming from $_POST['date_range'].
*
* Mirrors the behaviour in MonsterInsights_Custom_Dashboard_Ajax::get_custom_dashboard_data().
*
* @return array Normalized date range with 'start' and 'end'.
*/
public function get_date_range_from_request() {
$date_range = array();
if ( ! empty( $_POST['date_range'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
$decoded = json_decode( stripslashes( $_POST['date_range'] ), true ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
if ( is_array( $decoded ) ) {
$date_range = $decoded;
}
}
return $this->normalize_date_range( $date_range );
}
/**
* High-level helper: get overview data for the current request's date_range POST param.
*
* This is intended to be called from AJAX handlers so that the date range
* parsing/normalization logic lives in a single place (the API client).
*
* @return array|WP_Error|MonsterInsights_API_Error Response data keyed by overview ID, or error.
*/
public function get_overview_for_request() {
$date_range = $this->get_date_range_from_request();
return $this->get_overview(
$date_range['start'],
$date_range['end']
);
}
/**
* Get overview report data for an explicit start/end date range.
*
* @param string $start Start date (Y-m-d).
* @param string $end End date (Y-m-d).
*
* @return array|WP_Error|MonsterInsights_API_Error Response data keyed by 'overview', or error.
*/
public function get_overview( $start, $end ) {
$queries = array( self::build_query() );
return $this->query(
$start,
$end,
$queries
);
}
/**
* Execute the overview reporting query.
*
* @param string $start Start date (Y-m-d).
* @param string $end End date (Y-m-d).
* @param array $queries List of query definitions.
*
* @return array|WP_Error|MonsterInsights_API_Error
*/
public function query( $start, $end, $queries ) {
$body = array(
'start' => $start,
'end' => $end,
'queries' => $queries,
'plugin_version' => MONSTERINSIGHTS_VERSION,
);
return $this->request( 'api/v3/reporting/query', $body, 'POST' );
}
/**
* Override the parent request method to match the reporting relay API requirements.
*
* This is essentially the same as MonsterInsights_API_Custom_Dashboard::request(),
* adapted to this standalone client.
*
* @param string $endpoint The API endpoint.
* @param array $params The request parameters.
* @param string $method The request method.
*
* @return array|WP_Error|MonsterInsights_API_Error
*/
protected function request( $endpoint, $params = array(), $method = 'POST' ) {
$url = trailingslashit( $this->base_url ) . $endpoint;
$args = array(
'method' => $method,
'timeout' => 15,
'headers' => array(
'X-Relay-License' => $this->license,
'X-Relay-Site-Key' => $this->key,
'X-Relay-Token' => $this->token,
'X-Relay-Site-URL' => $this->site_url,
'Content-Type' => 'application/json',
),
'body' => wp_json_encode( $params ),
);
$response = wp_remote_request( $url, $args );
if ( is_wp_error( $response ) ) {
return $response;
}
$response_code = wp_remote_retrieve_response_code( $response );
$response_body = wp_remote_retrieve_body( $response );
$decoded_body = json_decode( $response_body, true );
// Check for successful response.
if ( $response_code >= 200 && $response_code < 300 ) {
if ( isset( $decoded_body['success'] ) && $decoded_body['success'] ) {
return isset( $decoded_body['data'] ) ? $decoded_body['data']['data'] : array();
}
}
// Handle error responses with a MonsterInsights_API_Error shape.
if ( isset( $decoded_body['error'] ) && is_array( $decoded_body['error'] ) ) {
if ( isset( $decoded_body['error']['code'], $decoded_body['error']['message'] ) ) {
return new MonsterInsights_API_Error( $decoded_body );
}
}
// Fallback error handling.
$error_message = __( 'An unknown error occurred.', 'google-analytics-for-wordpress' );
if ( isset( $decoded_body['message'] ) ) {
$error_message = $decoded_body['message'];
} elseif ( isset( $decoded_body['error'] ) && is_string( $decoded_body['error'] ) ) {
$error_message = $decoded_body['error'];
}
return new WP_Error(
'api_error',
$error_message,
array(
'response_code' => $response_code,
'response_body' => $response_body,
)
);
}
}