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

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

更新日:2019年05月05日

作成日: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. 入力された情報の保存
    • 入力した情報をデータベースに保存する処理を記述します。

以下はページのメタ情報を入力するための入力項目を2つ持つカスタムフィールドの作成例です。

//メタボックスの作成
function add_my_custom_meta_box() {
  add_meta_box(
    'meta_info',
    'メタ情報入力欄',
    'my_meta_box_markup',
    'post',
    'normal',
    'high',
    //表示用関数の第2パラメータを使って参照する値
     array( 
       'cf_key1' => 'my_title', 
       'cf_label1' => 'ページのタイトル',
       'cf_key2' => 'my_description',
       'cf_label2' => 'ページの説明'
     )
  );
}
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']['cf_key1']);  //'my_title'
  $cf_title_label = trim($box['args']['cf_label1']);  //'ページのタイトル'
  $cf_title_value = esc_html(get_post_meta($post->ID, $cf_title_key, true));
  $cf_description_key = trim($box['args']['cf_key2']);  //'my_description'
  $cf_description_label = trim($box['args']['cf_label2']);  //'ページの説明'
  $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
}

//入力された情報の保存
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; 
  }
  //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'); 

上記のコードを 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パラメータ:$metabox 連想配列
  • $screen(文字列):(オプション)メタボックスの表示先となるページ(画面)の種類 (post, page, link, dashboard, comment, カスタムポストタイプ名) を指定。初期値: null
  • $context(文字列):(オプション)編集画面での表示場所 (normal, advanced または side) 。初期値:advanced
  • $priority(文字列):(オプション) メタボックスが表示される優先度 ('high', 'core', 'default' または 'low') 。初期値:default
  • $callback_args(配列):(オプション)表示用関数の第2パラメータ($metabox)を連想配列で指定。初期値:null。表示用関数内で $metabox['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)を指定して表示用関数の第2パラメータを使って値を参照することもできます。以下は連想配列の値を変数にしていますが、直接文字列を指定しても問題ありません。

function add_my_custom_meta_box() {

  //表示用関数の第2パラメータを使って参照する値
  $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
}

以下は表示されるメタボックスの例です。

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

以下は投稿の新規作成画面で出力されるメタボックスの 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パラメータ

表示用コールバック関数で第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( 
       'cf_key1' => 'my_title', 
       'cf_label1' => 'ページのタイトル',
       'cf_key2' => 'my_description',
       'cf_label2' => 'ページの説明'
     )
  );
}
add_action('add_meta_boxes', 'add_my_custom_meta_box');

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

  • 定義では my_meta_box_markup($post, $box) のようにパラメータを2つ指定します。
  • 関数内では $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']['cf_key1']);
  $cf_title_label = trim($box['args']['cf_label1']);
  $cf_title_value = esc_html(get_post_meta($post->ID, $cf_title_key, true));
  $cf_description_key = trim($box['args']['cf_key2']);
  $cf_description_label = trim($box['args']['cf_label2']);
  $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
}

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 マークアップ

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 が返るので設定した値を削除した場合も実行されます)。

もし、値が設定されているかまでを判定する場合は、以下のように値が入っていない場合は 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( 
       'cf_key1' => 'my_title', 
       'cf_label1' => 'ページのタイトル',
       'cf_key2' => 'my_description',
       'cf_label2' => 'ページの説明',
       'cf_key3' => 'my_keywords',
       'cf_label3' => 'ページのキーワード(カンマ区切りで記述)'
     )
  );
}
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']['cf_key1']);  //'my_title'
  $cf_title_label = trim($box['args']['cf_label1']);  //'ページのタイトル'
  $cf_title_value = esc_html(get_post_meta($post->ID, $cf_title_key, true));
  $cf_description_key = trim($box['args']['cf_key2']);  //'my_description'
  $cf_description_label = trim($box['args']['cf_label2']);  //'ページの説明'
  $cf_description_value = esc_html(get_post_meta($post->ID, $cf_description_key, true));
  $cf_keywords_key = trim($box['args']['cf_key3']);  //'my_keywords'
  $cf_keywords_label = trim($box['args']['cf_label3']);  //'ページのキーワード(...)'
  $cf_keywords_value = esc_html(get_post_meta($post->ID, $cf_keywords_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>
    <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; 
  }
  //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']);	
    }
    if( isset( $_POST['my_keywords'] ) ) {
      //カスタムフィールドのキーが my_keywords に入力された情報を保存・更新
      update_post_meta($post_id, 'my_keywords', $_POST['my_keywords']);
    }
  }
}
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 タグは除去します。

キーワードはカンマ区切りで入力する前提になっているので、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";
    }
    
    //カスタムフィールドの 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');

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

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

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

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

  • 投稿 ID を使って判定
  • 投稿オブジェクトからスラッグを取得して判定
  • 投稿 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( 
         'cf_key1' => 'my_info', 
         'cf_label1' => 'ページの情報',
       )
    );
  }
}
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']['cf_key1']);  //
  $cf_info_label = trim($box['args']['cf_label1']);
  $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( 
         'cf_key1' => 'my_info', 
         'cf_label1' => 'ページの情報',
       )
    );
  }
}
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']['cf_key1']);  //
  $cf_info_label = trim($box['args']['cf_label1']);
  $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( 
         'cf_key1' => 'my_info', 
         'cf_label1' => 'ページの情報',
       )
    );
  }
}
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']['cf_key1']);  //
  $cf_info_label = trim($box['args']['cf_label1']);
  $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');