【備忘録】wordpressのループでquery_postsを使っちゃダメらしいという話。

Wordpress logo

あと1ヶ月ほどで開設から1周年を迎える当ブログ。
来るアニバーサリーデーを前に、新しいテンプレートの開発に着手しました。

テンプレートの開発も今回で三回目。
「とにかく形にする」がコンセプトの初代、「レスポンシブデザイン」がコンセプトの二代目(開発の様子はコチラ。)を経て、三代目の構想はかなり肥大化しています。

「今っぽいフラットデザインを取り入れたい」
「がっつりSEO対策をほどこしたテンプレートにしたい」
そして、初代と二代目は『wordpressレッスンブック』『wordpressデザインブック』という2冊の書籍をコピペしながら作ったため、深い所ま理解できていないままの箇所がたくさんあるんですが、今回はテンプレートで使われている処理についてちゃんと理解したいな~と思っています。

そんな中、初代・二代目のテンプレートでも多用している「query_posts」という関数について、気になる記事が。

実はこの記事、二代目のテンプレートを作っていた頃に目にしたんですが、当時は「何を言っているのかさっぱりわからん」という状況でした。
ただ、今回”ちゃんと理解して作る”という目標を達成するためにも、この「query_posts問題」にちゃんと向かい合ってみることにしました。

query_posts()を使うと何が問題なのか?

そもそも、query_posts関数が何をしているのかがよくわかっていなかったんですが、簡単に言うと以下のとおり。

そのテンプレートで主に表示するループの設定をデフォルトから変更したい場合に、メインのクエリーを上書きするのに使います。

そして、query_posts()を使うことが推奨されない理由は、

メインのクエリーを上書きしているので、ページ送りやナビゲーションやカテゴリーの選択を無効化してしまうことがあります。

query_postsはそもそもメインクエリーを改変する(主には、表示件数を変更したりといったアーカイブの表示設定の変更が)用途を想定されていたのに、それを越えてサブクエリーを発行するのに非常に多く使われているというところかなと思います。そのため、使う人が想像もしないような副作用がある。そのため、推奨されない流れになっているのだと思います。

また、

query_postsがメインクエリーを改変するのは、複数回DBアクセスが発生するため非効率です。

というデメリットもあるようです。

どうやらquery_posts()は、いったんデータベースから記事を取ってきたうえで、再度データベースに接続しなおすという二度手間をやっていて。
さらに、ページ送りやナビゲーションの選択を無効化してしまう不具合を防ぐためには、 wp_reset_query()を呼び出してクエリをリセットする必要があるんですが、wp_reset_query()でも一旦取ってきていた記事をunset。
再度データベースへのアクセスが発生するとのことで、実質3度のDBアクセスをすることになるそうで。

うーん、確かに非効率!!

query_posts()を使わないで、どうやって記事を表示するの?

上記の問題の解決方法としては、

サイドバーや特定のページで「あるカテゴリーの記事を5件表示する」というような場合には、メインクエリーを上書きするのではなく、別途サブクエリーを作成。
つまり、get_posts、もしくはWP_Queryを使うのがベター。

またメインクエリーを上書きする場合には、query_posts()ではなく pre_get_posts()フックを使うほうがベター。
pre_get_posts()フックを使う場合は、最初のDBアクセスの前にどのように記事を取得するかの設定を変更するため、複数回DBアクセスしてしまうquery_posts()よりも圧倒的に効率的です。


以上が、query_posts()問題のざっくりとした内容。

それをふまえて、今回のテンプレートでは「先頭に固定した記事以外を出力」するループとして、以下の処理を記述してみました。

[php htmlscript=”true”]
function customize_main_query($query) {
if ( is_admin() || ! $query->is_main_query() )
return;
if ( $query->is_front_page() ) {
$query->set( ‘ignore_sticky_posts’, 1 );
}
}
add_action( ‘pre_get_posts’, ‘customize_main_query’ );
[/php]

(上記の処理はfunction.phpに記述しています。)

設定が上書きされているのは、この部分だけ。

[php htmlscript=”true”]
$query->set( ‘ignore_sticky_posts’, 1 );
[/php]

なので、表示件数などは初期設定のままになります。

トップページ側の記述はシンプルに以下の通り。

[php htmlscript=”ture”]

// 表示処理は別のテンプレートを読み込んでます。


[/php]

“どのように記事を取得するか”の初期設定を上書きしているため、この処理で指定したとおりの記事が書き出されるわけです。

というわけで、トップページからquery_posts()を消し去ることができました。
現状のテンプレートでページ送りの不具合が起こっていたわけではないんですが、“効率化”という意味で改善されたはず!
そして、「いずれquery_postsが非推奨になるかも?」とビクビクしなくてよくなったという点で、精神衛生上もよい改善ができたんじゃないかと思うのでした。

テンプレ開発状況はこんな感じ!

wordpressのお勉強のついでに、GitHubの使い方も勉強してみよう!ということで、今回のテンプレート開発はGitHubでバージョン管理をすることにしました。
決して人様にお見せできるようなコードではないんですが、無料ユーザは非公開での開発ができないので、以下のURLでをさらしてみようと思います。

ultimate-ez/ultimateez_v3

素人のひどいコードに対して文句を言いたくなるところもあるかもしれませんが、何卒お手柔らかにお願いします。。

Commentsこの記事についたコメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です