fluentcrm-overview
FluentCRM拡張機能開発向けのスキルです。Free/Pro分割構成(FluentCRM = ファネルベース; FluentCampaign Pro = 統合機能・高度なアクション/ベンチマーク)、プラグインパスと定数、ブートストラップ順序(fluentcrm_loaded → fluentcrm_addons_loaded → fluent_crm/after_init)、モデル層(Subscriber、Funnel、FunnelSequence、FunnelSubscriber、FunnelMetric)、グローバルヘルパー(FluentCrmApi、fluentCrmDb、FunnelHelper)、コンタクトライフサイクルフック(fluent_crm/contact_created、_updated、_email_changed、_custom_data_updated)、スマートコード拡張フィルター(fluent_crm/extended_smart_codes)、適切な拡張コントラクトを選択するための判定マトリックスをカバーしています。新しいFluentCRM統合をスキャフォールディングする場合、拡張するコントラクトを選択する場合、または機能の配置場所を確認する場合に使用します。
description の原文を見る
Orient skill for FluentCRM extension development. Covers the Free / Pro split (FluentCRM = funnel chassis; FluentCampaign Pro = integrations + advanced actions / benchmarks), plugin paths and constants, the bootstrap order (fluentcrm_loaded → fluentcrm_addons_loaded → fluent_crm/after_init), the model layer (Subscriber, Funnel, FunnelSequence, FunnelSubscriber, FunnelMetric), the global helpers (FluentCrmApi, fluentCrmDb, FunnelHelper), the contact lifecycle hooks (fluent_crm/contact_created, _updated, _email_changed, _custom_data_updated), the smart-code extension filter (fluent_crm/extended_smart_codes), and a decision matrix for picking the right extension contract. Use when scaffolding a new FluentCRM integration, choosing which contract to extend, or asking where things live. Triggers on FluentCrmApi, fluentCrmDb, FunnelHelper, fluent_crm/contact_, fluent_crm/extended_smart_codes, FLUENTCRM, FLUENTCAMPAIGN.
SKILL.md 本文
FluentCRM: 開発者向けガイド
FluentCRM拡張機能を新しく始める際、またはどの契約を拡張すべきかまだ決まっていない場合は、まずこのスキルを選びましょう。これは概要層です。個別の拡張ポイントについての詳細は教えず、ファイルマップを示して、さらに詳しい専門スキル(fluentcrm-funnel-trigger、fluentcrm-funnel-action、fluentcrm-funnel-benchmark、fluentcrm-rest-options)へ導きます。
プラグインの識別情報
| フィールド | 値 | ソース |
|---|---|---|
| スラッグ | fluent-crm | ヘッダー |
| バージョン | 2.9.87 | fluent-crm.php:6 |
| Pro スラッグ | fluentcampaign-pro | ヘッダー |
| Pro バージョン | 2.9.86 | fluentcampaign-pro.php |
| ブートコンスタント | FLUENTCRM ('fluentcrm') | fluent-crm.php:20 |
| Pro コンスタント | FLUENTCAMPAIGN_PLUGIN_VERSION | fluentcampaign-pro.php |
| パスコンスタント (Free) | FLUENTCRM_PLUGIN_PATH | fluent-crm.php:22 |
| パスコンスタント (Pro) | FLUENTCAMPAIGN_PLUGIN_PATH | fluentcampaign-pro.php:20 |
| 最小 PHP バージョン (検証済み) | 7.4 | composer.json |
アクティベーション検出 — class_exists('FluentCRM') でテストしないでください(そのようなクラスは存在しません)。以下を使用します:
public static function isFluentCRMActive(): bool {
return defined('FLUENTCRM');
}
public static function isFluentCRMProActive(): bool {
return defined('FLUENTCAMPAIGN_PLUGIN_VERSION')
&& version_compare(FLUENTCAMPAIGN_PLUGIN_VERSION, '2.8.0', '>=');
}
(2.8.0 の下限は、BaseTrigger / BaseAction ライフサイクルの安定性ポイントです。コードがモデルAPIのみを使用する場合は削除できます。)
他のプラグイン向けアクティベーション検出の標準(読み込み順序の罠)
トリガー / アクション / ベンチマークは fluentcrm_loaded:5 に登録され、これは FluentCRM 自身の plugins_loaded:10 コールバックから発火します。登録機能内のすべての依存関係チェックは、その時点で実行され — ファイル読み込み時に宣言されたシンボルのみが 保証されます。WordPress は plugins_loaded:10 コールバックをプラグイン登録順序で実行し(インストール間で非決定的)、別のプラグインの plugins_loaded コールバック内部で設定されたシンボルはレースコンディションの危険があります。
安全 (ファイル読み込み時に宣言 — トップレベルスコープ、条件付き require なし):
| プラグイン | 使用方法 | 理由 |
|---|---|---|
| WooCommerce | class_exists('WooCommerce') | woocommerce.php はファイルスコープで class-woocommerce.php をインクルードします |
| FluentCampaign Pro | defined('FLUENTCAMPAIGN_PLUGIN_VERSION') | fluentcampaign-pro.php はファイルスコープで fluentcampaign_boot.php を require し、その中でコンスタントを define() します |
| WC Memberships | class_exists('WC_Memberships_Loader') | トップレベルのローダークラス、WC_Memberships 自体は init_plugin() 内で読み込まれレースコンディションの危険があります |
| LW LMS | class_exists('LightweightPlugins\\LMS\\Plugin') | オートローダーはファイルスコープで登録されます |
| Jet Engine | class_exists('Jet_Engine') | トップレベルのクラス宣言 |
非安全 (依存関係自体のコールバック内で宣言 — 登録時に使用しないでください):
// 間違い — wc_memberships() 関数は Memberships の
// plugins_loaded:10 コールバック内で宣言されます。登録機能が
// Memberships のコールバックより前に実行された場合、
// function_exists は false を返し、アクションはエディターから
// サイレントに除外されます。
return function_exists('wc_memberships');
// 正解 — WC_Memberships_Loader はファイルスコープにあります。
return class_exists('WC_Memberships_Loader');
依存関係のメインオブジェクトが初期化後にのみ存在する場合は、テスト対象となるトップレベルのローダー/登録機能を見つけてください(すべての形式の整ったプラグインは1つ持っています)。
Free vs Pro 一覧
| 機能 | Free (FluentCRM) | Pro (FluentCampaign) |
|---|---|---|
| 連絡先、リスト、タグ、セグメント | あり | あり |
| メールキャンペーン、シーケンス、テンプレート | あり | あり |
| フォーム、オプトイン | あり | あり |
| ファネル トリガー (BaseTrigger) | あり — 任意のプラグインから登録可能 | あり — 多数の組み込み (Tutor、LearnDash、LifterLMS、EDD、WishlistMember、AffiliateWP、Woo Subscriptions) |
| ファネル アクション (BaseAction) | あり — 任意のプラグインから登録可能 | あり — 多数の組み込み (高度な Woo、シーケンス追加/削除、カスタムフィールド更新) |
| ファネル ベンチマーク (BaseBenchMark) | あり — 任意のプラグインから登録可能 | あり — 追加の組み込み |
| 条件分岐 / A-B テストノード | いいえ | あり |
| 企業モジュール | あり | あり |
| Webhook 受信/送信 | あり | あり |
| SMTP / メールドライバーレイヤー | Free は WP mail / Fluent SMTP を使用 | Pro は高度なレポート機能を追加 |
4つの拡張契約(トリガー、アクション、ベンチマーク、スマートコード)は すべて Free に含まれます。Pro は主に組み込み統合 + UI機能です。Free を拡張するコンパニオンプラグインは Pro に対しても自動的に機能します。
ブートストラップ順序
plugins_loaded:10 ← プラグインがブートストラップをインスタンス化
↓
fluentcrm_loaded ← boot/app.php:41 から do_action('fluentcrm_loaded')
トリガー / アクション / ベンチマークをここに登録 (priority < 10)
FluentCampaign Pro の IntegrationHandler もここで実行
↓
fluentcrm_addons_loaded ← boot/app.php:42 から do_action('fluentcrm_addons_loaded')
FunnelHandler::handle が実行 (actions.php:76)
→ fluentcrm_funnel_settings オプションを読み込み
→ 保存されたトリガー名ごとに:
$argNum = apply_filters('fluentcrm_funnel_arg_num_'.$name, 1)
add_action($name, ..., 10, $argNum) ← ロック
↓
init:1000 ← boot/app.php:44-46 から do_action('fluent_crm/after_init')
argNum フィルターには遅すぎる
↓
... ランタイムイベントが発火 ...
唯一のタイミング規則 — すべてのトリガー / アクション / ベンチマークを fluentcrm_loaded 優先度 < 10 で登録します。fluent_crm/after_init または init にフックすると、マルチ引数が静かに削除されます。説明は fluentcrm-funnel-trigger を参照してください。
ファイルマップ
fluent-crm/
├── fluent-crm.php ← ヘッダー + ブートストラップエントリ
├── boot/
│ ├── app.php ← フレームワーク初期化、fluentcrm_loaded / addons_loaded ディスパッチ
│ └── …
├── app/
│ ├── Api/
│ │ ├── Classes/Extender.php ← 公開API面 (スマートコード拡張機能、連絡先API)
│ │ └── Classes/Contact.php ← fluentCrmApi('contacts') バックエンド
│ ├── Functions/helpers.php ← FluentCrmApi()、fluentCrmDb()、fluentCrmTimestamp() など
│ ├── Hooks/
│ │ ├── actions.php ← 組み込み `add_action` 登録
│ │ ├── filters.php
│ │ └── Handlers/ ← Funnel、Subscriber、Campaign など のハンドラー
│ ├── Http/Controllers/ ← REST エンドポイント (FunnelController、OptionsController など)
│ ├── Models/ ← Subscriber、Funnel、FunnelSequence など
│ ├── Services/
│ │ ├── Funnel/
│ │ │ ├── BaseTrigger.php
│ │ │ ├── BaseAction.php
│ │ │ ├── BaseBenchMark.php
│ │ │ ├── FunnelProcessor.php
│ │ │ └── FunnelHelper.php
│ │ ├── Helper.php
│ │ └── Libs/Parser/ ← スマートコードパーサー
│ └── Views/
└── ...
fluentcampaign-pro/
├── fluentcampaign-pro.php
└── app/
├── Hooks/Handlers/IntegrationHandler.php ← initFunnelActions / initBenchmarks / initTriggers
└── Services/Integrations/
├── TutorLms/CourseEnrollTrigger.php ← 標準的なトリガー参照
├── TutorLms/AddToCourseAction.php ← 標準的なアクション参照
├── WooCommerce/ ← 深い Woo 統合
├── LearnDash/, LifterLms/, EDD/, AffiliateWP/, WishlistMember/
└── …
使用するモデル
| モデル | クラス | 注記 |
|---|---|---|
| Subscriber | FluentCrm\App\Models\Subscriber | コア連絡先。getWpUserId()、tags、lists、email、status |
| Funnel | FluentCrm\App\Models\Funnel | 自動化。status ∈ {published, draft, archived} |
| FunnelSequence | FluentCrm\App\Models\FunnelSequence | ファネル内の手順。action_name がブロックにキー付け。type ∈ {action, benchmark, conditional} |
| FunnelSubscriber | FluentCrm\App\Models\FunnelSubscriber | 結合:連絡先 <-> ファネル。現在のシーケンス位置を追跡 |
| FunnelMetric | FluentCrm\App\Models\FunnelMetric | ステップごとの監査行。status ∈ {pending, complete, skipped, failed} |
| Tag | FluentCrm\App\Models\Tag | SubscriberPivot 経由で Subscriber と多対多の関係 |
| Lists | FluentCrm\App\Models\Lists | 同じ |
| Webhook | FluentCrm\App\Models\Webhook | インバウンド webhook 受信機 |
ステータス文字列の標準は 'complete'、'completed' ではありません — 詳細は fluentcrm-funnel-action を参照してください。
グローバルヘルパー
// API面 — 直接モデル書き込みより推奨
FluentCrmApi('contacts')->createOrUpdate($data);
FluentCrmApi('contacts')->getContact($emailOrId);
// データベースクエリビルダー — Eloquent をバイパスしてraw クエリ実行
fluentCrmDb()->table('fc_subscribers')->where('email', $email)->first();
// FunnelHelper — コンパニオンプラグインから最も使用される単一のユーティリティ
FunnelHelper::prepareUserData($wpUserId); // $subscriberData スケルトンを構築
FunnelHelper::getSubscriber($emailOrUserId); // Subscriber モデルを解決
FunnelHelper::ifAlreadyInFunnel($funnelId, $subId); // 重複排除ガード
FunnelHelper::removeSubscribersFromFunnel($funnelId, $subIds); // リスタートヘルパー
FunnelHelper::getUpdateOptions(); // 標準的な「存在する場合」ラジオオプション
FunnelHelper::changeFunnelSubSequenceStatus($funnelSubId, $sequenceId, 'complete');
FunnelHelper::maybeExplodeFullName($subscriberData); // "John Doe" → 名/姓に分割
FunnelHelper::createWpUserFromSubscriber($subscriber, $sendWelcomeEmail);
FluentCrmApi、fluentCrmDb、FluentCrm (サービスコンテナ) はすべて helpers.php で定義されています。
連絡先ライフサイクルフック
連絡先の状態が変わるたびに、レガシーアンダースコア名アクション と 新しいスラッシュ名アクション(2.8で導入)の両方が発火します。新しいコードではスラッシュ版をフックします。アンダースコア版は非推奨ですが、後方互換性のためにまだ発火します:
| 最新フック | レガシーエイリアス (非推奨) | 引数 | ソース |
|---|---|---|---|
fluent_crm/contact_created | fluentcrm_contact_created | $subscriber | Subscriber.php:970-971, 1145-1146 |
fluent_crm/contact_updated | fluentcrm_contact_updated | $subscriber, $dirtyFields | Subscriber.php:1006-1007, 1148 |
fluent_crm/contact_email_changed | (エイリアスなし) | $subscriber, $oldEmail | Subscriber.php:1095 |
fluent_crm/contact_custom_data_updated | fluentcrm_contact_custom_data_updated | $newValues, $subscriber, $updateValues | Subscriber.php:669-670 |
ファネルに依存せずに購読者の状態に反応する必要があるときに便利です。たとえば、連絡先データを外部CRMにミラーリングします。
スマートコード拡張
{{my_plugin.foo}} のようなカスタムテンプレートタグは、fluent_crm/extended_smart_codes フィルター経由で登録されます (Helper.php:329、Extender.php:108)。Extender API:
FluentCrmApi('extender')->addSmartCode(
'my_plugin', // 名前空間キー
__('My Plugin Tokens', 'my-plugin'), // グループタイトル
[
'my_plugin.contact_score' => 'Contact Score',
'my_plugin.last_purchase' => 'Last Purchase Date',
],
function ($code, $valueKey, $defaultValue, $subscriber) {
// $subscriber に対して $valueKey を解決します。文字列を返します。
if ($valueKey === 'contact_score') {
return (string) get_user_meta($subscriber->user_id, 'my_score', true);
}
return $defaultValue;
}
);
スマートコードはメール レンダー時に評価され、「カスタムフィールドの更新」などのアクション用の動的フィールドトークン内でも評価されます。不明なコードのフォールバックは apply_filters('fluentcrm_smartcode_fallback', $matches[0], $subscriber) です — レガシーな {{tag}} 形式に便利です。
ファネルレイヤーアーキテクチャ
┌──────────────────────────────────────────┐
│ トリガーが発火 (実際の WP アクション) │
│ 例: lw_lms_after_grant、tutor_after_ │
│ enrolled、woocommerce_new_order │
└────────────────────┬─────────────────────┘
│
┌────────────────────▼─────────────────────┐
│ FunnelHandler::mapTriggers │
│ (FunnelHandler.php:105-141) │
│ - マッチする trigger_name を持つ │
│ 公開ファネルを検索 │
│ - fluentcrm_funnel_start_* をディスパッチ│
│ - マッチする action_name を持つ │
│ 公開 BENCHMARK シーケンスを検索 │
│ - fluentcrm_funnel_benchmark_ │
│ start_* をディスパッチ │
└────────┬──────────────────────┬──────────┘
│ │
┌──────────▼──────────┐ ┌────────▼──────────┐
│ BaseTrigger::handle │ │ BaseBenchMark:: │
│ → startFunnelSequ- │ │ handle │
│ ence (新規実行) │ │ → startFunnelFrom │
│ │ │ SequencePoint │
│ │ │ (再開) │
└──────────┬──────────┘ └────────┬──────────┘
│ │
┌────▼──────────────────────▼────┐
│ FunnelProcessor::processSequence│
│ (シーケンスステップをループ) │
│ - シーケンスタイプ 'action' │
│ → fluentcrm_funnel_ │
│ sequence_handle_* │
│ → BaseAction::handle() │
│ - シーケンスタイプ 'benchmark'│
│ → 待機 │
│ - シーケンスタイプ 'conditional'│
│ → 分岐 (Pro) │
└─────────────────────────────────┘
決定マトリックス — 適切な契約を選択
| やりたいこと | 拡張する |
|---|---|
| X が発生したときに自動化を開始する | トリガー — fluentcrm-funnel-trigger |
| シーケンスステップで連絡先の作業を実行する | アクション — fluentcrm-funnel-action |
| X が発生するまでファネルを一時停止してから再開する | ベンチマーク — fluentcrm-funnel-benchmark |
| 上記のいずれかにマルチセレクトピッカーフィールドを追加する | REST オプションフィルター — fluentcrm-rest-options |
{{my_code.foo}} テンプレートタグを追加する | スマートコード拡張機能 — 上記の「スマートコード拡張」を参照 |
| ファネルなしで連絡先の状態に反応する | 連絡先ライフサイクルフック — 上記の表を参照 |
| カスタム REST エンドポイントを追加する | WP REST API — FluentCRM に特別なラッパーはありません。register_rest_route を使用します |
| カスタム連絡先フィールドを追加する | FluentCRM 管理画面 → 設定 → 連絡先カスタムフィールド。コードパスなし。 |
重要なルール
- トリガー / アクション / ベンチマーク登録に対して必ず
fluentcrm_loaded優先度 < 10 をフックしてください。 最も一般的なタイミングの罠です。 - アクションとベンチマークの
getBlock()に必ず'settings'をシードしてください。getBlockFields()['fields']キーごとに1つのキーです。これなしだとエディターが空のパネルをレンダリングし、JS コンソールがTypeError: Cannot read properties of undefinedをスローします。トリガーはこの罠を持っていません(デフォルトは抽象getFunnelSettingsDefaults()/getFunnelConditionDefaults()メソッドから来ます)。 - ステータス文字列の標準は
'complete'(not'completed')です。すべてのchangeFunnelSubSequenceStatusと$funnelMetric->statusに適用されます。 ->user_idではなくgetWpUserId()を使用します。Subscriberインスタンスから WP ユーザーを読み取るときです。FluentCrmApi('contacts')->createOrUpdate()を使用します。 コンパニオンコードで直接Subscriberモデルをインスタンス化するのではなく。API は リスト/タグアタッチメント、ダブルオプトイン処理、ライフサイクルフック発火をカプセル化します。2.8.0で Pro バージョン検出をピンします。 最新のライフサイクルに依存する場合です。古い Pro リリースは安定した BaseAction セマンティクスより前のものです。fluentcrm_funnel_start_*を直接キャッチしないでください。 常に BaseTrigger を経由します。FluentCRM は今後そのフックの周りに検証を追加する可能性があり、BaseTrigger を迂回することはprepareEditorDetails(__force_run_actionsインジェクションなど) を逃すことを意味します。- プラグインの存在検出はファイル読み込み時のシンボルを使用する必要があります。
class_exists('TopLevelClassFromMainFile')またはdefined('CONST_NAME')。別のプラグインのplugins_loadedコールバック内で宣言されたシンボルに対してfunction_exists()を使用することは決してしないでください — 非決定的なロード順序によって、チェックが一部のインストールでパスし他でフェイルします。上記の「アクティベーション検出標準」でプラグインごとの標準リストを参照してください。
一般的な間違い
- アンダースコア vs スラッシュフック変種を混同する — 両方は今日発火しますが、
fluentcrm_*は非推奨化トラック上にあります。新しい統合はfluent_crm/*をフックすべきです。 - プラグイン検出に
class_exists('FluentCRM')に頼る。そのようなクラスはありません。defined('FLUENTCRM')を使用します。 - トリガー / アクションをブートストラップ時にインスタンス化する
plugins_loaded上でfluentcrm_loaded間接化なし。FluentCRM がまだplugins_loaded時点でロードされていない可能性があります。それでさえ、BaseTrigger::register()が FluentCRM 自身のブート前に実行されるため、フィルターターゲットは完全に配線されていない環境です。 Subscriber::find()のような内部モデルメソッドを FluentCRM の外部から呼び出す。安定していますが、モデルの動作はマイナーバージョン間で変わります。読み取りにはFluentCrmApi('contacts')->getContact()を優先します。- 依存関係認識型登録をゲートするのに
function_exists('helper_fn')を使用する。古典的なロード順序レース — 依存関係がまず読み込まれるインストールで機能し、2番目に読み込まれるインストール上で静かに破断します。症状:トリガー / アクションがあるサイトのエディターに表示され、他では表示されない、エラーなし。常に「アクティベーション検出標準」に記載されているファイルスコープクラス/コンスタント標準を使用します。 - **実際には Pro を
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- Lonsdale201
- ライセンス
- MIT
- 最終更新
- 2026/5/9
Source: https://github.com/Lonsdale201/wp-agent-skills / ライセンス: MIT