WordPressのカスタム投稿タイプとカスタムフィールドの作り方!実務で使う最小構成で覚えよう
WordPressで「制作実績」や「お知らせ」のような専用の投稿枠を作る方法です。
通常の投稿にカテゴリーを作って分けている方が多いのではないかと思います。件数が増えてくると、ブログ記事とお知らせが同じ一覧に混ざって管理しづらくなります。
テーマの functions.php に20行ほど書けば作れます。プラグインを使う形と使わない形の両方を載せます。
カスタム投稿タイプの登場人物
コードを書く前に、この記事に出てくるものを整理しておきます。
カスタム投稿タイプ
投稿・固定ページに続く、3つめの入れ物です。「制作実績」という種類を新しく増やすようなイメージですね。
専用の管理画面メニューが増えて、通常の投稿とは別々に管理できるようになります。
カスタムフィールド
1件ごとに追加の入力欄を持たせる仕組みです。制作実績なら「クライアント名」「制作期間」「使用技術」あたりが入ります。
本文のエディタに書くのと違って、値だけを取り出せます。テンプレートの好きな位置に置けるので、レイアウトが崩れません。
functions.php
テーマに機能を足すためのファイルです。カスタム投稿タイプの登録はここに書きます。
書き方を間違えるとサイト全体が真っ白になります。編集する前にバックアップを取っておいてください。
テンプレートファイル
一覧ページ用の archive-works.php と、詳細ページ用の single-works.php です。works の部分に、これから作るカスタム投稿タイプの名前が入ります。
この時点で分からない言葉があっても、深く理解せずに先へ進んで問題ありません。管理画面が実際に変わるのを見てからのほうが、話が早いと思います。
カスタム投稿タイプを作ろう
functions.php に register_post_type を書く
テーマの functions.php の末尾に、次のコードを足します。ファイルの先頭にある <?php は書き足さず、その下に続けてください。
function aoi_register_works_post_type() {
$labels = array(
'name' => '制作実績',
'singular_name' => '制作実績',
'add_new_item' => '制作実績を追加',
'edit_item' => '制作実績を編集',
'all_items' => '制作実績一覧',
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'menu_position' => 6,
'menu_icon' => 'dashicons-portfolio',
'supports' => array( 'title', 'editor', 'thumbnail', 'custom-fields' ),
'show_in_rest' => true,
'rewrite' => array( 'slug' => 'works', 'with_front' => false ),
);
register_post_type( 'works', $args );
}
add_action( 'init', 'aoi_register_works_post_type' );
register_post_type()の第1引数worksが投稿タイプの名前です。テンプレートのファイル名もここに合わせますpublicをtrueにすると、管理画面にもサイト側にも表示されますhas_archiveをtrueにすると/works/の一覧ページが自動で作られますsupportsは編集画面に出す項目の指定です。custom-fieldsを入れておかないと、あとで足すカスタムフィールドをブロックエディタから扱えませんshow_in_restをtrueにすると、投稿と同じブロックエディタになります。文章や画像をブロック単位で置いていく、今の編集画面のことです。省くと旧エディタの見た目に戻りますmenu_positionは管理画面での並び順です。数字が小さいほど上に出ます。投稿が5、メディアが10なので、すでに使われている数字は避けます。6を指定すると投稿のすぐ下に入りますmenu_iconはWordPressに最初から入っているアイコンの名前です。dashicons-で始まるものから選べますadd_action( 'init', ... )で実行のタイミングを指定します。WordPressの読み込みが終わった直後に走ります
投稿タイプ名の付け方に気をつけよう
works の部分は自由に決められます。ただし、いくつか決まりがあります。
- 半角英小文字・数字・ハイフン・アンダースコアのみ。20文字以内
postpageattachmentrevisionはWordPressが使っています。この名前は指定できません- プラグインとぶつかりそうなときは
aoi_worksのように接頭辞を付けます。URLに出る文字列はrewriteのslugで別に決められるので、URLが長くなる心配はありません
パーマリンクを更新して404を防ぐ
コードを保存すると、管理画面の左メニューに「制作実績」が増えます。ただし、この時点で詳細ページを開くと404になります。

URLの振り分けルールが古いままだからです。[管理画面]→[設定]→[パーマリンク] を開いて、何も変更せずに「変更を保存」を押してください。
これでルールが作り直され、詳細ページが表示されるようになります。
カスタム投稿タイプで最初に詰まるのがここです。コードは合っているのにページが出ない、という状態になります。

管理画面にメニューが増えたか確認しよう
左メニューに「制作実績」が出ていれば成功です。試しに1件、タイトルと本文を入れて公開してみてください。
https://example.com/works/ で一覧が、記事ごとのURLで詳細が表示されます。ここまで来れば、あとは中身を足していくだけです。

カスタムフィールドを追加しよう
ACF(Advanced Custom Fields)を使う場合
ACFは、管理画面から入力欄を組み立てられるプラグインです。コードを書かずに済むので、納品後にクライアントが自分で更新するサイトに向いています。
[管理画面]→[ACF]→[フィールドグループ]→[新規追加] から作ります。
- フィールドラベルに「クライアント名」と入れます。フィールド名は
client_nameのように自動で埋まります - フィールドタイプは「テキスト」を選びます
- 下にある「設定」で、表示条件を「投稿タイプ」「等しい」「制作実績」にします
- 公開すると、制作実績の編集画面に入力欄が出てきます

表示条件は画面の下のほうにあります。ここを「制作実績」にしないと、通常の投稿に入力欄が出てしまいます。

テンプレート側での取り出しは1行です。
<?php echo esc_html( get_field( 'client_name' ) ); ?>esc_html() は、入力された文字をそのままHTMLとして解釈させないための関数です。フォームやカスタムフィールドから受け取った値には必ず通してください。
プラグインを使わずに書く場合
ACFを入れられない環境では、register_post_meta() で登録します。
function aoi_register_works_meta() {
register_post_meta( 'works', 'client_name', array(
'type' => 'string',
'single' => true,
'show_in_rest' => true,
'sanitize_callback' => 'sanitize_text_field',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
) );
}
add_action( 'init', 'aoi_register_works_meta' );
singleをtrueにすると「1件につき値は1つ」という扱いになります。省くと配列で返ってきますshow_in_restをtrueにすると、ブロックエディタから読み書きできますsanitize_callbackは保存する前に値を掃除する関数です。省いても動きますが、入力された文字をそのまま保存することになるので入れておきますauth_callbackは「誰が編集できるか」の判定です。edit_postsの権限を持つ人だけに絞っています
登録しただけでは入力欄は出てきません。編集画面のパネルから「カスタムフィールド」を表示するか、add_meta_box() で専用の欄を作ります。
ここは書く量が増えます。プラグインを入れられる環境なら、ACFに寄せたほうが早いと思います。
値の取り出しは get_post_meta() です。
<?php echo esc_html( get_post_meta( get_the_ID(), 'client_name', true ) ); ?>テンプレートファイルで表示しよう
一覧ページ(archive-works.php)
テーマフォルダに archive-works.php を新しく作ります。
<?php get_header(); ?>
<?php if ( have_posts() ) : ?>
<ul class="p-worksList">
<?php while ( have_posts() ) : the_post(); ?>
<li class="p-worksList__item">
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail( 'medium' ); ?>
<p><?php the_title(); ?></p>
</a>
</li>
<?php endwhile; ?>
</ul>
<?php endif; ?>
<?php get_footer(); ?>
- ファイル名を
archive-works.phpにすると、/works/を開いたときだけこのファイルが使われます have_posts()とthe_post()の組み合わせは、通常の投稿一覧と同じ書き方ですthe_post_thumbnail( 'medium' )のmediumは画像サイズの名前です。[管理画面]→[設定]→[メディア]で決まっている中サイズが使われます- 取得するコードを自分で書く必要はありません。
/works/を開いた時点で、制作実績だけが入った状態になっています
WP_Query という、条件を指定して投稿を取り出す仕組みもあります。ただし一覧ページでは出番がありません。

詳細ページ(single-works.php)
<?php get_header(); ?>
<?php while ( have_posts() ) : the_post(); ?>
<article class="p-works">
<h1><?php the_title(); ?></h1>
<?php the_post_thumbnail( 'large' ); ?>
<div class="p-works__body">
<?php the_content(); ?>
</div>
</article>
<?php endwhile; ?>
<?php get_footer(); ?>
投稿の詳細ページ(single.php)をコピーして、必要な部分だけ書き換える形でも問題ありません。
一覧の表示件数と並び順を変える
一覧ページの件数は、そのままだと [管理画面]→[設定]→[表示設定] の「1ページに表示する最大投稿数」に従います。
制作実績だけ件数を変えたいときは pre_get_posts を使います。表示する内容が決まる前に、条件へ割り込むための仕組みです。
function aoi_works_archive_query( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_post_type_archive( 'works' ) ) {
$query->set( 'posts_per_page', 12 );
$query->set( 'orderby', 'date' );
$query->set( 'order', 'DESC' );
}
}
add_action( 'pre_get_posts', 'aoi_works_archive_query' );
is_admin()で管理画面を除きます。この判定がないと、管理画面の投稿一覧まで12件になりますis_main_query()は、そのページの本体かどうかの判定です。サイドバーなどで別に取得しているものを巻き込まないための指定ですarchive-works.phpの中でWP_Queryを作り直す書き方もありますが、ページ送りが効かなくなります
カスタムフィールドの値を出力する
値をそのまま出すのではなく、空だったときの分岐を入れておきます。
<?php $client = get_field( 'client_name' ); ?>
<?php if ( $client ) : ?>
<p class="p-works__client">クライアント:<?php echo esc_html( $client ); ?></p>
<?php endif; ?>
納品後、クライアントが入力欄を空のまま公開することがあります。分岐がないと「クライアント:」というラベルだけがページに残ります。
運用が始まると必ず起きるので、条件分岐は最初から入れておきます。

カスタム投稿タイプの仕組み
なぜパーマリンクの更新が必要なのか
WordPressは、URLとページの対応表をデータベースに保存しています。リライトルールと呼ばれるものです。
/works/sample/ を開いたときに、どの投稿を出すかを決めているのがこの表です。
カスタム投稿タイプを登録しただけでは、表は古いまま残っています。パーマリンクの「変更を保存」を押すと表が作り直され、新しいURLが通るようになります。
コードから作り直す flush_rewrite_rules() という関数もあります。ただし毎回のアクセスで呼ぶと重くなるので、init の中には書かないでください。
テーマやプラグインを有効化したタイミングで、1回だけ呼ぶ形になります。

テンプレートファイルが選ばれる順番
WordPressは、開かれたURLの種類に応じてテンプレートを上から探します。制作実績の詳細ページなら次の順です。
single-works.phpsingle.phpsingular.phpindex.php
先に見つかったものが使われます。single-works.php を置くだけで制作実績のデザインを変えられるのは、この順番があるからです。
一覧ページも同じ仕組みです。archive-works.php → archive.php → index.php の順に探されます。
逆に言うと、archive-works.php を作らなければ既存の archive.php がそのまま使われます。
おわりに
カスタム投稿タイプとカスタムフィールドの、実務で使う最小構成でした!
投稿の種類が2つ3つで済むサイトなら、通常の投稿にカテゴリーを付けるほうが手間は少ないと思います。全部をカスタム投稿タイプにする必要はありません。
ただ、更新の頻度も表示する場所も違うコンテンツが混ざり始めたら、分けておいたほうが後が楽になります。functions.php に20行足すだけで作れるので、ぜひ試してみてください!