いろいろ調べたけどjavascript使う方法は避けたい。
できればスマートにフックしたかったけど、wpcf7側の書き方的に無理っぽい。
海外ではプラグインのコードを上書きしちゃう方法を見つけたけど、そうすると
更新時にいちいち元に戻るので、それも避けたい。
っていうか生理的にプラグインのコードを上書きしたくない。
そこでこんな方法でフックしてみた。
ちょっとコードは汚いままだけど、都道府県の実装もついでに載せておく。
selectでoptgroupを使えるようにする
step1. wpcf7で設定されているselectのタグ書き出し時に呼ばれるフックを外す
functions.php
[php]
remove_action(‘wpcf7_init’, ‘wpcf7_add_shortcode_select’);
[/php]
step2. そして外してしまったwpcf7_add_shortcode_selectの代わりに自分の関数が呼ばれるようにする
その方法はselect.phpからコピペするだけ
functions.php
[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);
}
[/php]
step3. optgroupが使えるようにする
この海外の記事を参考に。
ちょっと長いけど全部のせておく。
functions.php
[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( ‘‘,
// $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[1] . "\">";
} 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;
}
[/php]
使い方
使い方は、以下のように。
wordpressのcf7管理画面
[php]
[select* prefecture ‘!optgroup-関東’ ‘東京都’ ‘神奈川県’ ‘optgroup!’ ‘!optgroup-近畿’ ‘大阪’ ‘京都’ ‘optgroup!’]
[/php]
都道府県のselectをoptgroup付きで出力してみる
上述したようにダラダラと都道府県を書いていけばいいのだが、管理画面使いづらいし、フォームの他のコードも見づらくなるので、これもフックで処理したい。
ショートタグ
まずwordpressのcf7管理画面で以下のようにシンプルに書いておく。
wordpressのcf7管理画面
[php]
[select* prefecture]
[/php]
フック
つぎにフックする。
functions.php
[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);
[/php]