ブログ開設後の初めての記事になります。
未熟な部分もあるかと思いますが、よろしくお願いします。
さて、今回の記事は、サイトでよくある、新着情報などの記事を好きな場所に表示する方法です。
単純なようで、実は重要なテーマだったりします。
気合い入れて解説します。
方法は3つある
その方法は、3つあります。
- 記事のテンプレートで「query_posts」を使用する
- 記事のテンプレートで「get_posts」を使用する
- functions.phpで「pre_get_posts」を使用する
いずれの方法を用いても、同じような結果を返すことができます。
いったい何が問題なのか?
それでは、いったい何が問題なのでしょうか。
それについて解説する前に、ちょっと問いかけをしてみましょう。
- あなたは、どんな場合でも「query_posts」を使えばいいと思っていませんか?
- あなたは、「query_posts」がダメだって記事を見て、「pre_get_posts」のみを使っていませんか?
これに少しでもドキッとした方は、要注意ですよ!
そもそも、WordPressはPHPというプログラミング言語でできています。
こういったものを扱う際は、必ず「なぜ?」をもって構築することを強くお勧めします。
そうでないと、結局余分に時間がかかったりすることになりかねません。
(※これはある意味、自分への戒めでもあったりします。)
最初に挙げた3つの関数は、いずれも持つ意味が異なります。
それを理解せずに使用するのは大変危険、と言いたかったのです。
で、具体的には何が問題なの?
経験がある人にはあると思うのですが、例えば「query_posts」を使っていて、意図した記事が表示されない!という事態に陥ったことはありませんか?
それは、おそらく関数の意味を理解せずに使ったことが原因だと思います。
WordPressを業務で使用し始めて、最初にぶち当たる壁だと勝手に思っています。
そもそも、WordPressはどのように記事を表示しているのか?
WordPressは大変よくできたアプリケーションです。
だからこそ、ここまでシェアを伸ばしました。
皆さんご存知かと思いますが、WordPressでは記事の内容をMySQLというデータベースに格納し、それを必要に応じて引っ張り出して表示します。
(WordPressに限らず、ほとんどのWEBアプリケーションはこの形態をとっていると思います。)
何をどのように引っ張り出すかは、URLを基本情報として、テーマファイルを参照し、中身を解析し、指示に従って記事を読み込みます。
実は、テーマファイルの中身に関係なく、テーマファイルを参照している時点で、WordPressはあらかじめ記事を読み込んでいます。
そのため、
while( have_posts() ) : the_post(); //処理が入ります。 endwhile;
上記のように記載しても、何かしらの記事が表示されるのです。
これらの記事は、グローバル変数である、$wp_queryに格納されています。
$wp_queryに格納されているデータのことを「メインクエリー」と言ったりします。
このことを踏まえたうえで、各関数の詳細を見ていきましょう。
各関数の詳細
query_posts
$arg = array( //どういう記事をどのように読み込むのか、設定を定義します ); query_posts( $args ); while ( have_posts() ) : the_post(); //the_title();なども使えます endwhile; wp_reset_query();
ちなみに、このままだと全然使い物にならないので、コピペで利用しないように!
上記のように記載すると、$argの設定内容に沿って記事が取得され、$wp_queryの内容が更新されます。
もちろん、the_title()といった、$wp_queryの内容を参照する関数も使用できます。
wp_reset_query()は、query_postsによって編集してしまった$wp_queryの内容を、編集以前のものに戻してくれます。
実はこのquery_postsは、将来的には廃止されるんじゃないかという噂があります。
当分先だとは思いますが、もし廃止になったWordPressに更新すると、query_postsの記述があるページはすべて真っ白な画面になることでしょう・・・。
(テンプレートファイルでメインクエリーを読み込むのですから、確かに何のために存在する関数なのか、よくわかりませんね)
それでもなお、使用している方が多いのは、Google検索でヒットするWordPressの入門記事が総じて古いからではないでしょうか。
検索等で得た情報は、必ず情報の日付を確認するといいですね。
get_posts
$arg = array( //どういう記事をどのように読み込むのか、設定を定義します ); $news_posts = get_posts( $args ); foreach ( $news_posts as $news ) : //the_title等は使えません echo '<li>'.$news->post_title.'</li>'; endforeach;
上記は、get_postsの基本的な構文です。
query_postsと比較していただけるとわかりますが、異なる点は次のようなところでしょうか。
- whileではなく、foreachを使用している
- the_title等が使用できないので、$news->post_titleを等を使用している
- wp_reset_queryが必要ない
get_postsは、$wp_queryを書き換えません。
そのため、the_titleを指定すると、本来そのテンプレートが読み込む投稿情報が吐き出されます。
get_postsの基本的な考え方としては、get_posts($arg)によって取得された投稿情報を変数(今回は$news_posts)に格納し、その変数($news_posts)からforeachによって投稿1つ1つを取り出し、さらに別の変数(今回は$news)に格納しながらループを作っています。
$newsの中身をdumpして表示(var_dump($news)で表示できる)するとわかりますが、$newsにpost_titleなどが格納されています。
それらを、状況に応じて表示すればいいわけです。
別に特殊なことをしているわけではなく、the_title()と指定した際には、WordPressが自動で行っていることを手動で行っている、というだけの話です。
じゃあ、なぜそんな面倒なことをしてまでget_postsを使う必要があるのか?
それは、あるテンプレートで呼び出される本来の投稿情報はそのままに、別の記事を呼び出したい・・・というときに力を発揮します。
そういった、別の記事を呼び出すことを、「サブクエリー」と呼びます。
query_postsを使用すると、the_titleなどの情報は書き換えられます。
この時点で、テンプレートで呼び出される本来の投稿情報は呼び出すことができなくなります。
もちろん、wp_reset_queryを使用すれば本来の投稿情報は戻ってきますから、query_postsだけでもサブクエリーが実現できなくはありません。
しかし、query_postsはメインクエリーを変更することが本来の目的のため、そのような使用方法は間違っています。
また、これは未検証ですが、ページの表示速度低下につながる恐れもあります。
pre_get_posts
functions.phpに記載
add_action( 'pre_get_posts', 'sample_pre_get_posts' ); function sample_pre_get_posts($query) { if ( is_admin() || ! $query->is_main_query() ) return; if ( $query->is_category('news') ) { $query->set( 'posts_per_page', '5' ); } }
pre_get_postsは上記のように使用します。
functions.phpに書くようにしてください。
詳しい説明は割愛しますが、pre_get_postsはアクションフックの一つです。(アクションフックについて分からない方は検索してください)
管理画面にもアクションフックは管理画面にも適用されてしまうので、is_adminとis_main_queryを指定しています。
そして、2つ目のif文でnewsカテゴリーの時に、表示件数を5件にするように指示をしています。
pre_get_postsは、表示件数や表示させない投稿を指定するなど、細かい設定を担います。
メインクエリーのみが変更されます。(という指定をしています。)
まとめ
上記のようにそれぞれがまったく違う役割を持っていることがわかっていただけたと思います。
その役割を理解したうえで使わないと、ページネーションが動かない!、なんか思った通りの記事が引っ張れない!という事態になりかねません。
なかなかにややこしいですよね・・・。
この記事でも上記の関数を網羅できているわけではありませんが、この辺りをマスターすれば、WordPressいじれます!って言えると思います。
・・・初めての記事でしたが、いかがでしょうか。
間違っている点やわからない点があればご指摘いただければと思います。
できる限りで対応します。
この記事は大変重要なので、徐々に編集もする予定です。