Snow Monkey Forms で受け付けた申込データを Google スプレッドシートに自動記録したい——そんな要望をいただき、WordPress プラグイン+Google Apps Script(GAS)の連携キットを開発しました。
開発の過程でハマった落とし穴がいくつかあり、日本語での情報がほぼ見つからなかったので、同じ構成を検討されている方の参考になればと思い記録しておきます。
やりたかったこと
イベントの参加申込フォームを Snow Monkey Forms で作り、送信されたデータを Google スプレッドシートに自動で蓄積。スプレッドシート側にはダッシュボード(申込数・企業別集計・残り枠など)を用意して、関係者がリアルタイムで状況を把握できるようにしたい、というものです。
完成形のイメージはこんな感じです。
- フォーム送信 → スプレッドシートに即反映
- ダッシュボードで申込数・定員残り・企業別集計を自動表示
- 重複チェック・定員管理も自動
- WordPress 管理画面からフィールドマッピングや Webhook URL を設定可能(コード編集不要)
これをClaudeでコードを1行も書かずに実現しました。
構成
[Snow Monkey Forms]
│ フォーム送信
▼
[WordPress プラグイン]
│ JSON で POST
▼
[Google Apps Script(ウェブアプリ)]
│ データ処理・書き込み
▼
[Google スプレッドシート]
├── 申込データシート
├── ダッシュボード(QUERY関数で自動集計)
└── エラーログ
WordPress 側はプラグインとして実装し、GAS 側は CONFIG を書き換えるだけで使い回せる汎用コードにしました。
落とし穴① — Snow Monkey Forms のフック名
これが一番大きなハマりポイントでした。
ネット上の記事やAIに聞くと snow_monkey_forms/after_submission というフック名が出てきますが、このフックは Snow Monkey Forms のソースコード上に存在しません。
GitHub のソースコードを実際に読んで確認したところ、do_action が定義されているのは2箇所だけでした。
// AdministratorMailer.php(管理者メール送信後)
do_action(
'snow_monkey_forms/administrator_mailer/after_send',
$is_sended, // bool
$this->responser, // Responser オブジェクト
$this->setting, // Setting オブジェクト
$mail_parser // MailParser
);
// AutoReplyMailer.php(自動返信メール送信後)
do_action(
'snow_monkey_forms/auto_reply_mailer/after_send',
// ...同じ引数
);
引数も3つではなく 4つ。そしてフォームデータは配列ではなく Responser オブジェクトとして渡されるので、取得方法も違います。
// ❌ 動かない
function my_handler( $responser, $setting, $data ) {
$name = $data['name'];
}
add_action( 'snow_monkey_forms/after_submission', 'my_handler', 10, 3 );
// ✅ 正しい
function my_handler( $is_sended, $responser, $setting, $mail_parser ) {
$all_data = $responser->get_all(); // 連想配列で取得
$name = $responser->get('name'); // 個別取得も可
}
add_action( 'snow_monkey_forms/administrator_mailer/after_send', 'my_handler', 10, 4 );
なお、このフックは管理者メール送信後に発火するため、Snow Monkey Forms 側で管理者メールの送信先が設定されていないとフック自体が発火しません。フォームは正常に動いているのにスプレッドシートに何も反映されない……という場合は、ここを確認してみてください。
落とし穴② — GAS の 302 リダイレクト問題
WordPress から GAS のウェブアプリに POST すると、HTTPステータスコードのエラーが返ってくる問題に遭遇しました。これは GAS 固有のリクエストフローが原因です。
GAS のウェブアプリは POST を受けると、データ処理後に 302 リダイレクトを返します。
WordPress Google
│ │
├── POST ──────────→ script.google.com/.../exec
│ │ ← ここでデータ処理
│ ←── 302 + Location ─┤
│ │
├── GET ───────────→ script.googleusercontent.com/...
│ │ ← レスポンスを返すだけ
│ ←── 200 + JSON ─────┤
ポイントは、リダイレクト先(googleusercontent.com)は GET のみ受け付けるということです。
400 Bad Request の原因
WordPress の wp_remote_post はリダイレクト追跡時にリクエストボディの扱いが不安定で、Google 側が不正なリクエストとして弾いてしまいます。
405 Method Not Allowed の原因
cURL で CURLOPT_POSTREDIR = 3(リダイレクト後も POST を維持)を設定すると、GET しか受け付けないリダイレクト先に POST を送ってしまい 405 エラーになります。
解決策
cURL の CURLOPT_FOLLOWLOCATION だけを使い、CURLOPT_POSTREDIR は設定しないのが正解です。cURL のデフォルト動作では 302 リダイレクト時に POST → GET に変換されるので、GAS のフローと合致します。
curl_setopt_array( $ch, [
CURLOPT_URL => $webhook_url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $json_body,
CURLOPT_FOLLOWLOCATION => true, // リダイレクト追跡
CURLOPT_MAXREDIRS => 5,
// CURLOPT_POSTREDIR は設定しない(405 の原因になる)
] );
cURL が使えない環境向けには、wp_remote_post で redirection => 0(自動追跡OFF)にして、レスポンスの Location ヘッダーを取得し、wp_remote_get で手動追跡するフォールバックも実装しました。
落とし穴③ — デプロイ URL の罠
これは単純ですが、GAS のウェブアプリ URL を間違えると 401 エラーになります。
✅ https://script.google.com/macros/s/AKfycb.../exec ← ウェブアプリURL
❌ https://docs.google.com/spreadsheets/d/... ← スプレッドシートURL
❌ https://script.google.com/home/projects/... ← エディタURL
❌ https://script.google.com/macros/s/.../dev ← 開発版(外部アクセス不可)
また、デプロイ時の「アクセスできるユーザー」は**「全員」**にする必要があります。「自分のみ」だと WordPress からのリクエストが認証エラーで弾かれます。
プラグインの設計
管理画面で完結する設計にしました。
- Webhook URL — GAS のデプロイ URL を貼り付けるだけ
- フィールドマッピング — テーブル UI で SMF のフィールド名と GAS のキー名を対応付け。行の追加・削除も管理画面から
- テスト送信 — ワンクリックでダミーデータを送信し、接続確認
- 送信ログ — 成功・失敗を記録。トラブル時の原因特定に使用
- リトライ — 送信失敗時の自動再試行(回数設定可)
- 有効/無効トグル — 一時的に連携を停止したい場合に
コードを触らずに運用できるので、案件ごとにフィールド構成が違っても管理画面だけで対応できます。
GAS 側の設計
GAS 側も CONFIG オブジェクトに集約して汎用化しました。
const CONFIG = {
EVENT_NAME: 'セミナー名',
CAPACITY: 30,
DEADLINE: '2025-07-10',
CHECK_DUPLICATE: true,
DUPLICATE_KEY: 'email',
COLUMNS: [
{ gas_key: 'name', label: '氏名', width: 130 },
{ gas_key: 'email', label: 'メール', width: 220 },
{ gas_key: 'company', label: '企業名', width: 180 },
// ...案件ごとに追加
],
};
setup 関数を実行するとヘッダー行の生成、列幅・書式設定、条件付き書式、ドロップダウン、ダッシュボード、エラーログシートがすべて自動で作られます。
フィールドを追加したい場合は COLUMNS に1行足して setup を再実行するだけで、既存データを壊さずにヘッダーが更新されます。
まとめ
Snow Monkey Forms と Google スプレッドシートの連携は、仕組み自体はシンプルですが、実装レベルでは3つの落とし穴がありました。
- フック名が間違っている情報が多い — ソースコードを直接読んで確認するのが確実
- GAS の 302 リダイレクト —
wp_remote_postではなく cURL を使い、POSTREDIR は設定しない - デプロイ URL とアクセス権 —
/execで終わる URL + アクセス権「全員」
とくに1番目は、フォームのメール送信は正常に動いているのにスプレッドシートには何も起きない、という症状になるので原因特定に時間がかかります。同じ構成を検討されている方はお気をつけください。
今回開発したキットは、CONFIG とマッピングを変えるだけで別の案件にも転用できる汎用設計にしています。WordPress のフォーム → スプレッドシート連携でお困りの方は、お気軽にご相談ください。







