【初心者向け】Wordpressテーマを自作する［archive.php］［category.php］［taxonomy.php］

ここでは、WPのテーマを作る上で必須の`archive.php`のコードを交えた解説を行います。
タイトルには`category.php`とも入れていますが、現時点ではどちらも同じものと考えていただいていいです。
基本的な考え方は他ページとあまり変わりませんが、`archive.php`だからこそ注意したいことなどありますので、最後まで読んでいただけると幸いです。

:::note info
ファイルの構造や解説等、Wordpress（以下、WP）のテーマを自作する際の基本的な部分は、こちらの記事で紹介しています。
+ [【初心者向け】Wordpressテーマを自作する際に分かってると良いかもしれない事](
https://qiita.com/makkie/items/dc764c2845492079c0af)
+ `index.php`のコードを知りたいよって方はこちら
[【初心者向け】Wordpressテーマを自作する[index.php]](https://qiita.com/makkie/items/b5231a9f63b076c70af8)
+ `header.php`のコードを知りたいよって方はこちら
[【初心者向け】Wordpressテーマを自作する[header.php]](https://qiita.com/makkie/items/6d19ec0da990486ec6ab)
+ `footer.php`のコードを知りたいよって方はこちら
[【初心者向け】Wordpressテーマを自作する[footer.php]](https://qiita.com/makkie/items/65cd4be0e9c4ccbf7776)
+ `singular.php` `single.php` `page.php`のコードを知りたいよって方はこちら
[【初心者向け】Wordpressテーマを自作する［singular.php］［single.php］［page.php］](https://qiita.com/makkie/items/1b7f1961f5970b4f6f21)
:::
とりあえず解説はいいからコードだけ、の方は以下をどうぞ。
## コード（HTMLとPHP）
```diff_php
<?php /*
==========================================
Theme Name: Archive + Category
==========================================
*/
get_header(); ?>
<div class="wrap">
<main id="archive">
<div class="breadcrumb-area">
    <?php output_breadcrumb(); ?>
</div><!--//class="breadcrumb-area"-->
<?php
//先頭辞を非表示
add_filter( 'get_the_archive_title_prefix', function($prefix) {
    $prefix = ''; //空文字代入
    return $prefix;
});
$archtitle = get_the_archive_title();
echo '<h1 class="en-txt under-line">' .$archtitle. '</h1>';
?>
<?php
	if(have_posts()) :
?>
    <div class="archive-frame">
<?php
		while (have_posts()) : the_post();
?>
    <section class="archive-box">
	<a href="<?php the_permalink(); ?>">
		<?php
		if(has_post_thumbnail()){
			echo '<figure class="thumb-img4">' .get_the_post_thumbnail(). '</figure>';
		} else {
			echo '<figure class="thumb-img4"><img src="' .get_template_directory_uri(). '/images/noimages.png"></figure>';
		}
		?>
		<h4><?php the_title(); ?><span class="moddate en-txt"><?php the_modified_date('Y/m/d') ?></span></h4>
        <?php
        //本文を文字数制限表示
        if(mb_strlen($post->post_content,'UTF-8')>50){
            $content= str_replace('\n', '', mb_substr(strip_tags($post-> post_content), 0, 50,'UTF-8'));
            echo '<div class="txt-box">' .$content.'……'. '</div>';
        }else{
            echo '<div class="txt-box">' .str_replace('\n', '', strip_tags($post->post_content)). '</div>';
        }
         ?>
	</a>
	</section><!--//class="archive-box"-->
<?php
		endwhile;
?>
    </div><!--//class="archive-frame"-->
    <?php
    //ページネーション
    the_posts_pagination(array(
        'prev_text' => 'PREV',
        'next_text' => 'NEXT'
    ));
    ?>
<?php
	endif;
?>
</main>
<?php get_sidebar(); ?>
    </div><!--// class="wrap"-->
<?php
get_footer(); ?>
```
## そもそも「アーカイブ」（Archive）ってなに？
「アーカイブ」と検索すると「データをまとめて保存しておくこと」とあります。
WPでは、「アーカイブ」と言うと「記事一覧」のことを指します。

例えば、企業サイトでよくある、新着情報等を一覧で表示したり、特定のカテゴリを一覧表示する時に「アーカイブ」と言います。

## 解説
### archive.phpとは
WPのテーマを自作する際の**必須ファイル**です。
カテゴリ毎`category.php` タクソノミー毎`taxonomy.php` ユーザー毎`author.php`、日付毎`date.php`、タグ毎`date.php`のアーカイブ表示がある場合、`archive.php`は不要です。
と言う事は、上記ファイルは全部`archive.php`で兼用できると言う事になります。
必須テンプレートは公式Codexにも掲載されていますので確認してください。

https://wpdocs.osdn.jp/%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E9%9A%8E%E5%B1%A4

別記事でも書いていますが、私はテーマファイルは最小構成にしたいと考えており、デザインがシンプルであるなら、兼用できるものは兼用してしまおう、数行の条件分岐で済むなら1ファイルにまとめてしまおうと考えています。
ですので、タイトルには`archive.php` `category.php` `taxonomy.php`と3種類のテンプレート名を入れています。この3つは上述したことを踏まえた上で、`archive.php`に集約することができます。

以前私が書いた記事ではシンプルで最小のファイル構成を書いています。参考にどうぞ。

https://qiita.com/makkie/items/dc764c2845492079c0af

ただ、「集約する」ことが必ずしもいいことではない場合もありますので、状況に合わせてファイルは分けて使うようにしてください。
特に`カスタム投稿`は、`カスタム投稿タイプアーカイブ` `カスタムタクソノミーアーカイブ`とあるため、初見は分かりにくいです。
WPの良い所は、表示したいアーカイブ専用のテンプレートを用意すれば、コードの間違えやファイル名の付け方を間違えなければ、簡単に表示されることだと思っているので、`どの条件`で`どのテンプレートが表示されるのか`を理解して活用していただければと思います。

### 必須なコード
ヘッダーを読み込む`get_header();`、フッターを読み込む`get_footer();`、`loop`の`<?php if(have_posts()) : while(have_posts()) : the_post(); ?>`がないと始まらないですね。
`<?php endwhile; endif; ?>`で`loop`を終わらせるのも忘れずに。

既に[【初心者向け】Wordpressテーマを自作する［singular.php］［single.php］［page.php］](https://qiita.com/makkie/items/1b7f1961f5970b4f6f21)をご覧になっている方は、最初に記載しているコードの`loop`の位置が違う事に気づかれたと思います。
以下では、それも含めて細かくコードの解説をします。

### コードの説明
下記の部分は、プラグインなしの自作「パンくずリスト」を独自の関数で読み込んでいます。
```diff_php
<div class="breadcrumb-area">
    <?php output_breadcrumb(); ?>
</div><!--//class="breadcrumb-area"-->
```
プラグインだと、更新されないとセキュリティホールになったり、余計な機能が付いていてサーバの容量を圧迫したり、自分の思った挙動にならなかったりと面倒なことが起きがちですが、自分で書いたシンプルなコードであれば、テーマファイルを読み込んだタイミングで有効化され、カスタマイズも簡単にできます。

コードはこちらで記事にしていますので参考にどうぞ。

https://qiita.com/makkie/items/c7597343e0d040ab08b0

#### Loopを始める前に
WPのテンプレートと言えば「とにかく何を置いても`loop`を書く」だと思うのですが、アーカイブのタイトルは記事名ではなく、カテゴリ名やタクソノミー名なので、それらを取得し表示します。

```diff_php
<?php
//先頭辞を非表示
add_filter( 'get_the_archive_title_prefix', function($prefix) {
    $prefix = ''; //空文字代入
    return $prefix;
});
$archtitle = get_the_archive_title();
echo '<h1 class="en-txt under-line">' .$archtitle. '</h1>';
?>
```
本来アーカイブで表示するタイトルは`the_archive_title();`という関数で表示しますが、この関数で表示すると名称の先頭に「 **カテゴリー：**」や「 **タグ：** 」と言う文言が自動で付与されます。
閲覧する方々には、カテゴリーとタグを区別する必要性はないかなという事で私は`add_filter`を使って表示しないようにしています。
```diff_php
add_filter( 'get_the_archive_title_prefix', function($prefix) {
    $prefix = ''; //空文字代入
    return $prefix;
});
```
で先頭辞を非表示にし、
```diff_php
$archtitle = get_the_archive_title();
echo '<h1 class="en-txt under-line">' .$archtitle. '</h1>';
```
で`add_filter`で先頭辞を非表示にしたタイトルを変数`$archtitle`に入れて、`echo`で表示します。
アーカイブページのタイトルなので`h1`タグで囲んでいます。
ここでは変数に入れていますが、変数に入れずに
```diff_php
echo '<h1 class="en-txt under-line">' .get_the_archive_title(). '</h1>';
```
としても先頭辞なしで表示されます。

Codexにもある様に、` get_the_archive_title();`は、タクソノミーやタームのアーカイブでもタイトルを取得できるので、もしテンプレートを`taxonomy.php`として分ける場合でもそのまま使えます。

https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/get_the_archive_title

#### Loopのはじまり
`Loop`のはじまりと言えば、

```diff_php
<?php
if(have_posts()) :
    while(have_posts()) : the_post();
?>
```
ですが、`archive.php`だとちょっと違う書き方をします。

```diff_php
<?php
	if(have_posts()) :
?>
    <div class="archive-frame">
<?php
		while (have_posts()) : the_post();
?>
```
`if(have_posts()) :`と`while (have_posts()) : the_post();`の間に`div`が入っています。
`<div class="archive-frame">`は、アーカイブページで表示する記事の大枠です。
私は`display: flex;`（横並び）を使う際に使うことがほとんどです。
下図でいう所の赤枠の部分が`<div class="archive-frame">`です。
![Qiita_archive.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3004345/668a66fb-4de9-d1dc-0d15-3c71ab820b86.jpeg)
ざっくりとした感じでいうと`if(have_posts()) :`は`記事があるか`を確認する、`while (have_posts()) : the_post();`は`記事があったら繰り返し表示する`というコードです。
初めてアーカイブページを作るという方良くやりがちなのが、`page.php`や`single.php`の様に
```diff_php
<?php
if(have_posts()) :
    while(have_posts()) : the_post();
?>
    <div class="archive-frame">
```
と`while (have_posts()) : the_post();`の下に`div`を書いてしまう事です。
そうすると、`<div class="archive-frame">`は大枠なのに、`while (have_posts()) : the_post();`の下にあるので、繰り返し処理の対象となり繰り返し表示されてしまいます。
繰り返し処理をするのは、下図でいう所の青枠の部分、コードでいうと
```diff_php
    <section class="archive-box">
        ......
	</section><!--//class="archive-box"-->
```

の部分ですので、`if(have_posts()) :`の`記事がある時に表示`の下に`<div class="archive-frame">`を入れて、`while (have_posts()) : the_post();`と繰り返し処理をします。
`もし投稿があったら = if(have_posts()) :` `ここにある投稿を繰り返し処理 = (have_posts()) : the_post();`と覚えると書き間違いが防げるかと思います。

#### 記事の表示
アーカイブのページでは、アイキャッチと記事のタイトル、本文の一部を表示して、どこをクリックしても該当記事のページへジャンプする様にリンクを付与します。
アイキャッチの他に記事の中の画像をアイキャッチとして表示する方法もありますが、アイキャッチ画像が設定されていない場合に「NoImages」とアイキャッチがないよと画像表示したことで、お客様側が「見た目が良くない」とチェックして設定するようになったので、当該機能を実装するよりも、`if(has_post_thumbnail())`に`else `で「NoImages」と書かれた画像を表示する様にした方が、私の経験上よかったです。
まず、 **記事中に画像を必ず入れる** と言う事がルール化されていないと結局「NoImages」を表示しなければならず、条件分岐が増えるだけなので...。

```diff_php
    <section class="archive-box">
	<a href="<?php the_permalink(); ?>">
		<?php
		if(has_post_thumbnail()){
			echo '<figure class="thumb-img4">' .get_the_post_thumbnail(). '</figure>';
		} else {
			echo '<figure class="thumb-img4"><img src="' .get_template_directory_uri(). '/images/noimages.png"></figure>';
		}
		?>
		<h4><?php the_title(); ?><span class="moddate en-txt"><?php the_modified_date('Y/m/d'); ?></span></h4>
        <?php
        //本文を文字数制限表示
        if(mb_strlen($post->post_content,'UTF-8')>50){
            $content = str_replace('\n', '', mb_substr(strip_tags($post-> post_content), 0, 50,'UTF-8'));
            echo '<div class="txt-box">' .$content.'……'. '</div>';
        }else{
            echo '<div class="txt-box">' .str_replace('\n', '', strip_tags($post->post_content)). '</div>';
        }
         ?>
	</a>
	</section><!--//class="archive-box"-->
```
`the_modified_date('Y/m/d')`は`更新日`なので、`公開日`を表示したい場合は`the_time('Y/m/d')`としてください。
`the_date()`は別記事でも書いていますが、Codexにある様に`同じ日に複数の記事がある場合、最初の記事の公開日しか取得しない`という挙動をするので、アーカイブページで使うと悲しいことになりますので、必ず`the_time('Y/m/d')`としてください。

https://wpdocs.osdn.jp/%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%BF%E3%82%B0/the_date

アーカイブでは、複数の記事を高さや横幅など揃えて並べて表示したいので、本文は文字数を指定して、一部だけ表示する様にしています。

```diff_php
if(mb_strlen($post->post_content,'UTF-8')>50){
```
50文字を超える場合、一部だけ表示する様に条件分岐しています。
「50文字」は半角（１バイト文字）での文字数なので、ざっくり日本語は25文字くらいです。

`mb_substr(strip_tags($post-> post_content)`でHTMLタグを削除し、`str_replace`で半角スペースを`'\n'`置換し`''`で削除しています。
特定のタグ（例は`<span><br>`）を残したい場合は、`mb_substr(strip_tags($post-> post_content)`に`mb_substr(strip_tags($post-> post_content, '<span><br>')`と追加します。
`$content`変数に入れて、`echo`で表示しますが、文末には続きがある事が分かる様に`'……'`を入れています。
`More`を入れてもいいですね。
`else`（50文字以下）では、HTMLタグと半角スペースを削除して全文表示する様にしています。

#### Loopの終わり
`endwhile;`と`endif;`は忘れずに、必ず最後に書いてください。
さらにアーカイブページは`ページネーション`と言われる、ページ番号を表示する関数も忘れずに入れましょう。
```diff_php
<?php
		endwhile;
?>
    </div><!--//class="archive-frame"-->
    <?php
    //ページネーション
    the_posts_pagination(array(
        'prev_text' => 'PREV',
        'next_text' => 'NEXT'
    ));
    ?>
<?php
	endif;
?>
```
```diff_php
'prev_text' => 'PREV',
'next_text' => 'NEXT'
```
の部分は好きな文言を入れることができます。
以前は、プラグインや自作でごにょごにょやってやっと表示できていたページネーションも、現在（WP4.1.0から実装）はこの関数だけで簡単に実装できるようになりました。

https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/the_posts_pagination

上記コードを実装すると以下の様なコードが出力されるので、それに合わせてCSSを適用してください。
```diff_html
<nav class="navigation pagination" area-label="投稿">
<h2 class="screen-reader-text">投稿ナビゲーション</h2>
    <div class="nav-links">
        <span area-current="page" class="page-numbers current">1</span>
        <a class="page-numbers" href="******">2</a>
        <a class="next page-numbers" href="*****">NEXT</a>
    </div>
</nav>
```

## まとめ
前述した様に、`archive.php`は`category.php` `taxonomy.php`を兼用できるファイルなので、それに書くコードもできるだけ幅を持たせたコードを書くようにしていますので、もし`category.php` `taxonomy.php`と別ファイルにする場合でも、そのままコードが使えるようにしています。
`loop`の部分さえ気を付けて条件分岐を使い分けられれば、それほど難しくもないかと思います。

ファイルもコードもシンプルに、あとで自分が見ても、他人が見ても何をしているのか分かる様にを頭に置いて、日々コーディングしています。
10年以上WPでWEBサイト制作をしていますが、独学のため、色々間違えている個所などありましたらご指摘いただけますと幸いです。