Contact Form 7でカスタムフィールドの内容を選択肢にしつつ、入力必須にする

![スクリーンショット 2025-05-02 16.33.27.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21117/7c87dbbe-08f1-4b97-a376-605d4403c5b1.jpeg)

私がこの記事を書いている時点で、実装できた手順を共有します。
選択肢を動的にする方法はいくつかあったのですが、入力必須とする方法は意外と見つからなかったです。

## この記事で実装する機能

-  WordPressのメール送信プラグイン「Contact Form 7」で、投稿内にフォームを埋め込む
-  フォームには日付の選択を追加する
-  選択肢は「Advanced Custom Fields Pro」の繰り返しフィールドで、投稿ごとに管理する
-  初期状態は空白としておき、能動的な選択を必須にする
-  選択した内容をメールの本文に反映して送信する

## 全体の流れ

- 入力欄を生成するカスタムショートコードを作成する
- ACFの繰り返しフィールドを、ドロップダウンリストの各項目にする
- 既存のショートコードと同様に、フォームのテンプレートに書き込む

## できないこと

ラジオボタン（input type="radio"）では「初期状態が空白、かつ選択必須」とすることができません。ドロップダウンリスト（select > option要素）でなければならないことに注意してください。
ラジオボタンは「必ずどれかが選択されている」前提のUIですから、これは当然の仕様と言えます。

また、選択肢と送信内容を違う値にしたり、満員なら disabled にするなどは、Contact Form 7の機能ではできません。フォームを表示させてからJavaScriptで動的に加工する必要があります。

## やってはいけない方法

Contact Form 7には、カスタムショートコードを作成する関数がいくつか用意されています。HTMLを直接出力する `wpcf7_add_form_tag` が一番簡単で、以下のようにコードを書けば `[my_cf7_input]` が使えるようになります…
が、この方法だと入力必須などの、Contact Form 7が用意してくれているオプションを使用できず、今回の要件を満たせません。

``` PHP
function my_add_cf7_event_url(){
    ob_start();
    global $post;
?>
    ここにフォーム入力のHTMLを書く
<?php
    return ob_get_clean();
}
wpcf7_add_form_tag('my_cf7_input', 'my_add_cf7_event_url');
```

## 望ましい方法

Contact Form 7には、より詳細なカスタムショートコードを作成する関数として `wpcf7_form_tag_data_option` が用意されています。
ドロップダウンリストのオプションには、必須を表す `*` 、初期値空白を表す `include_blank` などに加えて、`data:任意名` があります。これと `wpcf7_form_tag_data_option` を併用すると、選択肢をフォームテンプレートに書くのではなく、PHP処理から渡すことができます。

```
[select* my_select data:MyOptions include_blank]
```

### `wpcf7_form_tag_data_option` の使い方

ショートコードで指定したデータ名 `MyOptions` は配列 `$options` の値の一つとして渡されています。これを条件に以下の通り、配列 `$values` に選択肢を値として渡すと、ドロップダウンリストに反映されます。

空白の選択肢は必要ありません。フォームテンプレート側で `include_blank` オプションを付けていれば、空白の選択肢を最初に挿入してくれます。

```PHP
function my_wpcf7_form_tag_data_option( $values, $options, $args ) {
    if( in_array( 'MyOptions', $options ) ) {

        $values[] = '選択肢 1';
        $values[] = '選択肢 2';
        $values[] = '選択肢 3';

        return $values;
    }
}
add_filter( 'wpcf7_form_tag_data_option', 'my_wpcf7_form_tag_data_option', 10, 3 );
remove_action( 'wpcf7_swv_create_schema', 'wpcf7_swv_add_select_enum_rules', 20, 2 );
```

フィルターフックを実行したあとで、 `wpcf7_swv_create_schema` というアクションフックを解除してください。解除しないと、WordPress 5.9以降でエラーが出るようになりました。

[selectのoption値で送信エラーとなる \| WordPress\.org](https://wordpress.org/support/topic/select%E3%81%AEoption%E5%80%A4%E3%81%A7%E9%80%81%E4%BF%A1%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%A8%E3%81%AA%E3%82%8B/)

## 最終的なコード

先ほどのコードを拡張して、ACFの繰り返しフィールド `my_fields` の日時サブフィールドを選択肢として渡してあげたコードが以下となります。

```PHP
function my_wpcf7_form_tag_data_option( $values, $options, $args ) {
    if( in_array( 'MyOptions', $options ) ) {
        while( have_rows( 'my_fields' ) ) :
            the_row();
            $my_date = get_sub_field( 'my_date' );
            $my_time = get_sub_field( 'my_time' );
            $values[] = $my_date . ' ' . $my_time;
        endwhile;
        return $values;
    }
}
add_filter( 'wpcf7_form_tag_data_option', 'my_wpcf7_form_tag_data_option', 10, 3 );
remove_action( 'wpcf7_swv_create_schema', 'wpcf7_swv_add_select_enum_rules', 20, 2 );
```

これで `data:MyOptions` が使用可能になったので、以下の通りショートコードを書くと、投稿ごとに異なる選択肢のドロップダウンリストが生成されます。

### フォームテンプレート

```
[select* my_select data:MyOptions include_blank]
```

### メールテンプレート

```
[my_select]
```

## おわりに

Contact Form 7は、送信ボタンを押したあとは確認画面を表示せず、問題のない内容であればすぐに送信処理を行います。WordPressのフォーム送信プラグインはだいたいこの仕様で、確認画面が出ることが当たり前だった日本でも、利用者側が慣れてきた感があります。

ですが今回のように能動的な選択が必要となる場合、初期値を最初の項目にしていたり、必須チェックをしていないと、思わぬトラブルに繋がります。即送信させるということは、フォームを作る側も慎重になるべきです。

また、公式のフックを利用しているとはいえ、プラグインを加工する以上はアップデート後の仕様変更による不具合リスクがあります。実装したい場合は、納品後のメンテナンスが可能な案件か、まず検討してください。