【Contact Form 7】セレクトボックスの選択肢を動的に設定する

セレクトボックス

Contact Form 7、WordPressでサイトを構築するときによく利用する、有名なフォーム作成プラグインです!このプラグインでセレクトボックスを挿入する際、以下のようなショートコードを埋め込みます。

[select select-name "value1" "value2" "value3"]

この、「value1, value2, value3」となっているのが、セレクトボックスの中の選択肢なのですが、例えば、年月日の「月」のセレクトボックスを設けようとすると、このようなショートコードを用意する必要が出てきます。

[select select-month "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12"]

…いや、動的に出したくない??「年」の時、きつくない??
他にも、投稿のカテゴリーを選択肢として出すとか、特定の投稿タイプのタイトルを選択肢として出すとか、そんな要望がきっとあるはず。

ぐぐってみると…出てくるやり方は、wpcf7_add_form_tag() を使ってオリジナルのフォームタグ(ショートコード)を作ってみようというもの。
…天下の Contact Form 7 が、選択肢いじくれるフィルターフックを用意してないとか、あるのかと。。。

ということで、きっと、すでにどこかで既出だとは思いますが、フィルターフックを見つけましたよというお話です!
※Contact Form 7 の v.5.1.4 で確認しています。

フィルターフックの見つけ方

いつもの grep を使って、セレクトボックスを生成しているコードを特定していきます。

[kusanagi@minkapi contact-form-7]$ grep -irn '<option' *
modules/select.php:101:         $html .= sprintf( '<option %1$s>%2$s</option>',
modules/number.php:169:                 <option value="number" selected="selected"><?php echo esc_html( __( 'Spinbox', 'contact-form-7' ) ); ?></option>
modules/number.php:170:                 <option value="range"><?php echo esc_html( __( 'Slider', 'contact-form-7' ) ); ?></option>

ファイル名からして生成している感あふれる「modules/select.php」を覗いてみます。

foreach ( $values as $key => $value ) {
    if ( $hangover ) {
        $selected = in_array( $value, (array) $hangover, true );
    } else {
        $selected = in_array( $value, (array) $default_choice, true );
    }

    $item_atts = array(
        'value' => $value,
        'selected' => $selected ? 'selected' : '',
    );

    $item_atts = wpcf7_format_atts( $item_atts );

    $label = isset( $labels[$key] ) ? $labels[$key] : $value;

    $html .= sprintf( '<option %1$s>%2$s</option>',
        $item_atts, esc_html( $label ) );
}

option タグを生成しているのは101~102行目で、$values で foreach して生成していることから、この $values に選択肢が格納されているはず。そこで、$values がどう作られたのか遡って確認してみる。

if ( $data = (array) $tag->get_data_option() ) {
    $tag->values = array_merge( $tag->values, array_values( $data ) );
    $tag->labels = array_merge( $tag->labels, array_values( $data ) );
}

$values = $tag->values;
$labels = $tag->labels;

61行目の $tag->get_data_option() で何かしら取れれば、それを array_merge() して選択肢として利用しているみたい。 $tag->get_data_option() を grep で探索。

[kusanagi@minkapi contact-form-7]$ grep -irn 'function get_data_option(' *
includes/form-tag.php:319:      public function get_data_option( $args = '' ) {

「includes/form-tag.php」の該当行を覗いてみる。

public function get_data_option( $args = '' ) {
    $options = (array) $this->get_option( 'data' );

    return apply_filters( 'wpcf7_form_tag_data_option', null, $options, $args );
}

やっぱり!フィルターフック発見しましたー!!ぱちぱち
引数確認すると、ショートコードの data 属性で判別することができそうです。

フィルターフックを利用して選択肢を動的に出力してみた

Contact Form 7 側のショートコードは以下のように入力します。

[select month data:AutoMonth]

ショートコード内では、選択肢は特に入力しません。このショートコードが年月日の「月」を出力したいんだと判別できるように、data 属性として「AutoMonth」を指定しています。
あとは、独自プラグインでもfunctions.php でも、以下のようにフックしてあげればOK!

add_filter( 'wpcf7_form_tag_data_option', 'custom_select_values', 10, 3 );
function custom_select_values( $values, $options, $args ) {
        if ( in_array( 'AutoMonth', $options ) ) {
                $values = range( 1, 12 );
        }
        return $values;
}

これで、選択肢には自動で1~12の整数が表示されます。
if 文を増やせば、複数のセレクトボックスの中身をいじれますし、今回は range() で整数をつっこんでるだけですが、カテゴリー名だって投稿タイトルだって、配列形式で渡してあげれば動的に出力されます。

選択肢を動的に出したいだけの場合は、このフィルターフックを使う方が wpcf7_add_form_tag() より圧倒的におすすめです!

ちょこっと追記

記事を書き終えた後に、公式サイトを見ていたらこんな記事を見つけました。

あれ?これ、今回取り上げたフック使ってるんじゃないか…?

[kusanagi@minkapi contact-form-7]$ grep -irn 'wpcf7_form_tag_data_option' *
includes/form-tag.php:322:              return apply_filters( 'wpcf7_form_tag_data_option', null, $options, $args );
modules/listo.php:7:add_filter( 'wpcf7_form_tag_data_option', 'wpcf7_listo', 10, 3 );

やっぱり!!!!!!