WordPress Logo WordPress カスタムフィールドの使い方

カスタムフィールドの基本的な使い方や add_meta_box で独自にカスタムフィールドを追加する方法、その際の wp_nonce_field を使った CSRF 対策などについての覚え書きです。

更新日:2022年03月13日

作成日:2019年05月04日

カスタムフィールドの概要

WordPress には、記事のタイトルや本文以外に「カスタムフィールド」と言う独自の情報を追加して利用できる機能があります。

カスタムフィールドは初期設定では表示されていない(場合がある)ので、その場合は右上のオプションのアイコンをクリックして「オプション」を表示させて「カスタムフィールド」の項目にチェックを入れます。

表示オプションのカスタムフィールドの項目

カスタムフィールドの領域が表示されるので、値を入力するには ▼ のアイコンをクリックします。

投稿画面に追加されたカスタムフィールド

以下のようなカスタムフィールドの入力欄が表示されます。「名前」と「値」を入力して「カスタムフィールドを追加」をクリックするとカスタムフィールドのデータが保存されます。

カスタムフィールドの入力欄

カスタムフィールドは一度追加すると、他の記事でも次回以降はプルダウンから選択することができます。

追加されたカスタムフィールドとその入力欄

カスタムフィールドは「名前(キー)」とその「値」の組み合わせからなっていてこれらの情報はメタデータと呼ばれています。

「名前」はカスタムフィールドの情報(メタデータ)を識別するための名称(キー)で、「値」は対応する情報を指します。1つの記事で同じ「名前」を複数回使って「値」を複数設定することもできます。

同じ「名前」で追加したカスタムフィールド

新しいカスタムフィールドを設定するには「新規追加」をクリックすると、新たに名前を入力できるようになります。また、その際に名前の入力欄でクリックするか「キャンセル」をクリックするとすでに入力されている名前を選択することができます。

カスタムフィールドの「新規追加」をクリックした際

WordPress Codex 日本語版:カスタムフィールドの使い方

カスタムフィールドを表示

カスタムフィールドは入力しただけでは表示することができないので、テンプレートにテンプレートタグを記述して表示します。

カスタムフィールドを表示するテンプレートタグは複数ありますが、the_meta() と言うテンプレートタグを使用するとその記事に設定したカスタムフィールドを全て表示することができます。

このテンプレートタグはパラメータがないので、以下のようにループ内に記述するとその投稿に設定されているカスタムフィールドを表示することができます。

<?php the_meta(); ?>

カスタムフィールドの設定例

例えば、上記のようにカスタムフィールドが設定されている場合は、以下のように出力されます。

<ul class="post-meta">
  <li><span class="post-meta-key">場所:</span> 東京タワー, 浅草寺</li>
  <li><span class="post-meta-key">期間:</span> 5月3日~5月10日</li>
</ul>

the_meta

現在の投稿のカスタムフィールドの内容を出力します。

the_meta() は全てのカスタムフィールドの名前と値を「名前:値」という形で<ul>と<li>でマークアップして出力します。このテンプレートタグはループ内または個別投稿のテンプレート(single.php など)内で使する必要があります。

但し、the_meta() は出力されるマークアップを変更したり、特定のフィールドだけを出力するといったカスタマイズはできません。

the_meta()

パラメータ
なし
戻り値
なし
利用可能箇所
ループ内または個別ページ内

このテンプレートタグはパラメータがないので、以下のようにループ内や個別ページのテンプレートに記述するとその記事に設定されているカスタムフィールドを表示することができます。

<?php the_meta(); ?>

以下が出力例です。

ul 要素には post-meta クラスが付与され、カスタムフィールドの名前と値は li 要素内に出力されます。

カスタムフィールドの「名前」は post-meta-key クラスが付与された span 要素で囲まれます。

同じ「名前」に複数の「値」がある場合はカンマ区切りで表示されます。

<ul class="post-meta">
  <li><span class="post-meta-key">場所:</span> 東京タワー, 浅草寺</li>
  <li><span class="post-meta-key">期間:</span> 5月3日~5月10日</li>
</ul>

カスタムフィールドの設定例

以下は the_meta() のソースです。

function the_meta() {
  if ( $keys = get_post_custom_keys() ) {
    $li_html = '';
    foreach ( (array) $keys as $key ) {
      $keyt = trim( $key );
      if ( is_protected_meta( $keyt, 'post' ) ) {
        continue;
      }

      $values = array_map( 'trim', get_post_custom_values( $key ) );
      $value  = implode( $values, ', ' );

      $html = sprintf(
        "<li><span class='post-meta-key'>%s</span> %s</li>\n",
        /* translators: %s: Post custom field name */
        sprintf( _x( '%s:', 'Post custom field name' ), $key ),
        $value
      );

      /**
       * Filters the HTML output of the li element in the post custom fields list.
       * @since 2.2.0
       * @param string $html  The HTML output for the li element.
       * @param string $key   Meta key.
       * @param string $value Meta value.
       */
      $li_html .= apply_filters( 'the_meta_key', $html, $key, $value );
    }

    if ( $li_html ) {
      echo "<ul class='post-meta'>\n{$li_html}</ul>\n";
    }
  }
}

カスタムフィールドの情報を取得・出力

カスタムフィールドに入力した情報(メタデータ)を取得するテンプレートタグは複数あります。get_post_meta() を使えばほとんどのことが可能だと思います(他の関数は内部的にはこの関数を呼び出しています)が、目的に応じてテンプレートタグを使い分けます。

取得される値はエスケープ処理はされておらず入力されたそのままの文字列なので、esc_attresc_html などを使って必要に応じてエスケープ処理します。

get_post_meta

投稿 ID とカスタムフィールドの名前(キー)を指定して特定のカスタムフィールドの値を返します。

名前(キー)を指定しない場合は全てのカスタムフィールドの値を配列として返しますが、内部的に使用されている値も返されます。

可能な場合はカスタムフィールドの情報(メタデータ)をキャッシュから取得します。

get_post_meta($post_id, $key, $single)

パラメータ
  • $post_id(整数):(必須) カスタムフィールドを取得したい投稿の ID。
    ループ内で投稿 ID を取得するには get_the_ID() を使います(または $post->ID)。
    サブループ内では投稿オブジェクトの ID プロパティ(例: $my_post->ID)を使用します。
  • $key(文字列):(オプション) 取得したいカスタムフィールドの名前(キー)の文字列。初期値:空文字列。
  • $single(真偽値):(オプション) true を指定した場合、文字列として単一の値を返します。false または何も指定しない場合、カスタムフィールドの配列を返します。初期値: false。
戻り値
  • $id のみを指定して $key を指定しない場合、その投稿に関するすべてのカスタムフィールドの値(内部的に使用されている値も含む)を配列として返します。
  • $single が false または何も指定しない場合、指定したキーを持つ全ての値からなる配列。
  • $single を true に指定した場合、指定されたキーを持つ最初の値の文字列(個々の値が配列である場合は最初の配列が返る)。
  • 返す値がなかった場合は空の配列($single を true に指定した場合は空の文字列)。
利用可能箇所
どこでも

以下はループ内で現在の投稿のカスタムフィールドの全てのキーから値を取得する例です。

これは get_post_custom() をパラメータなしで実行するのと同じことになります。

<?php $meta = get_post_meta( get_the_ID() ); ?>

以下は取得した値(上記の $meta)の var_dump() での実行結果の例です。

連想配列のキーがカスタムフィールドの名前になっていて、値は配列になっています。

_edit_lock や _edit_last などの内部的な値も含まれていることがわかります。

array(5) {
  ["_edit_lock"]=>
  array(1) {
    [0]=>
    string(12) "1556328510:1"
  }
  ["_edit_last"]=>
  array(1) {
    [0]=>
    string(1) "1"
  }
  ["場所"]=>
  array(2) {
    [0]=>
    string(15) "東京タワー"
    [1]=>
    string(9) "浅草寺"
  }
  ["期間"]=>
  array(1) {
    [0]=>
    string(20) "5月3日~5月10日"
  }
  ["_encloseme"]=>
  array(1) {
    [0]=>
    string(1) "1"
  }
}

因みに、以下のように $key に空文字列と $single に true を指定しても上記と同じ結果になってしまい配列が返されます。

$meta = get_post_meta( get_the_ID(), '', true );

基本的な使い方

投稿 ID とカスタムフィールドのキー名を指定してそのカスタムフィールドの値を取得します。

以下はループ内で現在の投稿の「場所」と言う名前のカスタムフィールドの値を取得する例です。

この場合、第3パラメータの $single を指定していないので、該当する値が1つでも配列が返されます。

<?php $meta = get_post_meta( get_the_ID(), '場所'); ?>

以下は上記で取得した値を出力する例です。投稿によっては該当するフィールドがない場合がありますが、その場合は空の配列が返されるのでエラーにはなりませんが、該当するフィールドに値が設定されている場合のみ処理しています。

カスタムフィールドには HTML が許可されているので esc_html() でエスケープ処理しています。

<?php 
$meta = get_post_meta( get_the_ID(), '場所');

if($meta) {
  foreach($meta as $val) {
    echo esc_html($val) . '<br>';
  }
}
?>

値を1つだけ取得する場合

1つの投稿に対して同じ名前のカスタムフィールドを複数持つことができるので、get_post_meta() の戻り値はデフォルトでは配列になっています。

1つの値(複数ある場合は最初の値)だけを文字列として取得するには、3つ目のパラメータに「true」を指定します。

<?php 
$meta = get_post_meta( get_the_ID(), '場所', true);

echo esc_html($meta);
?>

1つの値(最初の値)だけを文字列として取得する場合は、get_post_meta() を使わず以下のように $post->キー名 で値を取得することもできます(キー名はクォートで囲みません)。

<?php echo esc_html( $post->場所 ); ?>

もし、カスタムフィールドに入力された改行も出力する際に反映させたい場合は nl2br() を使います。

<?php 
echo nl2br( esc_html( get_post_meta( get_the_ID(), '場所', true) ) ); 
//以下でも同じ
echo nl2br( esc_html( $post->場所 ) );
?>

カスタムフィールドの値を元にリンクを出力する例

以下は特定のカスタムフィールドが設定されていれば、カスタムフィールドの名前と値を使ってリンクを出力する例です。

カスタムフィールドには以下のような情報を設定する前提です(値はカンマで区切る必要があり、あまり実用的ではないかも知れません)。

  • カスタムフィールドの名前(キー):リンク
  • カスタムフィールドの値:サイト名と URL をカンマ区切りで指定

10行目では、カンマ区切りの値を分割した URL 文字列の前後の空白文字を除去しています。もし URL の前に空白文字があると esc_url() で処理する際に空文字列が返されてしまいます。

<?php
//名前(キー)が「リンク」のカスタムフィールドの値を配列で取得
$links = get_post_meta($post->ID, 'リンク');
$output = '';
if($links) {  //取得した配列が空でなければ以下を実行
  foreach($links as $link){
    //カスタムフィールドの値をサイト名と URL に分割
    $values = explode(',', $link);
    //前後に入っている可能性のある空白文字を除去
    $url = trim($values[1]);
    $site_name = trim($values[0]);
    //カスタムフィールドから取得した値はエスケープ処理
    $output .= '<li><a href="' .  esc_url( $url ) .'">' 
            . esc_html($site_name) .'</a></li>' ."\n";  
  }
  echo '<ul>' . $output. '</ul>'."\n";
}
?>

関連項目:値を元にリンクを出力

関連ページ:カスタムフィールドの値をタイトルとして出力(1)

以下は get_post_meta() のソースです。

get_metadata() の第1パラメータ(オブジェクトの種類 comment, post, term, user)に post を指定した実行結果を返しています。

WordPress Code Reference: get_metadata()

function get_post_meta( $post_id, $key = '', $single = false ) {
  return get_metadata( 'post', $post_id, $key, $single );
}

以降に掲載されている他のカスタムフィールドの情報を取得する関数は、get_post_meta() の派生的な関数です。

get_post_custom

指定した記事や固定ページの全てのカスタムフィールドの情報を配列で返します。

パラメータなしで実行すると、現在処理中の投稿からカスタムフィールドが読み込まれその「名前」と「値」からなる連想配列が返されます。

パラメータとして投稿の ID を指定すると、その投稿のカスタムフィールドが読み込まれます。

可能な場合はカスタムフィールドの情報(メタデータ)はキャッシュから取得されます。

get_post_custom( $post_id )

パラメータ
$post_id(整数):(オプション) カスタムフィールド情報を取得したい投稿の ID。初期値:現在の投稿(global $post の ID)
戻り値
カスタムフィールドに設定した情報の連想配列。
  • 連想配列のキーがカスタムフィールドの名前になり、値は 0 から始まる配列(同じ名前に対して複数の値が存在するため)になっています。
  • 同じ名前に複数の値を登録した場合、登録したときの順序と配列に読み込まれる順序は一致するとは限りません。
  • カスタムフィールドの名前の先頭に「_(アンダーバー)」の付いているフィールドは内部的に使用されているものです。
利用可能箇所
基本的にはループ内(投稿ID を指定すればどこでも可能)

取得されるデータは、以下のような連想配列になっています。

  • 連想配列のキー:カスタムフィールドの名前
  • 連想配列の値:キー(名前)に対応する値の配列(同じ名前に対して複数の値が存在するため)
<?php
$meta = get_post_custom( );
var_dump($meta);
?>
//カスタムフィールドが設定されている場合の例
array(5) {
  ["_edit_lock"]=>  //キー(内部的なもの)
  array(1) { //値(配列)
    [0]=> 
    string(12) "1556412106:1"
  }
  ["_edit_last"]=>  //キー(内部的なもの)
  array(1) { //値(配列)
    [0]=>
    string(1) "1"
  }
  ["場所"]=>  //キー
  array(2) { //値(配列)
    [0]=>
    string(15) "東京タワー"
    [1]=>
    string(9) "浅草寺"
  }
  ["期間"]=>  //キー
  array(1) { //値(配列)
    [0]=>
    string(20) "5月3日~5月10日"
  }
  ["_encloseme"]=>  //キー(内部的なもの)
  array(1) { //値(配列)
    [0]=>
    string(1) "1"
  }
}

//カスタムフィールドが設定されていない場合の例
array(3) {
  ["_edit_lock"]=>  //キー(内部的なもの)
  array(1) {
    [0]=>
    string(12) "1555235522:1"
  }
  ["_wp_old_slug"]=>  //キー(内部的なもの)
  array(1) {
    [0]=>
    string(39) "the_content-%e3%83%86%e3%82%b9%e3%83%88"
  }
  ["_edit_last"]=>  //キー(内部的なもの)
  array(1) {
    [0]=>
    string(1) "1"
  }
}

以下は単純に p 要素と改行を使って get_post_custom() で取得した値を出力する例です。取得するカスタムフィールド情報は(多次元の)配列になっています。

名前の先頭にアンダーバー(_)の付いているフィールドは内部的に使用されているものなので正規表現を使って除外しています(5行目)。

<?php
$meta = get_post_custom( );
 
foreach($meta as $name => $values) {
  //内部的に使用されている(アンダーバーから始まる)もの以外
  if(!(preg_match("/^_/", $name))){
    echo '<p>キー名 : ' .esc_html($name) .'<br>';
    //$values も配列
    foreach($values as $value) {
      echo esc_html($value) .'<br> ';
    } 
    echo '</p>';
  }
}
?>

以下は get_post_custom() のソースです。

get_post_meta() の第1パラメータのみを指定した実行結果を返しています。

function get_post_custom( $post_id = 0 ) {
  $post_id = absint( $post_id );
  if ( ! $post_id ) {
    $post_id = get_the_ID();
  }

  return get_post_meta( $post_id );
}

get_post_custom_keys

指定した記事や固定ページの全てのカスタムフィールドの名前(キー)を格納した配列を取得します。

get_post_custom() で取得した値(配列)の名前の配列のみを返す関数です。

カスタムフィールドを扱う際に個々の投稿(固定ページ)に設定してあるカスタムフィールドの名前を取得して判定する場合などに使ったりします。その後、必要に応じて名前を元に get_post_custom_values() で値を取得することができます。

get_post_custom_keys($post_id);

パラメータ
$post_id(整数):(オプション) カスタムフィールドの名前(キー)を取得したい投稿の ID。初期値:現在の投稿(global $post の ID)
戻り値
すべてのカスタムフィールドの名前(キー)を格納した配列。
利用可能箇所
投稿の ID を指定しない場合はループ内、ID を指定すればどこでも可能

以下は現在のページのカスタムフィールドの全ての名前(内部的な値を除く)を配列に格納する例です。確認のために echo で出力しています。

カスタムフィールドの名前は、もし前後に空白文字が入っていれば trim() でそれらを削除しています。

<?php
//カスタムフィールドの全ての名前を読み込み変数 $keys_all に代入
$all_keys = get_post_custom_keys();	
//配列変数 my_keys を初期化
$my_keys = array();	

foreach($all_keys as $key) {
  //「_」が先頭に付いているカスタムフィールドの名前は除外する
  if( !preg_match('/^_/', $key)) {	
    //配列 my_keys に前後の空白を削除したカスタムフィールドの名前を格納
    $my_keys[] = trim($key);	
  }
}

//カスタムフィールドの名前を出力(確認用)
foreach($my_keys as $my_key) {
  echo esc_html( $my_key ).'<br>';
}
?>

以下は get_post_custom_keys() のソースです。

array_keys()get_post_custom() の結果からキーの配列のみを取得して返しています。

function get_post_custom_keys( $post_id = 0 ) {
  $custom = get_post_custom( $post_id );

  if ( ! is_array( $custom ) ) {
    return;
  }

  if ( $keys = array_keys( $custom ) ) {
    return $keys;
  }
}

get_post_custom_values

指定した投稿からパラメータで指定したキーを持つ全てのカスタムフィールドの値を配列で取得します。

get_post_custom() で取得した値(配列)から指定したキーの値(の配列)を返す関数です。

get_post_custom_values( $key, $post_id )

パラメータ
  • $key(文字列):(必須) カスタムフィールドのキー(名前)
  • $post_id(整数):(オプション) カスタムフィールドの値を取得したい投稿の ID。初期値:現在の投稿(global $post の ID)
戻り値
すべてのカスタムフィールドの値を格納した配列。指定したキー(名前)を持つカスタムフィールドが存在しない場合は null を返す。
利用可能箇所
投稿の ID を指定しない場合はループ内、ID を指定すればどこでも可能

以下はループ内でカスタムフィールドの名前が「場所」の値を取得して出力する例です。

出力する際には配列の添え字の値 +1 の後に値を表示しています。

<?php
$mykey = '場所';
$mykey_values = get_post_custom_values( $mykey );
if($mykey_values) {
  foreach ( $mykey_values as $key => $value ) {
    $value = esc_html($value);
    echo $key + 1  .":  $value ( $mykey )<br>"; 
  }
}
?>

以下は get_post_custom_values() のソースです。

get_post_custom() の結果からパラメータで指定したキーの配列のみを取得して返しています。

function get_post_custom_values( $key = '', $post_id = 0 ) {
  if ( ! $key ) {
    return null;
  }

  $custom = get_post_custom( $post_id );

  return isset( $custom[ $key ] ) ? $custom[ $key ] : null;
}

post_custom

現在の投稿の指定されたキー(名前)のカスタムフィールドの値を返します。

post_custom( $key )

パラメータ
$key(文字列):(オプション) カスタムフィールドのキー(名前)。初期値:空文字列。
※オプションとなっているが、何も指定しない(または空文字を指定する)と false が返る。
戻り値
パラメータで指定されたカスタムフィールドの値。
  • 値が複数ある場合は配列
  • 値が1つの場合は値の文字列(HTML を含む)
  • カスタムフィールドが設定されていない場合やパラメータを指定しない場合は false
利用可能箇所
ループ内

以下はループの中で「場所」という名前(キー)のカスタムフィールドの値を出力する例です。

post_custom() の返す値はそのキーに対応する値が複数ある場合は配列、1つの場合は文字列、存在しない場合は false を返します。

4行目では値が存在するかを判定して存在する場合のみ出力するようにしています。

5行目では取得した値が配列かどうかを判定して、配列の場合は foreach() を使って出力しています。

<?php
$meta = post_custom('場所');
    
if($meta) {
  if(is_array($meta)){
    foreach($meta as $value) {
      echo esc_html($value) .'<br>';
    }
  }else{
    echo esc_html($meta);
  }
}
?>

以下は post_custom() のソースです。

get_post_custom() をパラメータなしで実行した結果(現在の投稿のカスタムフィールド情報の全て)から、パラメータで指定されたものを返しています。

また、取得した情報の数が1つの場合は配列の最初の要素(値の内容)を返し、複数ある場合は配列を返しています。

function post_custom( $key = '' ) {
  $custom = get_post_custom();

  if ( ! isset( $custom[ $key ] ) ) {
      return false;
  } elseif ( 1 == count( $custom[ $key ] ) ) {
      return $custom[ $key ][0];
  } else {
      return $custom[ $key ];
  }
}

独自にカスタムフィールドを追加

独自のカスタムフィールドの入力項目欄を作成する方法です。以下がおおまかな流れです。

  1. メタボックスの作成
    • 記事の編集画面は「メタボックス」と呼ばれる枠で囲んだ項目の組み合わせで構成されています。
    • 独自の入力項目を作成する場合にも、まずは新しいメタボックスを作成します。
  2. 入力エリアの HTML の作成
    • メタボックスの中に表示する入力項目などの HTML をコールバック関数で記述します。
    • 入力欄は HTML のフォーム(input 要素など)を利用します。
  3. 入力された情報の保存
    • 入力した情報をデータベースに保存する処理を記述します。

設定したカスタムフィールドの値を取得して表示するには get_post_meta() などを使います。

以下は input 要素(ページのタイトル)と textarea 要素(ページの説明)の2つの入力項目を持つカスタムフィールドの例です。

いろいろな作成方法がありますが、以下ではほぼ同じことを少し異なる方法で記述する例です。

Sample 1
  • 1つの add_meta_box() で2つの入力項目を一緒に作成(グループ化される)
  • add_meta_box() の第7パラメータ $callback_args を使用
Sample 2
  • Sample 1同様、1つの add_meta_box() で2つの入力項目を一緒に作成
  • add_meta_box() の第7パラメータ $callback_args は使用せず、独自の変数を設定
Sample 3
  • 2つの入力項目を別々の add_meta_box() で作成
  • add_meta_box() の第7パラメータ $callback_args は使用しない

以下は、2つの入力項目を1つの add_meta_box() を使って作成する例です。

add_meta_box() で指定できる画面上に表示されるタイトル文字列は1つなので、それぞれの項目の HTML を出力する際に、label 要素を使って項目別のタイトルを出力しています。

Sample 1
//メタボックスの作成
function add_my_custom_meta_box() {
  add_meta_box(
    'meta_info',  //編集画面の HTML 要素の id 属性
    'メタ情報入力欄',  //画面上に表示されるタイトル文字列
    'my_meta_box_markup', //HTML を出力するコールバック関数(表示用関数)名
    'post',
    'normal',
    'high',
    //入力エリアの HTML を出力する表示用関数の第2パラメータを使って参照する値を指定
     array( 
       'title_key' => 'my_title',   //カスタムフィールドのキー
       'title_label' => 'ページのタイトル',  //項目別のタイトル
       'description_key' => 'my_description',   //カスタムフィールドのキー
       'description_label' => 'ページの説明'  //項目別のタイトル
     )
  );
}
add_action('add_meta_boxes', 'add_my_custom_meta_box');

//入力エリアの HTML を出力する関数(第2引数 $box を指定する方法)
function my_meta_box_markup($post, $box) {
  wp_nonce_field('meta_box_title_and_description_action', 'my_meta_box_nonce');
  $cf_title_key = trim($box['args']['title_key']);  //'my_title'
  $cf_title_label = trim($box['args']['title_label']);  //'ページのタイトル'
  $cf_title_value = esc_html(get_post_meta($post->ID, $cf_title_key, true));  //カスタムフィールド my_title の値
  $cf_description_key = trim($box['args']['description_key']);  //'my_description'
  $cf_description_label = trim($box['args']['description_label']);  //'ページの説明'
  $cf_description_value = esc_html(get_post_meta($post->ID, $cf_description_key, true));  //カスタムフィールド my_description の値
?>
<div id="meta_info">
  <p>ページのメタ情報を入力してください。</p>
  <div>
    <label for="<?php echo $cf_title_key; ?>"><?php echo $cf_title_label; ?></label><br>
    <input type="text" name="<?php echo $cf_title_key; ?>" value="<?php echo $cf_title_value; ?>">
  </div>
  <div>
    <label for="<?php echo $cf_description_key; ?>"><?php echo $cf_description_label; ?></label><br>
    <textarea name="<?php echo $cf_description_key; ?>" rows="3"><?php echo $cf_description_value; ?></textarea>
  </div>
</div>
<?php
}

//入力された情報の保存
function save_my_custom_meta_box($post_id) {
  //HTML出力用関数で設定した nonce を取得
  $my_meta_box_nonce = isset($_POST['my_meta_box_nonce']) ? $_POST['my_meta_box_nonce'] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if(!wp_verify_nonce($my_meta_box_nonce, 'meta_box_title_and_description_action')) {	
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 
    return; 
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if(!current_user_can('edit_post', $post_id)) { 
    return; 
  }
  //カスタムフィールドのキーの配列
  $my_cf_keys = ['my_title', 'my_description'];
  
  //add_meta_box の第4パラメータ($screen)で指定した投稿タイプを確認
  if($_POST['post_type'] == 'post'){ 
    //各カスタムフィールドのキーで繰り返し
    foreach( $my_cf_keys as $cf_key ) {
      if( isset( $_POST[$cf_key] ) ) {
        update_post_meta($post_id, $cf_key, $_POST[$cf_key]);
      }
    }
  }
}
add_action('save_post', 'save_my_custom_meta_box'); 

上記のコードを functions.php に記述すると、投稿の編集画面で以下のような独自のカスタムフィールドが表示されます。

上記コードでは省略していますが、input 要素などにインラインの CSS でスタイルを指定しています。

独自のカスタムフィールドのスクリーンショット

以下は Sample 1 とほぼ同じですが、add_meta_box() の第7パラメータ $callback_args は使用せず、代わりに独自のグローバル変数を使う例です(表示されるメタボックスは Sample 1 と全く同じ)。

メタボックスの作成や HTML を出力する関数、入力された情報を保存する関数の中では独自に設定した変数にアクセスするには global キーワードの指定が必要です。

Sample 1 や Sample 3 では、入力された情報を保存する関数の中でカスタムフィールドのキーを記述する必要がありますが、この場合は独自に設定した変数を使うことができます。

但し、グローバル変数はどこで値が設定・変更されているかわかりづらいため、多用するとソースコードが読みにくくなりバグの原因ともなるので、できるだけ利用しない方が良いとされています。

Sample 2
//カスタムフィールドのキーとHTMLで出力する文字(ラベル)の変数を設定
$my_box_data = array() ;
$my_box_data["key"]["title"] = 'my_title' ; //カスタムフィールドのキー
$my_box_data["label"]["title"] = 'ページのタイトル' ; //出力する文字(ラベル)
$my_box_data["key"]["description"] = 'my_description' ; //カスタムフィールドのキー
$my_box_data["label"]["description"] = 'ページの説明' ;  //出力する文字(ラベル)

//メタボックスの作成
function add_my_custom_meta_box() {
  add_meta_box(
    'meta_info',
    'メタ情報入力欄',
    'my_meta_box_markup',
    'post',
    'normal',
    'high'
  );
}
add_action('add_meta_boxes', 'add_my_custom_meta_box');
 
//入力エリアの HTML を出力する関数(引数は $post のみ)
function my_meta_box_markup($post) {
  wp_nonce_field('meta_box_title_and_description_action', 'my_meta_box_nonce');
  //global キーワードを指定
  global $my_box_data; //独自に設定した変数にアクセス
  $cf_title_key = trim($my_box_data['key']['title']); //'my_title'
  $cf_title_label = trim($my_box_data['label']['title']); //'ページのタイトル'
  $cf_title_value = esc_html(get_post_meta($post->ID, $cf_title_key, true)); //カスタムフィールド my_title の値
  $cf_description_key = trim($my_box_data['key']['description']);//'my_description'
  $cf_description_label = trim($my_box_data['label']['description']); //'ページの説明'
  $cf_description_value = esc_html(get_post_meta($post->ID, $cf_description_key, true)); //カスタムフィールド my_description の値

?>
<div id="meta_info">
  <p>ページのメタ情報を入力してください。</p>
  <div>
    <label for="<?php echo $cf_title_key; ?>"><?php echo $cf_title_label; ?></label><br>
    <input type="text" name="<?php echo $cf_title_key; ?>" value="<?php echo $cf_title_value; ?>">
  </div>
  <div>
    <label for="<?php echo $cf_description_key; ?>"><?php echo $cf_description_label; ?></label><br>
    <textarea name="<?php echo $cf_description_key; ?>" rows="3"><?php echo $cf_description_value; ?></textarea>
  </div>
</div>
<?php
}
 
//入力された情報の保存
function save_my_custom_meta_box($post_id) {
  //HTML出力用関数で設定した nonce を取得
  $my_meta_box_nonce = isset($_POST['my_meta_box_nonce']) ? $_POST['my_meta_box_nonce'] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if(!wp_verify_nonce($my_meta_box_nonce, 'meta_box_title_and_description_action')) {	
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 
    return; 
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if(!current_user_can('edit_post', $post_id)) { 
    return; 
  }
  
  //global キーワードを指定(カスタムフィールドのキーの配列は $my_box_data['key'])
  global $my_box_data;
  
  //add_meta_box の第4パラメータ($screen)で指定した投稿タイプを確認
  if($_POST['post_type'] == 'post'){ 
    //各カスタムフィールドのキーで繰り返し
    foreach( $my_box_data['key'] as $cf_key ) {
      if( isset( $_POST[$cf_key] ) ) {
        update_post_meta($post_id, $cf_key, $_POST[$cf_key]);
      }
    }
  }
}
add_action('save_post', 'save_my_custom_meta_box');   

以下は2つの入力項目を個別に add_meta_box() を使って作成する例です。こちらの方が場合によっては簡潔に(わかりやすく)記述できるかも知れません。

それぞれの add_meta_box() で画面上に表示されるタイトル文字列を指定しているので、HTML の出力ではそれぞれの要素(input と textarea)のみを出力し label 要素は使っていません。

また、add_meta_box() の第7パラメータ $callback_args は使用していないので、HTML を出力する関数ではカスタムフィールドのキーを直接 name 属性に指定しています。もちろん Sample 1 同様、第7パラメータを使用することもできます。

Sample 3
//メタボックスの作成
function add_my_custom_meta_box() {
  add_meta_box(
    'title_info',  //編集画面の HTML 要素の id 属性
    'タイトル情報を入力', //画面上に表示されるタイトル文字列
    'my_meta_box_title_markup', //HTML を出力する表示用関数名
    'post',
    'normal',
    'high'
  );
 
  add_meta_box(
    'description_info',  //編集画面の HTML 要素の id 属性
    'ページの説明を入力', //画面上に表示されるタイトル文字列
    'my_meta_box_description_markup', //HTML を出力する表示用関数名
    'post',
    'normal',
    'high'
  );
}
add_action( 'add_meta_boxes', 'add_my_custom_meta_box' );
 
//HTML を出力する関数(表示されるタイトル文字列:タイトル情報を入力)
function my_meta_box_title_markup( $post ) {
  wp_nonce_field( 'meta_box_title_action', 'my_title_meta_box_nonce' );
  //カスタムフィールド my_title の値
  $cf_title_value = esc_html(get_post_meta($post->ID, 'my_title', true)); 
  ?>
<div id="title_info">
  <input type="text" name="my_title" value="<?php echo $cf_title_value; ?>">
</div>
<?php
}
 
//HTML を出力する関数(表示されるタイトル文字列:ページの説明を入力)
function my_meta_box_description_markup( $post, $box ) {
  wp_nonce_field( 'meta_box_description_action', 'my_description_meta_box_nonce' );
  //カスタムフィールド my_description の値
  $cf_description_value = esc_html(get_post_meta($post->ID, 'my_description', true)); 
  ?>
<div id="meta_info">
  <textarea name="my_description" rows="3"><?php echo $cf_description_value; ?></textarea>
</div>
<?php
}
 
//入力された情報の保存
function save_my_meta_box( $post_id ) {
  //HTML出力用関数で設定した nonce をそれぞれ取得
  $my_title_meta_box_nonce = isset( $_POST[ 'my_title_meta_box_nonce' ] ) ? $_POST[ 'my_title_meta_box_nonce' ] : null;
  $my_description_meta_box_nonce = isset( $_POST[ 'my_description_meta_box_nonce' ] ) ? $_POST[ 'my_description_meta_box_nonce' ] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if ( !wp_verify_nonce( $my_title_meta_box_nonce, 'meta_box_title_action' ) ) {
    return;
  }
  if ( !wp_verify_nonce( $my_description_meta_box_nonce, 'meta_box_description_action' ) ) {
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
    return;
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if ( !current_user_can( 'edit_post', $post_id ) ) {
    return;
  }
  
  //カスタムフィールドのキーの配列
  $my_cf_keys = ['my_title', 'my_description'];
  
  //add_meta_box の第4パラメータ($screen)で指定した投稿タイプを確認
  if($_POST['post_type'] == 'post'){ 
    //各カスタムフィールドのキーで繰り返し
    foreach( $my_cf_keys as $cf_key ) {
      if( isset( $_POST[$cf_key] ) ) {
        update_post_meta($post_id, $cf_key, $_POST[$cf_key]);
      }
    }
  }
}
add_action( 'save_post', 'save_my_meta_box' );

上記のコードを functions.php に記述すると、投稿の編集画面で以下のようなカスタムフィールドが表示されます。前述の例との違いは、こちらは別々のメタボックスになっています(開閉のアイコンがそれぞれ表示されています)。

独自のカスタムフィールドのスクリーンショット

メタボックスの作成

記事の編集画面に独自のカスタムフィールドを表示する領域(メタボックス)を add_meta_box() を使って作成します。

add_meta_box() はメタボックスを追加する関数で、add_action を使って add_meta_boxes または add_meta_boxes_{post-type} アクションフックに登録して使用します。

アクションフックの中では必要な数だけ add_meta_box() を使って複数のメタボックスを作成することができます。

add_meta_box

編集画面にメタボックス(独自のカスタムフィールド入力項目)を作成する関数です。add_meta_boxes アクションフックに登録して使用します。

add_meta_box( $id, $title, $callback, $screen, $context, $priority, $callback_args )

パラメータ
  • $id(文字列):(必須)編集画面セクションの HTML 要素の id 属性の値
  • $title(文字列):(必須)画面上に表示される編集画面セクションのタイトル
  • $callback(callback):(必須) 編集画面セクションに HTML を出力するコールバック関数名。コールバック関数は次の2つのパラメータ(省略可能)を受け取ることができます。
    • 第1パラメータ:$post 現在のページの(投稿)オブジェクト
    • 第2パラメータ:$box 連想配列
  • $screen(文字列):(オプション)メタボックスの表示先となるページ(画面)の種類 (post, page, link, dashboard, comment, カスタムポストタイプ名) を指定。初期値: null
  • $context(文字列):(オプション)編集画面での表示場所 (normal, advanced または side) 。初期値:advanced
  • $priority(文字列):(オプション) メタボックスが表示される優先度 ('high', 'core', 'default' または 'low') 。初期値:default
  • $callback_args(配列):(オプション)表示用関数の第2パラメータ($box)を連想配列で指定。初期値:null。表示用関数内で $box['args']['キー'] で参照できます。
戻り値
なし
利用可能箇所
add_meta_boxes アクション または add_meta_boxes_{post-type} アクション

以下は「メタ情報入力欄」というタイトルのメタボックスを作成する例です。

add_meta_boxes アクションフックは必要に応じて $post_type(投稿タイプ)と $post(投稿オブジェクト)の2つのパラメータを受け取ることができます。

function add_my_custom_meta_box($post_type, $post) {
  add_meta_box(
    'meta_info', //表示する HTML の id 
    'メタ情報入力欄', //編集画面セクションのタイトル
    'my_meta_box_markup', //HTML を表示する関数名
    'post',  //メタボックスの表示先(投稿の編集画面で表示)
    'normal', //表示する位置
    'high' //表示する優先度(一番上に表示)
  );
}
add_action('add_meta_boxes', 'add_my_custom_meta_box', 10, 2);

特定の投稿タイプの編集時のみフックを実行したい場合は、 add_meta_boxes_{post_type} を使用することができます。こちらは $post(投稿オブジェクト)のパラメータを1つだけを受け取ります。

こちらの方が他の投稿タイプに対して不必要なフックを作成することを防ぐことができます。

function add_my_custom_meta_box($post) {
  add_meta_box(
    'meta_info', //表示する HTML の id 
    'メタ情報入力欄', //編集画面セクションのタイトル
    'my_meta_box_markup', //HTML を表示する関数名
    'post',  //メタボックスの表示先(投稿の編集画面で表示)
    'normal', //表示する位置
    'high' //表示する優先度(一番上に表示)
  );
}
add_action('add_meta_boxes_post', 'add_my_custom_meta_box');

前述の例ではメタボックスを追加する対象は投稿(post)のみでしたが、以下のようにすると固定ページにも追加することができます。

第4パラメータ $screen を配列で指定して、foreach() で処理しています。配列 $screens の要素を増やせば対象を増やすことができます。

function add_my_custom_meta_box() {
  $screens = array( 'post', 'page' );
  foreach ( $screens as $screen ) {
     add_meta_box(
      'meta_info',
      'メタ情報入力欄',
      'my_meta_box_markup',
      $screen, //'post', 'page'
      'normal',
      'high'
    );
  }
}
add_action('add_meta_boxes', 'add_my_custom_meta_box');

第7パラメータ($callback_args)を指定することで、入力エリアの HTML を出力する際に表示用関数の第2パラメータを使ってここで設定した値を参照することができます。カスタムフィールドの値を取得するためのキーや表示用関数で使用するラベルの文字などを設定しておくことができます。

以下の例では4〜5行目で設定した変数を連想配列の値にしていますが、直接文字列を指定しても問題ありません。

function add_my_custom_meta_box() {

  //表示用関数の第2パラメータを使って参照する値を変数に格納(第7パラメータで使用)
  $var1 = '$var1 の値';
  $var2 = '$var2 の値';

  add_meta_box(
    'HTML の id', 
    '編集画面タイトル', 
    'コールバック関数名',
    'ページの種類',  
    'normal', 
    'high' ,
    //第7パラメータ($callback_args)は連想配列で指定
     array( 'foo' => $var1, 'bar' => $var2 )
  );
}
add_action('add_meta_boxes', 'add_my_custom_meta_box');

入力エリアの HTML を出力する関数(表示用関数)

add_meta_box() を記述しただけではメタボックスは表示されないので、第3パラメータで指定した HTML を出力するコールバック関数を定義します。

以下は、2つの入力欄(input/textarea 要素)を持つ HTML を出力するコールバック関数の例です。

  • コールバック関数はパラメータに現在の投稿オブジェクト $post を受け取ることができます。
  • 出力する HTML は一度 PHP を終了させて出力させる方法で記述しています(5行目~17行目)。
  • 2行目:CSRF 対策の設定( nonce の名前を「'my_meta_box_nonce」として設定。カスタムフィールドの値の保存・更新時にこの値を確認。)
  • 3~4行目:すでに入力済みのデータがあれば get_post_meta() で取得して、input 要素の value 属性と textarea 要素の値として設定。
    get_post_meta() のパラメータには以下を指定します。
    • $post->ID : この関数のパラメータに受け取った $post を使って投稿の ID を指定
    • カスタムフィールドの名前(キー):入力要素の name 属性の値(
    • true :単一の結果を取得
  • 6行目:外側の HTML 要素の id 属性には add_meta_box() のパラメータ $id で指定した値を設定
  • 10行目と14行目:()name 属性は get_post_meta() の第2パラメータ(キー)に指定する値

) 保存の処理の際に使用する update_post_meta() の第2パラメータ $meta_key と同じ値にする必要があります。保存処理の際に入力値は $_POST['name 属性の値'] として保存されます。

function my_meta_box_markup($post) {
  wp_nonce_field('meta_box_title_and_description_action', 'my_meta_box_nonce');
  $cf_title_value = esc_html(get_post_meta($post->ID, 'my_title', true));
  $cf_description_value = esc_html(get_post_meta($post->ID, 'my_description', true));
?>
<div id="meta_info">
  <p>ページのメタ情報を入力してください。</p>
  <div>
    <label for="my_title">ページのタイトル</label><br>
    <input type="text" name="my_title" value="<?php echo $cf_title_value; ?>">
  </div>
  <div>
    <label for="my_description">ページの説明</label><br>
    <textarea name="my_description" rows="3"><?php echo $cf_description_value; ?></textarea>
  </div>
</div>
<?php
}

以下は表示されるメタボックスの例です。上記コードでは省略していますが、input 要素などにインラインの CSS でスタイルを指定しています。

良い方法かどうかはわかりませんが HTML の出力と一緒に <style>〜</style> を出力してスタイルを指定することもできます。

サンプルコードにより表示されるメタボックスの例

以下は投稿の新規作成画面で出力されるメタボックスの HTML です。

5行目の input 要素の value 属性と9行目の textarea 要素には値がまだ設定されていないので空の状態です。

<div id="meta_info">
  <p>ページのメタ情報を入力してください。</p>
  <div>
    <label for="my_title">ページのタイトル</label><br>
    <input type="text" name="my_title" value="">
  </div>
  <div>
    <label for="my_description">ページの説明</label><br>
    <textarea name="my_description" rows="3"></textarea>
  </div>
</div>

textarea 要素を使う場合の注意点

入力欄に textarea 要素を使う場合は <textarea>〜</textarea> の間に余分な空白や改行を入れないようにします。

以下のように記述してしまうと、保存(更新)の際に入力欄の先頭に毎回余分な空白が追加されていってしまいます。

<textarea name="my_description" rows="3">
  <?php echo get_post_meta($post->ID, 'my_description', true); ?>
</textarea>

以下のように <textarea></textarea> の間に何も入れないようにします。

<textarea name="my_description" rows="3"><?php echo get_post_meta($post->ID, 'my_description', true); ?></textarea>

表示用関数の第2パラメータ

入力エリアの HTML を出力する表示用(コールバック)関数で第2パラメータを利用するには add_meta_box() の第7パラメータ($callback_args)を指定します。

add_meta_box() の第7パラメータは連想配列で指定します。

以下は表示用関数の第2パラメータで add_meta_box() で設定した値を参照できるようにする例です。

function add_my_custom_meta_box() {

  add_meta_box(
    'meta_info',
    'メタ情報入力欄',
    'my_meta_box_markup',
    'post',
    'normal',
    'high',
    //第7パラメータ($callback_args)は連想配列で指定
    //表示用関数の第2パラメータを使って参照する値
     array( 
       // 'キー名' => '値', 
       'title_key' => 'my_title', 
       //for 属性や name 属性の値、get_post_meta() のキーとして使用
       'title_label' => 'ページのタイトル', 
       //出力するラベル(文字)として使用
       'description_key' => 'my_description',
       //for 属性や name 属性の値、get_post_meta() のキーとして使用
       'description_label' => 'ページの説明'
       //出力するラベル(文字)として使用
     )
  );
}
add_action('add_meta_boxes', 'add_my_custom_meta_box');

上記のように設定すると、表示用関数では2つ目のパラメータを受け取ることができます。

  • 定義では function my_meta_box_markup($post, $box) のようにパラメータを2つ指定します。
  • 関数内では2つ目のパラメータ $box を使って $box['args']['キー名'] で参照することができます。
  • 受け取った値には念のため trim() を使っています。
function my_meta_box_markup($post, $box) {
  wp_nonce_field('meta_box_title_and_description_action', 'my_meta_box_nonce');
  $cf_title_key = trim($box['args']['title_key']);
  $cf_title_label = trim($box['args']['title_label']);
  $cf_title_value = esc_html(get_post_meta($post->ID, $cf_title_key, true));
  $cf_description_key = trim($box['args']['description_key']);
  $cf_description_label = trim($box['args']['description_label']);
  $cf_description_value = esc_html(get_post_meta($post->ID, $cf_description_key, true));
?>
<div id="meta_info">
  <p>ページのメタ情報を入力してください。</p>
  <div>
    <label for="<?php echo $cf_title_key; ?>"><?php echo $cf_title_label; ?></label><br>
    <input type="text" name="<?php echo $cf_title_key; ?>" value="<?php echo $cf_title_value; ?>">
  </div>
  <div>
    <label for="<?php echo $cf_description_key; ?>"><?php echo $cf_description_label; ?></label><br>
    <textarea name="<?php echo $cf_description_key; ?>" rows="3"><?php echo $cf_description_value; ?></textarea>
  </div>
</div>
<?php
}

以下は2つ目のパラメータ $box を使わない場合の例(前述)で、内容的には同じことです。

こちらの方が記述量は少なくて済みますが、キーなどの値は直接入力する必要があります。

2つ目のパラメータを使う場合は、メタボックスを作成する関数 add_meta_box() の記述の中で、カスタムフィールドの名前(キー)や入力要素のラベル(文字)などを設定しておけるので、変更が必要な場合は add_meta_box() 側で変更することができます。

但し、入力された情報を保存する際はこのパラメータを参照することはできません。

function my_meta_box_markup($post) {
  wp_nonce_field('meta_box_title_and_description_action', 'my_meta_box_nonce');
  $cf_title_value = esc_html(get_post_meta($post->ID, 'my_title', true));
  $cf_description_value = esc_html(get_post_meta($post->ID, 'my_description', true));
?>
<div id="meta_info">
  <p>ページのメタ情報を入力してください。</p>
  <div>
    <label for="my_title">ページのタイトル</label><br>
    <input type="text" name="my_title" value="<?php echo $cf_title_value; ?>">
  </div>
  <div>
    <label for="my_description">ページの説明</label><br>
    <textarea name="my_description" rows="3"><?php echo $cf_description_value; ?></textarea>
  </div>
</div>
<?php
}

2つ目のパラメータ $box を使う場合と使わない場合の違いは以下のようなものです。以下の例では値を変数に入れてから HTML に記述していますが、HTML に直接記述しても結果は同じです。

get_post_meta() で入力済みのデータを取得して HTML に記述する際に、2つ目のパラメータを使わない場合は、以下のように記述します。

  • label 要素の for 属性:直接記述(my_title)
  • label 要素の文字:直接記述(ページのタイト)
  • input 要素の name 属性:直接記述(my_title)
  • input 要素の value 属性:キーは直接記述(my_title)して get_post_meta() で取得
$cf_title_value = esc_html(get_post_meta($post->ID, 'my_title', true));

<label for="my_title">ページのタイトル</label>
<input type="text" name="my_title" value="<?php echo $cf_title_value; ?>">

2つ目のパラメータを使う場合は、以下のように記述します。

  • label 要素の for 属性: $box['args']['cf_key1']
  • label 要素の文字: $box['args']['cf_label1']
  • input 要素の name 属性: $box['args']['cf_key1']
  • input 要素の value 属性:キーは $box['args']['cf_key1']を使って get_post_meta() で取得
$cf_title_key = trim($box['args']['title_key']);
$cf_title_label = trim($box['args']['title_label']);
$cf_title_value = esc_html(get_post_meta($post->ID, $cf_title_key, true));
 
<label for="<?php echo $cf_title_key; ?>"><?php echo $cf_title_label; ?></label>
<input type="text" name="<?php echo $cf_title_key; ?>" value="<?php echo $cf_title_value; ?>">

CSRF 対策

CSRF 対策として、wp_nonce_field() を使って nonce(トークン)を隠しフィールドに設定します。

CSRF 対策の1つ「トークン方式」で、トークン(ランダムな文字列)を発行し、そのトークンが一致する場合にのみ処理を実行するようにします。

wp_nonce_field

hidden 属性(type = "hidden")が付与された input 要素に生成した nonce(トークン)の値を設定して出力します。

この input 要素は画面上に表示されませんが、ソースを見れば確認することができます。

また、パラメータ $echo に false を指定すると Nonce フィールドの HTML マークアップを返します。

wp_nonce_field( $action, $name, $referer, $echo )

パラメータ
  • $action(文字列):(オプション) アクションの名前。この値を元に nonce を生成します(オプションになっていますが、ユニークな値を指定します)。初期値: -1
  • $name(文字列):(オプション) nonce の名前。この値が input 要素の name 属性の値になります(ユニークな値を指定します。$_POST[ $name ] としてトークンの確認の際に使用します)。初期値: '_wpnonce'
  • $referer(真偽値):(オプション) referer フィールドを設定するかどうか。 初期値: true
  • $echo(真偽値):(オプション) hidden フィールドをフォームに出力するかどうか。初期値: true
戻り値
$echo に false を指定した場合は Nonce フィールドの HTML マークアップ

※ $action と $name はオプションですが、デフォルトの値(-1 と _wpnonce)を使用するのはセキュリティが低下するため、独自の値を設定します。

wp_nonce_field() をテンプレートに記述すると以下のような HTML が出力されます。

デフォルトでは $referer は true なので、隠しフィールドを生成するページの URL の情報を含む input 要素も出力されます。同一のページから送信されたデータかどうかをチェックするのに使えます。

<?php wp_nonce_field('my_action','my_nonce'); ?>
                  
//以下のような HTML が出力される                  
<input type="hidden" id="my_nonce" name="my_nonce" value="生成された nonce" />
<input type="hidden" name="_wp_http_referer" value="input 要素を出力するページの URL" /> 

以下が wp_nonce_field() のソースです。

function wp_nonce_field( $action = -1, $name = '_wpnonce', $referer = true, $echo = true ) {
  $name        = esc_attr( $name );
  $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';

  if ( $referer ) {
    $nonce_field .= wp_referer_field( false );
  }

  if ( $echo ) {
    echo $nonce_field;
  }

  return $nonce_field;
}

value 属性に設定される nonce の値は wp_create_nonce() を使ってパラメータに $action を指定して生成されます。

nonce の値は現在の時刻、$action、現在のユーザー ID に基づいて生成されます。(wp_create_nonce のソース

nonce の確認

wp_nonce_field() で生成した値を検証するには wp_verify_nonce() または check_admin_referer() を使います。

この例では「入力された情報の保存」の際に行っています。

wp_verify_nonce

nonce が有効かどうかを検証します。

wp_verify_nonce( $nonce, $action )

パラメータ
  • $nonce(文字列):(必須) 検証する nonce。wp_nonce_field() で指定した $name を使って $_POST[ $name ] とします。
  • $action(文字列/整数):(オプション) アクションの名前。nonce 生成時と同じ値にします。
戻り値
認証に失敗すれば false、成功すれば次のような整数値(1または2)
  • 1:nonce は過去12時間以内に発行されている
  • 2:nonce は過去12時間~24時間以内に発行されている

以下は wp_nonce_field('my_action', 'my_nonce') で生成した nonce を検証する例です。

<?php 
//wp_nonce_field('my_action', 'my_nonce') で生成した nonce を検証
if(!wp_verify_nonce($_POST['my_nonce'], 'my_action')) {	
  //nonce を確認し値が書き換えられていれば return(何もしない)
  return;
}
?>

入力された情報の保存

メタボックスの入力項目に入力された情報を update_post_meta() を使ってカスタムフィールドのデータとして(データベースに)保存・更新する必要があります。

また、その際に CSRF 対策として wp_verify_nonce() を使って HTML を出力する関数で設定した nonce を検証します。

update_post_meta() は指定したカスタムフィールドが存在しなければ値を追加し、存在すれば値を更新します。

以下は update_post_meta() の概要です。

update_post_meta

指定した投稿のカスタムフィールドの値を更新(または追加)する関数です。

指定した投稿のカスタムフィールドが存在しない場合は、add_post_meta() を実行してカスタムフィールドを追加します。

update_post_meta( $post_id, $meta_key, $meta_value, $prev_value )

パラメータ
  • $post_id(整数):(必須) 対象の投稿 ID。
  • $meta_key(文字列):(必須) カスタムフィールドのキー(名前)
  • $meta_value(mixed):(必須) カスタムフィールドの新しい値
  • $prev_value(mixed):(オプション)同じキーのカスタムフィールドが複数ある場合、このパラメータに現在登録されている値を指定して区別する必要があります。省略すると、指定したキーを持つ全てのカスタムフィールドの値が更新されます。初期値: ''
戻り値
カスタムフィールド情報を更新できた場合は true、更新できなかった場合は false を返します。カスタムフィールドが存在しない場合はそのカスタムフィールドを追加して meta_id を返します。

カスタムフィールドに入力や変更された情報は、投稿が保存される際に保存するので save_post アクションフックを使います。

save_post は投稿や固定ページが作成または更新されたとき実行されるアクションです。

パラメータには投稿 ID と投稿オブジェクトなどを受け取ることができます。以下の例では投稿 ID のみを利用しています。

以下がカスタムフィールドの値が設定されたり更新された際にその情報を保存するコードです。

カスタムフィールドの各キーには対応する1つの値が設定されることを想定しています。

function save_my_custom_meta_box($post_id) {
  //HTML出力用関数で設定した nonce を取得
  $my_meta_box_nonce = isset($_POST['my_meta_box_nonce']) ? $_POST['my_meta_box_nonce'] : null;
  //nonce を確認し値が正しくなければ return (何もしない:CSRF 対策)
  if(!wp_verify_nonce($my_meta_box_nonce, 'meta_box_title_and_description_action')) {	
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 
    return; 
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if(!current_user_can('edit_post', $post_id)) { 
    return; 
  }
  //add_meta_box の第4パラメータ($screen)で指定した投稿タイプを確認
  if($_POST['post_type'] == 'post'){ 
    //カスタムフィールドのキーが my_title に入力された情報を保存・更新
    if( isset( $_POST['my_title'] ) ) {
      update_post_meta($post_id, 'my_title', $_POST['my_title']);
    }
    //カスタムフィールドのキーが my_description に入力された情報を保存・更新
    if( isset( $_POST['my_description'] ) ) {
      update_post_meta($post_id, 'my_description', $_POST['my_description']);	
    }
  }
}
add_action('save_post', 'save_my_custom_meta_box'); 

カスタムフィールドの値の追加及び更新は update_post_meta() を使います。

  • 第1パラメータ(投稿 ID):save_my_custom_meta_box() のパラメータで受けた $post_id
  • 第2パラメータ(カスタムフィールドのキー):HTML を出力する関数で指定した入力要素(input 要素など)の name 属性の値
  • 第3パラメータ(カスタムフィールドの値): $_POST['name 属性の値']

19行目~21行目:isset() で $_POST['my_title'] がセットされているかを判定しています(空文字列でも true が返るので設定した値を削除した場合も実行されます)。

update_post_meta() を使って入力された情報を保存・更新する部分は全て同じ処理になるので、複数ある場合はカスタムフィールドのキーの配列を用意して foreach で記述した方が簡潔になり、変更する場合も楽になります。

function save_my_meta_box( $post_id ) {
  $my_meta_box_nonce = isset( $_POST[ 'my_meta_box_nonce' ] ) ? $_POST[ 'my_meta_box_nonce' ] : null;
  if ( !wp_verify_nonce( $my_meta_box_nonce, 'meta_box_title_and_description_action' ) ) {
    return;
  }
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
    return;
  }
  if ( !current_user_can( 'edit_post', $post_id ) ) {
    return;
  }
  
  //カスタムフィールドのキーの配列
  $my_cf_keys = ['my_title', 'my_description'];
  
  if($_POST['post_type'] == 'post'){ 
    //各カスタムフィールドのキーで繰り返し
    foreach( $my_cf_keys as $cf_key ) {
      if( isset( $_POST[$cf_key] ) ) {
        update_post_meta($post_id, $cf_key, $_POST[$cf_key]);
      }
    }
  }
}
add_action( 'save_post', 'save_my_meta_box' );

もし、値が設定されているかまでを判定する場合は、以下のように値が入っていない場合は delete_post_meta() を使って値を削除するようにします(そうしないと値が削除できなくなります)。

但し、値が 0 の場合でも false になります。

if( isset( $_POST['my_title'] ) && $_POST['my_title'] ) {
  update_post_meta($post_id, 'my_title', $_POST['my_title']);
} else {
  delete_post_meta( $post_id, 'my_title', get_post_meta($post_id, 'my_title', true) );
}

または、以下のように記述して値が空でない場合を判定してもほぼ同じです。

if( isset( $_POST['my_title'] ) && $_POST['my_title'] !== '' ) {
  update_post_meta($post_id, 'my_title', $_POST['my_title']);
} else {
  delete_post_meta( $post_id, 'my_title', get_post_meta($post_id, 'my_title', true) );
}
delete_post_meta

指定したキー(と値)を持つカスタムフィールドを全て削除します。

delete_post_meta( $post_id, $meta_key, $meta_value )

パラメータ
$
  • post_id(整数):(必須) 削除対象の投稿 ID。
  • $meta_key(文字列):(必須) カスタムフィールドのキー(名前)
  • $meta_value(mixed):(オプション) 削除したいカスタムフィールドの値。同じキーのカスタムフィールドが複数ある場合、このパラメータに削除する値を指定して区別する必要があります。省略すると、指定したキーを持つカスタムフィールドはすべて削除されます。
戻り値
成功なら true、失敗なら false

カスタムフィールドの値を title タグに出力

独自のカスタムフィールドに入力された値を使って、title タグや keywords や description の meta タグを出力する例です。

独自のカスタムフィールドを作成するコードは以下になります。前述の例とほぼ同じですが、キーワードの入力欄を追加しています。

//メタボックスの作成
function add_my_custom_meta_box() {
  add_meta_box(
    'meta_info',
    'メタ情報入力欄',
    'my_meta_box_markup',
    'post',
    'normal',
    'high',
    //表示用関数の第2パラメータを使って参照する値
     array( 
       'title_key' => 'my_title',  //カスタムフィールドのキー
       'title_label' => 'ページのタイトル', //編集画面に出力する文字
       'description_key' => 'my_description', //カスタムフィールドのキー
       'description_label' => 'ページの説明', //編集画面に出力する文字
       'keywords_key' => 'my_keywords', //カスタムフィールドのキー
       'keywords_label' => 'ページのキーワード(カンマ区切りで記述)' //編集画面に出力する文字
     )
  );
}
add_action('add_meta_boxes', 'add_my_custom_meta_box');
 
//入力エリアの HTML を出力する関数
function my_meta_box_markup($post, $box) {
  wp_nonce_field('meta_box_title_and_description_action', 'my_meta_box_nonce');
  $cf_title_key = trim($box['args']['title_key']);  //'my_title'
  $cf_title_label = trim($box['args']['title_label']);  //'ページのタイトル'
  $cf_title_value = esc_html(get_post_meta($post->ID, $cf_title_key, true)); //カスタムフィールド my_title の値
  $cf_description_key = trim($box['args']['description_key']);  //'my_description'
  $cf_description_label = trim($box['args']['description_label']);  //'ページの説明'
  $cf_description_value = esc_html(get_post_meta($post->ID, $cf_description_key, true));  //カスタムフィールド my_description の値
  $cf_keywords_key = trim($box['args']['keywords_key']);  //'my_keywords'
  $cf_keywords_label = trim($box['args']['keywords_label']);  //'ページのキーワード'
  $cf_keywords_value = esc_html(get_post_meta($post->ID, $cf_keywords_key, true));  //カスタムフィールド my_keywords の値
?>
<div id="meta_info">
  <p>ページのメタ情報を入力してください。</p>
  <div>
    <label for="<?php echo $cf_title_key; ?>"><?php echo $cf_title_label; ?></label><br>
    <input type="text" name="<?php echo $cf_title_key; ?>" value="<?php echo $cf_title_value; ?>">
  </div>
  <div>
    <label for="<?php echo $cf_description_key; ?>"><?php echo $cf_description_label; ?></label><br>
    <textarea name="<?php echo $cf_description_key; ?>" rows="3"><?php echo $cf_description_value; ?></textarea>
  </div>
  <div>
    <label for="<?php echo $cf_keywords_key; ?>"><?php echo $cf_keywords_label; ?></label><br>
    <input type="text" name="<?php echo $cf_keywords_key; ?>" value="<?php echo $cf_keywords_value; ?>">
  </div>
</div>
<?php
}
 
//入力された情報の保存
function save_my_custom_meta_box($post_id) {
  //HTML出力用関数で設定した nonce を取得
  $my_meta_box_nonce = isset($_POST['my_meta_box_nonce']) ? $_POST['my_meta_box_nonce'] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if(!wp_verify_nonce($my_meta_box_nonce, 'meta_box_title_and_description_action')) {	
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 
    return; 
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if(!current_user_can('edit_post', $post_id)) { 
    return; 
  }
  
  //カスタムフィールドのキーの配列
  $my_cf_keys = ['my_title', 'my_description', 'my_keywords'];
  
  //add_meta_box の第4パラメータ($screen)で指定した投稿タイプを確認
  if($_POST['post_type'] == 'post'){ 
    //各カスタムフィールドのキーで繰り返し
    foreach( $my_cf_keys as $cf_key ) {
      if( isset( $_POST[$cf_key] ) ) {
        update_post_meta($post_id, $cf_key, $_POST[$cf_key]);
      }
    }
  }
}
add_action('save_post', 'save_my_custom_meta_box'); 

以下は add_meta_box の第7パラメータを使わないで、独自の(グローバル)変数 $my_box_data を使用する例です。内容的には前述と全く同じものです。

//カスタムフィールドのキーとHTMLで出力する文字(ラベル)の変数を設定
$my_box_data = array() ;
$my_box_data["key"]["title"] = 'my_title' ; //カスタムフィールドのキー
$my_box_data["label"]["title"] = 'ページのタイトル' ; //出力する文字(ラベル)
$my_box_data["key"]["description"] = 'my_description' ; //カスタムフィールドのキー
$my_box_data["label"]["description"] = 'ページの説明' ;  //出力する文字(ラベル)
$my_box_data["key"]["keywords"] = 'my_keywords' ; //カスタムフィールドのキー
$my_box_data["label"]["keywords"] = 'ページのキーワード(カンマ区切りで記述)' ; //出力する文字(ラベル)

//メタボックスの作成
function add_my_custom_meta_box() {
  add_meta_box(
    'meta_info',
    'メタ情報入力欄',
    'my_meta_box_markup',
    'post',
    'normal',
    'high'
  );
}
add_action('add_meta_boxes', 'add_my_custom_meta_box');

//入力エリアの HTML を出力する関数
function my_meta_box_markup($post, $box) {
  wp_nonce_field('meta_box_title_and_description_action', 'my_meta_box_nonce');
  global $my_box_data; //独自に設定した変数にアクセス
  $cf_title_key = trim($my_box_data['key']['title']); //'my_title'
  $cf_title_label = trim($my_box_data['label']['title']); //'ページのタイトル'
  $cf_title_value = esc_html(get_post_meta($post->ID, $cf_title_key, true)); //カスタムフィールド my_title の値
  $cf_description_key = trim($my_box_data['key']['description']);//'my_description'
  $cf_description_label = trim($my_box_data['label']['description']); //'ページの説明'
  $cf_description_value = esc_html(get_post_meta($post->ID, $cf_description_key, true)); //カスタムフィールド my_description の値
  $cf_keywords_key = trim($my_box_data['key']['keywords']); //'my_keywords'
  $cf_keywords_label = trim($my_box_data['label']['keywords']); //'ページのキーワード'
  $cf_keywords_value = esc_html(get_post_meta($post->ID, $cf_keywords_key, true)); //カスタムフィールド my_keywords の値
?>
<div id="meta_info">
  <p>ページのメタ情報を入力してください。</p>
  <div>
    <label for="<?php echo $cf_title_key; ?>"><?php echo $cf_title_label; ?></label><br>
    <input type="text" name="<?php echo $cf_title_key; ?>" value="<?php echo $cf_title_value; ?>">
  </div>
  <div>
    <label for="<?php echo $cf_description_key; ?>"><?php echo $cf_description_label; ?></label><br>
    <textarea name="<?php echo $cf_description_key; ?>" rows="3"><?php echo $cf_description_value; ?></textarea>
  </div>
  <div>
    <label for="<?php echo $cf_keywords_key; ?>"><?php echo $cf_keywords_label; ?></label><br>
    <input type="text" name="<?php echo $cf_keywords_key; ?>" value="<?php echo $cf_keywords_value; ?>">
  </div>
</div>
<?php
}
 
//入力された情報の保存
function save_my_custom_meta_box($post_id) {
  //HTML出力用関数で設定した nonce を取得
  $my_meta_box_nonce = isset($_POST['my_meta_box_nonce']) ? $_POST['my_meta_box_nonce'] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if(!wp_verify_nonce($my_meta_box_nonce, 'meta_box_title_and_description_action')) {	
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 
    return; 
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if(!current_user_can('edit_post', $post_id)) { 
    return; 
  }
  
  //global キーワードを指定(カスタムフィールドのキーの配列は $my_box_data['key'])
  global $my_box_data;
  
  //add_meta_box の第4パラメータ($screen)で指定した投稿タイプを確認
  if($_POST['post_type'] == 'post'){ 
    //各カスタムフィールドのキーで繰り返し
    foreach( $my_box_data['key'] as $cf_key ) {
      if( isset( $_POST[$cf_key] ) ) {
        update_post_meta($post_id, $cf_key, $_POST[$cf_key]);
      }
    }
  }
}
add_action('save_post', 'save_my_custom_meta_box'); 
title タグの出力

以下は title タグの出力の例です。add_theme_support( 'title-tag' ) で title タグが自動的に挿入されるようになっていることが前提です。

この例では pre_get_document_title フィルターを使って、カスタムフィールドに値が入力されている場合のみ title タグに(デフォルト以外の)値を出力しています。

この例の場合、カスタムフィールドの値が空かどうかを判定していませんが、get_post_meta() の $single を true に指定した場合は空の文字列が返り、pre_get_document_title フィルターでは空の文字列が返されると何もしません。

function change_title_tag_with_cfv( $title ) {
  
  //個別ページの場合
  if ( is_singular() ) {
    
    //カスタムフィールドの値を取得
    $cf_title_tag = get_post_meta( get_the_ID(), 'my_title', true );
    $title = esc_html( $cf_title_tag );
  }
  
  return $title;
}
add_filter( 'pre_get_document_title', 'change_title_tag_with_cfv' );
description と keywords の meta タグの出力

以下はカスタムフィールドに値が入力されている場合 description と keywords の meta タグを出力する例です。

この場合は head 要素内に meta タグを挿入するので wp_head アクションフックを使います。

description はカスタムフィールドに値が入力されていない場合は、抜粋が手動で入力されているかを has_excerpt() で判定して入力されていればその値(get_the_excerpt())を使用します。その際に HTML タグは除去します。

また、カスタムフィールド、手動入力の抜粋のいずれもない場合は自動抜粋の値を description に設定しています。その際に、自動抜粋で出力される文字(続きを読む)を削除しています(関連項目:文末の […] を変更)。

キーワードはカンマ区切りで入力する前提になっているので、explode() でカンマで分割して個々の値の前後の空白文字を除去して再度カンマ区切りの文字列に戻しています。

function add_meta_tags_with_cfv() {
  //個別ページの場合
  if ( is_singular() ) {
    
    //カスタムフィールドの my_description の値を取得
    $cf_description_tag = get_post_meta( get_the_ID(), 'my_description', true );
    
    //カスタムフィールドに my_description の値が設定されている場合のみ
    if($cf_description_tag) {
      //HTML タグを削除
      $description = strip_tags( trim($cf_description_tag) );
      //改行を半角スペースに変換
      $description = str_replace(array("\r", "\n"), ' ', $description);
      echo '<meta name="description" content="'. $description .'">' ."\n";
    }elseif(has_excerpt()) { //手動入力の抜粋がある場合
      //HTML タグを削除
      $excerpt = strip_tags( get_the_excerpt() );
      //改行を半角スペースに変換
      $excerpt = str_replace(array("\r", "\n"), ' ', $excerpt);
      echo '<meta name="description" content="'. $excerpt .'">' ."\n";
    }else { //カスタムフィールド、手動入力の抜粋のいずれもない場合は自動抜粋の値を設定
      setup_postdata(get_post($post->ID));
      $excerpt = strip_tags( get_the_excerpt($post->ID) );
      //改行を半角スペースに変換
      $excerpt = str_replace(array("\r", "\n"), ' ', $excerpt);
      //自動抜粋の文末に出力される文字(続きを読む)を削除(デフォルトは […] )
      $excerpt = str_replace('(続きを読む)', '', $excerpt);
      echo '<meta name="description" content="'. $excerpt .'">' ."\n";
    }    
    
    //カスタムフィールドの my_keywords の値を取得
    $cf_keywords_tag = get_post_meta( get_the_ID(), 'my_keywords', true );
    
    //カスタムフィールドに my_keywords の値が設定されている場合のみ
    if($cf_keywords_tag) {
      //カンマで分割後 trim で前後の空白を除去
      $array_keywords = array_map('trim', explode(',', $cf_keywords_tag) );
      //分割されたキーワードをカンマ区切りの文字列へ変換
      $trimmed_keywords = implode(',', $array_keywords);
      $keywords = esc_html( $trimmed_keywords );
      echo '<meta name="keywords" content="'. $keywords .'">' ."\n";
    }
  }  
}
add_action('wp_head', 'add_meta_tags_with_cfv');

canonical タグの出力

独自のカスタムフィールドに入力された値を canonical タグに出力する例です。

カスタムフィールドに値(正規ページの URL)が入力されている場合、重複コンテンツとして示すために rel="canonical" リンクタグを投稿の個別ページに出力します。

デフォルトで canonical タグが出力されるので、重複を避けるため remove_action('wp_head', 'rel_canonical') でその出力を解除しています(52行目)。

また、canonical タグの出力は、なるべく上の方に出力したいので、wp_head アクションフックに登録する際に優先度($priority)を 1 に指定しています。

//メタボックスの作成 (canonical タグ用)
function add_my_canonical_meta_box() {
  add_meta_box(
    'canonical_info',
    'canonical(正規ページの URL)を設定',
    'my_meta_box_canonical_markup',
    'post',
    'normal',
    'high'
  );
}
add_action('add_meta_boxes', 'add_my_canonical_meta_box');

//HTML を出力する関数
function my_meta_box_canonical_markup( $post ) {
  wp_nonce_field( 'meta_box_canonical_action', 'my_canonical_meta_box_nonce' );
  //カスタムフィールド my_title の値
  $cf_canonical_value = esc_html(get_post_meta($post->ID, 'my_canonical', true)); 
  ?>
<div id="canonical_info">
  <input type="text" name="my_canonical" value="<?php echo $cf_canonical_value; ?>">
</div>
<?php
}

//入力された情報の保存
function save_my_canonical_meta_box( $post_id ) {
  //HTML出力用関数で設定した nonce をそれぞれ取得
  $my_canonical_meta_box_nonce = isset( $_POST[ 'my_canonical_meta_box_nonce' ] ) ? $_POST[ 'my_canonical_meta_box_nonce' ] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if ( !wp_verify_nonce( $my_canonical_meta_box_nonce, 'meta_box_canonical_action' ) ) {
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
    return;
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if ( !current_user_can( 'edit_post', $post_id ) ) {
    return;
  }
  //add_meta_box の第4パラメータ($screen)で指定した投稿タイプを確認
  if($_POST['post_type'] == 'post'){
    if( isset( $_POST['my_canonical'] ) ) {
      update_post_meta($post_id, 'my_canonical', $_POST['my_canonical']);
    }
  }
}
add_action( 'save_post', 'save_my_canonical_meta_box' );

//デフォルトの canonical を削除
remove_action('wp_head', 'rel_canonical');

function add_canonical_tags_with_cfv() {
  //個別ページの場合
  if ( is_singular() ) {
    //カスタムフィールドの my_canonical の値を取得
    $cf_canonical = trim( get_post_meta( get_the_ID(), 'my_canonical', true ) );
    //カスタムフィールドに my_canonical の値が設定されている場合のみ
    if ( $cf_canonical ) {
      echo '<link rel="canonical" href="' . $cf_canonical . '">' . "\n";
    }
  }
}
add_action( 'wp_head', 'add_canonical_tags_with_cfv', 1 );

説明書きの追加

値を入力したりするのではなく、単に説明書きなどもカスタムフィールドとして表示することができます。

この場合、決まった文字(文章)を出力するだけなので、メタボックスの作成と表示する文章の HTML の出力だけで、入力された情報の保存は必要ないので簡単です。

add_meta_box() で表示する領域(メタボックス)を作成します。

function add_my_custom_meta_box() {
  add_meta_box('post_info','使い方','my_post_info','post','normal','high');
  
  ・・・その他の add_meta_box() を使ったメタボックスの作成(もしあれば)・・・
}
add_action('add_meta_boxes', 'add_my_custom_meta_box');

あとは表示する文章を出力する関数を記述するだけです。上記の場合、my_post_info という関数を作成します。

出力する HTML の id 属性は第2パラメータで指定した「post_info」になります。

function my_post_info() {
  global $post;
  wp_nonce_field(wp_create_nonce(__FILE__), 'my_nonce');
?>
<div id="post_info">
  <h4>メタ情報入力欄</h4>
  <dl>
    <dt>ページのタイトル(title 属性)</dt>
    <dd>オプションです。指定しない場合は、記事のタイトルが設定されます。</dd>
  </dl>
  <dl>
    <dt>ページの説明(description 属性)</dt>
    <dd>検索結果などに表示されるページの説明文です。最大124文字程度(60~100文字前後)で・・・</dd>
  </dl>
  <dl>
    <dt>キーワード(keywords 属性)</dt>
    <dd>オプションです。このページに関するキーワードを・・・</dd>
  </dl>
</div>
<?php
}

add_meta_box() で指定した文字列「使い方」が編集画面セクションのタイトルに表示されます。

上記の記述により表示されるメタボックスの例

特定のページにだけメタボックスを追加

特定の投稿タイプに対してメタボックスを作成(表示)する場合は、 add_meta_boxes_{post_type} アクションを使用することができます。

特定の投稿(ページ)のみにメタボックスを表示するには投稿 ID やスラッグを判定してメタボックスを追加するようにします。

以下のような方法が考えられます。

投稿 ID は add_meta_boxes アクションの場合は第2パラメータの $post から、add_meta_boxes_{post-type} アクションの場合は第1パラメータの $post から取得することができます。

または、アクション関数の中で以下のようにして投稿 ID を取得することもできますが、以下の例ではアクションのパラメータを利用します。

$post_id = '';
//投稿ID を $_GET['post']  または $_POST['post_ID'] から取得
if( isset($_GET['post'] ) || isset( $_POST['post_ID'] ) ) {
  $post_id = $_GET['post'] ? $_GET['post'] : $_POST['post_ID'] ;
}
投稿 ID を使って判定

以下は投稿 ID が「150」の固定ページの場合のみメタボックスを編集ページに追加する例です。

add_meta_box() の第4パラメータには「page」を指定しています。投稿の場合は「post」を指定します。

//特定のページへのメタボックスの作成(投稿 ID を使って判定)
function add_custom_meta_box_to_my_page($post_type, $post) {
  //投稿オブジェクトから ID を取得
  $post_id = $post->ID;
 
  //ID を比較して、合致すればメタボックスを追加
  if ($post_id == 150) {
    add_meta_box(
      'meta_info',
      'ページ情報入力欄',
      'my_meta_box_page_markup',
      'page',  //固定ページの場合
      'normal',
      'high',
      //表示用関数の第2パラメータを使って参照する値
       array( 
         'info_key' => 'my_info', 
         'info_label' => 'ページの情報',
       )
    );
  }
}
add_action('add_meta_boxes', 'add_custom_meta_box_to_my_page', 10, 2);

//入力エリアの HTML を出力する関数
function my_meta_box_page_markup($post, $box) {
  wp_nonce_field('meta_box_page_action', 'my_meta_box_page_nonce');
  $cf_info_key = trim($box['args']['info_key']);  //
  $cf_info_label = trim($box['args']['info_label']);
  $cf_info_value = esc_html(get_post_meta($post->ID, $cf_info_key, true));
?>
<div id="meta_info">
  <p>ページの情報を入力してください。</p>
  <div>
    <label for="<?php echo $cf_info_key; ?>"><?php echo $cf_info_label; ?></label><br>
    <input type="text" name="<?php echo $cf_info_key; ?>" value="<?php echo $cf_info_value; ?>" style="width:80%; margin:10px 0 20px;">
  </div>
</div>
<?php
}

//入力された情報の保存
function save_my_page_custom_meta_box($post_id) {
  //HTML出力用関数で設定した nonce を取得
  $my_meta_box_page_nonce = isset($_POST['my_meta_box_page_nonce']) ? $_POST['my_meta_box_page_nonce'] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if(!wp_verify_nonce($my_meta_box_page_nonce, 'meta_box_page_action')) {	
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 
    return; 
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if(!current_user_can('edit_post', $post_id)) { 
    return; 
  }
  
  //投稿 ID を確認
  if($post_id == 150){ 
    //カスタムフィールドのキーが my_info に入力された情報を保存・更新
    if(isset($_POST['my_info']) && $_POST['my_info']) {
      update_post_meta($post_id, 'my_info', $_POST['my_info']);
    } else {
      delete_post_meta( $post_id, 'my_info', get_post_meta($post_id, 'my_info', true) );
    }
  }
}
add_action('save_post', 'save_my_page_custom_meta_box'); 
投稿オブジェクトからスラッグを取得して判定

以下は、投稿オブジェクトからスラッグを取得して判定してスラッグが「about」の場合のみメタボックスを追加する例です。

//特定のページへのメタボックスの作成(投稿オブジェクトからスラッグを取得して判定)
function add_custom_meta_box_to_my_page($post_type, $post) {
  //投稿オブジェクトからスラッグを取得
  $slug = $post->post_name;
 
  //ID を比較して、合致すればメタボックスを追加
  if ($slug == 'about') {
    add_meta_box(
      'meta_info',
      'ページ情報入力欄',
      'my_meta_box_page_markup',
      'page',  //固定ページの場合
      'normal',
      'high',
      //表示用関数の第2パラメータを使って参照する値
       array( 
         'info_key' => 'my_info', 
         'info_label' => 'ページの情報',
       )
    );
  }
}
add_action('add_meta_boxes', 'add_custom_meta_box_to_my_page', 10, 2);

//入力エリアの HTML を出力する関数(前述の例と全く同じ)
function my_meta_box_page_markup($post, $box) {
  wp_nonce_field('meta_box_page_action', 'my_meta_box_page_nonce');
  $cf_info_key = trim($box['args']['info_key']);  //
  $cf_info_label = trim($box['args']['info_label']);
  $cf_info_value = esc_html(get_post_meta($post->ID, $cf_info_key, true));
?>
<div id="meta_info">
  <p>ページの情報を入力してください。</p>
  <div>
    <label for="<?php echo $cf_info_key; ?>"><?php echo $cf_info_label; ?></label><br>
    <input type="text" name="<?php echo $cf_info_key; ?>" value="<?php echo $cf_info_value; ?>" style="width:80%; margin:10px 0 20px;">
  </div>
</div>
<?php
}

//入力された情報の保存
function save_my_page_custom_meta_box($post_id) {
  //HTML出力用関数で設定した nonce を取得
  $my_meta_box_page_nonce = isset($_POST['my_meta_box_page_nonce']) ? $_POST['my_meta_box_page_nonce'] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if(!wp_verify_nonce($my_meta_box_page_nonce, 'meta_box_page_action')) {	
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 
    return; 
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if(!current_user_can('edit_post', $post_id)) { 
    return; 
  }
  
  //パラメータの $post_id(投稿 ID)からスラッグを取得
  $slug = get_post_field( 'post_name', $post_id );
  //スラッグを確認
  if($slug == 'about'){ 
    //カスタムフィールドのキーが my_info に入力された情報を保存・更新
    if(isset($_POST['my_info']) && $_POST['my_info']) {
      update_post_meta($post_id, 'my_info', $_POST['my_info']);
    } else {
      delete_post_meta( $post_id, 'my_info', get_post_meta($post_id, 'my_info', true) );
    }
  }
}
add_action('save_post', 'save_my_page_custom_meta_box'); 

上記の場合、「入力された情報の保存」の関数ではスラッグの取得に get_post_field() を使用していますが、アクション関数に2つのパラメータ($post_id, $post)を受け取って、以下のように投稿オブジェクト($post)からスラッグを取得することもできます。

add_action ではパラメータの数を指定するパラメータを追加する必要があります。

//入力された情報の保存
function save_my_page_custom_meta_box($post_id, $post) {
  //HTML出力用関数で設定した nonce を取得
  $my_meta_box_page_nonce = isset($_POST['my_meta_box_page_nonce']) ? $_POST['my_meta_box_page_nonce'] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if(!wp_verify_nonce($my_meta_box_page_nonce, 'meta_box_page_action')) {	
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 
    return; 
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if(!current_user_can('edit_post', $post_id)) { 
    return; 
  }
  
  //★パラメータの $post(投稿オブジェクト)からスラッグを取得
  $slug = $post->post_name;
  //スラッグを確認
  if($slug == 'about'){ 
    //カスタムフィールドのキーが my_info に入力された情報を保存・更新
    if(isset($_POST['my_info']) && $_POST['my_info']) {
      update_post_meta($post_id, 'my_info', $_POST['my_info']);
    } else {
      delete_post_meta( $post_id, 'my_info', get_post_meta($post_id, 'my_info', true) );
    }
  }
}
add_action('save_post', 'save_my_page_custom_meta_box', 10, 2);
テンプレートファイル名を取得して判定

特定のテンプレートを使っている固定ページに追加するには、get_post_meta($post_id,'_wp_page_template',TRUE) でテンプレートファイル名を取得して判定します。

以下は、top.php と言う固定ページのテンプレートファイル(カスタムテンプレート)を使っているページにのみメタボックスを追加する例です。

//特定のページへのメタボックスの作成(テンプレートファイル名を取得して判定)
function add_custom_meta_box_to_my_page($post_type, $post) {
  //投稿オブジェクトから ID を取得
  $post_id = $post->ID;
 
  //適用しているテンプレートファイル名を取得
  $template_file = get_post_meta($post_id,'_wp_page_template',true);
 
  //テンプレートを比較して、合致すればメタボックスを追加
  if ($template_file == 'top.php') {
    add_meta_box(
      'meta_info',
      'ページ情報入力欄',
      'my_meta_box_page_markup',
      'page', //固定ページの場合
      'normal',
      'high',
      //表示用関数の第2パラメータを使って参照する値
       array( 
         'info_key' => 'my_info', 
         'info_label' => 'ページの情報',
       )
    );
  }
}
add_action('add_meta_boxes', 'add_custom_meta_box_to_my_page', 10, 2);

//入力エリアの HTML を出力する関数(前述の例と全く同じ)
function my_meta_box_page_markup($post, $box) {
  wp_nonce_field('meta_box_page_action', 'my_meta_box_page_nonce');
  $cf_info_key = trim($box['args']['info_key']);  //
  $cf_info_label = trim($box['args']['info_label']);
  $cf_info_value = esc_html(get_post_meta($post->ID, $cf_info_key, true));
?>
<div id="meta_info">
  <p>ページの情報を入力してください。</p>
  <div>
    <label for="<?php echo $cf_info_key; ?>"><?php echo $cf_info_label; ?></label><br>
    <input type="text" name="<?php echo $cf_info_key; ?>" value="<?php echo $cf_info_value; ?>" style="width:80%; margin:10px 0 20px;">
  </div>
</div>
<?php
}

//入力された情報の保存
function save_my_page_custom_meta_box($post_id) {
  //HTML出力用関数で設定した nonce を取得
  $my_meta_box_page_nonce = isset($_POST['my_meta_box_page_nonce']) ? $_POST['my_meta_box_page_nonce'] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if(!wp_verify_nonce($my_meta_box_page_nonce, 'meta_box_page_action')) {	
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 
    return; 
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if(!current_user_can('edit_post', $post_id)) { 
    return; 
  }
  
  //テンプレートファイル名を取得
  $template_file = get_post_meta($post_id,'_wp_page_template',true);
  //テンプレートファイル名で判定
  if($template_file = 'top.php'){ 
    //カスタムフィールドのキーが my_info に入力された情報を保存・更新
    if(isset($_POST['my_info']) && $_POST['my_info']) {
      update_post_meta($post_id, 'my_info', $_POST['my_info']);
    } else {
      delete_post_meta( $post_id, 'my_info', get_post_meta($post_id, 'my_info', true) );
    }
  }
}
add_action('save_post', 'save_my_page_custom_meta_box');

チェックボックスを使う

チェックボックスを使って複数の項目を選択できるようにして、選択された値を取得する方法です。

チェックボックスなど複数の値を選択できる要素の場合、type = "text" の input 要素や textarea 要素とは少し異なります。

チェックボックスの input 要素の name 属性には配列を指定して、配列で受け取るようにします(配列で指定しないと、複数選択された項目の中の最後の項目の値が返ります)。

以下はフルーツの項目をチェックボックスで表示して選択できるようにする例です。

上記の記述により表示されるメタボックスの例

全体
//メタボックスの作成
function add_my_fruit_meta_box() {
  add_meta_box(
    'fruit_info',  //編集画面の HTML 要素の id 属性
    'フルーツ入力欄',  //画面上に表示されるタイトル文字列
    'my_fruit_box_markup', //HTML を出力する表示用関数の名前
    'post',
    'normal',
    'default',
    array(
      'fruit_key' => 'my_fruit'  //カスタムフィールドのキー
    )
  );
}
add_action( 'add_meta_boxes', 'add_my_fruit_meta_box' );

//フルーツを選択するチェックボックスの HTML を出力する関数
function my_fruit_box_markup( $post, $box ) {
  //表示するフルーツの項目の連想配列
  $fruits = array(
    'apple' => 'りんご',
    'banana' => 'バナナ',
    'grape' => 'ぶどう',
    'melon' => 'メロン',
    'orange' => 'オレンジ',
    'strawberry' => 'いちご'
  );
  //CSRF 対策
  wp_nonce_field( 'event_meta_box_action', 'my_fruit_meta_box_nonce' );
  
  //カスタムフィールドのキー 'my_fruit'
  $cf_fruit_key = trim( $box[ 'args' ][ 'fruit_key' ] ); 
  //★★★ 取得する値は配列なのでエスケープ処理は出力時に実施
  $cf_fruit_value = get_post_meta( $post->ID, $cf_fruit_key, true ); 
  //cf_fruit_value の値(選択されている値の配列)がない場合は空の配列
  $cf_fruit_value_array = $cf_fruit_value ? $cf_fruit_value : array(); 
  ?>
<style> /* スタイルの指定 */
  #fruit_info label.check-box {
    margin-right: 2rem;
    line-height: 30px;
  }
</style>
<div id="fruit_info">
  <p>好きなフルーツにチェックを入れてください</p>
  <?php
  //4つ表示して改行するためのカウント
  $count = 0;
  //フルーツの連想配列 $fruits を使用 $fruits = array('apple' => 'りんご',...)
  foreach ( $fruits as $value ) {
    //in_array で $cf_fruit_value_array の値の中に $value と同じ値があれば checkd を付与
    $checked = '';
    if ( in_array( $value, $cf_fruit_value_array ) )$checked = ' checked';
    // name 属性は配列(fruit_key[])を指定する必要があります
    echo '<label class="check-box"><input type="checkbox" name="' . $cf_fruit_key . '[]" value="' . esc_attr( $value ) . '"' . $checked . '>' . esc_html( $value ) . '</label>';
    $count++;
    if ( $count % 4 === 0 )echo '<br>'; //4つ表示して改行
  }
  ?>
</div>
<?php
}

//メタボックスに入力された情報の保存
function save_my_fruit_metabox( $post_id ) {
  //HTML出力用関数で設定した nonce を取得
  $my_fruit_meta_box_nonce = isset( $_POST[ 'my_fruit_meta_box_nonce' ] ) ? $_POST[ 'my_fruit_meta_box_nonce' ] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if ( !wp_verify_nonce( $my_fruit_meta_box_nonce, 'event_meta_box_action' ) ) {
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
    return;
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if ( !current_user_can( 'edit_post', $post_id ) ) {
    return;
  }
  //add_meta_box の第4パラメータ($screen)で指定した投稿タイプを確認
  if ( $_POST[ 'post_type' ] == 'post' ) {
    //カスタムフィールドのキーが my_fruit に入力された情報を保存・更新
    if ( isset( $_POST[ 'my_fruit' ] ) && $_POST[ 'my_fruit' ] ) {
      update_post_meta( $post_id, 'my_fruit', $_POST[ 'my_fruit' ] );
    } else {
      delete_post_meta( $post_id, 'my_fruit', get_post_meta( $post_id, 'my_fruit', true ) );
    }
  }
}
add_action( 'save_post', 'save_my_fruit_metabox' );

以下は詳細です。

add_meta_box() でメタボックスの作成

add_meta_box() を使って「フルーツ入力欄」というタイトルのメタボックスを作成します。チェックボックスのカスタムフィールドのキーは「my_fruit」としています。

メタボックスの作成
function add_my_fruit_meta_box() {
  add_meta_box(
    'fruit_info',  //編集画面の HTML 要素の id 属性
    'フルーツ入力欄',  //画面上に表示されるタイトル文字列
    'my_fruit_box_markup', //HTML を出力する表示用関数の名前
    'post',
    'normal',
    'default',
    array(
      'fruit_key' => 'my_fruit'  //カスタムフィールドのキー
    )
  );
}
add_action( 'add_meta_boxes', 'add_my_fruit_meta_box' );
HTML を出力する関数

チェックボックスに表示するフルーツの項目の連想配列を作成しています(4行目〜11行目)。

この例の場合、チェックボックスの項目は日本語で表示し、内部的に英字の値を利用するので、連想配列にしています。

また、この連想配列($fruits)をこの関数の外側で宣言するとグローバル変数となるので、値を表示する際に single.php などからアクセスすることができます。

get_post_meta() で取得する値 $cf_fruit_value は、項目が1つでも選択されている場合は配列になります(チェックボックスの要素の name 属性を配列で指定しているため)。何も選択されていない場合は、空の文字列になります(18行目)。

何も選択されていない場合や初期状態の場合は空の配列を代入して、38行目の in_array() で処理できるようにしています(20行目)。

出力する HTML はフルーツの項目の連想配列($fruits)と foreach() を使ってそれぞれの input 要素の value 属性に連想配列の値を esc_attr() でエスケープ処理して設定しています。表示する値も esc_html() でエスケープ処理しています(40行目)。

その際に name 属性にはカスタムフィールドのキーに [] を付けた値を設定して、配列としてデータを送信するようにしています(40行目)。

また、in_array() で $cf_fruit_value_array の値の中に $value と同じ値があれば checkd 属性を付与します(37〜38行目)。

//フルーツを選択するチェックボックスの HTML を出力する関数
function my_fruit_box_markup( $post, $box ) {
  //表示するフルーツの項目の連想配列
  $fruits = array(
    'apple' => 'りんご',
    'banana' => 'バナナ',
    'grape' => 'ぶどう',
    'melon' => 'メロン',
    'orange' => 'オレンジ',
    'strawberry' => 'いちご'
  );
  //CSRF 対策
  wp_nonce_field( 'event_meta_box_action', 'my_fruit_meta_box_nonce' );
  
  //カスタムフィールドのキー 'my_fruit'
  $cf_fruit_key = trim( $box[ 'args' ][ 'fruit_key' ] ); 
  //★★★ 取得する値は配列なのでエスケープ処理は出力時に実施
  $cf_fruit_value = get_post_meta( $post->ID, $cf_fruit_key, true ); 
  //cf_fruit_value の値の配列(選択されている値がない場合は空の配列を代入)
  $cf_fruit_value_array = $cf_fruit_value ? $cf_fruit_value : array(); 
  ?>
<style> /* スタイルの指定 */
  #fruit_info label.check-box {
    margin-right: 2rem;
    line-height: 30px;
  }
</style>
<div id="fruit_info">
  <p>好きなフルーツにチェックを入れてください</p>
  <?php
  //4つ表示して改行するためのカウント
  $count = 0;
  //フルーツの連想配列 $fruits を使用 $fruits = array('apple' => 'りんご',...)
  foreach ( $fruits as $value ) {
    //in_array で $cf_fruit_value_array の値の中に $value と同じ値があれば checkd を付与
    $checked = '';
    if ( in_array( $value, $cf_fruit_value_array ) )$checked = ' checked';
    // name 属性は配列(fruit_key[])を指定する必要があります
    echo '<label class="check-box"><input type="checkbox" name="' . $cf_fruit_key . '[]" value="' . esc_attr( $value ) . '"' . $checked . '>' . esc_html( $value ) . '</label>';
    $count++;
    if ( $count % 4 === 0 )echo '<br>'; //4つ表示して改行
  }
  ?>
</div>
<?php
}

以下のような HTML が出力されます。

<div id="fruit_info">
  <p>好きなフルーツにチェックを入れてください</p>
  <label class="check-box">
    <input type="checkbox" name="my_fruit[]" value="りんご">
    りんご</label>
  <label class="check-box">
    <input type="checkbox" name="my_fruit[]" value="バナナ">
    バナナ</label>
  <label class="check-box">
    <input type="checkbox" name="my_fruit[]" value="ぶどう">
    ぶどう</label>
  <label class="check-box">
    <input type="checkbox" name="my_fruit[]" value="メロン">
    メロン</label>
  <br>
  <label class="check-box">
    <input type="checkbox" name="my_fruit[]" value="オレンジ">
    オレンジ</label>
  <label class="check-box">
    <input type="checkbox" name="my_fruit[]" value="いちご">
    いちご</label>
</div>
選択された値の保存

チェックボックスで選択された値を保存する部分です。内容は「入力された情報の保存」を参照ください。

//メタボックスに入力された情報の保存
function save_my_fruit_metabox( $post_id ) {
  //HTML出力用関数で設定した nonce を取得
  $my_fruit_meta_box_nonce = isset( $_POST[ 'my_fruit_meta_box_nonce' ] ) ? $_POST[ 'my_fruit_meta_box_nonce' ] : null;
  //nonce を検証し値が正しくなければ return(何もしない)
  if ( !wp_verify_nonce( $my_fruit_meta_box_nonce, 'event_meta_box_action' ) ) {
    return;
  }
  //自動保存ルーチンかどうか。(記事の自動保存処理として呼び出された場合の対策)
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
    return;
  }
  //ユーザーが編集権限を持っていない場合は何もしない
  if ( !current_user_can( 'edit_post', $post_id ) ) {
    return;
  }
  //add_meta_box の第4パラメータ($screen)で指定した投稿タイプを確認
  if ( $_POST[ 'post_type' ] == 'post' ) {
    //カスタムフィールドのキーが my_fruit に入力された情報を保存・更新
    if ( isset( $_POST[ 'my_fruit' ] ) && $_POST[ 'my_fruit' ] ) {
      update_post_meta( $post_id, 'my_fruit', $_POST[ 'my_fruit' ] );
    } else {
      delete_post_meta( $post_id, 'my_fruit', get_post_meta( $post_id, 'my_fruit', true ) );
    }
  }
}
add_action( 'save_post', 'save_my_fruit_metabox' );
値の表示

以下は single.php などでチェックボックスの選択された項目を取得して表示する例です。

この例の場合、チェックボックスで項目が選択されていれば、get_post_meta( get_the_ID(), 'my_fruit', true ) で取得される値は配列に、何も選択されていなければ空の文字列になります。

以下では取得した値が配列の場合のみ、出力するようにしています(6行目)。

また、count() を使って配列の要素の数が2つ以上の場合はタイトルを「My Favorite Fruits」と複数形で表示し、1つの場合は単数形で表示しています(9行目〜13行目)。

各項目は foreach で処理する際に、esc_html() でエスケープ処理して li 要素として出力しています。

<?php
//カスタムフィールドの値を取得
$my_fruits = get_post_meta( get_the_ID(), 'my_fruit', true );

//取得した値が配列であれば
if ( is_array( $my_fruits ) ) {

  //配列の要素の数が2以上の場合
  if ( count( $my_fruits ) > 1 ) {
    echo '<h3>My Favorite Fruits :</h3>';
  } else { //配列の要素の数が1つの場合
    echo '<h3>My Favorite Fruit :</h3>';
  }

  echo '<ul>';
  foreach ( $my_fruits as $fruit ) {
    echo '<li>' . esc_html( $fruit ) . '</li>';
  }
  echo '</ul>';
}
?>

以下はフルーツの項目の連想配列($fruits)を使って、出力する際にそのキーの値をリンクの URL の一部として利用する例です。

連想配列($fruits)は HTML を出力する関数の外側で宣言しておけば(グローバル変数になるので)、こちら側には記述しないで済みます。※但し、その場合は「HTML を出力する関数」の中で $fruits を参照する際に global $fruits; としておく必要があります。(関連項目:functions.php

連想配列のキーの値は array_keys() で取得して、戻り値は配列なので最初の要素 [0] を取得しています。

<?php
//カスタムフィールドの値を取得
$my_fruits = get_post_meta( get_the_ID(), 'my_fruit', true );

//フルーツの項目の連想配列
$fruits = array(
  'apple' => 'りんご',
  'banana' => 'バナナ',
  'grape' => 'ぶどう',
  'melon' => 'メロン',
  'orange' => 'オレンジ',
  'strawberry' => 'いちご'
);

//取得した値が配列であれば
if ( is_array( $my_fruits ) ) {

  //配列の要素の数が2以上の場合
  if ( count( $my_fruits ) > 1 ) {
    echo '<h3>My Favorite Fruits :</h3>';
  } else { //配列の要素の数が1つの場合
    echo '<h3>My Favorite Fruit :</h3>';
  }

  echo '<ul>';

  foreach ( $my_fruits as $fruit ) {
    echo '<li><a href="' . esc_url( home_url() ) . '/fruits/' . array_keys( $fruits, $fruit )[ 0 ] . '">' . esc_html( $fruit ) . '</a></li>';
  }

  echo '</ul>';
}
?>

上記の場合、例えば「メロン」と「いちご」が選択されている場合は以下のような HTML が出力されます。

<h3>My Favorite Fruits :</h3>
<ul>
  <li><a href="http://localhost/wordpress/fruits/melon">メロン</a></li>
  <li><a href="http://localhost/wordpress/fruits/strawberry">いちご</a></li>
</ul>

カスタムフィールドの値

取得したカスタムフィールドの値は var_dump() を使って確認することができます。

$my_fruits = get_post_meta( get_the_ID(), 'my_fruit', true );
 
echo '<pre>';
var_dump($my_fruits);
echo '</pre>'; 

以下は「メロン」と「いちご」が選択されている場合の例です。

array(2) {
  [0]=>
  string(9) "メロン"
  [1]=>
  string(9) "いちご"
}

以下は「メロン」のみが選択されている場合の例です。

array(1) {
  [0]=>
  string(9) "メロン"
}

以下は何も選択されていない場合の例です。

string(0) ""

カスタムフィールドを検索対象に

WordPress のデフォルトの検索機能はカスタムフィールドが検索対象になっていないので、例えば以下を functions.php に記述することで、カスタムフィールドを検索対象にすることができます。

functions.php
//サイト内検索でカスタムフィールドの内容も検索結果に含める
function custom_search($search, $wp_query) {
  global $wpdb;

  if (!$wp_query->is_search)
    return $search;
  if (!isset($wp_query->query_vars))
    return $search;

  $search_words = explode(' ', isset($wp_query->query_vars['s']) ? $wp_query->query_vars['s'] : '');
  if ( count($search_words) > 0 ) {
    $search = '';
    $search .= "AND post_type = 'post'";  //投稿を対象にする場合
    foreach ( $search_words as $word ) {
      if ( !empty($word) ) {
        $search_word = '%' . esc_sql( $word ) . '%';
        $search .= " AND (
           {$wpdb->posts}.post_title LIKE '{$search_word}'
          OR {$wpdb->posts}.post_content LIKE '{$search_word}'
          OR {$wpdb->posts}.ID IN (
          SELECT distinct post_id
          FROM {$wpdb->postmeta}
          WHERE meta_value LIKE '{$search_word}'
          )
        ) ";
      }
    }
  }
  return $search;
}
add_filter('posts_search','custom_search', 10, 2);

上記は13行目で post_type = 'post' を指定して、投稿を検索の対象にしていますが、カスタム投稿タイプの投稿を対象にするには post_type にそのカスタム投稿タイプを指定します。

//カスタム投稿タイプ exhibition を検索の対象にする場合
$search .= "AND post_type = 'exhibition'";  

//以下は投稿またはカスタム投稿タイプ exhibition を検索の対象にする場合
//$search .= "AND (post_type = 'exhibition' OR post_type = 'post')";