【第6回】アーカイブページを作ろう【WPテーマ作成】

WordPressテーマ作成

本シリーズは、WordPressのテーマ作成を勉強し、まとめたものである。

前回は、複数の種類のテンプレートで共通の部品を切り出すテンプレートパーツを解説した。

ヘッダーフッターなどの予め用意されているものと、その他自作するものがあること、それらはWordPress関数でインポートできることを覚えておこう。

今後作る内容もこれらを使うことになるので、どこに何が書いてあるかを常に意識するように。

以下がその記事だ。

さて、今回は新たにアーカイブページを作っていこう。

第2回で見たように、カテゴリー、タグと月ごとの投稿を同じarchive.phpで作成していく。

ここで、第4回で説明したWordPressループも再登場する。

使い方はほぼ同じだが、以前よりもループ感が増し、実感も湧いてくるだろう。

その他、ページネーションも同時に実装する。

この時に使える関数なんかもあるので、使いながら紹介していこう。

なお、本シリーズは以下の本を参考にしている。

[改訂版]WordPress 仕事の現場でサッと使える! デザイン教科書[WordPress 5.x対応版] Webデザイナー養成講座
Amazon.co.jp: [改訂版]WordPress 仕事の現場でサッと使える! デザイン教科書[WordPress 5.x対応版] Webデザイナー養成講座 eBook: 中島 真洋, ロクナナワークショップ: Kindleストア

他にも、公式ドキュメントなど参照する場合は随時リンクを貼っていこう。

スポンサーリンク

今回のゴール

記事を表示するsingle.phpもそうだったのだが、今回もとりあえずそれぞれの内容が表示されるところをゴールとする。

そのため、やり方は本記事で分かると思うが、それをそのまま実際のページとして使うことはないだろう。

もちろん、本シリーズが進んでいくとこの内容も書き換えることになる。

サンプルページも紹介するが、やはりその内容はその時点で組んでいるところまで進んでいるので、そこは注意しておこう。

実際のHTMLの構造やCSSでの見た目調整は、ある程度コンテンツが出来上がってからやる予定なので、今しばらくお待ちいただきたい。

実装の前に下準備

さて、前回から引き続きご覧頂いている方はそこにも書いたが、そもそも表示するコンテンツがないとどうしようもない

で、今回はページネーションも実装するため、その遷移などを確認するために多量の記事が必要だ。

デフォルトの設定は10件ごとの表示なので、そこを変更しないのであれば最低でも11件、できれば21件以上はあると嬉しい。

ということで、その記事を用意しておこう。

…とはいっても、そんな大量の記事を手作業で追加していくのも大変だ。

そこで、メインで運用しているブログがあればその記事をエクスポートし、それをそのままインポートしてからカテゴリーとタグをつけていこう

今回はサイトの引っ越し等ではないので、そこまで細かいところの確認は不要だ。

ちなみに、一回エクスポートしてその中身を見ればどんな構造になっているか分かると思うので、それをコピペして必要な箇所を直してからインポートすればサンプル記事を量産できたりもする。

アーカイブページの作成

では本題、アーカイブページを作っていく。

ただ、今回はちょっと説明のしかたを変えさせてもらう。

先に、ファイルの作成や既存のファイルの修正を全て終わらせ、その後にそれぞれで何をしているか解説、という形にしよう。

archive.php(新規作成)

まずは、このarchive.phpを新たに作り、中身を書いていこう。

やはりテーマディレクトリの直下に新しくarchive.phpを作成し、その中に以下の内容を記載してほしい。

<!-- 共通ヘッダー読み込み -->
<?php get_header(); ?>

<!-- アクセスされたページ種別でタイトルの文字を調整 -->
<?php
    $page_title = "";
    if(is_category()){
        $page_title = "カテゴリー「" . single_cat_title("", false) . "」";
    }else if(is_tag()){
        $page_title = "タグ「" . single_tag_title("", false) . "」";
    }else if(is_date()){
        $page_title = get_the_date("Y年n月");
    }
    $page_title .= "の記事一覧";
?>

<!-- タイトルを出力 -->
<h1><?php echo $page_title; ?></h1>

<!-- WordPressループで記事一覧を表示 -->
<?php if(have_posts()): ?>
    <?php while(have_posts()): ?>
        <?php the_post(); ?>
        <div>
            <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
            <?php the_post_thumbnail("medium"); ?>
            <?php the_excerpt(); ?>
        </div>
    <?php endwhile; ?>
<?php endif; ?>

<!-- ページネーションを表示する関数を呼び出し -->
<?php the_pagenation(); ?>

<!-- 共通フッター読み込み -->
<?php get_footer();

さて、書き終わったら早速表示…といきたいところだが、この中で使っているthe_pagenation関数は、元々用意されているものではない

後で定義するものなので、このままだと関数が定義されていないというエラーが出てしまう。

そのため、一旦下の内容も全て書き終えてから確認するようにしよう。

functions.php(追記)

次に、今書いた通り関数を定義するのだが、それはfunctions.phpに書く。

…のだが、以前WordPress設定関連の処理を分けたように、今回の内容も別ファイルにまとめ、それを読み込む形にしよう。

今回は新たにユーザー定義関数を作成するので、そのままud-functions.phpというファイルをlibディレクトリ内に作成しようと思う。

ユーザー定義関数は英語でUser Defined Functionなので、その頭文字を取っただけだ。

そのため、それを読み込む処理をここに追記することになる。

というわけで、functions.phpは以下のように直そう。

<?php

// WordPressの設定ファイルを読み込む
require_once(__DIR__ . "/lib/setting.php");

// ユーザー定義関数のファイルを読み込む
require_once(__DIR__ . "/lib/ud-functions.php");

なお、この段階でページを表示しようとすると、今度はこのファイルを読み込めないというエラーも出る。

繰り返しになるが、結果の確認はこの下もやってからにしよう。

lib/ud-functions.php(新規作成)

最後、今読み込む指定をしたud-functions.phpを新規作成し、中身を書いていく。

過去にWordPress設定用にlib/setting.phpを作っているので、そのままやっていればディレクトリはあるはずだ。

もしご自身の環境でディレクトリ構造を変えている場合は、それに合わせてほしい。

その中に、新しくud-functions.phpを作成し、以下の内容を記載しよう。

<?php

// ページネーションのHTMLを文字列として取得する
function get_the_pagenation(){
    global $wp_query;
    $big = 999999999;
    $args = array(
        "base" => str_replace($big, "%#%", esc_url(get_pagenum_link($big))),
        "total" => $wp_query->max_num_pages,
        "current" => max(1, get_query_var("paged")),
        "mid_size" => 1
    );

    return paginate_links($args);
}

// ページネーションのHTMLを出力する
function the_pagenation(){
    echo get_the_pagenation();
}

これで、今回の記述は全て完了になる。

この状態で、カテゴリーやタグ、月の一覧ページにアクセスしてみよう。

すると、そのアクセスした内容の一覧ページが出来上がっているはずだ。

私の開発環境のリンクも貼っておこう。

確認してほしいポイントは3点。

まず、ページ最上部に表示されているタイトル部分が、それぞれ適切な表示になっていること。

次に、実際に記事の一覧が下に表示されていること。

そして、ページ最下部にページネーションの表示があり、実際に遷移できること。

この3つが、今回実装した内容だ。

ちなみに、カテゴリーやタグのページは、記事を表示した時に入っているカテゴリーやタグのリンクをクリックしてもらえれば飛べるはずだ。

本シリーズと合わせて進めていただいている方は、以下の部分だ。

カテゴリー、タグ一覧ページへのリンク箇所

月ごとのページは、パーマリンク設定によって変わってくる。

私の環境の場合で説明しよう。

まず、管理画面の「設定」→「パーマリンク設定」のところで、共通設定をカスタム構造にしてある。

その記述部分は、/contents/%postname%/だ。

この状態であれば、サイトリンク/contents/yyyy/mm/でアクセスできる。

具体的に、私の開発環境(https://shinoarchive.com/theme-create)で、2021年3月の投稿を表示する画面はhttps://shinoarchive.com/theme-create/contents/2021/03/というリンクだ。

他の設定の場合は…各自で調べてみてほしい。

調べる方法は、どのテンプレートファイルでもいいので以下の関数を実行し、その結果を表示する。

get_month_link($year, $month);

この$yearには年を西暦で4桁、$monthには月をそれぞれ数字で渡してあげ、戻り値はURLのテキストとなる。

そのため、以下1行をどこかのテンプレートで実行してあげれば、2021年3月のアーカイブページへのURLが表示される。

echo get_month_link(2021, 3);

あとは、この年、月を表示させたいところに変えてあげれば、そのURLでアクセスできるはずだ。

ソースコードの解説

では、それぞれの実装内容を個別で詳しく見ていこう。

ページタイトル

ここでは、大きく二つのパートに分けている。

  1. タイトルとして表示する文言を作成
  2. 1で作成した内容を出力

2は単に変数をechoで出力しているのみなので問題ないと思う。

1で色々とやっているので、深掘りしていこう。

最初に、今アクセスされたページの種別で場合分けをしている。

この場合分けに使うのが、WordPressで用意されている条件分岐タグと呼ばれる関数群だ。

色々な種類や使い方があり、全体像は公式ドキュメントを参照しよう。

今回は、そのうち3つを使用している。

それぞれ、今アクセスされているページが該当するものであればtrueを、そうでなければfalseを返す関数だ。

条件分岐タグ該当するページ種類
is_categoryカテゴリー一覧ページ
is_tagタグ一覧ページ
is_date日付別のページのいずれか
ex) 年別、月別、日別など
今回使用している条件分岐タグ

これを使えば、例えば今カテゴリーページとしてアクセスされているなら、という内容を書くことが可能になる。

今回は、それぞれでページタイトルとして出力する文字列を作成している。

その作成時にもそれぞれ異なる関数を使っているので、それらも見ていこう。

カテゴリーページでは、その表示しているカテゴリーの文字列を取得するsingle_cat_title関数を使用。

これは、引数無しでも実行することが可能で、その場合はカテゴリー名をそのままHTMLとしてそこに出力する。

今回は引数を二つ渡し、以下の形で実行している。

single_cat_title(文字列, 戻り値制御)

一つ目で渡す文字列は、この関数で取得するカテゴリー名の前に追加するテキストを渡す。

今回は文字列の連結でやってしまっているので、空列を渡して何も追加していない。

二つ目が重要で、ここは真偽値を渡す。

trueを渡すとそのままHTMLとして出力、省略時もtrueを渡したことになる。

falseを渡すと、出力しようとしている内容を文字列の戻り値として受け取ることが可能だ。

今回はfalseを渡し、それで得られたカテゴリー名を使ってタイトルを作っている。

次に、タグページで使っているsingle_tag_title関数

これは、単にsingle_cat_title関数から取得する内容がタグに変わっただけで、その他は全く同じ。

…書き上げてから気づいたのだが、single_cat_title関数でもタグページにアクセスされている場合はそのタグ名を取得できるようだ。

試したところ、確かに問題なく動作した。

が、どちらを使うべきかがちょっと分からず、今はサンプル通り別々の関数を使う状態にさせてもらう。

もし何か分かれば、追記・修正することにしよう。

そして、月ごとのページで使っているget_the_date関数

これは、今回の場合はアクセスされたページの日付を取得してくれるもので、上二つとは異なり元々文字列を返す関数だ。

引数として、日付フォーマットを渡している。

get_the_date(日付フォーマット)

この日付フォーマットはそのまま日付をどう表示するかを指定するもので、どんな内容を指定できるかは公式ドキュメントのこちらで参照できる。

今貼ったリンク先にも書かれているが、このフォーマットはWordPress独自のものではなく、PHP側のものだ。

今回はY年n月と指定しており、まずYで西暦4桁の年を取得し後ろにを表示。

次にnで0詰めをしない月を取得して後ろにを表示だ。

ここで例えばmとすると、1月から9月まではその前に0が一つ入るので、その違いに注意しよう。

ちなみに、ここで引数を省略した場合を補足。

省略すると、WordPressで設定されているフォーマットに従って日付が返される。

この設定は、管理画面「設定」→「一般設定」の「日付設定」部分だ。

デフォルトではY年n月j日となっており、これをそのまま使うと月別アーカイブなのに日付まで出てしまう

そういったことを避けるため、今回はフォーマットを指定している、という感じだ。

この設定では、例えば記事を表示した時に表示したいフォーマットを指定しておくといいだろう。

こんな感じで、それぞれの条件に従って文字列を作成し、その後で共通の文言をさらに追加すればタイトルで表示する文字列の完成、というわけだ。

記事一覧

ここで、以前も出したWordPressループを使って、それぞれ該当する記事の一覧を出力する。

とはいえ、アクセスされた時点でそれに適したメインクエリが自動で設定されているので、単にそれを取得して表示すればいい。

二つ、新たにWordPress関数を使用しているので、それを補足していこう。

まずthe_permalink関数、これはその記事のパーマリンクをそこに表示する関数だ。

これをaタグのhref属性内で出力すれば、その記事へのリンクを貼ることができる。

次にthe_excerpt関数、今度はその記事の抜粋を表示する関数

今回は記事一覧なので、記事内容全てを取得する必要はない。

そこでこれを使えば、記事抜粋が入力されていればその内容を、入力されていなければ本文の先頭から一定文字数だけを抜き出してくれる

…のだが、実は日本語だと上手く文字数がカウントされず、ほぼ全てが表示されてしまうこともあるようだ。

それを避けるため、プラグインを一つ入れておこう。

WP Multibyte Patchというもので、これを使うと日本語でもデフォルトで110文字に抑えてくれる。

他にも機能があるので、よかったら公式サイトを参照してみてほしい。

というわけで、これで記事の一覧が表示できる…のだが。

実は、ここで表示できるのはデフォルトでは10件のみだ。

というのも、WordPressではページネーションを考慮した件数だけメインクエリに含むようになっている。

そのため、通常であればページネーションの実装が必須だ。

このデフォルトの設定が10件で、管理画面の「設定」→「表示設定」の「1ページに表示する最大投稿数」で変更できる。

気になる方は、ここを変更してもう一度一覧ページへアクセスしてみよう。

ページネーション

さて、ここが今回のメインの内容だ。

そもそも前提として、ページネーションをやってくれるプラグインは存在する。

…しかし、折角なのでそこも自力で実装してみよう。

まず、archive.phpでは単に自作関数を呼んでるだけなので、その関数側を見ていこう。

もう一度、その関数を以下に記載する。

// ページネーションのHTMLを文字列として取得する
function get_the_pagenation(){
    global $wp_query;
    $big = 999999999;
    $args = array(
        "base" => str_replace($big, "%#%", esc_url(get_pagenum_link($big))),
        "total" => $wp_query->max_num_pages,
        "current" => max(1, get_query_var("paged")),
        "mid_size" => 1
    );

    return paginate_links($args);
}

// ページネーションのHTMLを出力する
function the_pagenation(){
    echo get_the_pagenation();
}

呼び出しているのは下のthe_pagenation関数、これは上で定義しているget_the_pagenation関数の結果をechoしているだけ。

その、get_the_pagenation関数が、そのページに合わせてページネーション部分のHTMLを作り、それを文字列として返すようになっている。

この中でやっているのは、実は単に一つ関数を実行しているだけ…なのだが、その関数に渡す引数を色々と作る必要がある。

実行しているのはpaginate_links関数、これに適切な引数を渡すことで、ページネーション部品を取得することが可能だ。

paginate_links($args)

引数を一つ受け取るのだが、その中身は配列で、色々な情報を含ませることができる。

この関数の公式ドキュメントはこちら、とりあえず配列の中身一覧を出すと以下のような感じだ。

キー名意味デフォルト値
base生成するリンクのベースURL“%_%”
formatページネーション部分のURL構造“?page=%#%”
total全体のページ数1
current現在表示しているページ番号0
show_all省略しない場合はtrue
省略する場合はfalse
false
end_size両端に表示する個数1
mid_size現在を除く、前後に表示する個数2
prev_next「次へ」や「前へ」のリンクを入れる場合はtrue
これらを入れない場合はfalse
true
prev_text「前へ」のリンクに表示するテキスト__(‘&laquo; Previous’)
next_text「次へ」のリンクに表示するテキスト__(‘Next &raquo;’)
type戻り値の形式
・”plain” : 文字列
・”array” : 配列
・”list” : ulタグを使ったHTML構造
“plain”
add_args追加のクエリ引数の配列false
add_fragmentそれぞれのリンクに付け加える文字列(空列)
before_page_numberページ番号の直前に付け加える文字列(空列)
after_page_numberページ番号の直後に付け加える文字列(空列)
paginate_links引数の中身

このうち、今回は4つの引数を使用している。

base

これは、ページネーションに貼るリンクの形式を指定する。

通常は、%_%という列を含む形で指定し、その部分にformatで指定した内容が置換される。

で、そのformatには%#%という列を含ませ、そこに実際のページ番号を表す数字が入ってくれる。

例えば、このbasehttps://example.com/%_%format?page=%#%としてあげたとき、3ページ目のURLはhttps://example.com/?page=3となる、ということ。

…のだが、内部動作的にも今書いたことがそのまま行われているだけなので、base%_%を入れずに%#%を直接入れてしまえば、formatは意味を成さなくなる。

公式のサンプルもその形で使っているので、それを参考に今回もそうさせてもらう。

さて、実際に指定している内容を見てみよう。

"base" => str_replace($big, "%#%", esc_url(get_pagenum_link($big)))

ここでやっているのは、とりあえず具体的な番目のページのリンクを取得し、その番目の数字を%#%に置き換えるということ。

一番外側にあるstr_replace関数はPHP側のもので、第三引数に渡した文字列の中から第一引数の文字列を探して、それを第二引数に置換して返すという処理を行う。

その元となる第三引数のところに注目してみる。

内側のget_pagenum_link関数今表示されているページについて、引数に渡した番目のページリンクを取得してくれる。

例えば、カテゴリー一覧ページでget_pagenum_link(2)とすれば、その一覧の2ページ目のURLが取得できる、という感じだ。

そのURLの中には、2ページ目であるという情報が入っていることになる。

ここに今回は$big、つまり999999999というやたら大きい数字を渡しているが、これにはしっかり意味がある

上に書いた通り、これで取得できたURLについて、ここで渡した数字部分を置換することになる。

そのため、通常URLに含むような列を指定すると想定外の部分が置換されてしまうことになる。

そして、このget_pagenum_link関数は数字しか指定できないので、通常は入らなさそうなやたら大きい数字を入れて取得しているのだ。

第三引数の外側、esc_url関数URL内に含まれる有害な列を無害化するためのもの

セキュリティのために入れている、と思ってくれれば大丈夫だ。

これで、具体的なページネーションのURLを取得できた。

あとは、その中に仮で入れていた$bigの部分を%#%に置換してあげれば、ベースとなるURL列の完成だ。

それをbaseプロパティに渡してあげればここは完了となる。

total

ここには、ページネーションで遷移する最大ページ数を指定する。

この情報は、ページアクセス時のメインクエリの中に含まれている…のだが、関数ではなく直接情報を取得する。

具体的には、$wp_queryというオブジェクトに入っている、max_num_pagesプロパティだ。

今これは関数として切り出しており、このオブジェクトはそのままでは使えない。

そこで、グローバル変数として定義することを記載すれば、それを使えるようになる。

関数先頭に入っているglobal $wp_query;がそれだ。

他にも色々な情報がこのオブジェクトに入っているが、それらはまた使う時に解説しよう。

current

今度は、今表示しているページ番号を指定する。

こちらは取得する専用の関数が用意されており、get_query_var関数がそれだ。

この関数は他にも色々な情報を取得できるのだが、今回はpagedという文字列を渡して今現在の表示されているページ番目を取得している。

ここで注意しなければいけないのが、1ページ目だけ上手く取得できないということ。

2ページ目以降を表示していればその数字が返ってくるのだが、1ページ目だけ0という数字が返ってくる

そして、0をcurrentに指定してしまうと不具合の元になってしまう。

軽く調べたのだが、なぜこうなるのかの明確な理由は分からなかった。

ただ、1ページ目だけ異なる点としてはURLに1ページ目を表す部分がないので、このURLから取得しているのではないか、とにらんでいる。

で、get_query_var関数にはもう一つ引数を渡すことができ、そこには値が取得できなかった場合の戻り値を指定する。

ということは、get_query_var("paged", 1)とすればいいのでは?と思われるかもしれない。

実は、これで不可能だ。

1ページ目では、0という値の取得はできている状態だ。

つまり、そちらが優先されてしまい、これで書いても1ページ目は0が返ってきてしまう

ではどうするのかというと、PHPのmax関数を使おう。

これは数字を複数渡すことで、その中で最も大きい数字を返してくれる

つまり…

"current" => max(1, get_query_var("paged"))

これで、1ページ目なら1を、2ページ目以降であればget_query_var("paged")の結果を得ることができる。

細かい仕様になるが、これを理解していないとページネーションが上手く機能しないので気を付けよう。

mid_size

これはオマケ的なものだ。

ここには、現在表示しているページの前後にいくつのリンクを省略せず表示するかを指定する。

デフォルトでは2が指定されており、例えば5ページ目を表示しているときは3から7ページ目のリンクが出てくるようになっている。

今回は1を指定したので、同じように5ページ目を表示していると4と6ページ目のリンクが出現する、という感じだ。

以上、この4項目を入力してpaginate_links関数を実行している。

これで、とりあえずではあるがページネーションを実装できた。

なお、見た目の調整用にtype出力するフォーマットを変えることもできるので、それも覚えておくといいだろう。

今後、そこをカスタマイズするときにこの内容も修正することになる。

おわりに

今回は、アーカイブページを実装した。

3つの段階に分けたが、それぞれが重要な内容なので、しっかりと処理の流れを把握しておこう。

特に、ページネーションは躓きやすいポイントの一つだろう。

関数の中身それぞれが何をしているか、なぜそうするのかを確認しておいてほしい。

さて、次回はこのままの流れで最新記事一覧を実装しよう。

今回の内容の復習にもなると思うので、まだよく分からない箇所があれば、次回の内容も併せて見ておくといいかもしれない。

2021/3/8追記

次回の内容、最新記事一覧の実装を行った。

ソースコードでやっている内容はほぼ今回と同じなので、それぞれ照らし合わせながら見ておくといいだろう。

また、後半でトップページにアクセスされたときや、固定ページをホーム、最新記事一覧に設定した場合の動作を詳細に見ている。

ここの部分がややこしいのだが、やはりテーマを作る上では欠かせない内容だろう。

検証環境で色々試し、実際にどうなっているのかを確認しながら進めてもらいたい。

コメント

タイトルとURLをコピーしました