
Contact Form 7(CF7)にCloudflare Turnstileを連携したのに動かないときは、テーマがwp_footerを通しておらず、Turnstile本体のスクリプト(api.js)が出力されていない可能性があります。CF7はフォームにウィジェット用の要素を挿入してくれますが、api.jsがなければトークンは作られません。この記事では、独自テンプレートの問い合わせページで実際に起きたこの問題と、連携が有効なときだけ読み込む条件つきの解決方法を紹介します。
背景: 公開にあわせてスパム対策を入れた
当社サイトの一般公開にあわせて、問い合わせフォームのスパム対策にCloudflare Turnstileを導入しました。設定は次のとおりです。
- Cloudflareでウィジェットを作成(Invisibleモード、Pre-clearanceはOFF)
- CF7の「インテグレーション」にサイトキーとシークレットキーを保存
CF7にはTurnstileとの連携機能が標準で入っているので、通常のテーマであればこれだけで動きます。
症状: ウィジェット要素はあるのに、トークンが作られない
ところが当社の問い合わせページでは、連携後にフォームのHTMLを確認すると、CF7が.cf-turnstileの要素を挿入しているのに、Turnstile本体のスクリプト(api.js)がページのどこにも出力されていませんでした。
原因はテンプレートの作りです。当社の問い合わせページは独自テンプレートで、wp_footerを通さず、CF7が必要とするJavaScriptを手動で読み込んでいます。そのため、通常ならwp_footer経由で出力されるTurnstileのスクリプトが、このページでは出てきませんでした。
この状態では検証用のトークンが作られないので、スパムだけでなく正当な問い合わせまで弾かれるおそれがありました。見た目には何も変わらない(Invisibleモードは元々何も表示しない)ため、気づきにくい不具合です。
実装: 連携が有効なときだけ、手動で読み込む
テンプレートの末尾、CF7本体のスクリプトを読み込んだ直後に、CF7が行うのと同じ読み込みを追加しました。
<?php if ( class_exists('WPCF7_Turnstile') && WPCF7_Turnstile::get_instance()->is_active() ): // Cloudflare Turnstile(CF7標準連携)。このテンプレートは wp_footer を通さないため、CF7本体と同じ読み込みを手動で行う ?>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async></script>
<script>document.addEventListener('wpcf7submit', function(){ if (window.turnstile) turnstile.reset(); });</script>
<?php endif; ?>
ポイントは2つです。
- 条件つきで読み込む:
WPCF7_Turnstile::get_instance()->is_active()は、CF7側でTurnstileの連携が有効なときだけ真になります。連携を外したり、プラグインの構成が変わってクラス自体がなくなったりしても、不要なスクリプトが残ったりエラーになったりしません。 - 送信のたびにリセットする: CF7は画面を再読み込みせずに送信するため、
wpcf7submitイベントでturnstile.reset()を呼び、次の送信に備えてウィジェットをリセットします。
検証: 自動テストでは最後まで確認できない
反映後に確認したのは次の点です。
- api.jsが読み込まれるのは問い合わせページだけで、他のページでは0件
- ウィジェットが描画されている(Invisibleモードなので高さは0)
- 応答用のhidden inputがフォーム内に生成されている
- 既存機能の遷移元に合わせたフォーム種類の自動選択が壊れていない
ハマりポイント
自動操作のブラウザではトークンが発行されない
確認に使った自動操作のブラウザでは、Turnstileのトークンが発行されませんでした。ボットを弾く仕組みなので当然ですが、これは「最後の送信テストは自動化できない」ことを意味します。実際の送信は人が実ブラウザで行い、完了メッセージの表示、通知メールの受信、受信履歴(Flamingo)への記録までを確認して、稼働と判断しました。
Invisibleモードにはプライバシーポリシーの記載が必要
Invisibleモードは画面に何も表示しないぶん、利用条件として、プライバシーポリシーでTurnstileの利用とTurnstile Privacy Addendumに触れる必要があります。当社では「不正利用防止ツールについて」という節を新設して対応しました。スクリプトが動いたところで終わりにせず、ここまでを導入作業に含めておくと漏れません。
まとめ
- CF7のTurnstile連携は、
wp_footerを通さない独自テンプレートではapi.jsが出力されず、トークンが作られません。 WPCF7_Turnstile::get_instance()->is_active()を条件に、api.jsの読み込みとwpcf7submitでのリセットを手動で追加すれば解決します。- 実送信のテストは人が実ブラウザで行います。Invisibleモードならプライバシーポリシーの追記も忘れずに。
スパム対策のバッジや読み込みを必要なページだけに絞る考え方は、reCAPTCHA v3のバッジを問い合わせページ以外で消す方法でも紹介しています。
Webサイトの構築や、こうした設計のご相談は、SERVICESからお気軽にどうぞ。
← TECH-BLOG一覧へ