Claude Skill

fluentcrm-smartcodes-segments

Add and parse FluentCRM 3.x SmartCodes and build Pro dynamic contact segments. Covers the addSmartCode method of FluentCrmApi('extender'), parser syntax, fallback/default values, transformers, funnel context smart codes, dynamic segment filters, and ContactsQuery advanced filter

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download lonsdale201-wp-agent-skills-fluentcrm_fluentcrm-smartcodes-segments-52f6020.zip · 3 KB
Part of lonsdale201/wp-agent-skills — 226 skills

Install

skills CLI npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/fluentcrm/fluentcrm-smartcodes-segments
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
Git git clone https://github.com/Lonsdale201/wp-agent-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

FluentCRM: SmartCodes and dynamic segments

Use this skill when a plugin needs to expose custom values inside FluentCRM emails, automation fields, templates, or Pro dynamic segments. Keep SmartCode parsing read-only and privacy-aware; these values can appear in outgoing emails.

Verification note: SmartCode registration and parsing are core FluentCRM 3.1.13 behavior. Dynamic segments are Pro behavior verified against local FluentCampaign Pro 3.1.13.

When to use this skill

  • Adding custom merge tags such as {{my_plugin.plan_name}}.
  • Parsing personalized FluentCRM text outside the normal campaign send path.
  • Adding context SmartCodes to automation editors for order, booking, LMS, or other event data.
  • Registering a Pro dynamic segment or advanced contact filter provider.
  • Reviewing code that hooks fluent_crm/extended_smart_codes, fluent_crm/smartcode_group_callback_*, fluentcrm_dynamic_segments, or fluentcrm_contacts_filter_*.

Register SmartCodes

Use the public Extender API after FluentCRM init:

add_action('fluent_crm/after_init', function () {
    if (!function_exists('FluentCrmApi')) {
        return;
    }

    FluentCrmApi('extender')->addSmartCode(
        'my_plugin',
        'My Plugin',
        [
            'plan_name'    => 'Plan Name',
            'renewal_date' => 'Renewal Date',
        ],
        function ($code, $valueKey, $defaultValue, $subscriber) {
            $userId = $subscriber ? (int) $subscriber->getWpUserId() : 0;
            if (!$userId) {
                return $defaultValue;
            }

            if ($valueKey === 'plan_name') {
                return get_user_meta($userId, 'my_plugin_plan', true) ?: $defaultValue;
            }

            if ($valueKey === 'renewal_date') {
                $date = get_user_meta($userId, 'my_plugin_renewal_date', true);
                return $date ? date_i18n(get_option('date_format'), strtotime($date)) : $defaultValue;
            }

            return $defaultValue;
        }
    );
});

The API key is extender in app/Api/config.php. Extender.php has an older docblock mentioning extend; use the registered config key unless you have runtime-tested an alias.

addSmartCode() adds UI metadata through fluent_crm/extended_smart_codes and parser behavior through fluent_crm/smartcode_group_callback_{key}. Its callback signature is:

function ($code, $valueKey, $defaultValue, $subscriber) {
    return $defaultValue;
}

Do not use reserved group keys: crm, other, contact, wp, fluentcrm, user, learndash, tutorlms, aff_wp, edd_customer, lifterlms, woo_customer.

Parser behavior

FluentCRM parses both syntaxes:

{{group.key}}
##group.key##

Defaults use one pipe:

{{contact.first_name|Friend}}

Transformers use double pipe:

{{contact.first_name||ucfirst}}
{{contact.email||strtolower}}

Supported local transformers in 3.1.13 include trim, ucfirst, strtolower, strtoupper, ucwords, concat_first, concat_last, and show_if.

When rendering custom text yourself, use the same filter FluentCRM uses:

$body = apply_filters('fluent_crm/parse_campaign_email_text', $body, $subscriber);

or call the parser directly:

use FluentCrm\App\Services\Libs\Parser\Parser;

$body = Parser::parse($body, $subscriber);

Do not manually replace CRM unsubscribe and manage-subscription URLs early. ShortcodeParser intentionally leaves crm.unsubscribe_url, crm.manage_subscription_url, crm.unsubscribe_html, and crm.manage_subscription_html for a later parsing pass in email/external-page flows.

Funnel context SmartCodes

Use fluent_crm_funnel_context_smart_codes when a SmartCode should appear only for specific automation trigger contexts.

add_filter('fluent_crm_funnel_context_smart_codes', function ($codes, $triggerName, $funnel) {
    if ($triggerName !== 'my_plugin_event') {
        return $codes;
    }

    $codes[] = [
        'key'        => 'my_event',
        'title'      => 'My Event',
        'shortcodes' => [
            '{{my_event.name}}' => 'Event Name',
            '{{my_event.id}}'   => 'Event ID',
        ],
    ];

    return $codes;
}, 10, 3);

If context values depend on the current automation run, parse through your group callback and read $subscriber->funnel_subscriber_id when available. Built-in Woo parsers load FunnelSubscriber::find($subscriber->funnel_subscriber_id) and use source_trigger_name plus source_ref_id to resolve the current order or subscription. Always return $defaultValue if context is missing.

Dynamic segments

Dynamic segments are Pro features. Register visible segment metadata with fluentcrm_dynamic_segments, and return a Subscriber-shaped query model from fluentcrm_dynamic_segment_{slug} when called with model => true.

use FluentCrm\App\Models\Subscriber;

add_filter('fluentcrm_dynamic_segments', function ($segments) {
    $segments[] = [
        'id'          => 0,
        'slug'        => 'my_plugin_vip',
        'title'       => 'My Plugin VIP Contacts',
        'subtitle'    => 'Contacts with VIP flag in My Plugin',
        'is_system'   => true,
        'description' => 'Dynamic segment from My Plugin data.',
    ];

    return $segments;
});

add_filter('fluentcrm_dynamic_segment_my_plugin_vip', function ($segment, $segmentId, $config) {
    $model = Subscriber::where('status', 'subscribed')
        ->where('source', 'my-plugin');

    $segment = [
        'id'          => $segmentId,
        'slug'        => 'my_plugin_vip',
        'title'       => 'My Plugin VIP Contacts',
        'is_system'   => true,
        'description' => 'Dynamic segment from My Plugin data.',
    ];

    if (!empty($config['model'])) {
        $segment['model'] = $model;
    }

    if (!empty($config['contact_count'])) {
        $segment['contact_count'] = $model->count();
    }

    if (!empty($config['subscribers'])) {
        $segment['subscribers'] = !empty($config['paginate'])
            ? $model->paginate()
            : $model->get();
    }

    return $segment;
}, 10, 3);

Return an ORM query builder for model, not an array of contacts. DynamicSegmentController will add with(['tags', 'lists']), search, optional commerce relation, allowlisted sort, custom fields, and pagination.

Campaign sending applies where('status', 'subscribed') to dynamic-segment models before selecting contacts. Admin previews may request other statuses depending on the UI path.

Advanced filter providers

ContactsQuery dispatches advanced filter providers with:

do_action_ref_array('fluentcrm_contacts_filter_' . $providerName, [&$q, $items]);

Register a provider by mutating the query by reference:

add_action('fluentcrm_contacts_filter_my_plugin', function (&$query, $items) {
    foreach ((array) $items as $item) {
        $property = sanitize_key($item['property'] ?? '');
        $operator = sanitize_key($item['operator'] ?? '');
        $value    = $item['value'] ?? null;

        if ($property === 'vip' && $operator === '=') {
            $query->where('source', $value === 'yes' ? 'my-plugin-vip' : 'my-plugin');
        }
    }
}, 10, 2);

Keep provider SQL bounded and allowlist every property/operator. Do not interpolate request data into raw SQL.

Safety checklist

  • Return defaults for missing contacts, missing users, deleted orders, missing funnel runs, or disabled dependencies.
  • Escape output at the final render boundary if you print parsed values in admin or frontend HTML.
  • Do not expose private user meta or tokens through SmartCodes unless the email recipient is allowed to see them.
  • Keep SmartCode callbacks fast; they may run once per recipient per field.
  • Do not parse unsubscribe/manage URLs outside FluentCRM's send/external-page flow unless you know the target object has the required email/contact context.

Cross-references

  • Use fluentcrm-contact-models for Subscriber, Lists, Tag, User, and ContactsQuery basics.
  • Use fluentcrm-automation-sequence-models when SmartCodes depend on FunnelSubscriber source metadata.
  • Use fluentcrm-rest-options for editor picker option lists.

References

Files (wp-agent-skills)
  • SKILL.md 9.7 KB
    ---
    name: fluentcrm-smartcodes-segments
    description: Add and parse FluentCRM 3.x SmartCodes and build Pro dynamic contact segments. Covers the addSmartCode method of FluentCrmApi('extender'), parser syntax, fallback/default values, transformers, funnel context smart codes, dynamic segment filters, and ContactsQuery advanced filter providers. Use when a plugin exposes custom merge tags, parses personalized text, adds automation context values, registers dynamic segments, or extends advanced contact filtering. Triggers on addSmartCode, fluent_crm/extended_smart_codes, fluent_crm/smartcode_group_callback_, Parser::parse, fluent_crm_funnel_context_smart_codes, fluentcrm_dynamic_segments, fluentcrm_dynamic_segment_, fluentcrm_contacts_filter_.
    metadata:
      wp-skills-author: "Soczó Kristóf"
      wp-skills-contact: "mailto:lonsdale201@hotmail.com"
      wp-skills-plugin: "fluent-crm"
      wp-skills-plugin-version-tested: "3.1.13"
      wp-skills-wp-version-tested: "7.1"
      wp-skills-php-min: "7.4"
      wp-skills-last-updated: "2026-08-25"
    ---
    
    # FluentCRM: SmartCodes and dynamic segments
    
    Use this skill when a plugin needs to expose custom values inside FluentCRM emails, automation fields, templates, or Pro dynamic segments. Keep SmartCode parsing read-only and privacy-aware; these values can appear in outgoing emails.
    
    Verification note: SmartCode registration and parsing are core FluentCRM 3.1.13 behavior. Dynamic segments are Pro behavior verified against local FluentCampaign Pro 3.1.13.
    
    ## When to use this skill
    
    - Adding custom merge tags such as `{{my_plugin.plan_name}}`.
    - Parsing personalized FluentCRM text outside the normal campaign send path.
    - Adding context SmartCodes to automation editors for order, booking, LMS, or other event data.
    - Registering a Pro dynamic segment or advanced contact filter provider.
    - Reviewing code that hooks `fluent_crm/extended_smart_codes`, `fluent_crm/smartcode_group_callback_*`, `fluentcrm_dynamic_segments`, or `fluentcrm_contacts_filter_*`.
    
    ## Register SmartCodes
    
    Use the public Extender API after FluentCRM init:
    
    ```php
    add_action('fluent_crm/after_init', function () {
        if (!function_exists('FluentCrmApi')) {
            return;
        }
    
        FluentCrmApi('extender')->addSmartCode(
            'my_plugin',
            'My Plugin',
            [
                'plan_name'    => 'Plan Name',
                'renewal_date' => 'Renewal Date',
            ],
            function ($code, $valueKey, $defaultValue, $subscriber) {
                $userId = $subscriber ? (int) $subscriber->getWpUserId() : 0;
                if (!$userId) {
                    return $defaultValue;
                }
    
                if ($valueKey === 'plan_name') {
                    return get_user_meta($userId, 'my_plugin_plan', true) ?: $defaultValue;
                }
    
                if ($valueKey === 'renewal_date') {
                    $date = get_user_meta($userId, 'my_plugin_renewal_date', true);
                    return $date ? date_i18n(get_option('date_format'), strtotime($date)) : $defaultValue;
                }
    
                return $defaultValue;
            }
        );
    });
    ```
    
    The API key is `extender` in `app/Api/config.php`. `Extender.php` has an older docblock mentioning `extend`; use the registered config key unless you have runtime-tested an alias.
    
    `addSmartCode()` adds UI metadata through `fluent_crm/extended_smart_codes` and parser behavior through `fluent_crm/smartcode_group_callback_{key}`. Its callback signature is:
    
    ```php
    function ($code, $valueKey, $defaultValue, $subscriber) {
        return $defaultValue;
    }
    ```
    
    Do not use reserved group keys: `crm`, `other`, `contact`, `wp`, `fluentcrm`, `user`, `learndash`, `tutorlms`, `aff_wp`, `edd_customer`, `lifterlms`, `woo_customer`.
    
    ## Parser behavior
    
    FluentCRM parses both syntaxes:
    
    ```text
    {{group.key}}
    ##group.key##
    ```
    
    Defaults use one pipe:
    
    ```text
    {{contact.first_name|Friend}}
    ```
    
    Transformers use double pipe:
    
    ```text
    {{contact.first_name||ucfirst}}
    {{contact.email||strtolower}}
    ```
    
    Supported local transformers in 3.1.13 include `trim`, `ucfirst`, `strtolower`, `strtoupper`, `ucwords`, `concat_first`, `concat_last`, and `show_if`.
    
    When rendering custom text yourself, use the same filter FluentCRM uses:
    
    ```php
    $body = apply_filters('fluent_crm/parse_campaign_email_text', $body, $subscriber);
    ```
    
    or call the parser directly:
    
    ```php
    use FluentCrm\App\Services\Libs\Parser\Parser;
    
    $body = Parser::parse($body, $subscriber);
    ```
    
    Do not manually replace CRM unsubscribe and manage-subscription URLs early. `ShortcodeParser` intentionally leaves `crm.unsubscribe_url`, `crm.manage_subscription_url`, `crm.unsubscribe_html`, and `crm.manage_subscription_html` for a later parsing pass in email/external-page flows.
    
    ## Funnel context SmartCodes
    
    Use `fluent_crm_funnel_context_smart_codes` when a SmartCode should appear only for specific automation trigger contexts.
    
    ```php
    add_filter('fluent_crm_funnel_context_smart_codes', function ($codes, $triggerName, $funnel) {
        if ($triggerName !== 'my_plugin_event') {
            return $codes;
        }
    
        $codes[] = [
            'key'        => 'my_event',
            'title'      => 'My Event',
            'shortcodes' => [
                '{{my_event.name}}' => 'Event Name',
                '{{my_event.id}}'   => 'Event ID',
            ],
        ];
    
        return $codes;
    }, 10, 3);
    ```
    
    If context values depend on the current automation run, parse through your group callback and read `$subscriber->funnel_subscriber_id` when available. Built-in Woo parsers load `FunnelSubscriber::find($subscriber->funnel_subscriber_id)` and use `source_trigger_name` plus `source_ref_id` to resolve the current order or subscription. Always return `$defaultValue` if context is missing.
    
    ## Dynamic segments
    
    Dynamic segments are Pro features. Register visible segment metadata with `fluentcrm_dynamic_segments`, and return a Subscriber-shaped query model from `fluentcrm_dynamic_segment_{slug}` when called with `model => true`.
    
    ```php
    use FluentCrm\App\Models\Subscriber;
    
    add_filter('fluentcrm_dynamic_segments', function ($segments) {
        $segments[] = [
            'id'          => 0,
            'slug'        => 'my_plugin_vip',
            'title'       => 'My Plugin VIP Contacts',
            'subtitle'    => 'Contacts with VIP flag in My Plugin',
            'is_system'   => true,
            'description' => 'Dynamic segment from My Plugin data.',
        ];
    
        return $segments;
    });
    
    add_filter('fluentcrm_dynamic_segment_my_plugin_vip', function ($segment, $segmentId, $config) {
        $model = Subscriber::where('status', 'subscribed')
            ->where('source', 'my-plugin');
    
        $segment = [
            'id'          => $segmentId,
            'slug'        => 'my_plugin_vip',
            'title'       => 'My Plugin VIP Contacts',
            'is_system'   => true,
            'description' => 'Dynamic segment from My Plugin data.',
        ];
    
        if (!empty($config['model'])) {
            $segment['model'] = $model;
        }
    
        if (!empty($config['contact_count'])) {
            $segment['contact_count'] = $model->count();
        }
    
        if (!empty($config['subscribers'])) {
            $segment['subscribers'] = !empty($config['paginate'])
                ? $model->paginate()
                : $model->get();
        }
    
        return $segment;
    }, 10, 3);
    ```
    
    Return an ORM query builder for `model`, not an array of contacts. `DynamicSegmentController` will add `with(['tags', 'lists'])`, search, optional commerce relation, allowlisted sort, custom fields, and pagination.
    
    Campaign sending applies `where('status', 'subscribed')` to dynamic-segment models before selecting contacts. Admin previews may request other statuses depending on the UI path.
    
    ## Advanced filter providers
    
    `ContactsQuery` dispatches advanced filter providers with:
    
    ```php
    do_action_ref_array('fluentcrm_contacts_filter_' . $providerName, [&$q, $items]);
    ```
    
    Register a provider by mutating the query by reference:
    
    ```php
    add_action('fluentcrm_contacts_filter_my_plugin', function (&$query, $items) {
        foreach ((array) $items as $item) {
            $property = sanitize_key($item['property'] ?? '');
            $operator = sanitize_key($item['operator'] ?? '');
            $value    = $item['value'] ?? null;
    
            if ($property === 'vip' && $operator === '=') {
                $query->where('source', $value === 'yes' ? 'my-plugin-vip' : 'my-plugin');
            }
        }
    }, 10, 2);
    ```
    
    Keep provider SQL bounded and allowlist every property/operator. Do not interpolate request data into raw SQL.
    
    ## Safety checklist
    
    - Return defaults for missing contacts, missing users, deleted orders, missing funnel runs, or disabled dependencies.
    - Escape output at the final render boundary if you print parsed values in admin or frontend HTML.
    - Do not expose private user meta or tokens through SmartCodes unless the email recipient is allowed to see them.
    - Keep SmartCode callbacks fast; they may run once per recipient per field.
    - Do not parse unsubscribe/manage URLs outside FluentCRM's send/external-page flow unless you know the target object has the required email/contact context.
    
    ## Cross-references
    
    - Use `fluentcrm-contact-models` for Subscriber, Lists, Tag, User, and ContactsQuery basics.
    - Use `fluentcrm-automation-sequence-models` when SmartCodes depend on `FunnelSubscriber` source metadata.
    - Use `fluentcrm-rest-options` for editor picker option lists.
    
    ## References
    
    - Local source: `Extender.php`, `ShortcodeParser.php`, `FunnelController.php`, `DynamicSegmentController.php`, `CustomSegment.php`, and `ContactsQuery.php`.
    - FluentCRM docs: Smart Codes, Parser, and Fluent ORM.
    - Official documentation: <https://developers.fluentcrm.com/modules/smart-code>
    - Official documentation: <https://developers.fluentcrm.com/helpers/parser>
    - Official documentation: <https://developers.fluentcrm.com/database/orm/>
    - Verified source paths:
      - `fluent-crm/app/Api/config.php`
      - `fluent-crm/app/Hooks/filters.php`
      - `fluent-crm/app/Services/Helper.php`
      - `fluentcampaign-pro/app/Services/DynamicSegments/BaseSegment.php`
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related