WordPress のホームページ(以下すべてトップページのこと…)のテンプレートは、「設定 > 表示設定 > ホームページの表示」を「最新の投稿」にするか「固定ページ」するかで変化しますのでとてもややこしいです。
で、考え方を変えて、それぞれの設定でメインループがどんなデータを持っているか(表示できる)から考えてみましたら簡単でした。
- メインループとはなにか…
- メインループが持っているデータ
- ホームページの表示「最新の投稿」の場合
- ホームページの表示「固定ページ」の場合1
- ホームページの表示「固定ページ」の場合2
- ホームページの表示「固定ページ」の場合3
- register_post_type_args フィルターフックを使う
- まとめ
01メインループとはなにか…
テーマをまったくのゼロからつくった経験から言いますと、front-page.php, home.php, page.php, index.php など、テンプレートの優先順位をあれこれ考えるよりも、ホームページで記事一覧のメインループを使うかどうかから考えれば混乱せずにすみます。
まずメインループとはなにかですが、WordPress が要求されたページの URL によってテンプレートファイルを呼び出す前に事前に取得しているデータのことです。たとえば、投稿ページ(記事ページ)が要求された場合にはその一記事のデータを持っていますし、カテゴリーページが要求されればその URL から該当するカテゴリーに属する複数の記事データを持っています。
で、ホームページの場合は、「設定 > 表示設定 > ホームページの表示」の設定によってメインループの持っているデータが変わるということです。
話が少しそれますが、投稿ページが要求された場合にはそもそもその一記事のデータしか持っていませんので、いわゆるループ処理をする必要はありません。これについては次の記事に書いています。
ということで、ホームページのメインループがどんなデータを持っているか、「ホームページの表示」の設定を変えて調べてみました。目的は、ホームページでメインループをつかった記事一覧を表示しつつ、それとは別にメインループをつかった「全」記事一覧のページができるかということです。
02メインループが持っているデータ
テーマフォルダ直下に、次のようなメインループだけのファイルを front-page.php, home.php, page.php, index.php のファイル名でつくります。また、それぞれのテンプレート名が表示されるようにしておきます。
<?php
get_header(); ?>
<?php
if ( have_posts() ) {
echo "<p>front-page.php</p>"; // それぞれのテンプレート名に変える
// Load posts loop.
while ( have_posts() ) {
the_post();
the_title('<p>', '</p>');
}
}
get_footer();
コードは、twentytwentyone のものです。
また、固定ページには「フロントページ」はタイトルだけ、「記事一覧」にはスラッグを blog としたページをつくっておきます。

03ホームページの表示「最新の投稿」の場合

デフォルトではこの設定になっています。
ホームページ

メインループは最新記事のデータを持っています。例では表示数は5件にしてありますので5件のタイトルが表示されています。
この状態で、front-page.php を削除しますと home.php、home.php を削除しますと index.php が使われます。メインループはすべて最新記事ですので、どのテンプレートファイルでも同じです。
固定ページの記事一覧

ドメイン名/blog/ にアクセスすれば「記事一覧」とした固定ページが表示されます。page.php が使われ、メインループは該当する固定ページの一記事だけです。
04ホームページの表示「固定ページ」の場合1

ホームページに固定ページ「フロントページ」を指定してみます。
ホームページ

メインループは、ホームページに指定している固定ページの一記事のみです。この例の場合はタイトルしか入っていませんので「フロントページ」と表示されています。
この状態で、front-page.php を削除しますと page.php、page.php を削除しますと index.php が使われます。
固定ページの記事一覧は、ホームページの表示「最新の投稿」の場合と同じです。
05ホームページの表示「固定ページ」の場合2

ホームページに固定ページ「フロントページ」、投稿ページに固定ページ「記事一覧」を指定してみます。
ホームページ
この場合のホームページは上記1の場合と同じで、メインループは、ホームページに指定している固定ページの一記事のみです。
投稿ページ

URL は、ドメイン名/blog/ です。投稿ページに使われるテンプレートは、home.php、メインループは記事一覧です。この状態で home.php を削除しますと index.php が使われます。
06ホームページの表示「固定ページ」の場合3

最後に、ホームページは指定なし、投稿ページに固定ページ「記事一覧」を指定してみます。
ホームページ

テンプレートには home.php が使われ、メインループは記事一覧です。front-page.php は使われません。この状態で home.php を削除しますと index.php が使われます。
投稿ページ

「記事一覧」のタイトルが表示されていますので固定ページが使われてはいますが、テンプレートは同じ home.php が使われています。当然こちらも home.php を削除しますと index.php が使われます。
現実的にはこれは使えないですね。
07register_post_type_args フィルターフックを使う
ということで、初期状態ではホームページと別ページ共にメインループを使って記事一覧を表示することは出来ないようです。もちろんサブループを使えば出来ますが、事前に読み込んでいるデータを使えればそれに越したことはないということです。
で、いろいろ調べていましたら、register_post_type_args フックを使えば出来るようです。日本語のドキュメントが読めなくなっていますので英語ページです。
function post_has_archive($args, $post_type)
{
if ('post' == $post_type) {
$args['has_archive'] = true;
$args['rewrite']['slug'] = 'blog'; // 任意のスラッグ名
}
return $args;
}
add_filter('register_post_type_args', 'post_has_archive', 10, 2);
has_archive bool|string
デフォルトは false、アーカイブを使う場合は true、またはスラッグ名。$rewrite が有効であれば適切にリライトされる。rewrite bool|array
リライトを有効にするかどうか、デフォルトは true 、$post_type が使われる。次のキーの配列を渡すことで変更できる。
slug string
パーマリンクのスラッグを変更する。
このコードを functions.php に書き、今回のチェックに使ってきた同じコードの archive.php を作成します。そしてこれが大切なんですが、「設定 > パーマリンク設定」の「パーマリンク構造」を「投稿名」のまま再保存します。リライトルールを書き換えていますのでこの再保存をしないと有効になりません。なお、今更ですが、パーマリンク構造は投稿名としていることを前提としています。
そして、ドメイン名/blog/ にアクセスしてみますと、

確かに、archive.php が使われてメインループの記事一覧が表示されています。
08まとめ
ということで、ホームページと別ページ共にメインループの記事一覧を使うためには、「設定 > 表示設定 > ホームページの表示」を「最新の投稿」にして、ホームページは front-page.php にメインループを有効に使って作成し、記事一覧ページは、フィルターフック register_post_type_args を使ってアーカイブを有効にする方法しかないということになります。
もちろんそんな面倒なことをしなくて、固定ページ、たとえば、page-blog.php にサブループを使った記事一覧のコードを書けば同じことが出来ます。ただメインループは何も指示しなくても WordPress がデフォルトで取得してくるデータです。微々たるものであってもそれを使えば表示は早くなりますし、サーバへの負荷も減ります。