独自のカスタムフィールド設定項目を作る

WordPressのカスタムフィールドは投稿ページや固定ページごとに情報を持たせて、いろいろな処理をするのにとても便利なのでいつも使っています。ですがデフォルトのカスタムフィールド編集画面はテキストエリアのみなので、性質の違う情報や1つのキーに複数の情報をもたせたい時に使い勝手が悪くなります。例えば、対象の記事にある項目が有効or無効のどちらかである情報を持たせたいとき、有効=’1’、無効=’0’という情報をテキストエリアに入力するのは少し使い勝手が悪いです。1種類のキー(meta_key)に複数の値を持たせたい場合、同じ名前のキーで違う値のものを追加していけば可能ですが、とても扱いにくいです。。
こういった場合は、チェックボックスを使って設定ができれば使い勝手がとても良くなります。それ以外にもラジオボタンやプルダウンメニューで選択設定を持たせることもとても有効です。
それではこれらの画面を作ってみましょう。

編集画面を作る

管理画面に独自のカスタムフィールド設定項目を持つには、以下の2つの流れの処理を行います。
まず”add_meta_boxes”をアクションフックして、カスタムフィールドの編集画面を作ります。以下のコードをfunction.phpに追加します。

“add_meta_box”の引数に設定するコールバック関数で、カスタムフィールドを設定するためのチェックボックスやラジオボタンなどを表示するHTMLを記述します。

/**
 * Adds a box to the main column on the Post and Page edit screens.
 */
function add_custom_fields() {

	$screens = array( 'post', 'page' );

	foreach ( $screens as $screen ) {

		add_meta_box(
			'my_meta_box_id',	// ID
			'My Meta Box',		// Meta Box Label
			'custom_fields_callback',			// Callback to show forms
			$screen,			// Post type name to add meta box (Include custom post type)
			'normal',			// Display position (normal, advanced, side)
	        'low'				// Orderby (high, core, default, low)
		);
	}
}
add_action( 'add_meta_boxes', 'add_custom_fields' );

/**
 * Prints the box content.
 *
 * @param WP_Post $post The object for the current post/page.
 */
function custom_fields_callback( $post ) {

	// Add a nonce field so we can check for it later.
	wp_nonce_field( 'save_custom_fields', 'custom_fields_nonce' );

	/*
	 * Use get_post_meta() to retrieve an existing value
	 * from the database and use the value for the form.
	 */
	/**
	 * Custom Field set by Text Field
	 */
    $value = get_post_meta(
        $post->ID,	// Post ID
		'tf_meta_key',		// Custom Field Key (meta key)
		true		// true: string, false: array
    );
    echo '<dl>';
    echo   '<dt>';
	echo     '<label for="tf_meta_key">Text Field</label>';
    echo   '</dt>';
    echo   '<dd>';
    echo     '<input id="tf_meta_key" name="tf_meta_key" style="width:100%" value="'.esc_attr($value).'" type="text" />';
	echo     '<p>Enter any string in the field.</p>';
    echo   '</dd>';
    echo '</dl>';

	/**
	 * Custom Field set by Text Area
	 */
    $value = get_post_meta(
        $post->ID,	// Post ID
		'ta_meta_key',		// Custom Field Key (meta key)
        true		// true: string, false: array
    );
    echo '<dl>';
    echo   '<dt>';
	echo     '<label for="ta_meta_key">Text Area</label>';
    echo   '</dt>';
    echo   '<dd>';
    echo     '<textarea id="ta_meta_key" name="ta_meta_key" style="width:100%">'.esc_attr($value).'</textarea>';
	echo     '<p>Enter any string in the area.</p>';
    echo   '</dd>';
    echo '</dl>';

	/**
	 * Custom Field set by wysiwyg editor
	 */
    $value = get_post_meta(
        $post->ID,	// Post ID
		'wysiwyg_meta_key',		// Custom Field Key (meta key)
        true		// true: string, false: array
    );
    echo '<dl>';
    echo   '<dt>';
	echo     '<label for="wysiwyg_meta_key">wysiwyg Editor</label>';
    echo   '</dt>';
    echo   '<dd>';
    wp_editor($value, 'wysiwyg_meta_key');
    echo   '</dd>';
    echo '</dl>';

	/**
	 * Custom Field set by Check Box
	 */
    $value = get_post_meta(
        $post->ID,	// Post ID
		'cb_meta_box',		// Custom Field Key (meta key)
        true		// true: string, false: array
    );
    echo '<dl>';
    echo   '<dt>';
	echo     'Check Box';
    echo   '</dt>';
    echo   '<dd>';
    echo     '<input name="cb_meta_box" value="0" type="hidden">';
    echo     '<label>';
    if ($value === '1') {
        echo   '<input name="cb_meta_box" value="1" checked="checked" type="checkbox">';
    } else {
        echo   '<input name="cb_meta_box" value="1" type="checkbox">';
    }
	echo       'Description text';
    echo     '</label>';
    echo   '</dd>';
    echo '</dl>';

	/**
	 * Custom Field set by Multiple Check Boxes
	 */
    $value = get_post_meta(
        $post->ID,	// Post ID
		'mcb_meta_key',		// Custom Field Key (meta key)
        false		// true: string, false: array
    );
    $list = array(
        1 => 'IE',
        2 => 'Chrome',
        3 => 'Safari',
        4 => 'FireFox',
        5 => 'Opera'
    );
    echo '<dl>';
    echo   '<dt>';
	echo     'Multiple Check Boxes';
    echo   '</dt>';
    echo   '<dd>';
    echo     '<ul>';
    foreach ($list as $_id => $_name) {
        echo   '<li>';
        echo     '<label>';
        if (in_array($_id, $value)) {
            echo   '<input name="mcb_meta_key[]" value="'.$_id.'" checked="checked" type="checkbox">';
        } else {
            echo   '<input name="mcb_meta_key[]" value="'.$_id.'" type="checkbox">';
        }
        echo       $_name;
        echo     '</label>';
        echo   '</li>';
    }
    echo     '</ul>';
    echo   '</dd>';
    echo '</dl>';

	/**
	 * Custom Field set by Radio Boxes
	 */
    $value = get_post_meta(
        $post->ID,	// Post ID
		'rb_meta_key',		// Custom Field Key (meta key)
        true		// true: string, false: array
    );
    $list = array(
        1 => 'windows',
        2 => 'mac',
        3 => 'linux',
    );
    echo '<dl>';
    echo   '<dt>';
	echo     'Radio Buttons';
    echo   '</dt>';
    echo   '<dd>';
    echo     '<input name="rb_meta_key" value="0" type="hidden">';
    echo     '<ul>';
    foreach ($list as $_id => $_name) {
        echo   '<li>';
        echo     '<label>';
        if ($_id == $value) {
            echo   '<input name="rb_meta_key" value="'.$_id.'" checked="checked" type="radio">';
        } else {
            echo   '<input name="rb_meta_key" value="'.$_id.'" type="radio">';
        }
        echo       $_name;
        echo     '</label>';
        echo   '</li>';
    }
    echo     '</ul>';
    echo   '</dd>';
    echo '</dl>';

	/**
	 * Custom Field set by Select Box
	 */
    $value = get_post_meta(
        $post->ID,	// Post ID
		'sb_meta_key',		// Custom Field Key (meta key)
        true		// true: string, false: array
    );
    $list = array(
        0 => '-----',
        1 => 'news',
        2 => 'blog',
        3 => 'shop',
        4 => 'business',
    );
    echo '<dl>';
    echo   '<dt>';
	echo     '<label for="sb_meta_key">Select Box</label>';
    echo   '</dt>';
    echo   '<dd>';
    echo     '<select id="sb_meta_key" name="sb_meta_key">';
    foreach ($list as $_id => $_name) {
        if ($_id == $value) {
            echo   '<option value="'.$_id.'" selected="selected">';
        } else {
            echo   '</option><option value="'.$_id.'" type="radio">';
        }
        echo       $_name;
        echo   '</option>';
    }
    echo     '</select>';
    echo   '</dd>';
    echo '</dl>';
}

カスタムフィールドの編集画面を作成したら、次に設定した値を保存する処理を記述します。以下のコードをfunction.phpに追加します。

/**
 * When the post is saved, saves our custom data.
 *
 * @param int $post_id The ID of the post being saved.
 */
function save_custom_fields( $post_id ) {

	/*
	 * We need to verify this came from our screen and with proper authorization,
	 * because the save_post action can be triggered at other times.
	 */

	// Check if our nonce is set.
	if ( ! isset( $_POST['custom_fields_nonce'] ) ) {
		return;
	}

	// Verify that the nonce is valid.
	if ( ! wp_verify_nonce( $_POST['custom_fields_nonce'], 'save_custom_fields' ) ) {
		return;
	}

	// If this is an autosave, our form has not been submitted, so we don't want to do anything.
	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
		return;
	}

	// Check the user's permissions.
	if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {

		if ( ! current_user_can( 'edit_page', $post_id ) ) {
			return;
		}

	} else {

		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}
	}

	/* OK, it's safe for us to save the data now. */

	$post_keys = array(		// true: string, false: array
		'tf_meta_key' => true,
		'ta_meta_key' => true,
		'wysiwyg_meta_key' => true,
		'cb_meta_box' => true,
		'mcb_meta_key' => false,
		'rb_meta_key' => true,
		'sb_meta_key' => true,
	);

	foreach ( $post_keys as $post_key => $unique ) {
		// String
		if ( $unique && isset( $_POST[$post_key] ) ) {
			// Sanitize user input.
//			$val = sanitize_text_field( $_POST[$post_key] );
			// Update the meta field in the database.
			update_post_meta(
				$post_id,			// Post ID
				$post_key,			// Custom Field Key
				$_POST[$post_key]				// Value
			);
		// Array
		} elseif ( isset( $_POST[$post_key] ) ) {
			$input_vals = (array)$_POST[$post_key];
			delete_post_meta(
				$post_id,	// post ID
				$post_key	// Custom Field Key
			);
			foreach ( $input_vals as $input_val ) {
				add_post_meta(
					$post_id,	// post ID
					$post_key,	// Custom Field Key
					$input_val,	// Value
					false		// true: string, false: array
				);
			}
		}
	}
}
add_action( 'save_post', 'save_custom_fields' );

※ nonce(ノンス)とは

nonce(ノンス)とはセキュリティの考え方の1つで「number used once」の略です。一度だけ使われる番号という意味で、ワンタイムトークンと呼ばれることもあります。POSTやGETなどのHTTPリクエストを使った悪意ある攻撃などから防御します。一度だけ使えるワンタイムトークンなので、重複したリクエストから悪意あるリプライ攻撃を見破り、Webサイトを保護します。WordPressのnonceは管理画面に対するCSRF攻撃(URL-wiki)対策としてより単純化されていて、データベースへの保存など重要な場面で、通常の認証や権限のチェックだけではスルーしてしまうCSRF攻撃を、nonceで防ぐのがお約束となっています。また厳密にはWordPressのnonceはワンタイムではなく24時間再利用が可能になっています。

これらの設定項目を使って内容を表示するとこのようになります。

各カスタムフィールドの値は必要に応じてエスケープやサニタイズを行ってください。
独自にカスタムフィールド設定項目を作成する方法を紹介しましたが、独自に作成するのが嫌な場合はプラグインを使う方法もあります。例えば、Advanced Custom Fieldsというプラグインを使えばとても簡単にカスタムフィールドを使うことができます。構築するサイトの内容や状況に応じてカスタムフィールドの使用方法を選んでください。

シェアする