| @@ -7,9 +7,9 @@ | ||
| 7 | 7 | ## Architecture |
| 8 | 8 | |
| 9 | 9 | | Class | Role | |
| 10 | 10 | |---|---| |
| 11 | -| `Imagify\Tracking\BaseTracking` | Abstract base: `can_track()`, `get_default_event_properties()` | | |
| 11 | +| `Imagify\Tracking\BaseTracking` | Abstract base: `can_track()`, `get_default_event_properties()`, `identify_user()` | | |
| 12 | 12 | | `Imagify\Tracking\Tracking` | Concrete: `track_media_optimized()`, `track_settings_saved()` | |
| 13 | 13 | | `Imagify\Tracking\Subscriber` | Subscribes to WordPress hooks and delegates to `Tracking` | |
| 14 | 14 | | `Imagify\Tracking\ServiceProvider` | Registers all module services into the DI container | |
| 15 | 15 | |
| @@ -16,8 +16,31 @@ | ||
| 16 | 16 | The module depends on two Strauss-prefixed vendor classes: |
| 17 | 17 | |
| 18 | 18 | - `Imagify\Dependencies\WPMedia\Mixpanel\Optin` — manages opt-in state |
| 19 | 19 | - `Imagify\Dependencies\WPMedia\Mixpanel\TrackingPlugin` — sends events to Mixpanel |
| 20 | + | |
| 21 | +--- | |
| 22 | + | |
| 23 | +## User identification (`distinct_id`) | |
| 24 | + | |
| 25 | +Mixpanel needs a `distinct_id` on every event to compute user-level metrics — MAU/DAU, retention, cohorts, funnels, unique users by feature. Without it, events are only aggregatable in bulk. | |
| 26 | + | |
| 27 | +`BaseTracking::identify_user()` registers it by calling `TrackingPlugin::identify()`, which hashes the identifier with **sha224** and registers it as a Mixpanel *super property* on the shared Mixpanel instance — so it lands on every event sent afterwards, including MCP events. No raw email or domain ever leaves the site. | |
| 28 | + | |
| 29 | +| Priority | Identifier | Rationale | | |
| 30 | +|---|---|---| | |
| 31 | +| 1 | `get_imagify_user()->email` | Same strategy as WP Rocket: one license = one Mixpanel user across all of its sites | | |
| 32 | +| 2 | Host of `get_home_url()` | Fallback for unlicensed sites or an unreachable API, so events still get a stable anonymized identity | | |
| 33 | +| 3 | *(none)* | If neither resolves, `identify()` is not called and the event carries no `distinct_id` | | |
| 34 | + | |
| 35 | +It is called from `get_default_event_properties()` — the single choke point every tracked event goes through. That placement is deliberate: | |
| 36 | + | |
| 37 | +- It reuses the `get_imagify_user()` result already needed for `license_owner` (transient-cached for 5 minutes), so no extra API call. | |
| 38 | +- It never runs on plugin bootstrap, unlike identifying in the constructor. | |
| 39 | + | |
| 40 | +A per-instance `identified` flag keeps it to one call per instance per request. | |
| 41 | + | |
| 42 | +> `distinct_id` is a Mixpanel super property, not an event property — it will not appear in `get_default_event_properties()` return values or in the `track_direct()` `$properties` argument. | |
| 20 | 43 | |
| 21 | 44 | --- |
| 22 | 45 | |
| 23 | 46 | ## Option key |