👌

サーバー移管で地獄を見た話し~reCAPTCHA v3の罠~

に公開

はじめに

本記事は、WordPress環境におけるreCAPTCHA v3導入時に発生した不可解な送信失敗エラーを、実際のサーバー移管案件でどのように調査・検証・暫定解決に至ったかを記録したものです。

対象読者:

  • Contact Form 7のエラーに悩んでいる方
  • Invisible reCAPTCHAなどの旧プラグインとの干渉に心当たりがある方
  • DBに残る設定情報がトラブルを引き起こしている可能性を考慮したい方

最終的に、スコアしきい値を調整して応急対応に至った事例ではありますが、同様の事象に苦しむ誰かのヒントになれば幸いです。
結果だけ知りたい方はStep 6にとんでください。

サーバー移管の話が来た。

WordPressでの構築、さくらのレンタルサーバー、Contact Form 7、reCAPTCHA v3。
よくある構成のはずなのに――
そこには予想以上に多くの地雷が埋まっていた。

色々、地獄を見たが、それはまた別の話。

⚠️注意:本記事で紹介する一連のサーバー・ドメイン移管案件は、
弊社営業が “7万円” で受注してきた案件でございます。

……この時点で不穏な香りがしてる方、正解です。
仕様書はなく、サーバーは動かず、フォームは飛ばず、画像も表示されませんでした。

今回は、その中でも特に手ごわかったフォームが送れない
「メッセージの送信に失敗しました。後でまたお試しください。
」という、変哲もないエラー文言の裏に潜んでいたreCAPTCHA v3の沈黙系バグとの戦いに絞って記録しておきたい。

サーバー移管時に遭遇した地獄(ざっくり)

  • 移管元はさくらのVPS
  • 移管先はこちらが用意したさくらのレンタルサーバー
  • 提供されたのは.wpressのみ(仕様書・設計書・要件定義すべてゼロ)
  • WP_DEBUG を有効にしたらNotice・Warningまみれ
  • 使用プラグインの多くが数年放置状態
  • カレンダー系プラグインのCSSが当たらない
  • 本番公開直前、クライアントが既に同ドメインをさくらで使っていた
  • DNSが通らず、クライアント側サーバーに急遽ファイルを移動

検証の軌跡:疑わしきはすべて潰す

Step 1:GTMとGA4のスクリプトが複数重複していた

header.php を確認すると、

  • GTM(Google Tag Manager)が2つ
  • さらに GA4の gtag.js も別で読み込まれていた

submit イベントへの干渉を疑い、すべてのスクリプトを一旦コメントアウト → テスト

結果:変化なし

Step 2:reCAPTCHAのドメイン設定に違和感

今回のreCAPTCHAは、こちら側で新たに発行したサイトキーとシークレットキーを使って構成していた。
(前の業者が設定していたreCAPTCHAとは完全に別のGoogleアカウント/プロジェクト

にもかかわらず、フォーム送信がうまくいかない。

もしかして、Google側で旧環境と何かバッティングしてるのでは?」と考え、
reCAPTCHAの管理画面や紐づけドメイン、score履歴などを再確認することにした。

→ 結果として明確な衝突は見つからなかったが、
新ドメインの評価がまだ十分に立っておらず、低スコア扱いされている可能性が濃厚だと判断。

Step 3:reCAPTCHA設定はプラグイン経由で行われていた

  • Contact Form 7とは別に、reCAPTCHA用のプラグインが導入されていた
  • 使用されていたプラグインはInvisible reCAPTCHA
  • WordPress6.8.1 x php7.4以上ではエラーを吐いてしまう。
  • プラグインの最終更新履歴は6か月前
  • 長期的に考えた時にCF7で完結する方向にシフト
  • しかし、プラグインを削除しても、相変わらず**「メッセージの送信に失敗しました。後でまたお試しください。**」
  • まさか、サイトキーとシークレットキー情報がDB内に残存されてる?

Step 4:DBに残存するキーが干渉していたかも?

  • wp_options テーブルを確認:
SELECT * FROM wp_options WHERE option_name LIKE '%recaptcha%';

居るやん・・・ガッツリと・・・

即座に、

DELETE FROM wp_options WHERE option_name LIKE 'invisible_recaptcha_%';

他にも無いか一通り確認。今回は適用外だったけど、必要ならって感じで。

wp_postmeta 確認・削除

-- 該当メタキーの存在確認
SELECT * FROM wp_postmeta WHERE meta_key LIKE 'invisible_recaptcha_%';
-- 削除
DELETE FROM wp_postmeta WHERE meta_key LIKE 'invisible_recaptcha_%';

wp_usermeta 確認・削除

-- 該当メタキーの存在確認
SELECT * FROM wp_usermeta WHERE meta_key LIKE 'invisible_recaptcha_%';

-- 削除
DELETE FROM wp_usermeta WHERE meta_key LIKE 'invisible_recaptcha_%';

wp_options の該当キー確認

-- recaptchaを含むすべてのオプション名を確認
SELECT * FROM wp_options WHERE option_name LIKE '%recaptcha%';

結果はというと・・・

メッセージの送信に失敗しました。後でまたお試しください。

orz

Step 5:CF7の構造変更に翻弄される

次に疑ったのは、CF7のインテグレーションで設定したキー情報がDBに保存されていないのでは?

今回のCF7のバージョンは6.0.6←ここ重要

早速確認:

SELECT * FROM wp_options WHERE option_name LIKE 'wpcf7_integration%';

いない。何処にもいない。ここでも、沼にはまるorz
何処にも登録されていない・・・だと?

いや、管理画面には登録されてるのに、SQL叩いても出てこない……なんで……(´゚ω゚`)

こうなりゃヤケクソだ!

-- 全テーブル中の recaptcha を含むオプション・メタデータを横断検索
SELECT table_name, column_name
FROM information_schema.columns
WHERE table_schema = DATABASE()
  AND column_name LIKE '%recaptcha%';
-- 対象となるテーブル・カラムの確認
SELECT table_name, column_name
FROM information_schema.columns
WHERE table_schema = DATABASE()
  AND data_type IN ('varchar', 'text', 'longtext')
  AND table_name LIKE 'wp_%';

-- このあと、各候補テーブルに対して以下を手動で実行
SELECT * FROM wp_options WHERE option_value LIKE '%recaptcha%';
SELECT * FROM wp_postmeta WHERE meta_value LIKE '%recaptcha%';
SELECT * FROM wp_usermeta WHERE meta_value LIKE '%recaptcha%';
-- テーブル全体をワイルドにスキャン(注意:やや重い)
SELECT table_name, column_name
FROM information_schema.columns
WHERE table_schema = DATABASE()
  AND (column_name LIKE '%wpcf7%' OR column_name LIKE '%recaptcha%');

何処にもいない・・・だと・・・(°Д°)

もうね、こうなると詰んだ気分になりますよ。ほんと。

一縷の望みをかけて

SELECT * FROM wp_options WHERE option_name LIKE '%wpcf7%';

option_valueの中を確認すると・・・

a:3:{s:7:"version";s:5:"6.0.6";s:13:"bulk_validate";a:4:{s:9:"timestamp";i:1743584415;s:7:"version";s:5:"6.0.5";s:11:"count_valid";i:0;s:13:"count_invalid";i:4;}s:9:"recaptcha";a:1:{s:40:"Your Site Key";s:40:"Your secret Key";}}

キタ━━━━(゚∀゚)━━━━!!
・・・いや、本質はそこじゃないΣ\( ̄ー ̄;)

ここで分かった事はCF7 6.0.6ではwpcf7_integrationは公式に廃止されているとの事。
全然関係ないところで右往左往。気を取り直して、他の原因を探してみる。

Step 6:reCAPTCHAスコアの閾値を下げてようやく成功

兎に角、検証しまくる

  • Edge、Firefox、Chrome、シークレットモード
  • それぞれ閲覧履歴の削除
  • 結果は、「メッセージの送信に失敗しました。後でまたお試しください。

ダメだ・・・詰んだ・・・

ChatGPT教授に藁にも縋る思いで縋りつく

返ってきた回答が「しきい値(スレッショルド)下げればいいんじゃね?
え?何それ美味しいの( º﹃º`)

言われるがまま、functions.php に以下を追加:

add_filter( 'wpcf7_recaptcha_threshold', function() {
    return 0.3; // 初期値は 0.5
} );

いやいや(ヾノ・∀・`)変わらんがなwww

更にreturn 0.2ダメ変んない。こうなりゃ一気にreturn 0.16

キタ━━━━(゚∀゚)━━━━!!

遂に

ありがとうございます。メッセージは送信されました。

いや、もうね、丸一日かかってますよ。ここまで来るのに。
最初はSMTP通ってんのに何で、JSのバッティング?くらいのノリだったのに、ここまで翻弄されるとは思ってませんでした(;'∀')

さて、ここまで来たら、どこまで「しきい値(スレッショルド)」を上げられるか気になるもの。
勿論、SPAMは阻止したいのでね。
ってなわけで、return 0.2がダメならreturn 0.19で試してみる。
すんなり送信完了。あれ?キャッシュ?ってなわけで、ブラウザ変えてreturn 0.2で試してみる。
気になる結果は・・・

「メッセージの送信に失敗しました。後でまたお試しください。
ですよね~(;'∀')知ってましたよ。もう君とは友達だもんね。
一先ず、閲覧履歴の削除してもう一回。うん。変わらないね。
ってなわけで、return 0.19再実行。すんなり通った。
ここが分水嶺ですな。

Step 7:本番環境に反映

あれだけ、開発環境で何度も試したんだ。頼むよ?と祈りながら、クライアントにテスト送信する旨を伝えてテスト送信。

ちゃんと、送信できたのを確認。
立て続けに送信テストをすると、即座にSPAM扱いで弾かれるので、閲覧履歴の削除かブラウザを変えて、数回試してみて問題ない事を確認。

これで、reCAPTCHA v3との戦いは完了となります。

教訓:「表示されている=動作している」じゃない

reCAPTCHA v3はUIに何も出ないため、壊れていても気づきにくい。
しかも、エラーやログすら吐かない。気づいたときにはもう地獄の底。

再発防止チェックリスト

  • Google側でreCAPTCHAのドメイン登録を明示的に確認
  • プラグインとCF7の連携構造を整理して一元化
  • wp_options の残骸データを掃除
  • 必要に応じて wpcf7_recaptcha_thresholdスコア閾値を調整
  • 本番環境では reCAPTCHA スコアのログ可視化を導入

おわりに

フォームが送れない → JSもPHPもエラーを出さない → デバッグ手段がない
こんな状況に出くわしたら、reCAPTCHA v3が静かにブロックしている可能性を疑ってみてください。

但し、サーバーの環境やドメイン依存など、Google reCAPTCHAの考え方はブラックボックスなので、全ての方に当て嵌まるとは思っておりません。
正直、しきい値を0.19まで下げないと動作しないというのも、考えてみれば不思議な話ですが、今回は暫定処置なので、根本解決には至っておりません。

今回の解決策は「しきい値を下げる」ことでの暫定対応に過ぎず、本質的にはドメイン評価の確立スコア可視化の仕組みの導入が必要と感じています。

今後の対応としては以下を検討予定です:

  • reCAPTCHA スコアのログ出力機能の導入(例:ログプラグイン or functions内で吐き出す)
  • サイトキー/シークレットキーの定期見直しと削除漏れ確認
  • Contact Form 7+reCAPTCHAの挙動に関する再検証と自動テストの仕組みづくり

「踏まないとわからない地雷」であり、ブラックボックスに悩まされることの多いreCAPTCHA v3ですが、こうした知見が少しでもトラブル回避や判断が、誰かの助けになれば幸いです。

ちなみに、この地雷案件、実はまだまだ続きがあるんです。
続編が気になる方は──Don't miss it! 😏

Discussion