agentsclimarketplace

Fluentcrm automation sequence models

Skill Lonsdale201/wp-agent-skills/fluentcrm/fluentcrm-automation-sequence-models

Work with FluentCRM 3.x automation subscriber state and FluentCampaign Pro email sequences. Covers FunnelSubscriber, FunnelSequence, FunnelProcessor, FunnelHelper, FunnelMetric, Pro Sequence, SequenceMail, and SequenceTracker. Use when enrolling a contact into an automation funnel, resuming from a benchmark, reading funnel progress, subscribing or unsubscribing contacts from Pro email sequences, or avoiding confusion between automation steps and email sequences. Triggers on FunnelSubscriber, FunnelSequence, startFunnelSequence, startFunnelFromSequencePoint, Sequence::subscribe, SequenceTracker, fc_funnel_subscribers, fc_sequence_tracker.From its SKILL.md

Install
npx -y skills add Lonsdale201/wp-agent-skills --skill fluentcrm-automation-sequence-models

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

10.2 KB, ~2.2k tokens by cl100k_base, as published. Nobody here has run it

FluentCRM: automation and email sequence models

Use this skill when code needs to start or inspect FluentCRM automations, or enroll contacts into FluentCampaign Pro email sequences. Keep these two systems separate: FunnelSequence is an automation step; FluentCampaign\App\Models\Sequence is a Pro email sequence stored in fc_campaigns.

Verification note: local source was FluentCRM core 3.1.8 and FluentCampaign Pro 3.1.8. Core 3.1.8 declares FLUENTCRM_MIN_PRO_VERSION as 3.1.8.

When to use this skill

  • Starting an automation funnel for a known contact or event.
  • Resuming a funnel from a benchmark sequence point.
  • Reading fc_funnel_subscribers progress, statuses, next sequence, or source metadata.
  • Enrolling or removing contacts from a Pro email sequence.
  • Reviewing code that writes directly to fc_funnel_subscribers, fc_funnel_sequences, or fc_sequence_tracker.

Automation data model

FluentCrm\App\Models\FunnelSubscriber maps fc_funnel_subscribers and tracks one contact inside one automation funnel.

Core fillable fields:

[
    'funnel_id',
    'subscriber_id',
    'status',
    'type',
    'next_sequence',
    'next_sequence_id',
    'last_sequence_id',
    'last_sequence_status',
    'last_executed_time',
    'next_execution_time',
    'starting_sequence_id',
    'source_trigger_name',
    'source_ref_id',
    'notes',
]

Common main statuses are draft, pending, active, waiting, completed, cancelled, and skipped. active() only scopes to status = active. Do not confuse the main status with last_sequence_status; FunnelHelper::changeFunnelSubSequenceStatus() writes last_sequence_status = complete when a normal step is processed. The benchmark direct-entry path can seed last_sequence_status = completed while creating a synthetic starting row; don't treat that as a value to write from action handlers.

Relations:

  • funnel() -> FluentCrm\App\Models\Funnel
  • subscriber() -> FluentCrm\App\Models\Subscriber
  • next_sequence_item() -> FunnelSequence
  • last_sequence() -> FunnelSequence
  • metrics() -> FunnelMetric rows for the same contact

FluentCrm\App\Models\FunnelSequence maps fc_funnel_sequences and represents a step in the automation builder. Important fields are funnel_id, parent_id, action_name, condition_type, type, status, conditions, settings, delay, c_delay, and sequence. The model serializes and unserializes settings and conditions.

Start a funnel safely

Do not directly insert FunnelSubscriber rows from a companion plugin. Use FunnelProcessor::startFunnelSequence(), which creates or finds the contact, handles pending/double-opt-in state, checks duplicates, creates the funnel subscriber, records the start hook, and processes immediate steps.

use FluentCrm\App\Models\Funnel;
use FluentCrm\App\Services\Funnel\FunnelProcessor;

if (!function_exists('FluentCrmApi')) {
    return;
}

$contact = FluentCrmApi('contacts')->getContactByUserRef($userId);
$funnel  = Funnel::where('id', (int) $funnelId)
    ->where('status', 'published')
    ->where('type', 'funnels')
    ->first();

if ($contact && $funnel) {
    (new FunnelProcessor())->startFunnelSequence($funnel, [], [
        'source_trigger_name' => 'my_plugin_event',
        'source_ref_id'      => (int) $eventId,
    ], $contact);
}

When you do not yet have a contact, pass subscriber data as the second argument:

(new FunnelProcessor())->startFunnelSequence($funnel, [
    'email'      => sanitize_email($email),
    'first_name' => sanitize_text_field($firstName),
    'status'     => 'subscribed',
], [
    'source_trigger_name' => 'my_plugin_event',
    'source_ref_id'      => (int) $eventId,
]);

Core manual attach uses the same pattern in SubscriberController: it filters contacts not already in the funnel and starts them with source_trigger_name => fcrm_manual_attach.

Duplicate and status guards

FunnelProcessor::startSequences() calls FunnelHelper::ifAlreadyInFunnel($funnelId, $subscriberId) and also relies on a unique DB constraint on (funnel_id, subscriber_id). Keep this path intact.

Processing later steps is status-gated. processFunnelAction() only processes contacts with status subscribed or transactional unless the funnel setting __force_run_actions is yes. Otherwise the funnel subscriber is marked cancelled.

The follow-up processor selects published funnels, due next_execution_time, and statuses from:

apply_filters('fluent_crm/funnel_subscriber_statuses', ['active']);

In 3.1.8 it also has batch controls:

  • fluent_crm/funnel_processor_batch_limit, default 200
  • fluent_crm/funnel_processor_max_processing_seconds, default 55

Resume from a benchmark

For benchmarks or goal-style entry points, use startFunnelFromSequencePoint($startSequence, $subscriber, $args, $metricArgs). It records a FunnelMetric, starts from the benchmark point if allowed, or advances an existing funnel subscriber when the target point is ahead of the current progress.

Do not create a new funnel subscriber manually for benchmark resumes. The processor handles:

  • can_enter = no
  • already completed or cancelled funnels
  • starting_sequence_id
  • last_sequence_id
  • next_sequence_id
  • pending contacts

recordFunnelMetric() uses FunnelMetric::firstOrCreate() and catches a race where another process inserted the metric between select and insert.

Read automation progress

Use ORM reads for reports and conditional logic:

use FluentCrm\App\Models\FunnelSubscriber;

$runs = FunnelSubscriber::where('subscriber_id', (int) $contactId)
    ->with(['funnel', 'next_sequence_item', 'last_sequence'])
    ->orderBy('id', 'DESC')
    ->get();

Prefer read-only access unless you are implementing FluentCRM internals. If you must update a run, update only state fields you own and do not skip the processor's hook path for executing actions.

Pro email sequences

FluentCampaign\App\Models\Sequence is a Pro email sequence. It maps fc_campaigns with a global scope type = email_sequence. Its child emails are SequenceMail rows, and each enrolled contact is tracked by SequenceTracker in fc_sequence_tracker.

Enroll contacts through Sequence::subscribe():

use FluentCampaign\App\Models\Sequence;
use FluentCampaign\App\Models\SequenceTracker;
use FluentCrm\App\Models\Subscriber;

$sequence = Sequence::find((int) $sequenceId);
$contact  = Subscriber::find((int) $contactId);

if ($sequence && $contact) {
    $already = SequenceTracker::where('campaign_id', $sequence->id)
        ->where('subscriber_id', $contact->id)
        ->first();

    if (!$already) {
        $sequence->subscribe([$contact]);
    }
}

Sequence::subscribe() loads SequenceMail rows ordered by delay, schedules first batch emails in fc_campaign_emails, parses subject/body smart codes with fluent_crm/parse_campaign_email_text, and creates or updates SequenceTracker.

Unsubscribe through the sequence model:

$sequence->unsubscribe([(int) $contactId], 'Removed by My Plugin');

This marks the tracker cancelled and cancels scheduled sequence emails. Do not delete SequenceTracker directly unless you intentionally want the admin-controller behavior, which removes tracker rows without cancelling scheduled emails.

SequenceTracker has a global scope type = sequence_tracker; status defaults to active. ofNextTrackers() selects active due trackers by next_execution_time <= current_time('mysql').

Common mistakes

  • Do not confuse FunnelSequence with FluentCampaign\App\Models\Sequence.
  • Do not insert into fc_funnel_subscribers for normal integrations; call FunnelProcessor.
  • Do not write completed through changeFunnelSubSequenceStatus() for normal action progress; that helper's default/canon is complete. Reserve completed for full automation run status and Pro email sequence tracker status.
  • Do not enroll a contact into an email sequence twice. Check SequenceTracker first.
  • Do not process unsubscribed contacts unless the funnel explicitly uses __force_run_actions.

Cross-references

  • Use fluentcrm-funnel-trigger when registering a new trigger in the automation builder.
  • Use fluentcrm-funnel-action for custom action step classes.
  • Use fluentcrm-funnel-benchmark for custom benchmark step classes.
  • Use fluentcrm-contact-models for contact/list/tag CRUD before starting automations.

References

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,851. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.