【WordPress】Advanced Custom Fieldsで独自のバリデーションを加える2パターン

2023年10月10日

カスタムフィールドを利用する上での定番プラグインの「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から実装されたみたいなので、利用時にはバージョンもチェックしてみてください。

参考:acf/validate_value-ACF
参考:acf/validate_save_post-ACF