Lifecycle campaigns
Lifecycle campaigns turn membership state transitions into named email triggers. The hourly worker omembership/lifecycle/run is the only entry point; all email delivery is dispatched through OMailer (or any plugin listening on the events).
Triggers
The campaign coordinator is OMembership_Lifecycle. It listens on three membership events and runs four sweep methods on every tick.
Event-driven:
omem/membership/created-> dispatchesomem/lifecycle/welcomeomem/membership/cancelled-> dispatchesomem/lifecycle/cancelledomem/membership/expired-> dispatchesomem/lifecycle/expired
Scheduled (hourly):
phprun_renewal_reminders() // 30, 7, 1 days before period end
run_onboarding_nudges() // 1, 3, 7 days after start, if no lesson completed
run_reengagement() // 14, 30, 60 days since last_activity_at
run_winback() // 7, 30, 90 days since cancelled_atEach sweep queries memberships in a one-hour window so the same member is never targeted twice for the same campaign.
OMailer forwarding
OMembership_Integration_OMailer::init() (guarded by integrations.omailer) maps each event to a named campaign trigger:
| Lifecycle event | Forwarded as |
|---|---|
omem/lifecycle/welcome | omembership.welcome |
omem/lifecycle/onboarding_nudge (day N) | omembership.onboarding.day{N} |
omem/lifecycle/renewal_reminder (day N) | omembership.renewal.day{N} |
omem/lifecycle/reengagement (day N) | omembership.reengagement.day{N} |
omem/lifecycle/winback (day N) | omembership.winback.day{N} |
omem/drip/released | omembership.drip |
omem/certificate/issued | omembership.certificate |
OMailer renders the campaign template and delivers via your configured SMTP transport.
Building your own listener
Every lifecycle event is dispatched through OMembership_Events::dispatch(), which mirrors to do_action. Any plugin can subscribe:
phpadd_action( 'omem/lifecycle/renewal_reminder', function( array $membership, int $days_until ) {
// $membership is hydrated via OMembership_Memberships::hydrate()
// $days_until is 30, 7, or 1
notify_my_crm( $membership['user_id'], $days_until );
}, 10, 2 );Disabling
Set engagement.lifecycle_enabled to false to stop the hourly tick (events still fire when state transitions happen, but the scheduled sweeps stop running). Disable per-campaign by returning early from your hooks rather than touching the worker.

