§8 公開フック(アクション/フィルター)

AppCotton は、ライセンス発行・ドメインアクティベーション・プラン課金(差額請求)・チェックアウト・Webhooks の各処理ポイントで拡張できるように、アクション / フィルターを公開しています。ここではよく使う代表フック推奨パターンをまとめます。すべてPHPから利用できます。


使い方の基本

// アクション
add_action('appcotton_license_activated', function($license_id, $license, $activation, $context){
    // 例: 外部CRMへ発火 / 管理者通知
}, 10, 4);

// フィルター
add_filter('appcotton_normalize_domain', function($domain, $raw){
    // 例: サブドメイン許容や社内TLDの正規化
    return $domain;
}, 10, 2);
  • 優先度: 10(標準)。同一タイミングで他の処理より前/後にしたい場合は変更してください。
  • $accepted_args: 必ず記載の数に合わせてください。
  • 戻り値: フィルターは必ず戻り値を返すこと。

アクション(do_action)

1) appcotton_license_issued

  • 発火: ライセンス新規発行直後(手動/無料/有料問わず)
  • 引数: ($license_id, $license, $order_or_null, $context)
  • 用途: 初回ウェルカムメール、外部台帳への登録
add_action('appcotton_license_issued', function($license_id, $license, $order, $context){
    // $license->license_key, $license->product_id, $license->activation_limit など
});

2) appcotton_license_activated

  • 発火: ドメインアクティベーション成功時
  • 引数: ($license_id, $license, $activation, $context)
  • 用途: 監査ログ、Slack通知、アクティベーション回数の独自集計
add_action('appcotton_license_activated', function($license_id, $license, $activation, $context){
    // $activation->domain, $activation->instance_id, $activation->ip, $activation->first_activated_at など
}, 10, 4);

3) appcotton_license_deactivated

  • 発火: ドメイン解除成功時
  • 引数: ($license_id, $license, $activation, $context)

4) appcotton_order_created

  • 発火: 注文オブジェクト生成時(無料発行・手動発行では null の場合あり)
  • 引数: ($order_id, $order, $context)

5) appcotton_order_paid

  • 発火: 決済成功(Stripe など)で「支払い済み」になった時
  • 引数: ($order_id, $order, $context)
  • 用途: 会計連携、領収書発行

6) appcotton_checkout_session_created

  • 発火: チェックアウトセッション生成後(差額課金/新規購入)
  • 引数: ($session, $payload, $context)
  • 備考: $payload は product_id / plan_id / user_id / meta など

7) appcotton_product_plan_saved

  • 発火: プランの新規・更新保存直後
  • 引数: ($plan_id, $plan, $is_update)

8) appcotton_webhook_received

  • 発火: Webhook 受信時(検証後)
  • 引数: ($event_type, $payload, $raw, $context)
  • 用途: Stripe イベントの横取り・補助処理

9) appcotton_db_repaired

  • 発火: 「設定 > DBリペア」完了時
  • 引数: ($report_array)
  • 用途: 管理者メールやログ保全

フィルター(apply_filters)

1) appcotton_normalize_domain

  • 目的: ドメイン文字列の正規化
  • 引数: ($normalized, $raw)
  • 戻り値: 正規化後ドメイン(例: sub.example.com
  • : 社内 TLD / ローカル用途許容や、www. の統一
add_filter('appcotton_normalize_domain', function($normalized, $raw){
    // 例: 常に www なしに統一
    return preg_replace('/^www\./', '', strtolower($normalized));
}, 10, 2);

2) appcotton_can_activate

  • 目的: アクティベーション可否の最終判定を上書き
  • 引数: ($allowed, $license, $domain, $context)
  • 戻り値: true|false
  • : 禁止ドメインリストの適用
add_filter('appcotton_can_activate', function($allowed, $license, $domain){
    $blocked = ['example.net', 'intranet.local'];
    return $allowed && ! in_array($domain, $blocked, true);
}, 10, 3);

3) appcotton_can_deactivate

  • 目的: 解除可否の判定
  • 引数: ($allowed, $license, $domain, $activation)
  • 戻り値: true|false

4) appcotton_license_activation_limit

  • 目的: 実行時点の有効化上限を動的に変更
  • 引数: ($limit, $license, $plan)
  • 戻り値: int-1 は無制限)
add_filter('appcotton_license_activation_limit', function($limit, $license, $plan){
    // 例: 社内アカウントは +1 ボーナス
    if (strpos($license->email ?? '', '@mycorp.com') !== false) {
        return ($limit < 0) ? -1 : $limit + 1;
    }
    return $limit;
}, 10, 3);

5) appcotton_proration_amount

  • 目的: 差額請求(アップグレード時)の金額調整(最小通貨単位)
  • 引数: ($amount, $from_plan, $to_plan, $license, $context)
  • 戻り値: int(例: JPY で 100 = 100円)
add_filter('appcotton_proration_amount', function($amount, $from, $to, $license){
    // 例: プロモ期間は 10% 割引
    $promo = (time() < strtotime('2025-12-31 23:59:59'));
    return $promo ? (int)round($amount * 0.9) : $amount;
}, 10, 4);

6) appcotton_mask_license_key

  • 目的: マイページ等でのキー表記(マスキング)を調整
  • 引数: ($masked, $license_key)
  • 戻り値: string

7) appcotton_rest_permission_check

  • 目的: REST エンドポイントの認可上書き
  • 引数: ($allowed, $request, $route_name)
  • 戻り値: true|WP_Error
add_filter('appcotton_rest_permission_check', function($allowed, $request, $route){
    // 例: IP 制限
    $whitelist = ['203.0.113.10'];
    $ip = $_SERVER['REMOTE_ADDR'] ?? '';
    if (!in_array($ip, $whitelist, true)) {
        return new WP_Error('forbidden', 'Not allowed from your IP', ['status' => 403]);
    }
    return $allowed;
}, 10, 3);

8) appcotton_checkout_metadata

  • 目的: チェックアウト(新規/差額)に付随するメタデータ追加
  • 引数: ($metadata, $license_or_null, $plan, $context)
  • 戻り値: array

9) メール関連

  • appcotton_email_headers / appcotton_email_subject / appcotton_email_body
  • 目的: 発行・アクティベート・アップグレード通知などのメール内容を調整
  • 引数の一例: ($value, $template, $vars, $context)
  • 戻り値: string|array(ヘッダは配列想定)

10) 表示・UI関連

  • appcotton_plan_display_data
    目的: 公開側(ショートコード / SDK UI)でのプラン表示データを上書き(例: ラベル/説明/注記/バッジ)
    引数: ($display, $plan, $product)戻り値: array

代表ユースケース集

A. ライセンス有効化の詳細ログを外部に送る

add_action('appcotton_license_activated', function($license_id, $license, $activation){
    error_log(sprintf(
        '[AppCotton] Activated: key=%s domain=%s user_id=%s',
        $license->license_key,
        $activation->domain,
        $license->user_id ?? 'n/a'
    ));
}, 10, 3);

B. 社内ネットワーク以外の解除を禁止

add_filter('appcotton_can_deactivate', function($allowed, $license, $domain, $activation){
    $corp = '.mycorp.internal';
    if (substr($domain, -strlen($corp)) !== $corp) {
        return false;
    }
    return $allowed;
}, 10, 4);

C. 差額課金の丸め/最低料金を強制

add_filter('appcotton_proration_amount', function($amount){
    $min = 100; // JPY 100円未満は切り上げ
    if ($amount > 0 && $amount < $min) {
        return $min;
    }
    return (int) ceil($amount / 10) * 10; // 10円刻みに丸め
}, 10, 1);

D. 公開 UI のプラン名に「イチオシ」バッジを付与

add_filter('appcotton_plan_display_data', function($display, $plan){
    if ((int)$plan->activation_limit === 3) {
        $display['badge'] = 'おすすめ';
    }
    return $display;
}, 10, 2);

フック設計の指針

  • 副作用は最小限にし、例外は投げずに WP_Error を返せる箇所では返す。
  • 長時間ブロッキングする外部 I/O は避け、必要なら非同期キューWebhookで。
  • 同じ処理を複数フックで重複させない(一意性の担保)。
  • ログ(debug.log など)に最低限の痕跡を残す。
  • バージョンアップでパラメータが増える可能性があるため、可変長引数isset() を意識。

互換性ポリシー(要点)

  • 引数の順序/意味は後方互換を尊重。
  • 引数の追加は許容(古いコードは受理数で無視)。
  • 既存引数の削除/型変更は非推奨。行う場合はメジャーアップデートで告知。
  • フック名は固定(改名は非推奨。必要時は旧名を残しながら非推奨化)。

トラブルシューティング

  • フックが動かない: 優先度/ 受理引数数のミスを確認
  • REST/チェックアウト関連: 認可は appcotton_rest_permission_check でデバッグログを出す
  • 差額が 0 になる: appcotton_proration_amount で割引や丸めが効いていないか確認
  • ドメイン不一致: appcotton_normalize_domain の処理順を見直す(www./大文字小文字)

まとめ

  • イベントを横取り=アクション
  • 値を差し替え=フィルター
  • よく使うのは
    • 有効化/解除(appcotton_license_activated/deactivated
    • 差額(appcotton_proration_amount
    • ドメイン正規化(appcotton_normalize_domain
    • REST 認可(appcotton_rest_permission_check
    • 表示データ(appcotton_plan_display_data

この章をベースに、必要なポイントだけピンポイントでフックを追加していけば、WooCommerce などの重い購買基盤を介さずに、AppCotton のライセンス運用を各サイト要件へ柔軟にフィットさせられます。