$npx -y skills add Lonsdale201/wp-agent-skills --skill fluentcrm-event-trackingTrack and consume FluentCRM 3.x contact events from companion plugins. Covers the experimental event_tracking flag, FluentCrmApi('event_tracker')->track(), fc_event_tracking, repeatable counter semantics, subscriber resolution by subscriber/email/user/current contact, fluent_crm/
| 1 | # FluentCRM: event tracking |
| 2 | |
| 3 | Use this skill when a plugin wants to record product usage, LMS actions, purchase milestones, profile events, or any other contact activity into FluentCRM's event timeline and Pro automation conditions. |
| 4 | |
| 5 | ## Guard the feature |
| 6 | |
| 7 | Event tracking is core FluentCRM code, but it is disabled by default behind the experimental setting: |
| 8 | |
| 9 | ```php |
| 10 | use FluentCrm\App\Services\Helper; |
| 11 | |
| 12 | if (!function_exists('FluentCrmApi') || !Helper::isExperimentalEnabled('event_tracking')) { |
| 13 | return; |
| 14 | } |
| 15 | ``` |
| 16 | |
| 17 | `FluentCrmApi('event_tracker')->track()` returns `WP_Error('not_enabled', ...)` when the flag is off. Always handle `WP_Error`. |
| 18 | |
| 19 | ## Track an event |
| 20 | |
| 21 | The API key is `event_tracker`: |
| 22 | |
| 23 | ```php |
| 24 | $event = FluentCrmApi('event_tracker')->track([ |
| 25 | 'subscriber_id' => (int) $contactId, // preferred when known |
| 26 | 'provider' => 'my-plugin', |
| 27 | 'event_key' => 'course_completed', |
| 28 | 'title' => 'Course completed', |
| 29 | 'value' => (string) $courseId, |
| 30 | ], true); |
| 31 | |
| 32 | if (is_wp_error($event)) { |
| 33 | return; |
| 34 | } |
| 35 | ``` |
| 36 | |
| 37 | Subscriber resolution order in `Tracker::track()`: |
| 38 | |
| 39 | - `subscriber` object, when supplied |
| 40 | - `subscriber_id` |
| 41 | - `email` |
| 42 | - `user_id` converted to the WP user's email |
| 43 | - current contact cookie / current user through `fluentcrm_get_current_contact()` |
| 44 | |
| 45 | Required fields are `event_key` and `title`. Both are truncated to 192 characters and sanitized. `provider` defaults to `custom`; `value` is sanitized as textarea text. |
| 46 | |
| 47 | ## Repeatable vs append-only |
| 48 | |
| 49 | Second argument controls storage behavior: |
| 50 | |
| 51 | ```php |
| 52 | FluentCrmApi('event_tracker')->track($data, true); // repeatable/default |
| 53 | FluentCrmApi('event_tracker')->track($data, false); // append a new row every time |
| 54 | ``` |
| 55 | |
| 56 | With `$repeatable = true`, FluentCRM looks up an existing row by `(subscriber_id, event_key, title)`, updates `value`, increments `counter`, saves, and fires `fluent_crm/event_tracked`. |
| 57 | |
| 58 | With `$repeatable = false`, it creates a new `fc_event_tracking` row every time and fires the same action. |
| 59 | |
| 60 | There is no unique DB key for the repeatable lookup in 3.1.8; the counter is application-level, not an atomic financial counter. Use it for automation/activity state, not exact billing/accounting. |
| 61 | |
| 62 | ## Action bridge |
| 63 | |
| 64 | `EventTrackingHandler` also registers: |
| 65 | |
| 66 | ```php |
| 67 | do_action('fluent_crm/track_event_activity', $data, $repeatable); |
| 68 | ``` |
| 69 | |
| 70 | That delegates to `FluentCrmApi('event_tracker')->track()`, but `do_action()` discards the return value. Use the API method directly when you need the created `EventTracker` or `WP_Error`. |
| 71 | |
| 72 | ## Event hook |
| 73 | |
| 74 | Every successful track fires: |
| 75 | |
| 76 | ```php |
| 77 | add_action('fluent_crm/event_tracked', function ($event, $subscriber) { |
| 78 | // $event is FluentCrm\App\Models\EventTracker |
| 79 | // $subscriber is FluentCrm\App\Models\Subscriber |
| 80 | }, 10, 2); |
| 81 | ``` |
| 82 | |
| 83 | FluentCampaign Pro's "Tracking Event Recorded" trigger listens to this exact hook with `actionArgNum = 2`. |
| 84 | |
| 85 | ## Pro automation trigger and action |
| 86 | |
| 87 | Pro trigger: `FluentCampaign\App\Services\Funnel\Triggers\TrackingEventRecordedTrigger` |
| 88 | |
| 89 | - `triggerName = fluent_crm/event_tracked` |
| 90 | - requires event tracking to be enabled |
| 91 | - only runs for contacts with `status = subscribed` |
| 92 | - checks configured `event_key` |
| 93 | - checks `minimum_event_count` against `EventTracker.counter` |
| 94 | - supports Pro condition groups through `fluent_crm/event_tracking_condition_groups` |
| 95 | - uses `source_trigger_name = fluent_crm/event_tracked` and `source_ref_id = $event->id` |
| 96 | |
| 97 | Pro action: `FluentCampaign\App\Services\Funnel\Actions\AddEventTrackerAction` |
| 98 | |
| 99 | - action name `add_contact_event_tracker` |
| 100 | - parses SmartCodes in title/value with `fluent_crm/parse_campaign_email_text` |
| 101 | - calls `FluentCrmApi('event_tracker')->track($eventAtts, is_unique === yes)` |
| 102 | |
| 103 | If you build a custom trigger/action around event tracking, still follow `fluentcrm-funnel-trigger` and `fluentcrm-funnel-action` for lifecycle and status rules. |
| 104 | |
| 105 | ## Contact filters and option source |
| 106 | |
| 107 | `EventTrackingHandler` registers the adv |