MW WP FormとVue.jsによる連動型セレクトボックス
WEB
導入環境
- node.js
- webpack
実現したいこと
- 固定ページにACFの繰り返しフィールドを使用して選択項目を設定
- ACFの繰り返しフィールドは親子関係を持つように制作
- コンタクトフォームにはMW WP Formを使用する
- ACFの親項目と子項目のそれぞれを別のセレクトボックスに代入
- 親項目の入ったセレクトボックスが変われば、子項目の内容も変わるようにしたい
- お問い合わせフォームの内容や、項目などをクライアント側でも操作可能にしたい
MW WP Formの使用
- Vue.jsにはv-modelを使用することで双方向でデータバインディングできる
- MW WP Formはタグに対して独自のテンプレートを使用することができる
Vue.jsを使用する上で、フォームの部品を改変し、アップデートにも対応できるMW WP Formは非常に都合がよかった。
v-modelを使用できるようにセレクトボックスを改変

上記を見てもらったらテーマフォルダ内にmw-wp-form > form-fields > select.phpという風にフォームの改変した部品をテーマフォルダ内に保管することで、バージョンアップにも対応できる。
今回は selectタグにv-modelを追加しました。
ただ単純にv-modelが計測するものはなんなのかを指定するために、v-modelの値にフォーム設置時の必須入力項目のnameを入れてます。
これでフォーム部分の準備は完了です。
取得したいデータの準備(ACF)
今回は固定ページ内にカスタムフィールド(ACF Pro)の繰り返しフォールドで用意しました。
※諸般の事情により、カテゴリーやタームでは準備してないです。

この配列をJSで取得して、フォームに代入していきます。
Javascriptを準備
- ここではwebpackでコンパイルすることを前提に書いていますので、開発環境の構築をしている人向けです
<script type="text/javascript">
//フォームのセレクトボックス連動
if (document.getElementById('mw_wp_form_mw-wp-form-xxx')) {
const mwformInstance = new Vue({
el: "#mw_wp_form_mw-wp-form-xxx",
data() {
return {
makers: [], //v-modelが入る箱
category: [], //v-modelが入る箱
years: [], //v-modelが入る箱
mwforms: [], //acfが入る箱
}
},
mounted(){
axios(BASEURL+'pages/'+page_id) //j-son取得
.then( (res) =>{
this.mwforms = res.data //用意したdataに取得したj-sonを代入
let hoge = this.mwforms.acf.audio.length //使用する配列に長さがあるかどうかを調べるために変数を用意
for (var i = 0; i < hoge; i++) { //for文で配列を回す
let op = document.createElement("option"); //optionを追加するために、定義する
op.value = this.mwforms.acf.audio[i].maker; //value値にforで回した値を代入
op.text = this.mwforms.acf.audio[i].maker; //テキスト値にforで回した値を代入
document.getElementById("makers").appendChild(op); //上記で代入したvalueとtextをoptionとしてselectタグ内に追加
}
})
},
watch: { //watchで監視できる
makers(value){ //一つ目のselectに入ったv-modelのvalueを計測
if(value){ //もしvalueがあれば
let obj = this.mwforms.acf.audio //acfの参照先を変数にセット
let hoge = obj.length //acf参照先に配列があるかどうか確認
for (var i = 0; i < hoge; i++) { //for文で回す
if(obj[i].maker === value){ //もし監視したvalueとacfの値が一致したら
//重要 ここからoption値の初期化
var select = document.getElementById("category").childNodes.length //まず2つ目のselectにoption値があるかどうかを確認
if(select){ //もしoptionがあれば
var category = document.getElementById("category") //2つ目のselectに実行するために宣言
var option = Array.from(document.getElementById("category").options) //optionをArray.fromで配列にする
while(category.lastChild){category.removeChild(category.lastChild)} //while文で回しながら、入っているoptionを全部削除
}
//重要 ここまでが初期化のコード
let fuga = obj[i].audiocategory.length //一つ目のfor文で回した配列の中にあるサブカテゴリに配列があるかどうか確認
for (var x = 0; x < fuga; x++) { //for文で回す
let op2 = document.createElement("option"); //optionを追加するために、定義する
op2.value = obj[i].audiocategory[x].category; //value値にforで回した値を代入
op2.text = obj[i].audiocategory[x].category; //テキスト値にforで回した値を代入
document.getElementById("category").appendChild(op2); //上記で代入したvalueとtextをoptionとしてselectタグ内に追加
}//ただし、これより前にoptionの値を初期化しないと、一つ目のselectが変更されるたびに、2つ目のselectのoptionが追加される
}
}
}
}
},
})
}
</script>
一気に書いたコードを貼り付けたので、わかりにくいとは思いますので簡単に説明します。
- axiosでwordpressのjsonへアクセスしてデータを取得
- 一つ目のセレクトボックスに対してアクセスしたデータの数だけoptionのkeyとvalueに代入して作ります。
ここがミソ
- Vueにあるwatchという機能を使用し、一つ目のセレクトボックスの値をリアルタイムで計測します
- この計測している値と合致した子配列を取得し、二つ目のセレクトボックスに代入します
ただしこのままであれば、一つ目のセレクトボックスを変えるたびに、二つ目のセレクトボックスに値が代入し続けられるので、optionがあれば初期化(削除)するコードを入れてあります。
Watchについて
watchで計測するには、まず上記コードのdataに計測したデータを入れる空配列を用意します。
その空配列をwatch部分で使用します。
※当たり前ですけど、v-modelの名前とdata名は一緒にしないとダメですよ〜
この形で下記のような連動セレクトボックスが追加できるようになります。

なんか色んな情報を参照しながらようやく形にできました。