JezK
Edit File: BaseTracking.php
<?php declare(strict_types=1); namespace Imagify\Tracking; use Imagify\Dependencies\WPMedia\Mixpanel\Optin; use Imagify\Dependencies\WPMedia\Mixpanel\TrackingPlugin; /** * Abstract base class for Imagify tracking. * * @since 2.3.0 */ abstract class BaseTracking { /** * The Mixpanel opt-in service. * * @var Optin */ protected $optin; /** * The Mixpanel tracking plugin service. * * @var TrackingPlugin */ protected $mixpanel; /** * Whether the Mixpanel user has already been identified during this request. * * @var bool */ private $identified = false; /** * Constructor. * * @param Optin $optin The Mixpanel opt-in service. * @param TrackingPlugin $mixpanel The Mixpanel tracking plugin service. */ public function __construct( Optin $optin, TrackingPlugin $mixpanel ) { $this->optin = $optin; $this->mixpanel = $mixpanel; } /** * Check if tracking is allowed. * * @return bool True if tracking is allowed, false otherwise. */ public function can_track(): bool { return $this->optin->can_track(); } /** * Returns the default event properties shared by every tracked event. * * IMPORTANT: do NOT add `domain`, `wp_version`, `php_version`, `plugin`, * `brand`, or `application` here. `TrackingPlugin::track_direct()` injects * those automatically and any value set here is silently overwritten. * * @return array<string, mixed> */ protected function get_default_event_properties(): array { $email = $this->get_license_owner_email(); $license_owner = '' !== $email ? hash( 'sha256', $email ) : ''; $this->identify_user( $email ); return [ 'context' => 'wp_plugin', 'license_owner' => $license_owner, ]; } /** * Registers a stable `distinct_id` super property on the Mixpanel instance. * * Mixpanel needs `distinct_id` on every event to compute user-level metrics * (MAU/DAU, retention, cohorts, funnels). `TrackingPlugin::identify()` hashes * the identifier with sha224 before it is registered, so no raw email or * domain ever leaves the site. * * The identifier is the Imagify license owner email — the same strategy as * WP Rocket, so one license maps to one Mixpanel user across all its sites. * When no license email is available (unlicensed or unreachable API), the * site host is used instead so events are still attributed to a stable, * anonymized identity rather than none at all. * * Called from `get_default_event_properties()` — the single choke point every * tracked event goes through — so the license user is fetched only once and * never on plugin bootstrap. Runs at most once per instance per request; the * underlying Mixpanel instance is shared, so the property applies to every * subsequent event. * * @param string $email The license owner email, or an empty string when unknown. * * @return void */ protected function identify_user( string $email ): void { if ( $this->identified ) { return; } $identifier = '' !== $email ? $email : $this->get_site_identifier(); if ( '' === $identifier ) { return; } $this->mixpanel->identify( $identifier ); $this->identified = true; } /** * Returns the Imagify license owner email. * * @return string The email, or an empty string when the account is unknown. */ private function get_license_owner_email(): string { $user = get_imagify_user(); if ( is_wp_error( $user ) || empty( $user->email ) ) { return ''; } return (string) $user->email; } /** * Returns the site host, used as a fallback identifier when no license email exists. * * @return string The host, or an empty string when it cannot be resolved. */ private function get_site_identifier(): string { $host = wp_parse_url( get_home_url(), PHP_URL_HOST ); return is_string( $host ) ? $host : ''; } }