WordPressサイトにカスタムフィールドを追加するには、ACF(Advanced Custom Fields)を使うケースが多いかもしれませんが、よりサイトの軽量化を狙うなどでプラグイン自体を使わずにカスタムフィールドを導入したい人向けの記事です。
フォームの見た目部分とは別に保存処理も記述しなければ動作せず、やや構造が理解しにくいのでしっかりまとめました。
この記事に書いたことを押さえれば、functions.php
に記述するべきことがはっきりわかるようになります。
プラグインを使用せずカスタムフィールドを追加する方法
プラグインを使わない場合、カスタムフィールドを追加するには以下のプログラムを用意する必要があります。
- カスタムフィールド用セクションの宣言
- 見た目(フォーム)部分の指定
- データの保存処理
上記3つが揃って正しく動くカスタムフィールドとなります。
例として完成版のコードを記載しておきます。
<?php
/**
* カスタムフィールド用セクションの宣言
*/
function create_custom_fields()
{
add_meta_box(
'custom_field_1', //セクションのID
'カスタムフィールドエリア', //セクションのタイトル
'custom_fields_form', //フォーム部分を指定する関数
'post', //投稿タイプ名
'normal', //セクションの表示場所
'default' //優先度
);
}
add_action('admin_menu', 'create_custom_fields');
/**
* 見た目(フォーム部分)の指定
*/
function insert_custom_fields($post)
{
//nounceフィールドの追加
wp_nonce_field('custom_field_save_meta_box_data', 'custom_field_meta_box_nonce');
//すでに保存されているデータを取得
$sample_text = get_post_meta($post->ID, 'sample_text', true);
$sample_radio = get_post_meta($post->ID, 'sample_radio', true);
?>
<label for="sample_text">テキスト項目</label>
<input id="sample_text" type="text" name="sample_text" value="<?php echo $sample_text; ?>">
<br>
<label for="sample_radio1">選択肢1</label>
<input id="sample_radio1" type="radio" name="sample_radio" value="1" <?php if ($sample_radio == 1) echo 'checked'; ?>>
<label for="sample_radio2">選択肢2</label>
<input id="sample_radio2" type="radio" name="sample_radio" value="2" <?php if ($sample_radio == 2) echo 'checked'; ?>>
<?php
}
/**
* データの保存処理
*/
function save_custom_fields($post_id)
{
//nounceがセットされているか確認
if (!isset($_POST['custom_field_meta_box_nonce'])) {
return;
}
//nounceが正しいか検証
if (!wp_verify_nonce($_POST['custom_field_meta_box_nonce'], 'custom_field_save_meta_box_data')) {
return;
}
//sample_textデータを保存
if (isset($_POST['sample_text'])) {
$data = sanitize_text_field($_POST['sample_text']);
update_post_meta($post_id, 'sample_text', $data);
}
//sample_radioデータを保存
if (isset($_POST['sample_radio'])) {
$data = sanitize_text_field($_POST['sample_radio']);
update_post_meta($post_id, 'sample_radio', $data);
}
}
add_action('save_post', 'save_custom_fields');
順を追って説明していきますね。
カスタムフィールド用セクションの宣言
まず最初にカスタムフィールドを扱うセクションを用意します。
ここで言う「セクション」とは、管理画面上で関連するカスタムフィールドをまとめた一塊のこと。
赤枠で囲った1つずつがセクションにあたります。
旧エディタのほうがもっと視覚的に別れていてわかりやすいですね。
1セクションの中に複数のカスタムフィールド(入力枠)を入れてもOK。
まずはカスタムフィールドを挿入する前に、WordPressではセクションをどうするか宣言する必要があるのです。
function create_custom_fields()
{
add_meta_box(
'custom_field_1', //セクションのID
'カスタムフィールドエリア', //セクションのタイトル
'custom_fields_form', //フォーム部分を指定する関数
'post', //投稿タイプ名
'normal', //セクションの表示場所
'default' //優先度
);
}
add_action('admin_menu', 'create_custom_fields');
functions.php
に挿入するコードの例です。
まずcreate_custom_fields
という関数を用意し、その中でadd_meta_box
を実行してセクションをどうするか決めています。
最後にadd_action
で管理画面の描画がされるときに関数を実行するようにしました。
add_actionの作り方
add_action
は()
の中に7つの引数(WordPress的にいうとパラメータ)を持つことができます。
ただし最後の1つは設定することはほぼないので、上記の例のように6つの設定値を把握しておけば問題ありません。
add_meta_box(
セクションID,
セクションタイトル,
フォーム部分を指定する関数,
投稿タイプ名,
セクションの表示場所,
優先度
);
【設定必須】セクションID
セクション全体のHTMLを生成するときに付与されるIDです。
<div id="cunstom_field_1" class="postbox ">
<div class="postbox-header">
<h2 class="hndle ui-sortable-handle">セクション名</h2>
<!-- 省略 -->
</div>
</div>
実際に出力されるセクションのHTMLを見ると、上記の例のように指定したID(custom_field_1
)が付与されているのがわかると思います。
【設定必須】セクションタイトル
文字通り、セクションタイトルに何を出すかの設定です。
こちらの例だと「ボーダー設定」と出ている見出しがセクションタイトルです。
<div id="cunstom_field_1" class="postbox ">
<div class="postbox-header">
<h2 class="hndle ui-sortable-handle">セクション名</h2>
<!-- 省略 -->
</div>
</div>
HTML上ではh2
タグに囲われた部分になります。
【設定必須】フォーム部分を指定する関数
実際にセクション内にどんな項目(input
、textarea
など)を置くかを定義する必要がありますが、それは別に(あとで)用意する関数にて具体的に指定します。
add_meta_box
では、フォームの中身を指定する関数名だけを入れておきます。
投稿タイプ名
セクションを表示させたい投稿タイプを指定します。
デフォルトで用意されている「投稿」であればpost
、「固定ページ」であればpage
、その他カスタム投稿タイプなどもIDをいれて指定可能です。
セクションの表示場所
セクションの表示場所をnormal
、advanced
、side
のどれかで指定します。
normal
とadvanced
は本文エリアの下に表示され(違いがわかりませんでした…)、side
では右側のサイドバーに表示。
side
はWordPressの本体バージョン2.7以降でのみ使用可能。
何も指定しないときは、デフォルトでadvanced
が採用されます。
優先度
セクションの表示順をhigh
、core
、default
、low
の4段階で指定します。
同じエリアに並ぶセクションが複数ある場合、high
の指定があるものから順に並ぶ仕様です。
何も指定がないときは自動でdefault
扱いとなります。
見た目(フォーム部分)の指定
次にセクション内に表示するフォームのHTMLを指定する関数を作ります。
先ほどのadd_meta_box
内ではcustom_fields_form
という関数を作る設定でした。
<?php
function insert_custom_fields($post)
{
//nounceフィールドの追加
wp_nonce_field('custom_field_save_meta_box_data', 'custom_field_meta_box_nonce');
//すでに保存されているデータを取得
$sample_text = get_post_meta($post->ID, 'sample_text', true);
$sample_radio = get_post_meta($post->ID, 'sample_radio', true);
?>
<label for="sample_text">テキスト項目</label>
<input id="sample_text" type="text" name="sample_text" value="<?php echo $sample_text; ?>">
<br>
<label for="sample_radio1">選択肢1</label>
<input id="sample_radio1" type="radio" name="sample_radio" value="1" <?php if ($sample_radio == 1) echo 'checked'; ?>>
<label for="sample_radio2">選択肢2</label>
<input id="sample_radio2" type="radio" name="sample_radio" value="2" <?php if ($sample_radio == 2) echo 'checked'; ?>>
<?php
}
今回の例では「テキスト項目」というテキスト入力欄、「選択肢」というラジオボタンを作成した例です。
もちろんチェックボックスやセレクトなども自由に使えます。
詳しくコードの解説をしていきますね。
関数実行時に引数を設定する
function insert_custom_fields($post)
{
//省略
}
関数insert_custom_fields
の実行時に、引数$post
を設定しました。
add_meta_box
で指定した名前の関数を実行する際に引数を入れておくと、関数内でセクションが表示されている投稿データがオブジェクトで扱えるようになります。
あとで入力欄を作っていくときに必要な投稿IDなどが参照できるんですね。
引数を指定していない場合も関数内でglobal $post;
と書いておけば投稿データを扱えますが、最初から引数に入れておくのが簡単でおすすめ。
nounceフィールドの追加
//nounceフィールドの追加
wp_nonce_field('custom_field_save_meta_box_data', 'custom_field_meta_box_nonce');
nounceとは、文字通り「1度きり、使いきり」で用いられるデータの送信の妥当性をチェックするためのパスワードを意味します。
具体的にはフォーム内で<input type="hidden" name="xxxxx" value="xxxx">
のように、ユーザーに見えないように自動でランダムな文字列を仕込んでおき、送信データ($_POST
)を保存するときに正しいパスワードが送られているかどうかチェックするもの。
不正なデータ送信・保存を防ぐための仕組みの一つです。
wp_nonce_field
を使うと、WordPressが勝手に必要なパスワードを生成してhidden
状態でタグを生成してくれます。
今回はname
属性にcustom_field_meta_box_nonce
を指定し(第2引数)、value
属性にはcustom_field_save_meta_box_data
をベースに生成する使い捨てパスワードを発行(第1引数)するようにしました。
<input type="hidden" name="custom_field_meta_box_nonce" value="XXXXXXXXXXX">
のようなものを作って出力した、という意味ですね。
これはデータの保存処理を作るときに使うので、頭の片隅に記憶しておいてください。
すでに保存されているデータを取得
//すでに保存されているデータを取得
$sample_text = get_post_meta($post->ID, 'sample_text', true);
$sample_radio = get_post_meta($post->ID, 'sample_radio', true);
inputタグを生成するときに、すでに保存された過去のデータがあればvalueに仕込んでおく必要があります。
あらかじめ保存されているデータを取得して変数$sample_text
、$sample_radio
に代入している部分です。
get_post_meta
という関数を使ってデータ取得できます。
get_post_meta(投稿ID, 取得データの項目名, true);
「データの項目名」はinput
タグなどのname
属性に設定している値を入れます。
今回は下記2種類のタグを作る予定なので、get_post_meta
を2回実行しました。
<input type="text" name="sample_text">
<input type="radio" name="sample_radio">
入力欄を生成
?>
<label for="sample_text">テキスト項目</label>
<input id="sample_text" type="text" name="sample_text" value="<?php echo $sample_text; ?>">
<br>
<label for="sample_radio1">選択肢1</label>
<input id="sample_radio1" type="radio" name="sample_radio" value="1" <?php if ($sample_radio == 1) echo 'checked'; ?>>
<label for="sample_radio2">選択肢2</label>
<input id="sample_radio2" type="radio" name="sample_radio" value="2" <?php if ($sample_radio == 2) echo 'checked'; ?>>
<?php
入力欄はHTMLを埋め込むので、いったん?>
と<?php
で囲んでPHPを終了してから記述しています。
もちろん<?php echo '<input type="text" .......'>; ?>
などとecho
を駆使してPHPのまま書いていってもいいのですが、量が多くて面倒なので今回の形としました。
HTML部分は素直に記述していてOK。
今回はなるべくシンプルに作っていますが、<div>
タグなどを使って装飾したりテーブルを組んだりしても問題ありません。
ただしvalue
部分には気をつけてください。
先ほど$sample_text
、$sample_radio
にて保存データを取得したため、value
部分でecho
して入れ込むようにしています。
するとユーザーがデータを編集するときに、先に前のデータが入っているので迷わずにすみます。
データの保存処理
function save_custom_fields($post_id)
{
//nounceがセットされているか確認
if (!isset($_POST['custom_field_meta_box_nonce'])) {
return;
}
//nounceが正しいか検証
if (!wp_verify_nonce($_POST['custom_field_meta_box_nonce'], 'custom_field_save_meta_box_data')) {
return;
}
//sample_textデータを保存
if (isset($_POST['sample_text'])) {
$data = sanitize_text_field($_POST['sample_text']);
update_post_meta($post_id, 'sample_text', $data);
}
//sample_radioデータを保存
if (isset($_POST['sample_radio'])) {
$data = sanitize_text_field($_POST['sample_radio']);
update_post_meta($post_id, 'sample_radio', $data);
}
}
add_action('save_post', 'save_custom_fields');
最後にデータを保存する処理を記述します。
これをしないと管理画面の見た目上はフォームがあって動作するように見えても一切データは保存・更新されないので、すごく大事な部分ですね。
関数実行時に引数を設定する
function save_custom_fields($post_id)
{
//省略
}
add_action('save_post', 'save_custom_fields');
最初にセクションを用意したとき同様、関数save_custom_fields
はadd_action
を使ってデータ保存処理時に実行されるようにしています。
引数に$post_id
を入れておくことで、関数内で保存しようしている記事IDを参照することが可能です。
記事IDは必ず必要になるので忘れないようにしてください。
nounceがセットされているか確認
//nounceがセットされているか確認
if (!isset($_POST['custom_field_meta_box_nonce'])) {
return;
}
先ほどフォーム部分のHTMLを作るときに、wp_nonce_field
を使ってnounceを生成しておきました。
もしデータ送信時(保存時)にnounceが含まれていないのであれば、管理画面を操作して所定の保存処理を行っていない不正送信の可能性があるので除外します。
nounceが正しいか検証
//nounceが正しいか検証
if (!wp_verify_nonce($_POST['custom_field_meta_box_nonce'], 'custom_field_save_meta_box_data')) {
return;
}
nounceが送信データに含まれていたとしても、フォーム生成時につくった使い切りパスワードと一致していなければ、これも不正送信の可能性があるので除外します。
wp_verify_nonce
という関数を使えば、送信されてきたnounceが正しいかどうか判別してくれます。
wp_verify_nonce(name属性に指定したもの, value属性に指定したもの)
wp_nonce_field
を実行したときに決めたname
属性とvalue
属性を引数に指定すると、正しいデータのときはtrue
、正しくないときはfalse
を返してくれます。
今回は!wp_coune_field()
として、false
になったとき = データが正しくないときを条件として指定しました。
逆に言えば、nounceが正しければ保存して問題ないということですね。
データを保存する
//sample_textデータを保存
if (isset($_POST['sample_text'])) {
$data = sanitize_text_field($_POST['sample_text']);
update_post_meta($post_id, 'sample_text', $data);
}
//sample_radioデータを保存
if (isset($_POST['sample_radio'])) {
$data = sanitize_text_field($_POST['sample_radio']);
update_post_meta($post_id, 'sample_radio', $data);
}
いよいよデータを保存します。
isset
を使って、フォームから送信されたデータのなかにカスタムフィールドの項目があるかどうか判定しています。
項目が含まれていた場合そのまま保存することもできますが、データ形式が不正にならないようにするため、sanitize_text_field
を実行してデータを調整しました。
調整後のデータをupdate_post_meta
という関数を使って保存。
update_post_meta(記事ID, name属性, 保存データ);
という形で保存(更新)されます。
まとめ
フォームを作るだけではなく、やや複雑な手順を踏む必要があるので理解していないと何をどうしたらいいのか困ってしまうのがカスタムフィールド。
- セクション(表示領域)確保
- フォーム生成
- 保存処理
の順で行っていけば問題ありません。
ぜひプラグインに頼らずカスタムフィールドを設定していってください。
コメント