Contact Form 7で宛先をカスタムフィールドから取得して動的に変更する方法(安全な実装)

WordPress

投稿(店舗など)ごとに問い合わせ先メールアドレスがカスタムフィールドに登録されている場合に、1つのContact Form 7フォームで送信先を動的に切り替える方法を紹介します。宛先が大量にあっても、フォームを宛先ごとに用意せず、カスタムフィールドの更新だけで運用できます。ここではオープンリレー(迷惑メールの踏み台)にならない安全な実装を解説します。

この記事でわかること

  • URLの post-id パラメータで対象投稿を渡す
  • 送信時に サーバー側でカスタムフィールドから宛先を再取得する
  • wpcf7_mail_components と CF7「メール」タブの設定
  • クライアントのhidden値を宛先に使ってはいけない理由(セキュリティ)
宛先メールアドレスを hidden フィールドの値で決めてはいけない
hiddenフィールドの値はブラウザの開発者ツールで誰でも書き換えられます。その値をそのままメール宛先に使うと、攻撃者が任意のアドレスへ送信できる「オープンリレー」になり、あなたのサーバーが迷惑メールの踏み台にされます。sanitize_email()形式を整えるだけで改ざんは防げません。安全にするには、クライアントからは投稿IDだけを受け取り、メールアドレスはサーバー側でカスタムフィールドから取得します。
スポンサーリンク

投稿ページのリンクに投稿IDを付ける

各投稿に置くフォームへのリンクに、その投稿のIDを post-id パラメータとして付けます。

PHP:フォームへのリンク(投稿IDを付与)
<a href="/contact/?post-id=<?php echo get_the_ID(); ?>">お問い合わせフォームへ</a>

フォームに投稿IDのhiddenフィールドを置く

Contact Form 7のフォームに、投稿IDを受け取るhiddenフィールドを追加します。default:get を付けると、URLの post-id パラメータの値が自動で入ります。

CF7:投稿IDのhiddenフィールド
[hidden post-id default:get]
メールアドレスはhiddenに入れない
旧来よく紹介される「宛先メールアドレスをhiddenに入れて送る」方法は前述のとおり危険です。この実装では運ぶのは投稿IDだけ。投稿IDを改ざんされても、たどり着けるのは実在する投稿に登録済みのアドレスだけで、任意のアドレスは指定できません。

送信時にサーバー側で宛先を再取得する

functions.php に次のコードを追加します。送信時に wpcf7_mail_components フィルターで、送られてきた post-id からカスタムフィールドのメールアドレスを取得し直して宛先に設定します。

functions.php:post-id から宛先を再取得(安全)
function my_cf7_dynamic_recipient($components, $form, $mail) {
  $target_form_id = 77; // 対象フォームのIDに置き換えてください

  if ($form->id() != $target_form_id) {
    return $components;
  }

  $submission = WPCF7_Submission::get_instance();
  if (!$submission) {
    return $components;
  }
  $posted = $submission->get_posted_data();

  // クライアントから受け取るのは投稿IDだけ。整数化する
  $post_id = isset($posted['post-id']) ? absint($posted['post-id']) : 0;
  if (!$post_id) {
    return $components;
  }

  // 宛先は「サーバー側で」カスタムフィールドから取得し直す(hidden値は信用しない)
  $email = get_post_meta($post_id, 'contact_mail', true); // 実際のキーに置き換え

  // 取得した値が正当なメール形式のときだけ採用
  if ($email && is_email($email)) {
    $components['recipient'] = $email;
  }
  return $components;
}
add_filter('wpcf7_mail_components', 'my_cf7_dynamic_recipient', 10, 3);
ポイントは「hidden値を信用しない」こと
宛先は $posted['recipient-email'] のような送信された値からは取りませんpost-idabsint() で整数化し、get_post_meta()サーバー側のデータから取り直しis_email() で検証してから設定します。これで改ざんされても任意送信を防げます。

CF7「メール」タブの設定

上のフィルターで宛先を上書きしますが、CF7の「メール」タブの「送信先」欄にはフォールバック用の管理者メールアドレスを入れておきます。カスタムフィールドが未設定だった場合(フィルターが宛先を上書きしない場合)に、ここに届くので取りこぼしを防げます。フォーム自体のカスタマイズ(class/id付与など)はContact Form 7でformタグにclass・idを設定する方法を参照してください。

関連して、送信できないトラブルの切り分けはContact Form 7で「送信できない」時の原因と解決チェックリスト、送信前に入力内容を加工する方法はユーザーの入力内容を一部加工して送信する方法も参考になります。

よくある質問(FAQ)

Q宛先メールアドレスをhiddenフィールドに入れて送ってはいけませんか?
Aいけません。hiddenの値は開発者ツールで改ざんでき、それをそのまま宛先に使うと任意のアドレスへ送れるオープンリレーになります。sanitize_email() は形式を整えるだけで改ざんは防げません。クライアントからは投稿IDだけを受け取り、宛先はサーバー側で get_post_meta() から取得し直してください。
Qカスタムフィールドの値をフォームの初期値に使うには?
ACF7のタグで default:get(URLパラメータから)などの初期値オプションが使えます。投稿のカスタムフィールド値を入れたい場合は wpcf7_form_tag フィルターでタグの値を動的に書き換えるか、JavaScriptでページ読み込み後に設定します。
Q種別によってメール内容や宛先を変えるには?
Awpcf7_mail_components フィルターで $components(recipient・subject・body 等)を条件分岐で書き換えます。宛先を切り替える場合も、送信値を直接使わず、サーバー側で許可された値に解決してから設定するのが安全です。

まとめ

  • 運ぶのは投稿IDだけ:リンクに ?post-id=、フォームに [hidden post-id default:get]
  • 宛先はサーバー側で再取得wpcf7_mail_componentsget_post_meta()is_email()
  • hidden値を宛先に使わない:改ざんによるオープンリレーを防ぐ
  • メールタブ:フォールバック用に管理者アドレスを入れておく

「クライアントからはIDだけ、宛先はサーバー側で確定」を守れば、複数宛先のフォームを安全に1つで運用できます。