acf

前回、個々のfieldへのカスタムバリデーションの追加には成功したので、今回は、いよいよ複数のfieldを使ったバリデーションに挑戦です。

『終了日』が指定されているときは『開始日』よりも過去だったらNGに、というバリデーションを追加したいのですが、問題となっているのは、以下の2つのACFの仕様。

  • acf/validate_value/name=フィールド名 のフックで簡単に参照出来るのは、『name=フィールド名』で指定したフィールドの値だけ
  • 各フィールドのinputのnameは、ACFが自動付与するhush値

これをデータベースの中を覗いて、解決しましょう。

入力フォームをみてみる

管理画面で実際の入力フォームのそれぞれのfieldのinputタグのnameをみてみると、

  • 開始日(start_date)は、acf[field_55a0c7e6feb08]
  • 終了日(end_date)は、acf[field_55a226e425841]

となっています。
acf/validate_value/name=end_date
のバリデーションフックを使用した時に、比較対象としたい 開始日(start_date) のPOSTされた値を参照するには、開始日のinputタグのname、『acf[field_55a0c7e6feb08]』を取得する必要があります。

データベースの中をみて、ACFの仕組みを理解する

お手軽にデータベースの中身を確認出来るplugin『Adminer』をインストールして、データベースの中を検索して見ましょう。

field_55a0c7e6feb08field_55a226e425841でDB全体を検索してみると、
postsテーブルに1つづつレコードがあるのが分かりました。

field_55a0c7e6feb08をもつpostを見てみると、post_titleが開始日、post_excerptがstart_date、post_nameがfield_55a0c7e6feb08、post_typeがacf-fieldとなっています。
なるほど、こんな風に設定した内容が格納されてるのか、ということで、
今度は、field_55a226e425841をもつpostの方を見てみます。

こちらは、post_titleが終了日、post_excerptがend_date、post_nameがfield_55a226e425841、post_typeがacf-field。これで、ACFの各フィールドの設定内容の格納状態は把握出来ました。

次に、この2つのレコードをよーく見てみると、post_parentのところに2869という共通の値が入っています。なので、今度は、2869で検索してみます。

postsテーブルで検出されたレコードのIDは2869、post_titleは日時選択、post_parentは0、post_typeはacf-field-group。これは、開始日、終了日が登録されているフィールドグループの設定内容のようです。
つまり、ACFでは、フィールドグループが1つのpostととして登録されていて、その子postとして、内包されるフィールド達が格納されてるみたいです。

ということは、同じpost_parentをもつpostから、post_titleもしくは、post_excerptの値で絞り込んで、特定のフィールドのpostを探して、そのpostのpost_nameを取得すれば、特定のフィールドのinputタグのnameが取れそうです。
これを独自の関数にして使い回せるようにしてみましょう。
こんな風に別のフィールドの値がとれたらいいなと。

フィールドBのPOSTされた値 = get_postdata_of_another_field( ‘フィールドA,Bを含むフィールドグループのpostID’, ‘フィールドBの名前’ );

フックの使い方をおさらい

ちょっと話をもどして、acf/validate_value/name={$field_name}のフックで使用する4つのパラメータについて復習します。
ACFご本家の解説ページをみると、$valid, $value, $field, $inputという4つの値が使える事が分かっています。この$fieldの中身は、{$field_name}で指定しているフィールドの情報のようですが、acf/validate_value/name=end_dateでは、具体的には、こんな内容になっていました。
※これの確認方法は、長くなるのでまた今度w

Array
(
    [ID] => 2905
    [key] => field_55a226e425841
    [label] => 終了日
    [name] => end_date
    [prefix] =>
    [type] => date_picker
    [value] =>
    [menu_order] => 1
    [instructions] =>
    [required] => 0
    [id] =>
    [class] =>
    [conditional_logic] => 0
    [parent] => 2869
    [wrapper] => Array
        (
            [width] =>
            [class] =>
            [id] =>
        )
    [_name] => end_date
    [_input] =>
    [_valid] => 1
    [display_format] => Y/m/d
    [return_format] => Y/m/d
    [first_day] => 1
)

ここにさっき検索に使った2869が入っています。ということは、『終了日』を内包するフィールドグループのpostIDは、$field[‘parent’]で取得出来てしまいます。これはラッキー!

実際のコード

ということで、長くなりましたが、以下、『終了日』のバリデーションフックを使って、『開始日』と『終了日』を比較するコードになります。

ちなみに、自分は、運用開始後にもフィールドラベルを調整する事が多いので、運用開始後にもほぼ変えないフィールドの名前=post_excerptの方を使って、別のフィールドを探し出す事にしています。

/**
 * 『終了日』が今日より過去、もしくは、『開始日』より過去ならNG
 */function check_end_date( $valid, $value, $field, $input ){
//ACFのお作法なのでそのままに
if( !$valid ) {
return $valid;
}
//POSTされた『開始日』の値を取得
$start_date = get_postdata_of_another_field( $field , ‘start_date’ );
//『終了日』に日付が入っていたらチェック
if( $value !== ” ){
//今日より過去ならNG
if ( strtotime( $value ) < strtotime( date_i18n('Y/m/d') ) ) {
return '今日以降の日付を入力してください';
}
//『開始日』より過去ならNG
elseif ( strtotime( $value ) < strtotime( $start_date ) ) {
return '『開始日』よりの先の日付を入力してください';
}
}

// 残りはOKな場合
return $valid;

}
add_filter( 'acf/validate_value/name=end_date' , 'check_end_date' , 10 , 4 );


/**
 * acfのvalidate_valueフック使用時に、postされた別のfieldの値を取得
 */function get_postdata_of_another_field( $field , $target ){
global $wpdb;
$sql = "SELECT post_name FROM $wpdb->posts WHERE post_excerpt = ‘%s’ AND post_parent = ‘%s’ LIMIT 1″;
$sql = $wpdb->prepare( $sql , $target , $field[‘parent’] );
$fieldname = $wpdb->get_var( $sql );
if( isset( $_POST[‘acf’][$fieldname] ) ){
return $_POST[‘acf’][$fieldname];
} else {
return false;
}
}

実際のエラー画面はこんな感じ。

error_sample2

これで、どんな複雑なバリデーションでも可能になった気がしてきましたよねw

半角英数のみチェック等の一般的なバリデーション付のpluginもあると思いますが、本格的なウェブアプリを作成するとなると、どんなバリデーションの要望が発生するかは、ふたを開けてみないとわからないもの。
ここを自力で乗り越えられるようになると、どんな案件でも『何でも来い!』な気分で迎えられると思います。

皆さんも、WordpressとACF PROを使って、さらに複雑な案件にチャレンジしてみてください!

※作成から2年前(806日経過)の記事です。内容が古い可能性があります。
東京都東日本橋の株式会社プレスマンPRESSMAN*Tech