【WordPress】Advanced Custom Fieldsで独自のバリデーションを加える2パターン
カスタムフィールドを利用する上での定番プラグインの「Advanced Custom Fields」(以下、ACF)はもちろん利用しています。
カスタムフィールドだけじゃなくて、フロントエンドフォームの作成もできるのが便利でデータ入力をしてもらうのにちょうど良い。
ですが、導入した頃からの一つの悩みが、バリデーションの設定方法がフィールドの設定では無いこと。
フォームらしく「必須」は設定できるんですけどね。
それでも特に問題も無く使って来ましたが、入力ミスや漏れが目立つようになり対策が必要に。
「UI改善だ!」と検討違いなことを考えつつ、調べて実装します。
と言っても、細かいバリデーションの内容を決めきれていないので、未入力チェックを目的に作成していきます。
フィルターフック「acf/validate_value」
最初に「ACF バリデーション」と調べたら出てきたのが、acf/validate_valueというフィルターフック。
ACFで作成したフィールドごとにバリデーションを設定できるようでした。
function validation_acf_data( $valid, $value, $field, $input_name ){
if( $valid !== true ){
return $valid;
}
if( empty( $value ) ){
return __( '入力して下さい' );
}
return $valid;
}
add_filter( 'acf/validate_value/カスタムフィールドの指定', 'validation_acf_data', 10, 4 );
ACFのリファレンスのコードから未入力チェックに変更しただけのコードですが。
acf/validate_valueは4つの引数があるので、それを利用していきます。・・・2つしか使っていませんが。
$validはエラーメッセージを返します。なので、6行目で未入力の場合に返すエラーメッセージを入れ、$validにreturnします。
$valueは検査対象となるカスタムフィールドの値。条件判定は$valueに対して行います。
add_filter()の第一引数で検査対象となるカスタムフィールドが設定できます。
・acf/validate_value:全フィールドに適用
・acf/validate_value/type={$type}:カスタムフィールドのタイプ(テキスト、テキストエリアなど)で指定
・acf/validate_value/name={$name}:カスタムフィールドの名前で指定
・acf_validate_value/key={$key}:カスタムフィールドのキーで指定
とこんな感じです。個人的には扱い慣れたキーの指定にするようにしています。
このフックではないですが、ACFはキー指定とする方が動作が安定するような。
これで未入力の場合、投稿は登録されず該当のフィールドにエラーが出てました。
が。フィールド数が多いので、各フィールド毎にadd_filter()で指定するのはなんか違うなぁと。
同じ処理する関数だけ用意して、フィールド毎にadd_filter()の動作を条件分岐で・・・
というコードを想像しても・・・うーん。
第三引数の$fieldで配列を指定できるので、複数フィールドを指定することもできそうでしたが。
仮での未入力チェックなので、内容を変えたい場合のメンテナンスがしにくそうなのも問題です。
アクションフック「acf/validate_save_post」
できればフックさせるのは一度で、項目ごとに設定しやすいのがないかと調査を進めると。
(追記:投稿の保存のタイミングで動作するアクションフックなので、結局は項目ごとにフックさせないと正常に動作しませんでした。すみません。)
アクションフックにacf/validate_save_postというものがあるそうで。
function validation_acf_data(){
if( empty( $_POST['form要素のname属性'] ) ){
acf_add_validation_error( 'form要素のname属性', '入力して下さい');
}
}
add_action( 'acf/validate_save_post', 'validation_acf_data' );
ACFのフォームはPOST送信されるので、その内容を検証するアクションフックとのことです。
どうもカスタムフィールドの値を検証するというよりも、他HTMLフォームなどからカスタムフィールドに値を保存する場合のバリデーションという気がします。
が、これならアクションフック一行で、各フィールドの未入力チェックができそうだなと。
(追記:同上です。できると思ったんですけどねー。)
まず検証に使用するのは、formから送信されたvalue値となるので。$_POSTで受け取ります。
デベロッパーツールなどでACFのformを調べると、name属性は’acf[field_0123456789qwe]’のようにacfとフィールドキーで構成されています。(フィールドキーは仮です。)
なので条件判定のところは以下のように指定します。
if( empty( $_POST['acf']['field_0123456789qwe] ) ){
このnameを持つPOST送信された値が条件に当てはまる(=未入力)の時に、して欲しい動作がエラー表示です。
ここにも、エラー表示とデータが保存されないように動作してくれるacf_add_validation_error()という関数が用意されています。
ここの第一引数はエラー表示させる場所のname属性を指定するので、HTMLの表記のまま入力します。
第ニ引数はエラーメッセージ。
先程の仮のフィールドキーを使用すると。
acf_add_validation_error( 'acf[field_0123456789qwe]', '入力して下さい');
テストしてみると、acf/validate_valueと同じ動作をしてくれました。
入力された内容を保存せずに、指定したフィールドのところでエラーメッセージが表示されていました。
使い分けは対象となるカスタムフィールドの量?
ということで、acf/validate_valueもacf/validate_save_postも同じ動作を確認できたわけですが。
使い分けはどうするべきか。
個人的には、検査対象となるカスタムフィールドの量で決めれば良いのかな?と思います。
acf/validate_value
・対象となるカスタムフィールドの量がそんなに多くない・検証する内容が決まっていて変更の可能性はほぼない
acf/validate_save_post
・対象となるカスタムフィールドの量が多め・検証する内容に変更の可能性がある
検証する値の量によるサーバーの負荷は気になるところですが。
条件分岐でうまくかわして行けば良いかなと思いますし。
追記
ちょこちょこ追記を入れましたが、こちらにまとめて置きます。
acf/validate_save_postは投稿の保存時に指定した関数を呼び出し、バリデーションを行ってくれます。
そのため、どうやら1つのフックに対して1つの動作(1つのacf_add_validation_error()の実行)しかできないようです。
なので、一つの$_POSTの値に対し、一つのアクションフックを作成することになります。
コードの書き方が変わるだけで、行数はどちらも変わらずということになりますね。残念。
では使い分けはというと、検証するカスタムフィールドの量で良いと思います。
一般的にフィルターフックの方が計算コストが高く、アクションフックの方が低いと言われているそうで。
量が少なければフィルターフックでも良さそうですが、多い場合はアクションフックの方が安定しそうな気がします。
あとは、処理のタイミングですかね。
フィルターフックは基本的には表示前の上書きのようなニュアンス。アクションフックは動作に付随して実行するというニュアンス。
どちらの方が適しているかです。
バリデーションで考えると、個人的にはadd_actionの方が良いかなぁとは思っています。
海外のサイトを見ると、スパム判定で使ったりしてるっぽいですね。
入力補助機能として
色々と便利なACFですが、バリデーションの情報はあまりなかったのでどうしようかと考えてました。
自作でのバリデーションも考えましたが、便利な関数が用意されていてよかったです。
バージョン5.0.0から実装されたみたいなので、利用時にはバージョンもチェックしてみてください。