更新日 2021.07.30

#11 カスタム投稿機能を使う

投稿ページ機能を拡張した「カスタム投稿タイプ」

Wordpressには「固定ページ」と「投稿ページ」がありますが、投稿ページを拡張したカスタム投稿という機能があります。

上記の例では「chef」と「cource」という名前のカスタム投稿タイプがある状態です。
WordPressに最初からある機能「投稿ページ」には、前回紹介したような「カスタムフィールド」という機能を追加できます。 カスタム投稿は投稿ページとは違う新たな投稿ページの仕様(デザイン・レイアウト)を作るための機能です。
自分の好きな項目を設定することで自由な一覧・詳細ページが作れます。
■サイトを更新管理する方が、HTMLの知識がない。
■標準の投稿とは別の投稿フォーマットを作りたい。
このような場合にカスタム投稿は便利です。
最初に、どんなページ構成にするのかという`設計`がなにより大事です

カスタム投稿タイプの作り方

  1. functions.phpにカスタム投稿タイプを設定
  2. 管理画面で記事を作成
  3. カスタム投稿タイプ用のテンプレートファイルを作る
  4. cssを記述

functions.phpで設定

まずfunctions.phpに、カスタム投稿ページでどんな項目を入れたいかを設定します。

/* ⑥カスタム投稿タイプの登録 */
function create_post_type()
{
  $labels = array(
    'name'          => 'CHEF',
    'singular_name' => 'CHEF',         /*nameと一緒で良い */
    'menu_name'     => 'シェフ',        /*メニュー項目の名前 */
    'all_items'     => 'シェフ一覧',    /*メタボックスの見出し */
    'add_new'       => 'シェフを追加',  /*管理画面ナビメニュー名 */
    'add_new_item'  => '新規シェフ投稿を追加',  /*見出しとボタンの名前 */
  );
  $args = array(
    'labels'        => $labels,
    'public'        => true,      /* 投稿タイプを公開にする */
    'has_archive'   => true,      /* アーカイブ(一覧)を有効にする(デフォルトはfalse)*/
    'show_in_rest'  => false,     /* グーテンベルグ 無効 */
    'menu_position' => 3,         /* 管理画面の左サイドメニューでの表示位置 */
    'menu_icon'     => 'dashicons-coffee',
    'supports'=> ['title', 'editor', 'thumbnail', 'excerpt', 'author', 'custom-fields'],
  );
  register_post_type('chef', $args);
}
add_action('init', 'create_post_type');
解説
関数の作成
まず関数のオプションの設定を作成します。配列で必要なオプションを入れていきます。

function create_post_type() {}
自由に関数名をつけましょう。

'labels' => $labels,
ラベル関係はオプションが多いので、更に連想配列を変数$labelsに入れて分けています。
管理画面での表示名などを設定していきます。
調べると=> __('CHEF')という書き方も見られますが、ロケール(多言語化)に応じて自動翻訳してくれる関数の書き方なので、いったん普通の書き方で大丈夫です。

'menu_icon' => 'dashicons-coffee',
このページでいろんなiconを選択できます。WordPress.org

'supports' => ['title', 'editor', 'thumbnail', 'excerpt',.....],
管理画面の記事作成ページで表示するウィジェットを指定しています。必要なものを適宜入れましょう。

'show_in_rest' => false,
この設定をtrueにすると、記事作成画面が新エディタ(グーテンベルク)で表示されます。初期値がfalseなので旧エディタのままで良い場合は記述しなくても良いです。

その他の設定はこちら Codex 日本語版

実行の設定

register_post_type('カスタム投稿タイプ名', 'パラメーター')
カスタム投稿タイプ名とパラメーター(設定値を入れている変数)を登録します。

add_action('フックされるアクション名', '実行する関数');
WordPressがWebサイトを表示させるため順次、特定の処理(アクション)をしていきます。そのアクションにフックさせ、登録している関数を実行します。
※フックに関しては後ほど詳しく説明します。

initはユーザーのログイン状態がどうなっているかを参照しているタイミングです。ここでカスタム投稿タイプを登録した関数 create_post_type() を実行します。
ファイル関係はこのようになります。
functions.phpを設定した段階で、「設定」→「パーマリンク設定」を表示し、何も変更せずに「変更を保存」ボタンをクリックしましょう。ページを表示させる際に必要な手順となります。

管理画面のダッシュボードの左のメニューのアイコンから新規記事を作成します。

カスタムフィールドを追加する

これに前回覚えたカスタムフィールドで名前と画像のフィールドを追加しましよう。

フィールドグループからシェフというグループを作成し、図の通りのフィールドを追加しましょう。

記事を追加

管理画面から「シェフを追加」をクリックし、新規記事を作ります。
記事の内容は適当に書いてみましょう。
写真はここからダウンロード しましょう。

シェフの記事を作ります。このような表示になります。

テンプレートを作成する

single-{カスタム投稿タイプ名}.phpで作成します。
ここの例ではregister_post_type('chef', $args)chefと設定したとおりsingle-chef.phpとなります。

<?php
get_header();
$flg = get_post_meta( get_the_ID() );  /*カスタム投稿タイプ 記事IDの有無*/
?>
<div class="contents_wrap">
<main class="main" role="main">
  <?php if( have_posts() ): while( have_posts() ): the_post(); ?>

  <?php if( !empty($flg) ): ?>
  <div class="chef">
      <div class="chef__img">
          <?php if( get_field('chef_image') ): ?>
            <div>
              <p><img src="<?php echo get_field('chef_image'); ?>"></p>
            </div>
          <?php endif; ?>
      </div>
      <div class="chef__txt">
          <h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
          <?php the_content(); ?>
          <h2><?php echo get_field('chef_name'); ?></h2>
      </div>
  </div>
  <?php endif; ?>

  <?php endwhile; endif; ?>
</main>
</div>

<?php
get_footer();

テンプレートファイルは見づらいですが、図解するとこんな感じです。

CSSの設定

.mainの中に次のcssを追記しましょう。

.chef{
  display:flex;
  margin:10px;
  font:normal 0.9em/2.4 serif;
  &__img{
    flex:1;
    margin-right:2em;
  }
  &__txt{
    flex:1;
    h1{
      font-size:1.8em;
      a{
        color:$titleColor;
      }
    }
    h2{
      width:100%;
      display:inline-block;
      text-align:right;
      color:$titleColor;
    }
  }
}

表示してみましょう

表示はこんな感じです。

もし表示されない場合は、設定 > パーマリンクの設定 を何も変更せずに[変更を保存]をクリックしましょう。

カスタム投稿タイプ一覧を表示してみましょう

他のシェフも2名追記して一覧に出してみましょう。まずはテンプレートに一覧を表示する部分を追記します。

<?php
$args = array(
  'post_type'    => 'chef',  /* 表示させたいカスタム投稿タイプ名 */
  'numberposts'  => 3,       /* 3件表示(デフォルトは5件) */
);
$the_query = new WP_Query($args); /* サブクエリを取得 */
?>

<div class="contents_wrap">
<main class="main" role="main">
  カスタム投稿記事を表示している箇所
</main>


<section class="list">
  <div class="list__item">
    <?php if( $the_query->have_posts() ): ?>
        <?php while( $the_query->have_posts() ): $the_query->the_post();?>
            <div>
              <a href="<?php the_permalink(); ?>">
                <div class="list__item-image" style="background-image: url(<?php the_post_thumbnail_url('medium');?>)"></div>
                <?php the_title(); ?>
              </a>
              <p><?php the_excerpt(); ?></p>
            </div>
        <?php endwhile; ?>
        <?php wp_reset_postdata(); ?>
        <?php else : ?>
        <p>関連アイテムはまだありません。</p>
    <?php endif; ?>
  </div>
</section>


</div>

WP_Query()とは


$the_query = new WP_Query($args);
WordPressはリクエストされたURLに対してデータベースに接続し、画面を表示するデータを自動で取得します(メインクエリ)。 そのデータをループさせることをメインループと呼び、標準の投稿ページやカテゴリーページなどを表示する際に使います。
WP_Query()はメインの条件とは異なる、例えばあるページにカスタム投稿の一覧を表示したいなどのサブクエリをループ (サブループ)させるための方法です。
サブクエリは、表示させたいデータ取得の条件の指示を、引数$argsに指定しクエリを発行します。

また必要な知識として、WordPressはページを表示するときに、対象の記事データの情報を$wp_queryというグローバル変数を作りデータを格納しています。 各ループ毎の現在の記事は、グローバル変数$postというオブジェクトに格納され、 $post->IDのようにIDプロパティを指定するなどして様々なデータを出力できます。

get_posts() と WP_Query()の違い

WP_Query()と違ってget_posts() は記事データのみを持っています。WP_Query()はより多くのパラメーターが利用でき複雑な処理ができます。 特に意味がなければWP_Query()を使って問題ないでしょう。
get_posts()
・投稿記事のデータのみ取得したい場合
・foreach()でループする
・テンプレートタグを使えるようにするため、ループ内にsetup_postdata($post)関数でデータをセットする必要がある
WP_Query()
・投稿記事のデータ以外の情報()も取得したい場合
・while()でループする
・have_posts()でデータの有無をチェックし、the_post()でカウントと値($post)の変更を行い、ループを実行し続けます
共通
・引数$argsに投稿を取得するための条件(パラメーター)を設定します。

※WP_Queryインスタンスは$the_queryという名前の変数に代入しています。ループ内部で$postsが動いているので、上書きしないように別の名前をつけましょう。

get_posts()
WP_Query()

<?php wp_reset_postdata(); ?>
必ずループ終了後にwp_reset_postdata()でサブループをリセットして、メインループのためにグローバル変数$postを復元しておきます。

CSSの調整


.main{
  いろいろ
}
.menu-logo{
  img{
    margin:20px auto;
  }
}
.list{
  margin:20px auto;
  &__item{
    display:flex;
    @include mq('max','lg'){
      display:block;
    }
    div{
      flex:3;
      @include mq('max','lg'){
        margin-top:40px;
      }
      p{
        display:block;
        margin-top:20px;
        width:90%;
      }
    }
    &-image{
      width:300px;
      height:300px;
      margin:10px 0;
      background-repeat:no-repeat;
    }
  }
}
カスタム投稿一覧の表示が確認できます

http://localhost:8003/chef/georges/ でアクセスするとこのような表示になります。

#12 カスタムタクソノミー機能を使う

カスタムタクソノミーについて

カスタム投稿タイプを設定してみましたがカテゴリーの機能を追加すればもっと便利になります。

標準の「投稿」にはカテゴリータグが標準機能として付いてきますが、 カスタム投稿タイプを作った場合は、標準機能以上の分類をしたい場合がほとんどのため、自分でカテゴリーやタグを作ることが多いです。

このときのカテゴリータグのことをカスタム タクソノミーと呼びます。 タクソノミーとは分類のことです。標準についているカテゴリー・タグもタクソノミーと呼べますが、 標準タクソノミーとは呼ばれません。あくまでカテゴリー・タグという名称になります。カスタム投稿の場合はカスタムタクソノミーと呼びます。

カスタムタクソノミーの作り方

  1. functions.phpのカスタム投稿タイプ内にカスタムタクソノミーを設定
  2. 管理画面でカスタムタクソノミーを登録
  3. カスタム投稿タイプ用のテンプレートにカスタムタクソノミーを記述
  4. cssを記述

functions.phpの設定

今回はシェフの個人ページに料理ジャンル在籍店舗の2つのカテゴリを追加したいと思います。
/* ⑦タクソノミー設定 */以下の箇所を追加しています。

function create_post_type()
{
  /* ⑥カスタム投稿タイプ 設定 */
  $labels = array(
    ・・・省略
  );
  $args = array(
    'labels' => $labels,
    ・・・省略
  );
  register_post_type('chef', $args);

  /* ⑦タクソノミー設定 */
  register_taxonomy(
    'food',  /* カスタムタクソノミー名  */
    'chef',  /* 対象のカスタム投稿タイプ */
    array(
      'label'             => '料理ジャンル',   /* カスタムタクソノミーラベル名 */
      'public'            => true,           /* 使用可能にします */
      'show_ui'           => true,           /* 管理画面上に編集画面を表示 */
      'hierarchical'      => true,           /* 階層を持たせるかどうか。falseにするとタグ扱いになる */
      'show_admin_column' => true,           /* 管理画面のカスタム投稿の一覧表示画面にタクソノミーを表示 */
    )
  );
  register_taxonomy(
    'shop',
    'chef',
    array(
      'label'             => '在籍店舗',
      'public'            => true,
      'show_ui'           => true,
      'hierarchical'      => true,
      'show_admin_column' => true,
    )
  );
  /* ⑦追加ここまで */
}
add_action('init', 'create_post_type');
▼解説

register_taxonomy('food', 'chef', $args);
register_taxonomy()の引数は(タクソノミーの名前, 対象のpostや投稿タイプ名, パラメータ); となります。
タクソノミーの名前
32文字以内で好きな名前をつけましょう。予約語は使えませんので確認(関数リファレンス しましょう。URLや管理画面で表示するときなどに使います。一度ここの名称を設定して管理画面で登録したあとここの名称を変更してしまうと、データが消えてしまうので気をつけましょう。
対象のpostや投稿タイプ名
カスタムタクソノミーを使う投稿ポストタイプを指定します。複数ある場合はarray('chef', 'typeA', 'typeB', 'typeC')とします。
パラメータ
各種項目の設定をします。色々ありますので確認(関数リファレンス してみましょう。
設定と実際の画面の関係はこのようになります。

管理画面から登録

料理ジャンルにはFrench, Italian, 日本を、 在籍店舗は東京, 大阪, 福岡を入れてみましょう。


名前とスラッグを入れましょう。
カウントに数字が入っていますが、登録したては0になります。

カスタム投稿タイプ用のテンプレートにカスタムタクソノミーを記述

カスタム投稿やカスタムタクソノミーのテンプレート関係はこの様になっています。
カスタムタクソノミーで作られた要素の一つ一つのことはタームという名称で呼ばれます。 この例では、タクソノミー名「shop」、管理画面で登録したスラッグ「tokyo, osaka, fukuoka」がタームとなります。
シェフの一覧を表示したい場合はarchive-chef.php
カスタムタクソノミー「在籍店舗」の一覧を表示したい場合はtaxonomy-shop.phpというテンプレートを作ります。
しかし、複数のカスタムタクソノミーがあった場合でも、テンプレートが同一で良い場合は、taxonomy.phpでも良いでしょう。
表示されるURL
カスタム投稿タイプ  :https://exsample.com/カスタム投稿タイプ名/投稿スラッグ/
カスタムタクソノミー :https://exsample.com/タクソノミー名/ターム/

archive-chef.php

一覧を出す場合はarchive-{カスタム投稿タイプ名}.phpでテンプレートファイルを作成します。
カスタム投稿タイプ「chef」の投稿一覧ページを作成し、カスタムフィールドや、アイキャッチ画像、カスタムタクソノミーを表示してみました。

<?php
get_header();
$args = array(
  'post_type' => 'chef',
  'orderby'   => 'date',
);
$the_query = new WP_Query($args);
?>

<div class="contents_wrap">
<main class="main" role="main">

  <?php if( $the_query->have_posts() ): ?>
  <?php while( $the_query->have_posts() ): $the_query->the_post(); ?>
  <div class="archive-chef">
    <h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
    <time datetime="<?php the_time('Y-m-d'); ?>"><?php the_time('Y.m.d'); ?></time>

    <p>■カスタムフィールド:      <?php the_field('chef_name'); ?></p>
    <p>■カスタムフィールド:      <?php echo wp_get_attachment_image( get_post_meta(get_the_ID(), 'chef_image', true), 'thumbnail' ); ?></p>
    <p>■アイキャッチ画像:       <?php echo get_the_post_thumbnail(get_the_ID(), 'thumbnail'); ?></p>
    <p>■カスタムタクソノミーfood:<?php echo get_the_term_list(get_the_ID(), 'food'); ?></p>
    <p>■カスタムタクソノミーshop:<?php echo get_the_term_list(get_the_ID(), 'shop'); ?></p>

    <div>■本文:<?php the_excerpt(); ?></div>
  </div>
  <?php endwhile; ?>
  <?php wp_reset_postdata(); ?>
  <?php endif; ?>

</main>
</div>

<?php
get_footer();
カスタムフィールドの画像、カスタムタクソノミーを取得する方法

get_post_meta( 投稿ID, カスタムフィールド名, true )
get_post_meta()でカスタムフィールドなどのメタデータが取得できます。
カスタムフィールドで設定した「画像」を表示したい場合は、まず画像IDを取得します。

wp_get_attachment_image(画像ID, サイズ)
続いてテンプレートタグwp_get_attachment_image() はget_post_meta()で取得した画像IDのデータでimg要素(HTML)を生成します。
サイズはthumbnail(150px), medium(300px), large(1024px), fullがあります。
※リンク画像にしたい場合はwp_get_attachment_link() を使いましょう。

get_the_term_list()
は、カスタムタクソノミーの値がハイパーリンク付きで出力されます。

http://localhost:8003/chef/でアクセスするとこのようになります。
cssで調整すればオリジナルの一覧ページができますね。

taxonomy.php


<?php
get_header();

$page_object = get_queried_object();
$args = array( 
  'post_type'      => 'chef',
  'taxonomy'       => $page_object->taxonomy,
  'term'           => $page_object->slug,
  'posts_per_page' => 5,
);
$custom_query = new WP_Query($args);
?>

<div class="contents_wrap">
<main class="main" role="main">

<h1><?php echo $page_object->slug ?></h1>

<?php if( $custom_query->have_posts() ): ?>
    <?php while( $custom_query->have_posts() ): $custom_query->the_post(); ?>
        <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
        <div class="data"><?php the_time('Y/m/d'); ?></div>
        <?php echo get_the_post_thumbnail(get_the_ID(), 'thumbnail'); ?>
        <div class="entry"><?php the_excerpt(); ?></div>
    <?php endwhile; ?>
<?php wp_reset_postdata(); ?>
<?php endif; ?>

<h3>カスタムタクソノミーのターム一覧</h3>
<ul>
  <?php
    $terms = get_terms($page_object->taxonomy);
    foreach ( $terms as $term ) {
      echo '<li><a href="'.get_term_link($term).'">'.$term->name.'</a></li>';
    }
  ?>
</ul>

</main>
</div>

<?php
get_footer();
前回の例によって、標準以外の情報を出力したかったのでサブループnew WP_Query( $args )を使いました。
▼解説
get_queried_objectゲット クエリード オブジェクト()で取得したデータを見てみましょう。
var_dump($page_object); をすると表示されているページのクエリ情報のオブジェクトが取得できます。
一覧ページで表示されているページのタクソノミーやスラッグ情報を取得できます。 ページのタイプによって表示される内容が異なりますので、毎回確認したほうが安全です。

object(WP_Term)#5298 (10) {
  ["term_id"]    => int(13)
  ["name"]       => string(6) "東京"
  ["slug"]       => string(5) "tokyo"
  ["term_group"] => int(0)
  ["term_taxonomy_id"]=> int(13)
  ["taxonomy"]   => string(4) "shop"
  ["description"]=> string(0) ""
  ["parent"]     => int(0)
  ["count"]      => int(2)
  ["filter"]     => string(3) "raw"
}
タクソノミー`shop`ではなく`food`と別のタームのページを表示しても、動的に文字列が変更できるので、 レイアウトの変更がないのであれば複数のtaxonomy-{カスタムタクソノミー名}.phpを作らなくても済みます。

別の方法として、wp_get_object_termswp ゲット オブジェクト タームズ()も利用できます。

wp_get_object_terms(タームを取得するオブジェクトのID, カスタムタクソノミー名);
↓
$term = wp_get_object_terms($post_ID, 'shop');
wp_get_object_terms() で、指定したカスタムタクソノミー名ごとのタームのオブジェクトデータを取得します。取得された$term[0]に各種データが入っています。 var_dunp($term[0])で確認するとget_queried_object()と同じ内容が確認できます。
ほかの情報を入れたい場合はarchive-{カスタム投稿名}.phpで使ったテンプレートタグを入れてみましょう。


$terms = get_terms('shop');
foreach ( $terms as $term ) {
  echo '<li><a href="'.get_term_link($term).'">'.$term->name.'</a></li>';
}
get_terms()で登録されているタームがある場合は、一覧を取得してliタグで表示させます。

http://localhost:8003/shop/tokyo/ で表示されます。
http://localhost:8003/shop/fukuoka/ や http://localhost:8003/food/french/ でも
同じtaxonomy.phpテンプレートで表示できます。
コピーしました
RSS https://cbc-study.com/rss.xml 
質問などあればSlackで! 誰でも無料でできます。
勧誘とかしないよー
cbc-study.slack.com