Sharable

システム&ウェブのシェアラブル

ContactForm7でselectにoptgroupをフックで追加したい

2015年12月30日

いろいろ調べたけどjavascript使う方法は避けたい。
できればスマートにフックしたかったけど、wpcf7側の書き方的に無理っぽい。

海外ではプラグインのコードを上書きしちゃう方法を見つけたけど、そうすると
更新時にいちいち元に戻るので、それも避けたい。
っていうか生理的にプラグインのコードを上書きしたくない。

そこでこんな方法でフックしてみた。

ちょっとコードは汚いままだけど、都道府県の実装もついでに載せておく。

selectでoptgroupを使えるようにする

step1. wpcf7で設定されているselectのタグ書き出し時に呼ばれるフックを外す

functions.php

remove_action('wpcf7_init', 'wpcf7_add_shortcode_select');

step2. そして外してしまったwpcf7_add_shortcode_selectの代わりに自分の関数が呼ばれるようにする

その方法はselect.phpからコピペするだけ

functions.php

add_action('wpcf7_init', 'my_wpcf7_add_shortcode_select');

function my_wpcf7_add_shortcode_select()
{
    wpcf7_add_shortcode(array('select', 'select*'),
        'my_wpcf7_select_shortcode_handler', true);
}

step3. optgroupが使えるようにする

この海外の記事を参考に。
ちょっと長いけど全部のせておく。

functions.php


function my_wpcf7_select_shortcode_handler($tag)
{
    $tag = new WPCF7_Shortcode($tag);

    if (empty($tag->name))
        return '';

    $validation_error = wpcf7_get_validation_error($tag->name);

    $class = wpcf7_form_controls_class($tag->type);

    if ($validation_error)
        $class .= ' wpcf7-not-valid';

    $atts = array();

    $atts['class'] = $tag->get_class_option($class);
    $atts['id'] = $tag->get_id_option();
    $atts['tabindex'] = $tag->get_option('tabindex', 'int', true);

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

    $atts['aria-invalid'] = $validation_error ? 'true' : 'false';

    $multiple = $tag->has_option('multiple');
    $include_blank = $tag->has_option('include_blank');
    $first_as_label = $tag->has_option('first_as_label');

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

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

    $defaults = array();

    $default_choice = $tag->get_default_option(null, 'multiple=1');

    foreach ($default_choice as $value) {
        $key = array_search($value, $values, true);

        if (false !== $key) {
            $defaults[] = (int)$key + 1;
        }
    }

    if ($matches = $tag->get_first_match_option('/^default:([0-9_]+)$/')) {
        $defaults = array_merge($defaults, explode('_', $matches[1]));
    }

    $defaults = array_unique($defaults);

    $shifted = false;

    if ($include_blank || empty($values)) {
        array_unshift($labels, '---');
        array_unshift($values, '');
        $shifted = true;
    } elseif ($first_as_label) {
        $values[0] = '';
    }

    $html = '';
    $hangover = wpcf7_get_hangover($tag->name);

    foreach ($values as $key => $value) {
        $selected = false;

        if ($hangover) {
            if ($multiple) {
                $selected = in_array(esc_sql($value), (array)$hangover);
            } else {
                $selected = ($hangover == esc_sql($value));
            }
        } else {
            if (!$shifted && in_array((int)$key + 1, (array)$defaults)) {
                $selected = true;
            } elseif ($shifted && in_array((int)$key, (array)$defaults)) {
                $selected = true;
            }
        }

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

        $item_atts = wpcf7_format_atts($item_atts);

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

        /**********************************
         *
         * 以下OPTGROUP用に改造した箇所
         *
         **********************************/
//        $html .= sprintf( '<option %1$s>%2$s</option>',
//            $item_atts, esc_html( $label ) );

        //BOF AMMENDMENT
        if (strpos(esc_attr($value), "!optgroup") > -1) {
            $exploded_value = explode('-', esc_attr($value));

            $html .= "<optgroup label=\"" . $exploded_value&#91;1&#93; . "\">";
        } elseif (esc_attr($value) == "optgroup!") {
            $html .= "</optgroup>";
        } //EOF AMMENDMENT
        else {
            $html .= sprintf('<option %1$s>%2$s</option>',
                $item_atts, esc_html($label));
        }
        //ここまで
    }

    if ($multiple)
        $atts['multiple'] = 'multiple';

    $atts['name'] = $tag->name . ($multiple ? '[]' : '');

    $atts = wpcf7_format_atts($atts);

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

    return $html;
}

使い方

使い方は、以下のように。

wordpressのcf7管理画面

[select* prefecture '!optgroup-関東' '東京都' '神奈川県' 'optgroup!' '!optgroup-近畿' '大阪' '京都' 'optgroup!']

都道府県のselectをoptgroup付きで出力してみる

上述したようにダラダラと都道府県を書いていけばいいのだが、管理画面使いづらいし、フォームの他のコードも見づらくなるので、これもフックで処理したい。

ショートタグ

まずwordpressのcf7管理画面で以下のようにシンプルに書いておく。

wordpressのcf7管理画面

[select* prefecture]

フック

つぎにフックする。

functions.php

function wpcf7_prefecture_form_tag($tag)
{

    if (!is_array($tag)) {
        return $tag;
    }

    $tagName = $tag['name'];
    $basetype = $tag['basetype'];

    if ('prefecture' == $tagName && 'select' == $basetype) {
        $regions = [
            '関東地方' => [
                '東京都', '神奈川県', '埼玉県', '千葉県', '茨城県', '栃木県', '群馬県'
            ],
            '北海道・東北地方' => [
                '北海道', '青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県'
            ],
            '中部地方' => [
                '新潟県', '富山県', '石川県', '福井県', '山梨県', '長野県', '岐阜県', '静岡県', '愛知県'
            ],
            '近畿地方' => [
                '大阪府', '兵庫県', '三重県', '滋賀県', '京都府', '奈良県', '和歌山県'
            ],
            '中国地方' => [
                '鳥取県', '島根県', '岡山県', '広島県', '山口県'
            ],
            '四国地方' => [
                '徳島県', '香川県', '愛媛県', '高知県'
            ],
            '九州・沖縄地方' => [
                '福岡県', '佐賀県', '長崎県', '熊本県', '大分県', '宮崎県', '鹿児島県', '沖縄県'
            ]];

        $results = [];

        foreach ($regions as $region => $prefectures) {
            $results[] = sprintf('!optgroup-%s', $region);

            foreach ($prefectures as $prefecture) {
                $results[] = $prefecture;
            }

            $results[] = 'optgroup!';
        }

        $tag['values'] = $results;
    }

    return $tag;
}
add_filter('wpcf7_form_tag', 'wpcf7_prefecture_form_tag', 11);
このエントリーをはてなブックマークに追加