カスタム投稿タイプを簡単に利用できるようにする便利コード

2012/03/28
カスタム投稿タイプに関連するカスタム分類をget_post_type_object関数で取得できるように修正。

ちょっと前置き

カスタム投稿タイプを使用する場合、管理を楽にするために、基本的にはプラグインCustom Post Type UIを使うようにしていました。しかし、WordPressで投稿とカスタム投稿タイプを同居させたときに問題が発生します。

具体的な例を挙げると、ブログを「/blog/」、新着情報を「/news/」にした場合。

理想 ブログのパーマリンク /blog/%year%/%monthnum%/%day%/%post_id%/
新着情報のパーマリンク /news/%year%/%monthnum%/%day%/%post_id%/
現実 ブログのパーマリンク /blog/%year%/%monthnum%/%day%/%post_id%/
新着情報のパーマリンク /blog/news/%year%/%monthnum%/%day%/%post_id%/

投稿のパーマリンク設定の「/blog/」というスラッグベースの部分が、カスタム投稿タイプのパーマリンクにも付与されてしまうのです。これを回避するには、カスタム投稿タイプを設定するときに、「rewrite->with_front => false」な感じでregister_post_typeすれば良いのですが、Custom Post Type UIにはそのような設定ができません。

Custom Post Type UIのカスタム投稿タイプ管理プラグインもいくつか試してみたのですが、Custom Post Type UIと同様、rewriteはtrue、falseの二択しか選択できず、with_frontの設定まではできないものばかりでした。

カスタム投稿タイプを簡単に拡張できるようにするコード

ということで、プラグインではなく、直接コードを書いてカスタム投稿タイプを作成するしかないだろうと。このとき、作成するカスタム投稿タイプが一つであれば問題ないのですが、複数必要な場合だと何度も同じコードを書くのは辛いし、保守性も良くありません。何か方法が無いか探してみると、下記の記事を見つけました。

ベースとなるクラスを作り、

  • カスタム投稿タイプを作成する関数
  • カスタム投稿タイプの情報をダッシュボードに表示する関数
  • カスタムタクソノミーを作成する関数

でそのクラスを利用するという方法です。これなら同じコードを何度も書く必要がなく便利そうです。ただ、クラスとは別にそれぞれ関数も定義する必要があるのが少し冗長な気がします。そこで、一つのクラスで設定、作成までできるよう「WordPress でカスタム投稿タイプを簡単に拡張できるようにするコード | ウェブル」のコードを参考にクラスを作成してみました。

コード

/**
 * カスタム投稿タイプ & カスタムタクソノミーのクラス
 */
class mw_manage_custom {
	private $custom_post_type = array();
	private $custom_post_dashboard = array();
	private $custom_taxonomy = array();
	 
	/**
	 * 実行
	 */
	public function init() {
		if ( !empty( $this->custom_post_type ) ) {
			add_action( 'init', array( $this, 'register_post_type' ) );
		}
		if ( !empty( $this->custom_post_dashboard ) ) {
			add_action( 'right_now_content_table_end', array( $this, 'right_now_content_table_end' ) );
		}
		if ( !empty( $this->custom_taxonomy ) ) {
			add_action( 'init', array( $this, 'register_taxonomy' ) );
		}
	}
	 
	/**
	 * カスタム投稿タイプの登録
	 * http://codex.wordpress.org/Function_Reference/register_post_type
	 * @param   String  表示名
	 *		  String  スラッグ(登録名)
	 *		  Array   サポートタイプ
	 *		  Array   オプション項目
	 */
	public function custom_post_type( $name, $slug, Array $supports = array(), Array $options = array() ) {
		$custom_post_type = array(
			'name' => $name,
			'slug' => $slug,
			'supports' => $supports,
			'options' => $options
		);
		$this->custom_post_type[] = $custom_post_type;
		$this->custom_post_dashboard( $slug );
	}
	 
	/**
	 * 多次元配列をマージ
	 * @param	Array	$a
	 * 			Array	$b
	 * @return	Array
	 */
	protected function array_merge( Array $a, Array $b ) {
		foreach ( $a as $key => $val ) {
			if ( isset( $b[$key] ) && is_array( $val ) ) {
				$b[$key] = $this->array_merge( $val, $b[$key] );
			} else {
				$b[$key] = $val;
			}
		}
		return $b;
	}
	 
	/**
	 * カスタム登録タイプの登録を実行
	 */
	public function register_post_type() {
		foreach ( $this->custom_post_type as $cpt ) {
			if ( empty( $cpt['supports'] ) ) {
				$cpt['supports'] = array( 'title', 'editor' );
			}
			$labels = array(
				'name' => $cpt['name'],
				'singular_name' => $cpt['name'],
				'add_new_item' => $cpt['name'].'を追加',
				'add_new' => '新規追加',
				'new_item' => '新規追加',
				'edit_item' => $cpt['name'].'を編集',
				'view_item' => $cpt['name'].'を表示',
				'not_found' => $cpt['name'].'は見つかりませんでした',
				'not_found_in_trash' => 'ゴミ箱に'.$cpt['name'].'はありません。',
				'search_items' => $cpt['name'].'を検索',
			);
			$default_options = array(
				'public' => true,
				'has_archive' => true,
				'hierarchical' => false,
				'labels' => $labels,
				'menu_position' => 20,
				'supports' => $cpt['supports'],
				'rewrite' => array(
					'slug' => $cpt['slug'],
					'with_front' => false
				)
			);
			$args = $this->array_merge( $default_options, $cpt['options'] );
			// 関連するカスタムタクソノミーがある場合は配列に持たせる
			$_taxonomies = array();
			foreach ( $this->custom_taxonomy as $custom_taxonomy ) {
				if ( in_array( $cpt['slug'], $custom_taxonomy['post_type'] ) ) {
					$_taxonomies[] = $custom_taxonomy['slug'];
				}
			}
			if ( !empty( $_taxonomies ) ) {
				$args_taxonomies = array(
					'taxonomies' => $_taxonomies
				);
				$args = array_merge( $args, $args_taxonomies );
			}
			register_post_type( $cpt['slug'], $args );
		}
	}
	 
	/**
	 * ダッシュボードに表示したいカスタム登録タイプを登録
	 */
	private function custom_post_dashboard( $custom_post_type ) {
		$this->custom_post_dashboard[] = $custom_post_type;
	}
	 
	/**
	 * ダッシュボードにカスタム登録タイプの情報を表示
	 */
	public function right_now_content_table_end() {
		foreach ( $this->custom_post_dashboard as $custom_post_type ) {
			global $wp_post_types;
			$num_post_type = wp_count_posts( $custom_post_type );
			$num = number_format_i18n( $num_post_type->publish );
			$text = _n( $wp_post_types[$custom_post_type]->labels->singular_name, $wp_post_types[$custom_post_type]->labels->name, $num_post_type->publish );
			$capability = $wp_post_types[$custom_post_type]->cap->edit_posts;
	  
			if ( current_user_can( $capability ) ) {
				$num = "<a href='edit.php?post_type=" . $custom_post_type . "'>$num</a>";
				$text = "<a href='edit.php?post_type=" . $custom_post_type . "'>$text</a>";
			}
	  
			echo '<tr>';
			echo '<td class="first b b_' . $custom_post_type . '">' . $num . '</td>';
			echo '<td class="t ' . $custom_post_type . '">' . $text . '</td>';
			echo '</tr>';
		}
	}
	 
	/**
	 * カスタムタクソノミーの登録
	 * http://codex.wordpress.org/Function_Reference/register_taxonomy
	 * @param   String  表示名
	 *		  String  スラッグ(登録名)
	 *		  Array   ポストタイプ
	 *		  Array   オプション項目
	 */
	public function custom_taxonomy( $name, $slug, Array $post_type, Array $options = array() ) {
		$custom_taxonomy = array(
			'name' => $name,
			'slug' => $slug,
			'post_type' => $post_type,
			'options' => $options
		);
		$this->custom_taxonomy[] = $custom_taxonomy;
	}
	 
	/**
	 * カスタムタクソノミーの登録を実行
	 */
	public function register_taxonomy() {
		foreach ( $this->custom_taxonomy as $ct ) {
			$default_options = array(
				'hierarchical' => false,
				'rewrite' => array(
					'with_front' => false
				)
			);
			$ct['options'] = array_merge( $default_options, $ct['options'] );
			register_taxonomy(
				$ct['slug'],
				$ct['post_type'],
				array(
					'hierarchical' => $ct['options']['hierarchical'],
					'label' => $ct['name'],
					'singular_name' => $ct['name'],
					'query_var' => true,
					'rewrite' => array(
						'with_front' => $ct['options']['rewrite']['with_front']
					)
				)
			);
		}
	}
}

使い方

まず上記のコードをfunctions.phpに記述します。そして、下記のような感じで使用します(下記のコードもfunctions.phpに記述します)。

// オブジェクト化
$mw_manage_custom = new mw_manage_custom();
// カスタム投稿タイプ「news」を定義
$mw_manage_custom->custom_post_type( '新着情報', 'news' );
// カスタム投稿タイプ「products」を定義
$mw_manage_custom->custom_post_type( '製品情報', 'products', array( 'title', 'editor', 'excerpt' ) );
// カスタム投稿タイプ「products」のカスタムタクソノミー「type」を定義
// $mw_manage_custom->custom_taxonomy( '用途', 'type', array( 'products' ), array( 'hierarchical' => true, 'rewrite' => array( 'with_front' => true ) ) );
// 実行
$mw_manage_custom->init();

これでカスタム投稿タイプ・カスタムタクソノミーの作成、カスタム投稿タイプ情報のダッシュボードへの表示が可能です。

register_post_typeなどのオプションはほとんどデフォルトから変更しないようなものも多いので、簡素にするためにそのようなものはわざと省いています。必要な場合はクラスを適当に拡張してご利用ください。

  • ブックマーク
  • Feedly

この記事を書いた人

キタジマタカシ

長崎在住、フリーランスのWordPress テーマ / プラグインデベロッパー。 多数のプロダクトをオープンソースで開発・公開しています。現在は WordPress 有料テーマ Snow Monkey を開発・販売しています。