2026年5月20日
2026年5月20日
カスタム投稿タイプのアーカイブページを作る方法|has_archive・archive-{post_type}.php・表示件数
カスタム投稿タイプ(例: news)の記事を /news/ のような一覧ページで見せるには、投稿タイプの登録時に has_archive を有効にし、必要に応じて専用のテンプレートを用意します。この記事では、クラシックテーマ(PHP テンプレート)を前提に、登録からテンプレート、表示件数の調整、404 の対処までを順に説明します。
関数と引数は developer.wordpress.org のリファレンス(register_post_type()、テンプレート階層、pre_get_posts)で2026年10月時点の内容を確認しています。
アーカイブページが表示される仕組み
register_post_type()のhas_archiveがtrueのとき、WordPress は一覧用の URL とリライトルールを作ります。既定値はfalseで、このままでは一覧ページはありません。has_archiveに文字列を渡すと、それが一覧の URL になります(例:'has_archive' => 'topics'なら/topics/)。trueのときはrewriteのslug(未指定なら投稿タイプ名)が使われます。- 一覧ページを開くと、テーマの中から次の順でテンプレートが探されます。
| 優先順 | クラシックテーマ | ブロックテーマ |
|---|---|---|
| 1 | archive-news.php |
templates/archive-news.html |
| 2 | archive.php |
templates/archive.html |
| 3 | index.php |
templates/index.html |
テンプレート階層の全体は WordPressのテンプレート階層 も参考にしてください。
手順1: has_archive を有効にして投稿タイプを登録する
テーマの functions.php(またはサイト用の独自プラグイン)に書きます。
<?php
function mytheme_register_news_post_type() {
register_post_type( 'news', array(
'labels' => array(
'name' => 'ニュース',
'singular_name' => 'ニュース',
'add_new_item' => 'ニュースを追加',
'edit_item' => 'ニュースを編集',
'all_items' => 'ニュース一覧',
'archives' => 'ニュース一覧',
),
'description' => '当社からのお知らせを掲載しています。', // 一覧ページの説明文に使える
'public' => true,
'has_archive' => true, // /news/ に一覧ページを作る
'rewrite' => array(
'slug' => 'news',
'with_front' => false, // パーマリンクの前置部分(/blog/ など)を付けない
),
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
'show_in_rest' => true, // ブロックエディターで編集する
'menu_icon' => 'dashicons-megaphone',
) );
}
add_action( 'init', 'mytheme_register_news_post_type' );
パーマリンクを更新する
has_archive や rewrite を追加・変更したあとは、リライトルールを作り直すまで一覧の URL が 404 になります。管理画面の「設定」→「パーマリンク」を開くとルールが作り直されます(「変更を保存」を押しても同じです)。WP-CLI が使える環境では次のコマンドでも構いません。
wp rewrite flush
flush_rewrite_rules() を init で毎回呼ぶのは処理が重くなるので避けます。プラグインで登録する場合は、有効化フック(register_activation_hook())の中で一度だけ呼ぶのが公式ドキュメントの推奨です。
一覧ページの URL は、テンプレートやメニューで次のように取得できます。
<?php
echo esc_url( get_post_type_archive_link( 'news' ) ); // https://example.com/news/
手順2: archive-news.php を作る
archive-news.php をテーマのフォルダー直下に置くと、ニュースの一覧だけがこのテンプレートで表示されます。子テーマを使っている場合は子テーマに置きます。
<?php
get_header();
?>
<main id="main" class="site-main">
<header class="page-header">
<h1 class="page-title"><?php post_type_archive_title(); ?></h1>
<?php the_archive_description( '<div class="archive-description">', '</div>' ); ?>
</header>
<?php if ( have_posts() ) : ?>
<div class="news-list">
<?php while ( have_posts() ) : the_post(); ?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<time datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>"><?php echo esc_html( get_the_date() ); ?></time>
<?php the_excerpt(); ?>
</article>
<?php endwhile; ?>
</div>
<?php
the_posts_pagination( array(
'prev_text' => '前のページ',
'next_text' => '次のページ',
) );
?>
<?php else : ?>
<p>ニュースはまだありません。</p>
<?php endif; ?>
</main>
<?php
get_footer();
post_type_archive_title()は投稿タイプの名前(labelsのname)を出力します。the_archive_description()は、投稿タイプの一覧ではregister_post_type()のdescriptionを出力します。説明が空なら何も出ません。- 記事一覧の部分をテーマ内の部品に分けたい場合は
get_template_part( 'template-parts/content', 'news' )のように呼び、template-parts/content-news.phpを作ります。ファイルが無いと何も表示されないので注意してください。
ブロックテーマでは PHP テンプレートの代わりに、サイトエディターで「ニュース」の一覧用テンプレートを追加するか、テーマの templates/archive-news.html に「クエリーループ」ブロックを置きます。
手順3: 表示件数と並び順を pre_get_posts で変える
一覧ページの表示件数は、既定では「設定」→「表示設定」の「1ページに表示する最大投稿数」に従います。ニュースだけ変えたい場合は、テンプレートの中で WP_Query を作り直すのではなく、pre_get_posts でメインクエリを書き換えます。こうするとページ送りもそのまま動きます。
<?php
function mytheme_news_archive_query( $query ) {
// 管理画面やサブクエリには手を出さない
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_post_type_archive( 'news' ) ) {
$query->set( 'posts_per_page', 12 );
$query->set( 'orderby', 'date' );
$query->set( 'order', 'DESC' );
}
}
add_action( 'pre_get_posts', 'mytheme_news_archive_query' );
テンプレートの中で new WP_Query() や query_posts() を使って件数を変えると、メインクエリの件数とずれて2ページ目以降が 404 になることがあります。pre_get_posts の使い方は pre_get_postsでメインクエリを変更する方法 で詳しく説明しています。
手順4: 見出しの「アーカイブ:」を消す
archive.php で the_archive_title() を使っていると、投稿タイプの一覧は「アーカイブ: ニュース」のように前置きが付きます。WordPress 5.5 以降は、前置きだけを get_the_archive_title_prefix フィルターで外せます。
<?php
function mytheme_archive_title_prefix( $prefix ) {
if ( is_post_type_archive( 'news' ) ) {
return '';
}
return $prefix;
}
add_filter( 'get_the_archive_title_prefix', 'mytheme_archive_title_prefix' );
archive-news.php で post_type_archive_title() を使っている場合は、前置きは最初から付きません。
複数の投稿タイプを archive.php でまとめて扱う
投稿タイプごとにテンプレートを分けず、archive.php 1つで見出しや部品を切り替えることもできます。
<?php
get_header();
?>
<main id="main" class="site-main">
<h1 class="page-title"><?php the_archive_title(); ?></h1>
<?php if ( have_posts() ) : ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
<?php endwhile; ?>
<?php the_posts_pagination(); ?>
<?php else : ?>
<p>記事が見つかりませんでした。</p>
<?php endif; ?>
</main>
<?php
get_footer();
get_template_part( 'template-parts/content', get_post_type() ) は、content-news.php があればそれを、無ければ content.php を読み込みます。
一覧ページが 404 になるときの確認点
| 症状 | 確認すること |
|---|---|
/news/ が 404 |
has_archive が true か。登録後に「設定」→「パーマリンク」を開いたか |
/news/ に固定ページが表示される |
同じスラッグ news の固定ページがあると衝突します。どちらかのスラッグを変えます |
| 2ページ目以降だけ 404 | テンプレート内で独自の WP_Query を使っていないか。件数は pre_get_posts で変えます |
| 一覧は出るが別のテンプレートが使われる | ファイル名が archive-{投稿タイプ名}.php になっているか(rewrite のスラッグではなく、登録した投稿タイプ名) |
| 何も表示されない | public や publicly_queryable が false になっていないか |
カスタム投稿タイプの記事ページ自体が 404 になる場合は カスタム投稿タイプが404になるときの対処 も確認してください。
まとめ
register_post_type()でhas_archiveをtrue(または一覧用のスラッグ)にし、「設定」→「パーマリンク」を開いてルールを作り直す- 専用の見た目にするなら
archive-{投稿タイプ名}.php(ブロックテーマはtemplates/archive-{投稿タイプ名}.html)を作る - 表示件数や並び順は
pre_get_postsでメインクエリを変える - 見出しの「アーカイブ:」は
get_the_archive_title_prefixで外せる