はじめに
WordPressのテーマを自力で作ろうとしたときに直面するWP_Queryですが、独自の方法で記事一覧を取得したりするときには地味に難儀します。
なのでこの記事ではWP_Queryの使い方を基本から応用まで幅広く紹介したいと思います。
WP_Queryとは?
まずは前提としてWP_Queryがどういうものなのか説明します。
WP_QueryとはWordPressが用意した独自の記事一覧取得条件を作るためのクラスです。
例えば現在から過去1年間に投稿された記事一覧や、特定のカテゴリーとタグの組み合わせを持つ記事一覧など、様々な条件で絞ることができます。
よくある使い方としては、純粋な記事一覧、トップページにカテゴリーごとの新着記事を3件ずつ取得したり、関連記事で同じカテゴリーを持った記事をランダムに取得したりなどがあります。
WP_Query の基本編
それではまず、WP_Queryの基本的な使い方を見ていきましょう。
前提として、style.css、functions.php、index.php(archive.phpでも可)、適当にカテゴリーやタグを設定したデモ記事を3〜4つほど準備してください。
特に記事は大事です。表示される記事がないとちゃんと動いているのか分かりにくいですからね。
それでは前提条件が揃ったら早速作ってみましょう。
まずは基本的な使い方です。
以下のコードをindex.phpのbodyタグより内側に記述してください。
<?php
// 条件をつくる
$args = array(
'post_type' => 'post', // 投稿タイプ(固定ページなら'page')
'post_status' => 'publish', // 公開状態
'order' => 'DESC', // 日付で降順(昇順の場合は'ASC')
'posts_per_page' => -1, // 1ページに表示される件数。-1の場合は取得された全記事を一気に出力。
);
?>
まずは条件の雛形を連想配列で作ります。
上から順に投稿タイプ、公開状態、並び順、1ページの表示数です。
この順番は前後しても大丈夫ですが、ある程度グループ分けをするような感じで並べておくといいかもしれません。
人によっては名前順で書くこともあるみたいですが、ここでは入門なのであまり気にせず進めます。
以前はWordPressの日本語解説サイト(CodeX)があったのですが、本家サイトのドキュメンテーションに移動してからは関数に関するページがごっそり無くなっていたので、詳しくは各人自力で調べてください。
続けて、以下のコードを先程のコードに続けて記述してください。
<?php
// 条件(省略)
// クエリを定義
$wp_query = new WP_Query( $args );
// ループ
if ( $wp_query->have_posts() ) {
while ( $wp_query->have_posts() ) {
$wp_query->the_post();
// 処理を記述
}
}
?>
上から順にクエリの定義、ループ、投稿データのリセットです。この順番は必須なので気をつけてください。
では簡単に上から説明していきます。
まずクエリの定義ですが、これはWordPress側で前もって準備されているWP_Queryというクラス(オブジェクト)を、初期化されたクローンとしてコピーを$wp_queryに渡しています。
このとき、引数で$argsが指定されていますが、WP_Query()の中に直接連想配列で記述しても本当は問題ありません。
new WP_Queryは引数として渡された条件を元に、それに合致する記事一覧を取得してくれます。
それでは次にループの箇所ですが、コメントアウトしている「処理を記述」以外の部分はほぼ固定なので、IMEの辞書かVSCodeのスニペットに登録しておくと一々書き直したりする手間が便利です。
さて、ループの解説ですが、if ( $wp_query->have_posts() )の部分では$wp_queryが記事を持っているか確認しています。
記事が1つでもあれば次のwhile ( $wp_query->have_posts() )でループが実行されます。
ここで$wp_query->have_posts()というのが2回出てきましたが、これは$wp_queryに対してアロー演算子(->)でhave_posts()というWP_Query内に設定された記事の有無をチェックする処理を実行しています。
have_posts()の返り値は記事があればtrue、なければfalseというシンプルなものです。
つまりif()で記事があればtrueでif文を通過し、while()でも記事がある限りtrueなので、その間ループが実行されて1記事ずつ$wp_queryから記事タイトルや本文、投稿日などを取得することができるというものです。
次にループ内で記述されている$wp_query->the_post()ですが、これは今何回目のループをしているかカウントしています。(実際の処理はそれだけではないが)
これが無いと、延々とループ内に記述される処理を繰り返し実行してしまいますので、必ず入れるようにしましょう。
では最後に、ループが終わった後でwp_reset_postdata()を実行してポストデータ(投稿データ)をリセットしましょう。
これをしないと続けて別のループを実行したときに前のデータを残したままループが走ってしまうことがあります。
<?php
// 条件(省略)
// クエリとループ(省略)
// 投稿データのリセット
wp_reset_postdata();
?>
さて、ではここまでのおさらいというかこれだけは覚えておいてという内容をまとめます。
- 条件を設定する
- クエリを作りループさせる
- 投稿データのリセット
たったこれだけ、簡単ですね。
では次は、ループの中身、つまり記事を出力するための方法について解説していきます。
記事を出力する
<?php
// 条件をつくる
$args = array(
'post_type' => 'post', // 投稿タイプ(固定ページなら'page')
'post_status' => 'publish', // 公開状態
'order' => 'DESC', // 日付で降順(昇順の場合は'ASC')
'posts_per_page' => -1, // 1ページに表示される件数。-1の場合は取得された全記事を一気に出力。
);
// クエリを定義
$wp_query = new WP_Query( $args );
// ループ
if ( $wp_query->have_posts() ) {
while ( $wp_query->have_posts() ) {
$wp_query->the_post();
// 処理を記述
}
}
// 投稿データのリセット
wp_reset_postdata();
?>
さて、記事一覧を表示するにあたり、一般的にはどのような項目が表示されるかリストアップしてみます。
- 記事タイトル
- アイキャッチ
- 公開日
- 更新日
- カテゴリー
- 本文(文字数制限の抜粋文など)
まあ大体こんな感じでしょうか。
ではこれらの項目を元に、先程のループなどを含めたベースのHTMLを書いてみましょう。
書き方は自由で構いませんが、またまた書くのが面倒な人のために簡単な雛形を用意したので、ここからはそれを元に解説していきます。
<div class="blogs">
<?php
// 条件をつくる
$args = array(
'post_type' => 'post', // 投稿タイプ(固定ページなら'page')
'post_status' => 'publish', // 公開状態
'order' => 'DESC', // 日付で降順(昇順の場合は'ASC')
'posts_per_page' => -1, // 1ページに表示される件数。-1の場合は取得された全記事を一気に出力。
);
// クエリを定義
$wp_query = new WP_Query( $args );
// ループ
if ( $wp_query->have_posts() ) :
while ( $wp_query->have_posts() ) :
$wp_query->the_post();
// 処理を記述
?>
<!-- ループの内容 ここから -->
<div class="blog">
<h3>ブログタイトル</h3>
<img src="URL">
<time datatime="YYYY-MM-DD">公開日</time>
<time datatime="YYYY-MM-DD">更新日</time>
<a href="リンクURL">カテゴリー1</a>
<a href="リンクURL">カテゴリー2</a>
...
<p>本文</p>
</div>
<!-- ループの内容 ここまで -->
<?php
endwhile;
endif;
// 投稿データのリセット
wp_reset_postdata();
?>
</div>
CSSは省きますが、見た目が気になる人はCSSで整えてもらって構いません。
まずは簡単に説明だけすると、最初に<div class=”blogs”>で記事を囲むulタグのようなラッパーを用意します。
続けて先程のループ処理などを記述し、ループの中に「ループの内容」とコメントアウトしている箇所を追加します。
<div class=”blog”>はいわゆるliタグのようなものです。
この「ループの内容」の中身が、ループする毎に1つずつ出力されて記事一覧が表示されます。
それでは出力内容をPHPで修正していきましょう。
まずは<h3>ブログタイトル</h3>からです。
ブログタイトルはthe_title()で直接出力できるので、<h3><?= the_title(); ?></h3>と修正します。
<img src=”URL”>ではイキャッチのURLはthe_post_thumbnail_url()で直接出力できます。
このとき、引数にサイズ名を指定することで、そのサイズのアイキャッチURLを出力できます。
今回はthumbnailというサムネイルサイズを引数に渡すので、<img src=”<?= the_post_thumbnail_url(‘thumbnail’); ?>”>となります。
<time datatime=”YYYY-MM-DD”>公開日</time>と<time datatime=”YYYY-MM-DD”>更新日</time>はthe_time()とhe_modified_time()を使うのですが、この関数には引数として日付のフォーマットを指定するとそのフォーマットに沿った日付を返してくれます。
<time datatime=”<?= the_time(‘Y-m-d’); ?>”><?= the_time(‘Y年m月d日’); ?></time>
<time datatime=”<?= the_modified_time(‘Y-m-d’); ?>”>’Y年m月d日'</time>
次は<a href=”リンクURL”>カテゴリー</a>ですが、こちらはaタグごと<?php the_category(‘ ‘); ?>と置き換えるだけでその記事に設定されたカテゴリーをリンク付きで全部出力してくれます。
最後に<p>本文</p>ですが、こちらは写真や装飾は以来ないので、文字列だけ出力したいはずです。
その場合、処理を追加しないといけないのでやり方をお伝えします。
手順自体は簡単で
- 記事から本文を文字列としてを取得する
- 文字列からHTMLタグを取り除く
- ショートコードを取り除く
- 出力する
という順番で、それをまとめた処理がこちらになります。
<?php
// 記事から本文を文字列としてを取得する
$content = get_the_content();
// 文字列からHTMLタグを取り除く
$content = wp_strip_all_tags( $content );
// ショートコードを取り除く
$content = strip_shortcodes( $content );
?>
<!-- 出力する -->
<p><?= $content; ?></p>
また、文字数を制限したい場合は以下の処理になります。
<?php
// 記事から本文を文字列としてを取得する
$content = get_the_content();
// 文字列からHTMLタグを取り除く
$content = wp_strip_all_tags( $content );
// ショートコードを取り除く
$content = strip_shortcodes( $content );
// ★★★★ 文字列がUTF-8で39文字より多いか確認する ★★★★
if ( mb_strlen( $content, 'UTF-8' ) > 39 ) {
// Trueの場合はUTF-8に変換且つ39文字までを取得する
$content = mb_substr( $content, 0, 39, 'UTF-8' );
// 39文字+「…」を付け加えて40文字に整える
$content .= '…';
}
?>
<!-- 出力する -->
<p><?= $content; ?></p>
これで一通り出揃いましたので、これらを1つにまとめましょう。
<div class="blogs">
<?php
// 条件をつくる
$args = array(
'post_type' => 'post', // 投稿タイプ(固定ページなら'page')
'post_status' => 'publish', // 公開状態
'order' => 'DESC', // 日付で降順(昇順の場合は'ASC')
'posts_per_page' => -1, // 1ページに表示される件数。-1の場合は取得された全記事を一気に出力。
);
// クエリを定義
$wp_query = new WP_Query( $args );
// ループ
if ( $wp_query->have_posts() ) :
while ( $wp_query->have_posts() ) :
$wp_query->the_post();
// 処理を記述
?>
<!-- ループの内容 ここから -->
<div class="blog">
<!-- ブログタイトル -->
<h3><?= the_title(); ?></h3>
<!-- アイキャッチ -->
<img src="<?= the_post_thumbnail_url('thumbnail'); ?>">
<!-- 公開日 -->
<time datatime="<?= the_time('Y-m-d'); ?>"><?= the_time('Y年m月d日'); ?></time>
<!-- 更新日 -->
<time datatime="<?= the_modified_time('Y-m-d'); ?>">'Y年m月d日'</time>
<!-- カテゴリー -->
<?php the_category(' '); ?>
<!-- 本文 -->
<?php
$content = get_the_content(); // 記事から本文を文字列としてを取得する
$content = wp_strip_all_tags( $content ); // 文字列からHTMLタグを取り除く
$content = strip_shortcodes( $content ); // ショートコードを取り除く
if ( mb_strlen( $content, 'UTF-8' ) > 39 ) { // 文字列がUTF-8で39文字より多いか確認する
$content = mb_substr( $content, 0, 39, 'UTF-8' ); //UTF-8に変換且つ39文字までを取得する
$content .= '…'; // 39文字+「…」を付け加えて40文字に整える
}
?>
<!-- 出力する -->
<p><?= $content; ?></p>
</div>
<!-- ループの内容 ここまで -->
<?php
endwhile;
endif;
// 投稿データのリセット
wp_reset_postdata();
?>
</div>
これで事前に作成した記事の分だけ出力されるはずです。
ページネーション
最後にページネーション(ページ番号)も追加しましょう。
例えば1ページに10件まで表示させるとして、投稿しているのが11件以上であれば11件目以降は2ページ目に移りますよね。
ページネーションは基本的には以下の記述をそのまま使い回せば良いです。
もちろん、オリジナルデザインのページネーションも作れるので、是非チャレンジしてみてください。
<div class="blogs">
<!-- 中略 -->
</div>
<!-- ページネーションを実装 -->
<?php the_posts_pagination(); ?>
それではまたノシ
コメント