2026年8月30日

2026年8月30日

WordPressのCMB2でメタボックスを作る実践ガイド:登録・繰り返しグループ・表示まで

CMB2 は、投稿編集画面などにメタボックス(カスタムフィールドの入力欄)を PHP のコードで追加するためのライブラリです。cmb2_admin_init フックの中で new_cmb2_box() を呼び、add_field() で入力欄を足すだけで、nonce の検証や保存処理は CMB2 が受け持ちます。この記事では、イベント情報の入力欄を例に、メタボックスの登録、繰り返しグループ、設定ページ、テンプレートでの表示、つまずきやすい点までを通して説明します。

CMB2 を使う前に確認すること

CMB2 は WordPress.org でプラグインとして配布されており、Composer(パッケージ名 cmb2/cmb2)でテーマやプラグインに同梱することもできます。どちらの方法でも、フィールドの定義は自分で書く PHP コードです。管理画面からフィールドを作る GUI はありません。

更新の頻度は時期によってまちまちなので、採用前にプラグインページの最終更新日と、使っている WordPress・PHP のバージョンで問題が報告されていないかを確認してください(2026年10月現在)。新規のサイトで長く使う前提なら、ACF やコアの register_post_meta() と比べて判断する価値があります。

定義を書く場所は、テーマではなくサイト専用プラグインか mu-plugin を勧めます。テーマを変えると入力欄が消え、データはあっても編集できなくなるためです。作業はステージング環境で、データベースのバックアップを取ってから行ってください。

CMB2 を読み込む

プラグインとして有効化した場合は、そのまま次の章のコードを書けます。Composer で同梱した場合は、CMB2 の init.php を読み込みます。

<?php
// サイト専用プラグインのメインファイル(例)
if ( file_exists( __DIR__ . '/vendor/cmb2/cmb2/init.php' ) ) {
    require_once __DIR__ . '/vendor/cmb2/cmb2/init.php';
}

CMB2 は複数のプラグインが別々に同梱していても、最も新しいバージョンだけが読み込まれる仕組みを持っています。同梱した CMB2 が使われていないように見えるときは、ほかのプラグインがより新しい版を持っていないかを確認します。

メタボックスを登録する

ここでは event という投稿タイプに、開催日・会場・申込 URL の入力欄を付けます。

<?php
add_action( 'cmb2_admin_init', 'myprefix_register_event_metabox' );

function myprefix_register_event_metabox() {
    $prefix = '_myprefix_event_';

    $cmb = new_cmb2_box( array(
        'id'           => 'myprefix_event_details',
        'title'        => 'イベント情報',
        'object_types' => array( 'event' ),
        'context'      => 'normal',
        'priority'     => 'high',
        'show_names'   => true,
    ) );

    $cmb->add_field( array(
        'name' => '開催日時',
        'id'   => $prefix . 'start',
        'type' => 'text_datetime_timestamp',
    ) );

    $cmb->add_field( array(
        'name' => '会場',
        'id'   => $prefix . 'venue',
        'type' => 'text',
    ) );

    $cmb->add_field( array(
        'name'      => '申込URL',
        'id'        => $prefix . 'url',
        'type'      => 'text_url',
        'protocols' => array( 'https' ),
    ) );
}

id がそのままメタキーになります。先頭をアンダースコアにすると、WordPress 標準の「カスタムフィールド」パネルに表示されない保護されたメタになり、CMB2 の入力欄だけで編集されるようになります。接頭辞を付けておくのは、ほかのプラグインとのキー衝突を避けるためです。

日付の型は保存形式で選びます。text_date は date_format で指定した文字列として保存され、text_date_timestamp や text_datetime_timestamp は UNIX タイムスタンプとして保存されます。開催日順に並べたり、終了したイベントを除いたりしたいなら、数値比較ができるタイムスタンプ型が扱いやすくなります。

繰り返しグループを作る

登壇者のように件数が決まっていない情報は group 型で作ります。

<?php
// myprefix_register_event_metabox() の中に追記
$group_id = $cmb->add_field( array(
    'id'      => $prefix . 'speakers',
    'type'    => 'group',
    'options' => array(
        'group_title'   => '登壇者 {#}',
        'add_button'    => '登壇者を追加',
        'remove_button' => '削除',
        'sortable'      => true,
    ),
) );

$cmb->add_group_field( $group_id, array(
    'name' => '名前',
    'id'   => 'name',
    'type' => 'text',
) );

$cmb->add_group_field( $group_id, array(
    'name' => '所属',
    'id'   => 'org',
    'type' => 'text',
) );

グループは1つのメタキーに、行ごとの配列をまとめてシリアライズした形で保存されます。そのためグループの中の値を meta_query で検索・並べ替えすることはできません。絞り込みに使う値はグループに入れず、単独のフィールドにしておきます。

権限で表示を絞る・独自の検証を足す

CMB2 は保存時に nonce を検証し、フィールドの型に応じたサニタイズを行います。それでも、特定の権限を持つ人だけに入力欄を見せたい、値の形式を独自に確かめたい、といった要件は自分で書きます。

<?php
$cmb->add_field( array(
    'name'            => '社内メモ',
    'id'              => $prefix . 'internal_note',
    'type'            => 'textarea_small',
    'show_on_cb'      => function () {
        return current_user_can( 'edit_others_posts' );
    },
    'sanitization_cb' => function ( $value ) {
        return sanitize_textarea_field( $value );
    },
) );

show_on_cb は入力欄を出すかどうか、sanitization_cb は保存前の値の整形を担当します。表示の可否だけでは保存の可否まで制御できない場面があるため、重要な値は保存側でも検証してください。

設定ページを作る

サイト全体の設定を1か所で管理したい場合は、object_types に options-page を指定します。

<?php
add_action( 'cmb2_admin_init', function () {
    $options = new_cmb2_box( array(
        'id'           => 'myprefix_site_options',
        'title'        => 'サイト設定',
        'object_types' => array( 'options-page' ),
        'option_key'   => 'myprefix_options',
        'capability'   => 'manage_options',
    ) );

    $options->add_field( array(
        'name' => '告知バナーの文言',
        'id'   => 'banner_text',
        'type' => 'text',
    ) );
} );

値は option_key の名前で1つのオプションにまとめて保存され、cmb2_get_option( 'myprefix_options', 'banner_text' ) で取り出せます。

テンプレートで表示する

CMB2 のメタボックスに入れた値は通常の投稿メタなので、get_post_meta() で読めます。出力時のエスケープは自分で行います。

<?php
$post_id  = get_the_ID();
$start    = get_post_meta( $post_id, '_myprefix_event_start', true );
$venue    = get_post_meta( $post_id, '_myprefix_event_venue', true );
$url      = get_post_meta( $post_id, '_myprefix_event_url', true );
$speakers = get_post_meta( $post_id, '_myprefix_event_speakers', true );

if ( $start ) {
    echo '<p>開催: ' . esc_html( wp_date( 'Y年n月j日 H:i', (int) $start ) ) . '</p>';
}
if ( $venue ) {
    echo '<p>会場: ' . esc_html( $venue ) . '</p>';
}
if ( $url ) {
    echo '<p><a href="' . esc_url( $url ) . '">申し込みはこちら</a></p>';
}
if ( is_array( $speakers ) ) {
    echo '<ul>';
    foreach ( $speakers as $speaker ) {
        $name = isset( $speaker['name'] ) ? $speaker['name'] : '';
        $org  = isset( $speaker['org'] ) ? $speaker['org'] : '';
        echo '<li>' . esc_html( $name ) . ( $org ? '(' . esc_html( $org ) . ')' : '' ) . '</li>';
    }
    echo '</ul>';
}

グループの各行は、入力されなかった子フィールドのキーが存在しないことがあります。isset() で確かめてから使うと、PHP の警告を避けられます。

つまずきやすい点

  • メタボックスが出ない: object_types の投稿タイプ名の綴り、CMB2 が読み込まれているか、フックが cmb2_admin_init か(フロント側のフォームでも使うなら cmb2_init)を順に確認します
  • ブロックエディターでの位置: メタボックスは本文の下の領域に表示されます。サイドバーには出ないため、編集者に場所を伝えておきます
  • REST API で値が見えない: 投稿メタは既定では REST API に含まれません。CMB2 のボックス設定で REST API への公開を指定する方法がありますが、公開した値は誰でも読める可能性があるので、社内メモなどは含めないでください
  • ID を後から変えた: 既存の値は古いメタキーに残ったままです。変更する場合は WP-CLI などでメタキーを移すスクリプトを用意してから切り替えます

まとめ

  • CMB2 は cmb2_admin_init で new_cmb2_box() と add_field() を呼ぶだけで、nonce と保存処理を任せられる
  • id がメタキーになる。接頭辞とアンダースコアで衝突と二重編集を防ぐ
  • 並べ替えや絞り込みに使う値はタイムスタンプ型や単独フィールドにし、グループには入れない
  • 権限は show_on_cb、検証は sanitization_cb で足し、出力は esc_html() / esc_url() でエスケープする
  • 定義はサイト専用プラグインか mu-plugin に置き、更新状況を確認してから採用する

お気軽にご相談ください

お見積りへ お問い合わせへ
▲