WordPressの「カスタム投稿」「カスタム分類」を使ってみよう

今回の番長ブログの担当、noguchiです。前の記事から間があいてしまいました。
楽しみにしている方(いるのか?)申し訳ありません。
間をあけてしまった分 、今回はがっつりと書きたいと思います。

自分が担当する案件の中で時々CMSを使って作業する案件があります。
CMSではWordPress・MovableTypeといったあたりが有名です。
今回はそのWordPressの「カスタム投稿」「カスタム分類」を使ってみようという内容です 。

今回の内容は以下の内容になります。

  1. カスタム投稿・カスタム分類について
  2. カスタム投稿を追加
  3. カスタム分類を追加
  4. カスタム投稿のカスタムフィールドを定義
  5. カスタム投稿の一覧画面に項目追加
  6. カスタム投稿の一覧画面で並び替えを追加

カスタム投稿・カスタム分類を知りたい方は3までをお読みください。
4からはさらに実案件に使える内容を書いていこうと思います。

今回の内容は長いのでまずはサンプルファイルを置いておきます。
サンプルファイルは以下の前提で作っています。

  • WordPress 3.4.1上で作成しました。
    (注意:他のバージョンでの動作を保証したものではありません)
  • 標準テーマ「Twenty Eleven」を継承したテーマ形式です。

また、解説中で以下のプラグインを使っております。
Custom Field Template

実際にサンプルファイルを使ってカスタム投稿を表示した画面は以下のものとなります。

画像はホーム画面ですが、最新記事の中にカスタム投稿を使ったデータ2つを表示しています。
メニューにはカスタム分類を使ったウィジェット表示をしてみました。
※デザインは標準のテーマからほとんどいじっていません。
 みなさんはデザインカスタマイズしてくださいね^^;

1. カスタム投稿・カスタム分類について

WordPressには「投稿」「固定ページ」のようなページの種類があります。他には「メディア」という画像やファイルを扱うためのものもありますが、これらはすべて「投稿タイプ」という扱いです。
その「投稿タイプ」を自作できるようにWordPress 3.0から「カスタム投稿」機能が追加されました。

また、「投稿」には「カテゴリ」「タグ」が関連付けできます。この「カテゴリ」のような分類をさらに作れるようにしたのが「カスタム分類(カスタムタクソノミー)」です。

たとえばショッピングサイトで「投稿」を使って商品紹介のページを作っていたとしましょう。
おそらく商品には「カテゴリ」を使うでしょう。
その際に「お店からのお知らせ」みたいなものを管理したいとします。
今まではこれも「投稿」「固定ページ」とかで管理していましたが、カスタム投稿を使って「お知らせ」というカスタム投稿を作ることができます。
この「お知らせ」には商品のカテゴリとは別な分類をカスタム分類として付けることができ、
「お知らせ」のために分類を追加しても商品の「カテゴリ」としては表示されません。
(「システムメンテナンス告知」なんて商品カテゴリがでたらイヤですよね^^;)

2. カスタム投稿を追加

では実際にカスタム投稿を追加するための方法を紹介します。

function book_type_register() {
  $main_label = '書籍';
  $labels = array (
    'name' => _x($main_label, 'books'),
    'singular_name' => _x($main_label, 'book')
  );
  $args = array (
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => true,
    'capability_type' => 'post',
    'hierarchical' => false,
    'menu_position' => 5,
    'supports' => array ('title'),
    'has_archive' => true
  );
  register_post_type('book', $args);
}
add_action('init', 'book_type_register', 0);
function magazine_type_register() {
  $main_label = '雑誌';
  $labels = array (
    'name' => _x($main_label, 'magazines'),
    'singular_name' => _x($main_label, 'magazine')
  );
  $args = array (
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => true,
    'capability_type' => 'post',
    'hierarchical' => false,
    'menu_position' => 5,
    'supports' => array ('title'),
    'has_archive' => true
  );
  register_post_type('magazine', $args);
}
add_action('init', 'magazine_type_register', 0);

「register_post_type」という関数がカスタム投稿を追加するための関数です。
第1引数がカスタム投稿の識別子です。
(WordPress標準の投稿タイプがあるので、識別子が被らないように気をつけてくださいね。
できるならプレフィックスをつけて置いたほうがいいかもしれません。)
今回はサンプルとして「book」「magazine」というカスタム投稿を追加しました。
第2引数はカスタム投稿のための設定です。
引数の中身は多いのでこちらのページで確認してください。
この関数をinitアクションの際に呼ばせることでシステムにカスタム投稿の存在を認識させます。
カスタム投稿を追加すると管理画面のメニューにカスタム投稿を管理するためのリンクが表示されます。

3. カスタム分類を追加

次はカスタム分類を追加します。

function book_genere_taxonomy() {
  $main_label = '書籍分類';
  $labels = array (
    'name' => $main_label,
    'singular_name' => $main_label
  );
  $args = array (
    'label' => $main_label,
    'labels' => $labels,
    'hierarchical' => true,
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => array ('slug' => 'book-genre')
  );
  register_taxonomy('bookgenre', 'book', $args);
}
add_action('init', 'book_genere_taxonomy', 0);
function magazine_genere_taxonomy() {
  $main_label = '雑誌分類';
  $labels = array (
    'name' => $main_label,
    'singular_name' => $main_label
  );
  $args = array (
    'label' => $main_label,
    'labels' => $labels,
    'hierarchical' => true,
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => array ('slug' => 'magazine-genre')
  );
  register_taxonomy('magazinegenre', 'magazine', $args);
}
add_action('init', 'magazine_genere_taxonomy', 0);

「register_taxonomy」という関数がカスタム分類を追加するための関数です。
第1引数がカスタム分類の識別子です。
今回はサンプルとして「bookgenre」「magazinegenre」というカスタム分類を追加しました。
第2引数は関連付けする投稿タイプの指定です。
サンプルでは文字列で指定していますが、複数の投稿タイプを指定する場合のために配列が使えるようです。
第3引数はカスタム分類のための設定です。
こちらの詳細もこちらのページで確認してください。
この関数をinitアクションの際に呼ばせることでシステムにカスタム分類の存在を認識させます。
カスタム分類を追加すると関連付けした投稿タイプの管理メニューの中にカスタム分類を管理するためのリンクが追加されます。

(「投稿」のリンクを押した際の「カテゴリ」「タグ」の表示され方と同じですね。)

4. カスタム投稿のカスタムフィールドを定義

カスタム投稿を作るのはもう完了しましたが、実案件ではおそらく入力項目が足りなくて困るでしょう。
「本文にすべて押し込む」なんて力技もありますが、せっかくですし「カスタムフィールド」まで駆使する、実案件でも使える内容を書きたいと思います。
カスタム投稿を追加する際の設定として「supports」という設定がありますが、
これはWordPressの入力・選択項目でどのようなものを使うかという設定があります。
タイトル・本文などがありますが、今回はあえてタイトルのみにしました。
それは他の項目は「カスタムフィールド」で補おうという考えからです。本文すら使いません!

カスタムフィールドを使う際に便利なのがプラグインCustom Field Templateです。
(カスタムフィールドを扱うためのプラグインは色々ありますが自分はこれを使います。)
プラグインを追加・有効化すると「設定」の中に「カスタムフィールドテンプレート」というリンクが追加されます。
サンプルとして「書籍情報」というテンプレートと「雑誌情報」というテンプレートを作ります。
「書籍情報」には「ISBN」「ASIN」「著者」「発売日」の項目をつけました。
ASINはAmazon内での商品コードですね。サムネイル画像を表示するのに使わせてもらうことにしました。
また、発売日は日付入力にしていますが、そうするとテキストボックスの脇にカレンダー表示のためのボタンが自動的に表示されます。(こういう補助はちょっと嬉しいですよね)
「雑誌情報」には「ASIN」「発売日」の項目を付けました。
これで「書籍」には「タイトル」「ISBN」「ASIN」「著者」「発売日」「書籍分類」が、
「雑誌」には「タイトル」「ASIN」「発売日」「雑誌分類」が情報として設定できるようになりました。
※カスタムフィールドテンプレートの設定で「カスタムフィールドのキーの代わりにラベルを使用する」「ボックスタイトルを置き換える」のオプションを有効にしています。

5. カスタム投稿の一覧画面に項目追加

せっかく情報を入力できるようにしたのでその情報を一覧画面でも出せるようにしてみようと思います。
「書籍」ではサムネイル画像、発売日、著書、書籍分類を出してみます。
「雑誌」では発売日、雑誌分類を出してみましょう。
項目を追加するためには見出しの定義、データの定義、2つの処理が必要です。

function book_manage_columns($columns) {
  $checkbox_index = array_shift(array_keys($columns));
  $checkbox = array_shift($columns);
  $columns = array_merge(array (
    $checkbox_index => $checkbox,
    'book_thumb' => ''
  ), $columns); // チェックボックスの後に入れたい
  //$columns['thumb'] = '書籍画像';
  $columns['book_publish_date'] = '発売日';
  $columns['book_author'] = '著者';
  $columns['book_genre'] = '書籍分類';
  return $columns;
}
add_filter('manage_book_posts_columns', 'book_manage_columns');
function book_manage_data($column_name, $post_id) {
  // 分類表示
  if ($column_name == 'book_genre') {
    $terms = get_the_terms($post_id, 'bookgenre');
    if ($terms) {
      foreach ($terms as $key => $value) {
        echo esc_attr($value->name);
        //最後以外は「,」を
        if (end(array_keys($terms)) != $key) {
          echo ', ';
        }
      }
    }
  }
  if ($column_name == 'book_author') {
    $author = get_post_meta($post_id, 'author', true);
    echo $author;
  }
  if ($column_name == 'book_isbn') {
    $isbn = get_post_meta($post_id, 'ISBN', true);
    echo $isbn;
  }
  if ($column_name == 'book_thumb') {
    $asin = get_post_meta($post_id, 'ASIN', true);
    $image_url = sprintf('http://images-jp.amazon.com/images/P/%s.09.THUMBZZZ.jpg', $asin);
    echo '<img src="' . $image_url . '" alt="" />';
  }
  if ($column_name == 'book_publish_date') {
    $publish_date = get_post_meta($post_id, 'publish_date', true);
    echo $publish_date;
  }
}
add_action('manage_book_posts_custom_column', 'book_manage_data', 10, 2);
function magazine_manage_columns($columns) {
  $checkbox_index = array_shift(array_keys($columns));
  $checkbox = array_shift($columns);
  $columns = array_merge(array (
    $checkbox_index => $checkbox,
    'magazine_thumb' => ''
  ), $columns); // チェックボックスの後に入れたい
  $columns['magazine_publish_date'] = '発売日';
  $columns['magazine_genre'] = '雑誌分類';
  return $columns;
}
add_filter('manage_magazine_posts_columns', 'magazine_manage_columns');
function magazine_manage_data($column_name, $post_id) {
  // 分類表示
  if ($column_name == 'magazine_genre') {
    $terms = get_the_terms($post_id, 'magazinegenre');
    if ($terms) {
      foreach ($terms as $key =&gt; $value) {
        echo esc_attr($value-&gt;name);
        //最後以外は「,」を
        if (end(array_keys($terms)) != $key) {
          echo ', ';
        }
      }
    }
  }
  if ($column_name == 'magazine_thumb') {
    $asin = get_post_meta($post_id, 'ASIN', true);
    $image_url = sprintf('http://images-jp.amazon.com/images/P/%s.09.THUMBZZZ.jpg', $asin);
    echo '<img src="' . $image_url . '" alt="" />';
  }
  if ($column_name == 'magazine_publish_date') {
    $publish_date = get_post_meta($post_id, 'publish_date', true);
    echo $publish_date;
  }
}
add_action('manage_magazine_posts_custom_column', 'magazine_manage_data', 10, 2);

見出しの定義のためには「manage_[カスタム投稿の識別子]_posts_columns」というフィルタを通します。
データの定義のためには「manage_[カスタム投稿の識別子] _posts_custom_column」というアクションを利用します。
「manage_[カスタム投稿の識別子] _posts_custom_column」というアクションの設定では、自作関数の引数2つをつけるためにadd_actionの第4引数で2を指定しています。これで自作関数で対象のカスタム投稿のIDが取得できます。

6. カスタム投稿の一覧画面で並び替えを追加

一覧で発売日を表示しましたが、これを並び替え可能にしてみたいと思います。

function book_manage_sortable($columns) {
  $columns['book_publish_date'] = 'book_publish_date';
  return $columns;
}
add_filter('manage_edit-book_sortable_columns', 'book_manage_sortable');
function book_publish_date_orderby($vars) {
  if (is_admin()) {
    if (isset ($vars['orderby']) && 'book_publish_date' == $vars['orderby']) {
      $vars = array_merge($vars, array (
        'meta_key' => 'publish_date',
        'orderby' => 'meta_value'
      ));
    }
  }
  return $vars;
}
add_filter('request', 'book_publish_date_orderby');
function magazine_manage_sortable($columns) {
  $columns['magazine_publish_date'] = 'magazine_publish_date';
  return $columns;
}
add_filter('manage_edit-magazine_sortable_columns', 'magazine_manage_sortable');
function magazine_publish_date_orderby($vars) {
  if (is_admin()) {
    if (isset ($vars['orderby']) && 'magazine_publish_date' == $vars['orderby']) {
      $vars = array_merge($vars, array (
        'meta_key' => 'publish_date',
        'orderby' => 'meta_value'
      ));
    }
  }
  return $vars;
}
add_filter('request', 'magazine_publish_date_orderby');

必要なのは「どのカラムが並び替え可能か」という設定と「並び替えの際にどのような動作をするか」という動作です。
カラムを並び替え可能にするためには「manage_edit-[カスタム投稿の識別子]_sortable_columns」というフィルタ、並び替えの動作は「request」というフィルタを通します。
「request」フィルタは管理画面だけで使われるわけでないのでis_adminで管理画面でのみ動作するようにしました。
(is_adminをはずせばカスタム投稿の一覧ページや検索ページで並び替えする時の動作としても使えるかもしれませんが今回は未検証・見送りとします。)
下の画面は管理画面で「書籍」の一覧画面の見出し部分をうつしたものです。
「発売日」がリンクになっているのがわかるでしょうか?
リンクをクリックすると発売日での昇順・降順での並び替えができます。

これで「書籍」「雑誌」を管理するための画面ができました。

あとは実際に「書籍」「雑誌」を表示するための画面ですが、説明が長くなりすぎたので今回はこの辺で。

※  サンプルファイルに含まれている他の実装は以下の通りです。

  • カスタム分類をカテゴリのように表示するためのウィジェット
  • カスタム分類による一覧表示
  • カスタム投稿を使って検索対象を絞り込む
  • カスタム投稿によるページ表示のカスタマイズ
  • 最新記事の中にカスタム投稿を追加する
  • 投稿の際にスラッグ(URLを決めるための設定)を自動的に更新