WordPressテーマCocoonでカスタム投稿タイプとカスタム分類を作成して一覧を表示させる【WordPress/PHP】

WordPress

カスタム投稿タイプやカスタム分類を追加する際、今までプラグインを使っていましたが、コードで実装しました。将来の自分がコピペできるようにメモしておきます。

なお、使用しているテーマは無料で使えるCocoonというテーマです。テーマの機能も使用して実装しました。
Cocoonは以下の公式サイトからダウンロードできます。

Cocoon
SEO・高速化・モバイルファースト最適化済みのシンプルな無料Wordpressテーマ。100%GPLテーマです。

カスタム投稿タイプ・カスタム分類とは

WordPressには投稿と固定ページ、2つの投稿タイプがありますが、独自に投稿タイプを追加することができます。この独自の投稿タイプのことをカスタム投稿タイプといいます。

投稿する記事は、主にカテゴリーに分類して登録しますが、この分類も独自のものを追加できます。
この独自の分類のことをカスタム分類(カスタムタクソノミー)と呼びます。

図にするとこんなイメージになるかと思います。

カスタム分類の「ターム」という言葉がわかりにくいですが、これは分類の項目のことです。
例えば、「お知らせ」の投稿タイプと「お知らせジャンル」のカスタム分類を作成した場合、タームは次のように表すことができます。

カスタマイズする内容

実装したい項目を確認

WordPressで運営しているお店のサイトがあるとして、今回、実装したい内容を次のように箇条書きにしました。

  • お店の「お知らせ」をブログの投稿とは別に管理したい。
  • 「お知らせ」はジャンルごとに分けて管理できるようにしたい。
  • トップページと「お知らせ」の個別ページにお知らせの一覧を最新5件ほど表示させたい。
  • お知らせ一覧には、どのジャンルに属するか分かりやすくラベルを表示させたい。

具体的には次のようにカスタマイズします。

  • お店のブログは通常の投稿で管理しますが、営業時間の変更や臨時休業など、営業に関するお知らせをカスタム投稿タイプで管理する。
  • 「お知らせ」はジャンルごとに管理したいので、カスタム分類でカテゴリーのように登録できるようにする。
  • お知らせ一覧は複数ページに表示したいので、使い回しができるようショートコードで表示する。

今回、実装するお店のホームページは、次のようなカフェのサイトです。トップには固定ページを設定しています。

トップページ

メインビジュアルの下に、カスタム投稿タイプで追加した「お知らせ」一覧を表示します。

トップーページ

「お知らせ」の個別ページ

お知らせ一覧にサムネイルは表示せず、属しているジャンル(ターム)をラベルで表示させます。

カスタマイズする前の確認事項

カスタム投稿タイプとカスタム分類を実装する前に、いくつか確認事項があります。

カスタム投稿タイプとカスタム分類を管理する名前を決める

カスタム投稿タイプとカスタム分類を実装するには、管理する名前がそれぞれ必要です。この名前はURLでも使用されるので、英数字またはハイフン「-」を使う名前が良さそうです。

今回使用する名前は以下の通りです。

  • カスタム投稿タイプ「お知らせ」の名前は「news」
  • カスタム分類「お知らせジャンル」の名前は「news-genre」

カスタマイズするファイルの確認

子テーマのfunctions.phpと、親テーマから子テーマにコピーしたsingle.phpを編集します。
single.phpはコピーの際、single-news.phpに名前を変更します。

これはテンプレートの命名規則が次のようになるからです。

single-<カスタム投稿タイプの名前>.php

子テーマのフォルダ内の構成は次のようになります。

管理画面にカスタム投稿タイプとカスタム分類を追加

まず、投稿の下にカスタム投稿タイプ「お知らせ」とカスタム分類「お知らせジャンル」を追加します。
これで「お知らせ」の記事を投稿できるようになります。

以下のコードを追加すれば、管理画面にカスタム投稿タイプとカスタム分類が表示されると思います。
環境によって変更が必要な箇所に色をつけました。

functions.phpはエラーが発生するとサイトが表示されなくなります。ファイルのバックアップを作成してから編集します。

functions.php

// カスタム投稿タイプ - news
// アイコンフォント
// https://developer.wordpress.org/resource/dashicons/#tickets-alt
function register_post_news_init() {
  $args = array(
    'public' => true, // 投稿タイプを公開する
    'label'  => 'お知らせ', // 管理画面での表示
    'menu_position' => 5, // 投稿の下に表示
    'menu_icon' => 'dashicons-info-outline', // アイコンフォント
    'has_archive' => true, // 一覧ページ作成
    //'hierarchical' => true, // 階層設定
    'show_in_rest' => true, // ブロックエディタ表示
    'supports' => [ // 投稿に表示する項目
      'title', // タイトル
      'editor',  // 編集
      'thumbnail',  // サムネイル
      'excerpt',  // 抜粋
      //'page-attributes' // ページ属性
    ]
  );
  register_post_type( 'news', $args );
}
// カスタム分類 - news-genre
function create_my_taxonomies() {
	$args = array(
		'hierarchical' => true, // 階層設定 falseだとタグ分類
		'label' => 'お知らせジャンル', // 管理画面での表示
    'show_in_rest' => true, // ブロックエディタ表示
	);
	register_taxonomy('news-genre', 'news', $args);
}
// 関数実行
add_action( 'init', 'register_post_news_init' );
add_action( 'init', 'create_my_taxonomies' );

カスタム投稿タイプとカスタム分類が管理画面に表示されたら、管理画面→設定→パーマリンクを何も変更しないで保存してください。そうしないとURLが反映されず404ページが表示されます。

以下の公式サイトを参考にしました。

▼カスタム投稿 register post type

https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/register_post_type

カスタム分類 register taxonomy

https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/register_taxonomy

カスタム投稿の一覧を[ショートコード]で表示させる

Cocconのショートコードでお知らせ一覧を表示させる

Cocoonの場合、次のような[ショートコード]を使って簡単に記事一覧を表示することができます。

「お知らせ一覧」を表示するショートコード

[new_list count=”5″ type=”border_partition” cats=”all” children=”0″ post_type=”news”]

[ショートコード]のpost_typeにカスタム投稿タイプのnewsを指定すれば「お知らせ」に登録した記事だけが表示されます。通常の投稿の場合はpost、固定ページを表示したい場合はpageを指定します。

上記の[ショートコード]を編集画面の好きな場所に貼り付けると、以下のようにカスタム投稿タイプの一覧が表示されます。

[ショートコード]について、詳しくは公式サイトが参考になります。

新着記事一覧を表示するショートコードの利用方法
新着記事ウィジェットのようなリスト表示を実現できるショートコードの利用方法です。

独自で作成したショートコードでお知らせ一覧を表示させる

Cocoonで表示させる一覧でも十分ですが、今回はタームをラベルで表示したかったので、独自のショートコードを作りました。以下のコードをfunctions.phpに追加します。

functions.php

// カスタム投稿表示 ショートコード
function taxonomy_list_create($atts) {
  $atts = shortcode_atts([
    // ショートコード初期値
    'type' => 'news',
    'count' => 5
  ], $atts, 'add_taxonomy_list');

  $args = array(
    // 記事取得オプション
    'post_type' => $atts['type'],
    'posts_per_page' => $atts['count'],
  );
  $out = '';
  // 記事取得
  $the_query = new WP_Query( $args );
  
  // ループ
  if ( $the_query->have_posts() ) {
    $out ='<div class="post_news">';
    $out .='<div class="new-entry-cards widget-entry-cards no-icon cf border-partition">';

    while ( $the_query->have_posts()) {
      $the_query->the_post();
      $post_id = get_the_ID(); // 記事のID取得
      $taxonomies = get_object_taxonomies( $atts['type'], 'objects' ); // タクソノミー取得
      $title = esc_html(get_the_title()); // タイトル取得
      $link = get_permalink(); // リンク取得
      $time = "";

      //更新日を取得
      if(get_the_time('U') !== get_the_modified_time('U')){
        $time = get_the_time(get_option('date_format'));
      }

      $out .= <<< EOD
      <a href="{$link}" class="new-entry-card-link widget-entry-card-link a-wrap" title="{$title}">
        <div class="new-entry-card widget-entry-card e-card cf">
          <div class="widget-entry-card-news">
            <span class="new-entry-card-post-date widget-entry-card-post-date post-date widget-entry-card-news">
              {$time}
            </span>
          </div><!-- /.widget-entry-card-news -->
          <div class="new-entry-card-content widget-entry-card-content card-content widget-entry-card-news">
            
      EOD;
          // 投稿が属するカスタム分類を表示
          foreach ( $taxonomies as $taxonomy_slug => $taxonomy ){
            $my_terms = get_the_terms(get_the_ID(), $taxonomy_slug);

            if ($my_terms && ! is_wp_error($terms)) {
              $out .='<div class="taxonomy_genre_ribon">';
              foreach( $my_terms as $term ){
                $out .='<span class="genre_icon genre-'. $term->term_id . '">' . $term->name . '</span>';
              }
              $out .='</div><!-- ./taxonomy_genre_ribon -->';
            }
          }
      $out .= <<< EOD
            <div class="new-entry-card-title widget-entry-card-title card-title">
            {$title}
            </div><!-- /.new-entry-card-title -->
          </div><!-- /.widget-entry-card-news -->
        </div><!-- ./new-entry-card -->
      </a><!-- /.new-entry-card-link -->
      EOD;
    }
    $out .= '</div><!-- /.new-entry-cards -->';
    $out .= '</div><!-- /.post_news -->';

    /* Restore original Post Data */
    wp_reset_postdata();
  } else {
    // no posts found
    $out = '<p>お知らせは見つかりませんでした。</p>';
  }
  return $out;
  
}
add_shortcode( 'add_taxonomy_list', 'taxonomy_list_create' );

PHP 7.3.x以前のバージョンを使用の場合
ヒアドキュメントにインデントがあるとエラーになってサイトが表示されなくなります。functions.phpに追加する際は、EOD〜EOD;のインデントを削除します。

作成した[ショートコード]は次のように使います。typeにはカスタム投稿タイプ、countには表示する記事の数を指定します。typeを省略するとnewsがデフォルトで設定されます。

[add_taxonomy_list type=”news” count=”5″]

上記の[ショートコード]を使用すると、Cocoonで表示させた一覧とは異なり、日付とラベルが表示され、サムネイルは非表示になった一覧が表示されます。

CSSもメモしておきます。読み込みができる任意の場所に保存します。
私は管理画面→外観→カスタマイズ→追加CSSに保存しました。

CSS

.new-entry-card-news {
    margin-right: 1.6%;
}
.widget-entry-card-news {
    margin-top: 0 !important;
    margin-left: 0;
    float:left;
}
.taxonomy_genre_ribon .genre_icon {
    display: inline-block;
    margin: 0 5px 5px 5px;
    padding: .3em .5em;
    background: #ccc;
    font-size: .7em;
}
.taxonomy_genre_ribon .genre_icon:first-child {
    margin-left: 0;
}

カスタム投稿の個別ページをカスタマイズする

個別ページのカスタマイズは、メモすることも特にないのでコードだけ残しておきます。
色をつけている箇所が追記したコードです。

single-news.php

<?php //通常ページとAMPページの切り分け
/**
 * Cocoon WordPress Theme
 * @author: yhira
 * @link: https://wp-cocoon.com/
 * @license: http://www.gnu.org/licenses/gpl-2.0.html GPL v2 or later
 */
if ( !defined( 'ABSPATH' ) ) exit;

if (!is_amp()) {
   get_header();
 } else {
   get_template_part('tmp/amp-header');
 }
?>

<?php //投稿ページ内容
get_template_part('tmp/single-contents'); ?>
<!-- カスタム分類一覧 -->
<?php
if ( have_posts() ) {
  echo '<ul class="post_terms">';
  while ( have_posts()) {
    the_post();
    $post_id = get_the_ID(); // 記事のID取得
    $post_type = $post->post_type;

    $taxonomies = get_object_taxonomies( $post_type, 'objects' );

    foreach ( $taxonomies as $taxonomy_slug => $taxonomy ){
      $post_terms = get_the_terms(get_the_ID(), $taxonomy_slug);
      foreach($post_terms as $term) {
        echo '<li>' . '<a href="' . get_term_link($term) . '"><span class="genre-'. $term->term_id . '">' . $term->name . '</span></a></li>';
      }
    }

  }
  echo '</ul>';
}
?>
<!-- /カスタム分類一覧 -->

<!-- お知らせ一覧 -->
<h2>お知らせ一覧</h2>
<?php
  echo do_shortcode('[add_taxonomy_list type="news" count="5"]');
?>
<!-- ./お知らせ一覧 -->


<?php get_footer(); ?>

<!-- 追加css -->
<style>
  /* 投稿者の情報と関連記事を非表示 */
  .author-info,
  .under-entry-content {display:none !important;}
  /* カスタム分類一覧 */
  .post_terms {
    padding-left: 0;
    text-align: right;
  }
  .post_terms li {
    list-style-type: none;
    display: inline-block;
    margin: 0 10px;
  }
  .post_terms li a {
    /* color: #999; */
  }
</style>

カスタマイズした内容は、先程の[ショートコード]を使って「お知らせ」一覧を表示し、記事が属するカスタム分類を表示させています。

あとは、投稿者情報など表示が不要なデータをCSSで非表示にしています。

まとめ

今回、初めてカスタム投稿タイプをプラグインなしで実装しましたが、思ったよりコードの量が少なかったです。
プラグインは更新が止まると使えなくなったり、数が増えると管理が大変です。。
なので頑張って独自で実装した方が良いかもしれないと思いました。

コメント