かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

WordPress ContactForm7 動的なオリジナルのフォームタグを作りたい。

WordPressでサイトを作る時のフォームの定番Contact Form 7はすごく便利なのですが、カスタム投稿から動的にselectタグを作るなどカスタマイズしたタグが欲しいことがあります。

ゴール (作りたいフォームタグ)

f:id:kikiki-kiki:20170730234424p:plain
例えばこんな感じに、タレント(talent)というカスタム投稿タイプを作成して所属するアイドルを登録して
フォームでは、お仕事を依頼するタレントを選べるようにしたいような場合。

タレントを登録・削除するたびに、フォームのセレクトタグのvalueの値を変更するのはメンドーだし、ジョニー先生に任せた時に上手く運用できるか怪しいので、タレントの登録情報を動的に取得してセレクトタグを出力できると運用の手間も減ってハッピーになれそうです。

※ カスタム投稿タイプの登録は割愛します

Contact Form 7 のカスタムフォームタグ・フォーム登録画面で使えるショートコードを作成する

Contact Form 7 は管理画面からショートコードを使ってフォームを作成できるので、同じようにショートコードのフォーマットでカスタムフォームタグを生成出来るようにしたいと思います。

どうやら wpcf7_add_form_tag と言う関数でショートコードと実際のフォームでどのように出力するかを決めているようでした。

contact-form-7/includes/form-tags-manager.php
function wpcf7_add_form_tag( $tag, $func, $features = '' ) {
  $manager = WPCF7_FormTagsManager::get_instance();
  return $manager->add( $tag, $func, $features );
}
note. Contact Form 7 バージョン 4.8.1
  • 第1引数が ショートコード
  • 第2引数が 実際のフォームに出力する際に呼ばれる関数
  • 第3引数が 使用できるオプション?

な感じっぽいです。

各フォームタグがどのように作られているかはcontact-form-7/modules/の中にあるtext.phpなどフォームパーツごとのファイル参考にしてカスタムフォームタグを作成していきます。今回はselectタグを作成するので contact-form-7/modules/select.php を参考に、 下の画像の感じで select_talent_list という名前のショートコードでタグが出力できるようにしたいと思います。👇

f:id:kikiki-kiki:20170731011733p:plain

functions.php にコードを記述します。

<?php // functions.php
// Contact Form 7 が導入されていて wpcf7_add_form_tag が有効な場合のみ
if( function_exists('wpcf7_add_form_tag') ) {
  // ※タグを出力するfunctionを先に記述していないと上手く動作しない
  function make_talent_select_tag($tag) {
    // 基本的な設定は参考にするタグの出力の仕方を参考に
    $t = new WPCF7_Shortcode($tag);
    $atts = [];
    $class = wpcf7_form_controls_class( $tag->type );
    $atts['class'] = $tag->get_class_option( $class );
    $atts['id'] = $tag->get_id_option();
    $atts['name'] = $tag->name;
    $name = sanitize_html_class( $atts['name'] );

    if ( $tag->is_required() ) {
      $atts['aria-required'] = 'true';
    }

    $atts['aria-invalid'] = $validation_error ? 'true' : 'false';
    
    // デフォルト選択 selected:値 というオプションがあれば該当するoptionタグを selected にする    
    $default = $tag->get_option( 'selected', '', true );

    // first_as_label オプションで先頭を未選択状態の文字を表示できるようにする
    $first_as_label = $tag->has_option( 'first_as_label' );
    $values = $tag->values;
    
    $options = '';
    if( $first_as_label && count($values)) {
      $options = '<option value>' . esc_html($values[0]) . '</option>';
    }

    // タレント名一覧を取得してセレクトタグのオプションにする
    $talents = get_talent_name_list();
    foreach($talents as $val) {
      $value = esc_attr($val);
      $selected = "";
      // デフォルト選択に該当している場合 selected 属性を出力する
      if( $default == $value) {
        $selected = ' selected="selected"';
      }
      $options .= '<option value="' . $value . '"' . $selected . '>' . esc_html($val) . '</option>';
    }

    $atts = wpcf7_format_atts( $atts );
    $html = sprintf(
      '<span class="wpcf7-form-control-wrap %1$s"><select %2$s>%3$s</select></span>',
      $name, $atts, $options
    );

    // 出力するタグのHTMLを返す
    return $html;
  }

  // ショートコードなどを登録
  wpcf7_add_form_tag(['select_talent_list', 'select_talent_list*'],
    'make_talent_select_tag',
    [
      'name-attr' => true,
      'selectable-values' => true,
    ]
  );

  // バリデーションは 元の select のものを利用
  add_filter( 'wpcf7_validate_select_talent_list', 'wpcf7_select_validation_filter', 10, 2 );
  add_filter( 'wpcf7_validate_select_talent_list*', 'wpcf7_select_validation_filter', 10, 2 );
}

// カスタム投稿タイプ `talent` のタイトル(名前)を返す
function get_talent_name_list() {
  $data = [];
  $args = array(
    'post_type'      => 'talent',
    'post_status'    => 'publish',
    'posts_per_page' => -1,
    'orderby'        => [
      'menu_order' => 'ASC',
      'date' => 'ASC',
    ],
  );
  $the_query = new WP_Query($args);
  if ( $the_query->have_posts() ) {
    while ( $the_query->have_posts() ) {
      $the_query->the_post();
      $talentName = get_the_title();
      $data[] = $talentName;
    }
  }
  // reset query
  wp_reset_postdata();
  return $data;
}

ざっくり作ってあるので、ショートコードにvalueを追加しても無視したり、他にあるオプションが使えなかったりしますが、

[select_talent_list <name> id:<id属性> class:<追加するclass> first_as_label "未選択状態に表示される文字"]

というショートコードでカスタム投稿タイプ talent 一覧を選択できるselectタグを作成することができました!

カスタム投稿タイプを変更すると、フォームタグが動的に変わる!

タレントに ジョニー別府 を追加・保存して、フォームをリロードすると…
f:id:kikiki-kiki:20170731010516p:plain

_人人人人人人人人人人人人人人人人人人人人人_
> 自動的に「ジョニー別府」が追加されます <
 ̄YYYYYYYYYYYYYYYYYYYY

元のselectタグのバリデーションを利用しているので、
[select_talent_list* first_as_label "---"] の様に入力必須にすれば未選択時にはちゃんとエラーが表示されました!
わーい! 

まとめ

プラグインの仕様が変わるとコードを更新しなければならなかったりしてくると思いますが、簡単に独自のフォームタグを作成することができるし、フォームパーツの出力はコードでどんなふうにもできるので、カスタム投稿だけでなく、タクソノミーを取得するとか色々と動的に更新されるフォームパーツを作ることができそうです!


[参考]

アイカツ! フォトonステージ! ! イラストコレクション

アイカツ! フォトonステージ! ! イラストコレクション