【WordPress】自作のHTMLフォームを使って色々とupdate_fieldする

カスタムフィールドは便利なんですが、投稿に紐づけられて値が保管されるため、同じフィールドを一括修正したい場合。

修正したい投稿を探して、値を変更して、保存・・・となります。

これを自作のHTMLを使って、できるだけ簡単にやりたいなと。

今回もAdvanced Custom Fieldsを使った内容です。

update_field()

カスタムフィールドの値を更新する方法としてAdvanced Custom Fieldsに用意されているのが、update_field()です。

update_field( 'フィールド名またはフィールドキー', '更新する値', '投稿ID');

更新対象のフィールドを、フィールド名またはフィールドキーで指定し。

更新する値を設定し。

更新したいフィールドの値が保管されている投稿IDを指定する。

という感じです。

update_field()を使用することで、公開ボタンを使わなくてもカスタムフィールドの値を更新することができます。

注意点はフィールドの指定方法です。

この関数はカスタムフィールドに値があることを前提として設計されているようです。

なので、値の入ってないカスタムフィールドに新規で値を登録する場合は、フィールドキーを指定しなければなりません。

フィールドだけ用意しておいて、別フォームから新たに値を更新する場合は、フィールド名では動作しないのは覚えておくと良いです。

テキストの更新

ということで、update_field()の使い方を見ていきます。

・作成したHTMLフォームに値を入れて送信(POSTまたはGET)
・PHPで値を受け取る(POSTまたはGET)
・update_field()で値の更新処理を行う

というのが基本的な流れです。

テキストを送信するフォームをHTMLで用意。

<form action="遷移先URL" method="POST">
  <input type="text" name="test-text" value="">
  <input type="hidden" name="post-id" value="10">
</form>

入力されるテキストの値はtest-textで送信し、更新するカスタムフィールドのある投稿のIDを隠しフィールドで送信しておきます。

このPOST送信されるvalueをPHPで受取り、update_field()で更新します。

$receive_text = $_POST['test-text'];
$update_post_id = $_POST['post-id'];

update_field( 'フィールド名またはフィールドキー', $receive_text, $update_post_id );

今回は$_POSTで書きましたが、いつもはfilter_input()を使ってます。

自作HTMLからカスタムフィールドの値を更新する方法について、以前に記事にしたような気がしてたんですが。

どうもしてなかったみたいで、急いでざっくり作らせて頂きましたw

なので、フィールド名やフィールドキーの想定も作らず・・・

ですが。これが基本的なupdate_field()の使い方となります。

チェックボックスとかセレクトボックスとか

ここからが記事を書き始めた本題で。

用意したカスタムフィールドが複数選択可能なチェックボックスやセレクトボックスの場合に、どう更新するかです。

この場合、カスタムフィールドには選択された値が配列で格納されています。

少し意味合いが違いますが、この記事で触れた通りです。

期待する動作としては、投稿済みで選択されている値の変更や修正・更新に使う値を、別のHTMLフォームで送信する。

ということになりますかね。

まずはHTMLフォームを作って行きますが。

更新用に使うHTMLフォームでも、カスタムフィールド作成時に使用した値を選択肢として表示できれば楽です。

まずは該当する投稿をクエリで取得します。

今回はカスタムフィールドに日付のフィールドを用意していたので、それを元に投稿データの絞り込みを行いました。

 //当日日付の取得処理
date_default_timezone_set( 'Asia/Tokyo' );
$today_date = new DateTimeImmutable();

//クエリの作成
$args = array(
            'post_type' => 'test-post',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'no_found_rows' => true,
            'meta_value' => $schedule_date->format( 'Y/m/d' ),
        );

//get_postsでクエリを取得
$post_data = get_posts( $args );

今回使用するカスタムフィールドは、別の投稿タイプで使用しているカスタムタクソノミーのタームを利用したので、ターム名もクエリで取得します。

これをHTMLフォームで使用するチェックボックスの値に使用します。

//使用するタームが保存されているカスタム投稿のクエリを作成
$term_args = array(
            'post_type' => 'another-post',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'order_by' => 'ID',
            'no_found_rows' => true,
            'tax_query' => array(
                array(
                    'taxonomy' => 'test-taxonomy',
                    'field' => 'slug',
                    'terms' => 'test-terms',
                ),
            ),
        );

//こちらもget_postsで取得
$checkbox_labels = get_posts( $term_args );

これでフォーム作成に必要な配列を取得できたので、チェックボックスを作っていきます。

チェックされているかどうかの判定もしてしまいます。

<?php 
//まずは投稿データを展開
foreach( $post_data as $post ){
 setup_postdata( $post );
 //投稿のIDを取得しておく
  $input_get_id = $post->ID;
?>

<!-- formを作成する -->
 <form method="POST" action="遷移先URLをお好みで">

<?php
  //投稿データでチェックされている値(配列)の取得
  $posted_cb_array = get_field( 'CBのフィールド名', $input_get_id );
  
   //ターム情報を展開して、チェックボックスを作成
  foreach( $checkbox_labels as $post ){
     setup_postdata( $post );
     //チェック判定
     //チェックされている値の配列がnullじゃなくて、タームが選択されている投稿のIDが配列に含まれているか
          //または配列じゃないけど、チェックされている値の投稿IDとタームが選択されている投稿のIDが同じか
     if( ( !is_null( $posted_cb_array ) && in_array( $post->ID, array_column( $posted_cb_array, 'ID' ) ) ) ||
         ( !is_array( $posted_cb_array ) && $post->ID == $posted_cb_array ) ){
?>
<!-- チェックを入れる -->
<input type="checkbox" id="<?php echo 'test-cb' . $input_get_id; ?>" name="<?php echo 'test-cb' . $input_get_id . "[]"; ?>" value="<?php echo $post->ID; ?>" checked />
<label for="<?php echo 'test-cb' . $input_get_id; ?>"><?php echo $post->post_title; ?></label><br/>
<?php
  } else {
?>
<!-- チェックを入れない -->
<input type="checkbox" id="<?php echo 'test-cb' . $input_get_id; ?>" name="<?php echo 'test-cb' . $input_get_id . "[values][]"; ?>" value="<?php echo $post->ID; ?>" />
<label for="<?php echo 'test-cb' . $input_get_id; ?>"><?php echo $post->post_title; ?></label><br/>
<?php
    }
   }
?>
<!-- 選択値が保存されている投稿のIDも渡す -->
<input type="hidden" name="<?php echo 'test-cb' . $input_get_id . "[id]"; ?>" value="<?php echo $input_get_id ?>">
<?php
wp_reset_postdata();
?>
<input type="submit" value="更新" >

ちょっと見にくくなりましたが、以前に書いたカスタムフィールドの値からセレクトボックスを作るのチェックボックス版です。

foreachの入れ子になっているのでわかりにくいかもしれません・・・

今回は複数選択に対応するため、name属性の最後に"[]"をつけてます。

そして、送信される値が2種類あるので、値には[value]、IDには[ID]とつけておきます。

これでチェックボックスで選択した値が、配列でPOST送信されるのです。

name属性などで文字列と投稿IDの連結をしていますが、複数投稿を取得してそれぞれの投稿IDをPOST送信するには、一意のnameじゃないとなので、同じ名前に投稿IDを加えて対処しています。

書きながら調整したので、なにか問題があればコメント等で教えていただけるとありがたいです。

なにはともあれ。

これで更新する値を送信するためのHTMLフォームができました。

更新処理を作る

やっと今回の本題です。

先にコードを乗せますが、自分が作成した時は同じページに遷移するようにしたので最初のforeachの後に書いています。

投稿IDを判定でも使用したので、それを活かすためです。

//更新処理
//IDを含むname属性が送信されていたら更新処理。
if( isset( $_POST[ 'test-cb' . $input_get_id ] ) && $_POST[ 'test-cb' . $input_get_id ][id] == $input_get_id ){
  //更新する値を変数に格納(しなくても良い)
  $update_value = $_POST[ 'test-cb' . $input_get_id ][value];
  //update_fieldで更新
  update_field( '更新するフィールドキー', $update_value, $input_get_id );
}

毎回更新処理が動いても困るので、POST送信されているかを判定。

POST送信されていたら、値で該当のカスタムフィールドを更新する。

という感じです。

ここで注意点が活きますが、チェックボックスは既に保存されている値(チェックが入っている値)が既存の値となり、新たにチェックをいれる値は新規の値として処理されるっぽいです。

投稿オブジェクト等を利用して作成すると、選択した値だけがHTML上に呼び出されたりしてるので、取得はしてるけど必要なものだけJSで呼び出している・・・という感じなんですよね。

なので、「フィールド名」ではなく「フィールドキー」で指定した方が安全だと思います。

複数のフィールドを更新する場合は、取得する値とupdate_field()の行を増やして対応できます。

更新先のチェックボックスがグループフィールド内の場合

グループフィールドの場合は連想配列を使ってサブフィールドをupdate_field()することも可能です。

サブフィールドは、グループフィールド内で作成するカスタムフィールドのことです。

例えばですが。

//グループフィールド内の更新する値を連想配列で入れる
$update_field_data = array(
   '更新したいサブフィールドのキー1' => '更新する値1',
   '更新したいサブフィールドのキー2' => '更新する値2',
);
//更新する
update_field( 'グループフィールドのキー', $update_field_data, '投稿ID' );

一応チェックボックスで扱っているので、「サブフィールドのキー」としていますが、テキストフィールドなどで値がすでに入力されている状態であれば、「フィールド名」でも可能です。

覚えれば色々と便利に

実は今回の作業が、同じ構成のカスタムフィールドなんだけど、フィールドグループもサブフィールド名も違うという構成でupdate_field()を使うというものでした。

なので、復習がてら調べながら進めていたのですが、思いの外ごちゃごちゃした記事になってしまったなと。

実際のコードは変数と条件分岐でもっとごちゃついてます・・・

できるだけ後で読みやすくなるようにはしてるつもりなんですけどねぇ・・・

update_field()は入力する人によって入力数を変えたい場合や、カスタムフィールドへの自動入力で使ったりと、意外と使うことが多いので、色々と使って見て下さい。

参考:PHP|HTMLのフォームから送信する値を配列、多次元配列として送受信する方法‐1NOTES
参考:Advanced Custom Fieldsのグループでupdate_fieldしたい‐Qiita