234 lines
6.1 KiB
PHP
234 lines
6.1 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Main handler for MonsterInsights' tracking.
|
|
*
|
|
* This class is responsible for sending tracking events to the MonsterInsights API.
|
|
* It handles event creation, data population, and communication with the API.
|
|
* It also manages a database table for storing and retrying events that fail to send.
|
|
*/
|
|
class MonsterInsights_Tracking {
|
|
|
|
/**
|
|
* Option name for tracking table version.
|
|
*
|
|
* @var string
|
|
*/
|
|
const TABLE_VERSION_OPTION = 'monsterinsights_tracking_events_table_version';
|
|
|
|
/**
|
|
* Current table schema version.
|
|
*
|
|
* Increment this value when the table schema changes to trigger a schema update.
|
|
*
|
|
* @var string
|
|
*/
|
|
const TABLE_VERSION = '1.0';
|
|
|
|
/**
|
|
* Tracking API class instance.
|
|
*
|
|
* @var MonsterInsights_API_Tracking
|
|
*/
|
|
private $api;
|
|
|
|
/**
|
|
* MonsterInsights Tracking singleton instance.
|
|
*
|
|
* @var MonsterInsights_Tracking
|
|
*/
|
|
private static $instance;
|
|
|
|
/**
|
|
* Flag to track if table existence has been verified during current request.
|
|
*
|
|
* This prevents multiple option lookups within the same request.
|
|
*
|
|
* @var bool
|
|
*/
|
|
private static $table_verified = false;
|
|
|
|
/**
|
|
* MonsterInsights_Tracking constructor.
|
|
*/
|
|
public function __construct() {
|
|
$this->api = new MonsterInsights_API_Tracking();
|
|
}
|
|
|
|
/**
|
|
* Ensures the tracking events database table exists.
|
|
*
|
|
* This method uses a multi-layer caching strategy for performance:
|
|
* 1. Static property check (instant, per-request)
|
|
* 2. WordPress option check (fast, autoloaded)
|
|
* 3. Schema creation only when needed
|
|
*
|
|
* The option stores a version number, allowing for future schema migrations
|
|
* by incrementing the TABLE_VERSION constant.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function maybe_create_table() {
|
|
// Layer 1: Static property check - fastest, prevents multiple checks per request.
|
|
if ( self::$table_verified ) {
|
|
return;
|
|
}
|
|
|
|
// Layer 2: Check stored table version option.
|
|
// This option is autoloaded by default, making it very fast to retrieve.
|
|
$stored_version = get_option( self::TABLE_VERSION_OPTION );
|
|
|
|
if ( self::TABLE_VERSION === $stored_version ) {
|
|
// Table exists with correct version, mark as verified for this request.
|
|
self::$table_verified = true;
|
|
return;
|
|
}
|
|
|
|
// Layer 3: Table needs to be created or updated.
|
|
self::setup_tracking_schema();
|
|
|
|
// Store the current version to prevent future checks.
|
|
update_option( self::TABLE_VERSION_OPTION, self::TABLE_VERSION, true );
|
|
|
|
self::$table_verified = true;
|
|
}
|
|
|
|
/**
|
|
* Sends an event to the API.
|
|
*
|
|
*
|
|
* @param string $event_name The name of the event to send.
|
|
* @param array $payload Optional. The event payload data.
|
|
* @param array $extra Optional. Extra parameters to include with the event.
|
|
*
|
|
* @return array|WP_Error|MonsterInsights_API_Error Returns the API response on success, or a WP_Error/MonsterInsights_API_Error on failure.
|
|
*/
|
|
public function send($event_name, array $payload = [], array $extra = []) {
|
|
|
|
if ( !MonsterInsights()->auth->is_authed() && !MonsterInsights()->auth->is_network_authed() ) {
|
|
return new WP_Error('401', __('MonsterInsights is not connected.', 'google-analytics-for-wordpress'));
|
|
}
|
|
|
|
$extra_params = [];
|
|
|
|
$extra_params = array_merge(
|
|
$extra_params,
|
|
$extra
|
|
);
|
|
|
|
$sent_event = new MonsterInsights_Tracking_Event($event_name, $payload);
|
|
|
|
$client_id = $extra_params['client_id'] ?? null;
|
|
|
|
if ( empty( $client_id ) ) {
|
|
$payment_id = $payload['transaction_id'] ?? null;
|
|
$client_id = $payment_id ?? monsterinsights_get_client_id( $payment_id );
|
|
}
|
|
|
|
if ( !empty($client_id) ) {
|
|
$extra_params['client_id'] = $client_id;
|
|
}
|
|
|
|
$result = $this->api->track_events(
|
|
[$sent_event],
|
|
$extra_params
|
|
);
|
|
|
|
// Handle WP_Error (network failures, timeouts, etc.)
|
|
if ( is_wp_error( $result ) ) {
|
|
$sent_event->update_error( [
|
|
'error' => $result->get_error_message(),
|
|
'details' => $result->get_error_data(),
|
|
] );
|
|
return $result;
|
|
}
|
|
|
|
// Handle MonsterInsights API errors
|
|
if ( $result instanceof MonsterInsights_API_Error ) {
|
|
$error_data = $result->get_error_data();
|
|
$sent_event->update_error( $error_data['body'] );
|
|
return $result;
|
|
}
|
|
|
|
$data = $result['data'];
|
|
|
|
$events_submitted = $data['events_submitted'];
|
|
$tracking_errors = $data['tracking_errors'];
|
|
|
|
if ( in_array( $sent_event->get_id(), $events_submitted ) ) {
|
|
// Delete tracked event from DB
|
|
$sent_event->delete();
|
|
} else {
|
|
// Try to find error for the specific event
|
|
$found_errors = array_filter( $tracking_errors, function( $e ) use ( $sent_event ) {
|
|
return $e['client_event_id'] === $sent_event->get_id();
|
|
});
|
|
|
|
if ( !empty($found_errors) ) {
|
|
// Grab first one
|
|
$sent_event->update_error($found_errors[0]);
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Get MonsterInsights' Tracking singleton
|
|
* @return MonsterInsights_Tracking
|
|
*/
|
|
public static function get_instance(): MonsterInsights_Tracking {
|
|
if ( !empty( self::$instance ) ) {
|
|
return self::$instance;
|
|
}
|
|
|
|
self::$instance = new self;
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Get DB table name for the tracking events
|
|
* @return string
|
|
*/
|
|
public static function get_db_table_name() {
|
|
global $wpdb;
|
|
return $wpdb->prefix . 'monsterinsights_tracking_events';
|
|
}
|
|
|
|
/**
|
|
* Set up the tracking_events db table.
|
|
* @return void
|
|
*/
|
|
public static function setup_tracking_schema() {
|
|
global $wpdb;
|
|
|
|
$table_name = self::get_db_table_name();
|
|
$charset_collate = $wpdb->get_charset_collate();
|
|
|
|
$sql = "CREATE TABLE $table_name (
|
|
id mediumint(9) NOT NULL AUTO_INCREMENT,
|
|
name tinytext NOT NULL,
|
|
status tinytext NOT NULL,
|
|
payload text,
|
|
extra_data text,
|
|
attempts tinyint DEFAULT 0 NOT NULL,
|
|
last_error text,
|
|
created_at datetime DEFAULT NOW() NOT NULL,
|
|
PRIMARY KEY (id)
|
|
) $charset_collate;";
|
|
|
|
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
|
dbDelta($sql);
|
|
}
|
|
}
|
|
|
|
if ( !function_exists('monsterinsights_tracking') ) {
|
|
|
|
/**
|
|
* Get the MonsterInsights tracking singleton
|
|
* @return MonsterInsights_Tracking
|
|
*/
|
|
function monsterinsights_tracking(): MonsterInsights_Tracking {
|
|
return MonsterInsights_Tracking::get_instance();
|
|
}
|
|
} |