Contact Form 7のセレクトボックスに動的に投稿した記事のデータを読み込む
仕事の最中、いつもやり取りしている人が大本のお客さんの質問を丸投げしてきた。
イベント的な告知をカスタム投稿タイプを利用して表示しているページがあるけど、そこに投稿している記事とContact Form 7に設定したイベント名の入力項目に当たる部分のセレクトボックスを連動できんの?って話だった。
要は「投稿した記事のタイトルなりフィールドのデータをContact Form 7のセレクトボックスに動的に読み込めないのか?」といったものである。
いや、そんなのやったことないし。
サイト制作のモチベーションが下がり切っている俺はコピペで済むならと調べてみたが、まぁそんなことをやっているものなんか調べてもなかなか出てこない。
ありそうだけどないってタイプの、少し面倒な部類の内容。
つまりは、自分で作らなければ出来ない。
コピペで済まないのでとりあえずは諦めてもらうことにした。
・・・が、個人的になんだか後味と気持ちが悪い。
申し訳ないと言うよりは、すでに面倒事として投げ出している自分へのやるせなさ。
まぁ、このままでは気が晴れそうにないので、数時間ほどContact Form 7のドキュメンテーション眺めたり、ソースを即席で少し解析したりして、とりあえず作ってみた。(実際に使うかどうかは置いといて・・・)
Contact Form 7の設定内のショートコードにセレクトボックス([select]ってやつ)があるので、今回はそれを使い回したいと思う。
といっても、ショートコードを出している関数部分をまるまる名前だけ変えてfunctions.phpに持ってくるということはしたくない。
できる限りソースが雑多になるのは避けたいんだよね。
というわけで、作ったソースコードを開示していく。
まずは、プラグインの設定内でのフォームテンプレートの入力項目として使えるように、新しくセレクトボックス様式のショートコードを作成する。
/* フォームテンプレート用にショートコードを追加 */ function theme_wpcf7_add_form_tag_eventselect() { wpcf7_add_form_tag( array( 'eventselect', 'eventselect*' ), 'theme_wpcf7_eventselect_form_tag_handler', array( 'name-attr' => true, 'selectable-values' => true, ) ); } add_action( 'wpcf7_init', 'theme_wpcf7_add_form_tag_eventselect', 10, 0 );
eventselectというショートコードを作成。アスタリスク付きは必須項目用。
Contact Form 7のフィルターフックで普段から独自のショートコードを追加しまくっている人にはごくごく見慣れたコードだと思う。
このショートコードは、フォームテンプレートでは単純に以下のような形で呼び出すものとする。
<dl><dt>イベント名<dt> <dd>[eventselect* evname]<dd> <dt>地区</dt> <dd>[text hoge]</dd> <dt>会場</dt> <dd>[text fuga]</dd></dl>
次に、追加したショートコードに該当する動作の関数を追加する。
これが、実際のフォーム側のショートコードを設定した箇所に表示されるセレクトボックスの元になる。
/* カスタム投稿タイプの「イベント」からセレクトボックス化 */ function theme_wpcf7_eventselect_form_tag_handler( $tag ) { $query = new WP_Query( array( 'post_type' => 'event', // 投稿タイプ 'post_status' => array( 'publish' ), 'nopaging' => true, ) ); $tag->options = array( 'include_blank' ); if ( $query->have_posts() ) { // オブジェクトのパラメータ値を初期化 $tag->raw_values = array(); $tag->values = array(); $tag->labels = array(); /* // これらは無視 $tag->pipes = null; $tag->attr = null; $tag->content = null; */ while ( $query->have_posts() ) { $query->the_post(); // 記事のタイトルを無理矢理突っ込む array_push( $tag->raw_values, esc_html( get_the_title() ) ); array_push( $tag->values, esc_html( get_the_title() ) ); array_push( $tag->labels, esc_html( get_the_title() ) ); } } // 書くと雑多になるのでセレクトボックスの関数を使い回し return wpcf7_select_form_tag_handler( $tag ); }
wpcf7_select_form_tag_handler()が実際にセレクトボックスを出しているContact Form 7のデフォルトのコード。
使えそうなものはそのまま使っておくことにする。
$tagにはコールバックされたショートコードのパラメータデータが入っており、これはstringデータではなくてオブジェクト配列や通常の配列の値が入ってくるようになってるみたいだ。
これらを書き換えることで動的にセレクトボックスの内容を変更する。
お馴染みのWP_Queryクラスで記事のデータを引っ張ってきて、$tagに設定されたオブジェクト配列を初期化した後、順次書き換える。(上記のコードでは選択肢を単純にタイトルに書き換えている。)
raw_values、values、labelsあたりは今回のケースでは必ず書き換えなければいけないため結構大事。
これらは普通にデフォルトのセレクトボックスで選択肢を設定したとき、例えばraw_valuesはこんな形で入っている。
object(WPCF7_FormTag)#xxxx (xx) {
~略~
[“raw_values”]=> array(1) {
[0]=> string(7) “selectA”
[1]=> string(7) “selectB”
}
~略~
}
セレクトボックスのオプションに表示する値とか、フォームで送信した時に取れる値とかに関係するので、こだわるならきちんと設定してみるといいかも。
pipes、attr、contentは即席で調べてもわからなかったのでひとまず無視。
pipesについてはraw_valuesに伴うデータとかが入っていたりと怪しいけど、これについてはまた次の課題に取っておくことにする。(忘れていなければだけど・・・。)
最後に追加したショートコードのバリデーションルールを追加する。
/* 全体バリデーション 他に特殊なバリデーションを追加している場合はそこに以下の条件を加える */ function theme_wpcf7_validate( $result, $tags ){ foreach( $tags as $tag ){ $type = $tag['type']; if ( 'eventselect' === $type || 'eventselect*' === $type ) $result = wpcf7_select_validation_filter( $result, $tag ); } return $result; } add_filter( 'wpcf7_validate', 'theme_wpcf7_validate', 11, 2 );
これも普段からバリデーションをガシガシ追加している人は見覚えがあると思う。自分はあんまり使ってないけど。
念のために補足しておくなら、wpcf7_validateのフィルターはフォーム全体に対してバリデーションをかけるので、同じ体系のコードで、他にバリデーションを行っている際は、条件を追加して使うようにしなければならない。(分岐はswitch文で行うのが一般的みたいね。)
以上でセレクトボックスに動的に記事のデータを読み込めるようになる。
動作を確認したところ、特に問題はなかったが、だいぶざっくりとした作成と確認なので使っているうちになにかでてくるかもしれない。
あと、サンプル的なコードのため、今回はセレクトボックスにはタイトルしか読み込んでいないけど、Advanced Custom Fieldsとかで、カスタムフィールドを出している場合、これらもデータに含めるようにすることも多分可能なはず。
またそのうち試してみよう(´・ω・`)