99
これからの by @HissyNC / WordBench Kobe Group pre_get_posts: What's the Right Way to Use? pre_get_posts の話をしよう 1

これからのpre_get_postsの話をしよう

Embed Size (px)

DESCRIPTION

第24回WordBench神戸で話した資料です。

Citation preview

Page 1: これからのpre_get_postsの話をしよう

これからの

by @HissyNC / WordBench Kobe Group

pre_get_posts: What's the Right Way to Use?

pre_get_postsの話をしよう

1

Page 2: これからのpre_get_postsの話をしよう

query_posts非推奨?『query_postsを捨てよ、pre_get_postsを使おう』というブログ記事を公開したところ、はてブなどでバズる。「いつの間にこんなことになっていたんだよ…」「非推奨だなんて!いますぐ直さなきゃ!」「急に言われても困る」「query_posts使いまくってたぜマジかよ…」「初心者にこの説明はキツイでしょ」等々の意見が噴出。

2

Page 3: これからのpre_get_postsの話をしよう

pre_get_postsとは何か?結局、Codexのquery_postsのページに非推奨の文字が入ったのは一時的なもので、その後表現が修正され、「query_postsの代わりにpre_get_postsフィルターを使うことを強く推奨する」となった。ではなぜ数多のWordPress本でも紹介されているquery_postsが推奨されないのだろうか。pre_get_postsフィルターとは何なのか。

3

Page 4: これからのpre_get_postsの話をしよう

まずテンプレートとは何か

4

Page 5: これからのpre_get_postsの話をしよう

データベースから目的のデータを

取得して表示するためのもの

5

Page 6: これからのpre_get_postsの話をしよう

ではない

6

Page 7: これからのpre_get_postsの話をしよう

テンプレートとは表示するデータを

整形するためのもの

7

Page 8: これからのpre_get_postsの話をしよう

データを取得する目的には

本来使わない

8

Page 9: これからのpre_get_postsの話をしよう

どんなデータを取得するかを決定するのは

9

Page 10: これからのpre_get_postsの話をしよう

URL

10

Page 11: これからのpre_get_postsの話をしよう

?p=1

?cat=1

?cat=1&post_type=book&paged=2

クエリー・ストリングという

$query_string

11

Page 12: これからのpre_get_postsの話をしよう

URLでどのデータを取得するかが決まるどんな処理を行う

かが決まる12

Page 13: これからのpre_get_postsの話をしよう

ほかのCMSでも同じ

13

Page 14: これからのpre_get_postsの話をしよう

URLがページの内容を表している

=インターネットの基本的な概念

14

Page 15: これからのpre_get_postsの話をしよう

ここで疑問

15

Page 16: これからのpre_get_postsの話をしよう

Webページにはたくさんのデータが表示されており各ページで共通の

ものもある16

Page 17: これからのpre_get_postsの話をしよう

たとえばサイドバーに

新着記事を5件表示URLとは関係なくどのページにもある

17

Page 18: これからのpre_get_postsの話をしよう

記事の下に関連記事を5件表示

URLとは間接的に関係があるが

直接示しているものではない

18

Page 19: これからのpre_get_postsの話をしよう

これらをサブクエリー

と呼ぶ19

Page 20: これからのpre_get_postsの話をしよう

?p=1

?cat=1

?cat=1&post_type=book&paged=2

クエリー・ストリングと直接対応しているデータのことを

20

Page 21: これからのpre_get_postsの話をしよう

メインクエリーと呼ぶ

21

Page 22: これからのpre_get_postsの話をしよう

メインクエリーと

サブクエリー違いを理解しよう

22

Page 23: これからのpre_get_postsの話をしよう

トップページの内容としてニュースカテゴリーの記事を表示するメインクエリー

orサブクエリー?

23

Page 24: これからのpre_get_postsの話をしよう

トップページの内容としてニュースカテゴリーの記事を表示するメインクエリー

orサブクエリー?

24

Page 25: これからのpre_get_postsの話をしよう

WordPressでは、フロントページは新着投稿か、固定ページか、2択です。CMSとしてはそれだ

け?と違和感がありますが、そういう設計ですので、本来特定のカテゴリーの記事をトップページで表示するのはWordPressではできません。get_postsを使うか、ウ

ィジェットを使いましょう

25

Page 26: これからのpre_get_postsの話をしよう

query_postsの迷宮

26

Page 27: これからのpre_get_postsの話をしよう

query_postsとは本来

メインクエリーを改変するためのもの

27

Page 28: これからのpre_get_postsの話をしよう

http://example.com/?cat=1

28

Page 29: これからのpre_get_postsの話をしよう

http://example.com/?cat=1

カテゴリーID が 1

28

Page 30: これからのpre_get_postsの話をしよう

http://example.com/?cat=1

have_posts() = 投稿が存在する?

カテゴリーID が 1

28

Page 31: これからのpre_get_postsの話をしよう

http://example.com/?cat=1

have_posts() = 投稿が存在する?

カテゴリーID が 1

the_post() = テンプレートタグを有効化

28

Page 32: これからのpre_get_postsの話をしよう

http://example.com/?cat=1

have_posts() = 投稿が存在する?

カテゴリーID が 1

the_post() = テンプレートタグを有効化

<a href=”<?php the_permalink(); ?>”><h2>

<?php the_title(); ?></a></h2>

28

Page 33: これからのpre_get_postsの話をしよう

http://example.com/?cat=1

have_posts() = 投稿が存在する?

カテゴリーID が 1

the_post() = テンプレートタグを有効化

<a href=”<?php the_permalink(); ?>”><h2>

<?php the_title(); ?></a></h2>

↓次の投稿へhave_posts() = 投稿が存在する?

28

Page 34: これからのpre_get_postsの話をしよう

カテゴリーを指定しているが、それ以外は?表示件数(10件?)

並び順(投稿日が新しい順)投稿タイプ(投稿)デフォルト設定がある

29

Page 35: これからのpre_get_postsの話をしよう

メインクエリーにはデフォルト設定がある

30

Page 36: これからのpre_get_postsの話をしよう

メインクエリーのデフォルト設定を変更したい= query_posts

31

Page 37: これからのpre_get_postsの話をしよう

32

Page 38: これからのpre_get_postsの話をしよう

?cat=1

32

Page 39: これからのpre_get_postsの話をしよう

?cat=1 デフォルト設定

32

Page 40: これからのpre_get_postsの話をしよう

?cat=1 デフォルト設定

クエリーストリングの生成

32

Page 41: これからのpre_get_postsの話をしよう

?cat=1

条件分岐タグの設定

デフォルト設定

クエリーストリングの生成

32

Page 42: これからのpre_get_postsの話をしよう

?cat=1

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

クエリーストリングの生成

32

Page 43: これからのpre_get_postsの話をしよう

?cat=1

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

クエリーストリングの生成

32

Page 44: これからのpre_get_postsの話をしよう

?cat=1

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化

<a href=”<?php the_permalink(); ?>”><h2>

<?php the_title(); ?></a>

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

クエリーストリングの生成

32

Page 45: これからのpre_get_postsの話をしよう

?cat=1

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化<h2>

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

クエリーストリングの生成

32

Page 46: これからのpre_get_postsの話をしよう

?cat=1

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化<h2>

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

クエリーストリングの生成

32

Page 47: これからのpre_get_postsの話をしよう

?cat=1

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化<h2>

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

クエリーストリングの生成

32

Page 48: これからのpre_get_postsの話をしよう

?cat=1

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化<h2>

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

クエリーストリングの生成

32

Page 49: これからのpre_get_postsの話をしよう

?cat=1

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化<h2>

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

クエリーストリングの生成

クエリーストリングの再生成

32

Page 50: これからのpre_get_postsの話をしよう

?cat=1

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化<h2>

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

クエリーストリングの生成

クエリーストリングの再生成

条件分岐タグの再設定

32

Page 51: これからのpre_get_postsの話をしよう

?cat=1

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化<h2>

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

クエリーストリングの生成

クエリーストリングの再生成

条件分岐タグの再設定

データベースから投稿を再取得

32

Page 52: これからのpre_get_postsの話をしよう

?cat=1

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化<h2>

条件分岐タグの設定

デフォルト設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

クエリーストリングの生成

クエリーストリングの再生成

条件分岐タグの再設定

データベースから投稿を再取得

query_posts以前のアレコレが消えてしまった!

32

Page 53: これからのpre_get_postsの話をしよう

大丈夫!戻す手段があります

33

Page 54: これからのpre_get_postsの話をしよう

wp_reset_query()

query_posts発動前の状態に戻す

34

Page 55: これからのpre_get_postsの話をしよう

query_posts何が問題なのか?

35

Page 56: これからのpre_get_postsの話をしよう

ページ送りが効かない(頻出)

原因 = $query_stringと結合していない

global $query_string;query_posts( $query_string . '&order=ASC' );

36

Page 57: これからのpre_get_postsの話をしよう

条件分岐タグの設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

query_posts()以前の条件でテンプレートが選ばれてしまう

=意図せず404になる37

Page 58: これからのpre_get_postsの話をしよう

条件分岐タグの設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

条件分岐タグの再設定

2回DBから投稿データを取得=非効率、表示遅速の原因

38

Page 59: これからのpre_get_postsの話をしよう

条件分岐タグの設定

データベースから投稿を取得

使用するテンプレートの読み込み

query_posts() = 投稿の再取得

条件分岐タグの再設定

条件分岐タグが上書きされる=混乱のもと

39

Page 60: これからのpre_get_postsの話をしよう

条件分岐タグの上書きと、query_posts()をサブクエリーの取得に使ってしまう間違いが

重なるとカオス40

Page 61: これからのpre_get_postsの話をしよう

header.php

footer.php

category.php is_category() = true

sidebar.phpでquery_posts()を使用

wp_reset_query()書き忘れ

is_category() = false

テンプレートファイルをまたいで影響が出る

41

Page 62: これからのpre_get_postsの話をしよう

まとめ

42

Page 63: これからのpre_get_postsの話をしよう

query_postsは便利だが、影響範囲が

大きすぎる

43

Page 64: これからのpre_get_postsの話をしよう

条件分岐の上書きは初心者には分かりにくい

44

Page 65: これからのpre_get_postsの話をしよう

これからの推奨される

方法45

Page 66: これからのpre_get_postsの話をしよう

メインクエリーの改変

=pre_get_posts

46

Page 67: これからのpre_get_postsの話をしよう

サブクエリーの作成

=get_posts

47

Page 68: これからのpre_get_postsの話をしよう

サブクエリーの作成

=get_posts

条件分岐タグが書き換わらない

47

Page 69: これからのpre_get_postsの話をしよう

用途によって使いわけよう

48

Page 70: これからのpre_get_postsの話をしよう

メインクエリーの改変

=pre_get_posts

49

Page 71: これからのpre_get_postsの話をしよう

function 関数( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( クエリーの改変を適用する条件 ) { $query->set( ‘パラメーター’, ‘値’ ); return; }}add_action( 'pre_get_posts', '関数名' );

pre_get_posts基本文法

50

Page 72: これからのpre_get_postsの話をしよう

function 関数( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( クエリーの改変を適用する条件 ) { $query->set( ‘パラメーター’, ‘値’ ); return; }}add_action( 'pre_get_posts', '関数名' );

pre_get_posts基本文法

管理画面とメインクエリー以外には適用しない

51

Page 73: これからのpre_get_postsの話をしよう

function 関数( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( クエリーの改変を適用する条件 ) { $query->set( ‘パラメーター’, ‘値’ ); return; }}add_action( 'pre_get_posts', '関数名' );

pre_get_posts基本文法表示条件を変更したいページを絞り込む

52

Page 74: これからのpre_get_postsの話をしよう

function 関数( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( クエリーの改変を適用する条件 ) { $query->set( ‘パラメーター’, ‘値’ ); return; }}add_action( 'pre_get_posts', '関数名' );

pre_get_posts基本文法

メインクエリーのパラメーターを設定

53

Page 75: これからのpre_get_postsの話をしよう

function 関数( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( クエリーの改変を適用する条件 ) { $query->set( ‘パラメーター’, ‘値’ ); return; }}add_action( 'pre_get_posts', '関数名' );

pre_get_posts基本文法

関数の名前は自由につけて良い

54

Page 76: これからのpre_get_postsの話をしよう

function 関数( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( クエリーの改変を適用する条件 ) { 処理 return; }}add_action( 'pre_get_posts', '関数名' );

pre_get_posts基本文法

【最重要】テーマのfunctions.phpに記載する

query_postsの様に各テンプレートには書かない

55

Page 77: これからのpre_get_postsの話をしよう

?cat=1 デフォルト設定

条件分岐タグの設定

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化

<a href=”<?php the_permalink(); ?>”><h2>

<?php the_title(); ?></a>

データベースから投稿を取得

使用するテンプレートの読み込み

クエリーストリングの生成

56

Page 78: これからのpre_get_postsの話をしよう

?cat=1 デフォルト設定

条件分岐タグの設定

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化

データベースから投稿を取得

使用するテンプレートの読み込み

クエリーストリングの生成

56

Page 79: これからのpre_get_postsの話をしよう

?cat=1 デフォルト設定

条件分岐タグの設定

have_posts() = 投稿が存在する?the_post() = テンプレートタグを有効化

データベースから投稿を取得

使用するテンプレートの読み込み

クエリーストリングの生成

pre_get_posts フィルター= クエリーストリングに無い条件の追加

56

Page 80: これからのpre_get_postsの話をしよう

function exclude_category_at_home( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( $query->is_home() ) { $query->set( 'cat', '-1,-1347' ); return; }}add_action( 'pre_get_posts', 'exclude_category_at_home' );

メインページから特定のカテゴリーを除外する

57

Page 81: これからのpre_get_postsの話をしよう

function exclude_category_at_home( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( $query->is_home() ) { $query->set( 'cat', '-1,-1347' ); return; }}add_action( 'pre_get_posts', 'exclude_category_at_home' );

メインページから特定のカテゴリーを除外する

メインページのみに制限

注意:is_home() ではなく$query->is_home()

58

Page 82: これからのpre_get_postsの話をしよう

function exclude_category_at_home( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( $query->is_home() ) { $query->set( 'cat', '-1,-1347' ); return; }}add_action( 'pre_get_posts', 'exclude_category_at_home' );

メインページから特定のカテゴリーを除外する

$query->set( ‘パラメーター’, ‘値’ );

使えるパラメーターはCodexの関数リファレンス/WP_Queryを参照

59

Page 83: これからのpre_get_postsの話をしよう

function search_exclude_cat_1( $query ) { if ( is_admin() || ! $query->is_main_query() ) return; if ( $query->is_search() ) { $query->set( 'category__not_in', array(1) ); return; }}add_action( 'pre_get_posts', 'search_exclude_cat_1' );

検索結果から特定のカテゴリーを除外する

60

Page 84: これからのpre_get_postsの話をしよう

function search_exclude_cat_1( $query ) { if ( is_admin() || ! $query->is_main_query() ) return; if ( $query->is_search() ) { $query->set( 'category__not_in', array(1) ); return; }}add_action( 'pre_get_posts', 'search_exclude_cat_1' );

検索結果から特定のカテゴリーを除外する

検索結果で

IDが1のカテゴリーを除外配列で指定することもできる

61

Page 85: これからのpre_get_postsの話をしよう

function search_only_post( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( $query->is_search() ) { $query->set( 'post_type', 'post' ); return; }}add_action( 'pre_get_posts', 'search_only_post' );

検索結果から固定ページを除外(投稿のみ)

62

Page 86: これからのpre_get_postsの話をしよう

function search_only_post( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( $query->is_search() ) { $query->set( 'post_type', 'post' ); return; }}add_action( 'pre_get_posts', 'search_only_post' );

検索結果から固定ページを除外(投稿のみ)

検索結果のみに制限

Codexのサンプルは$query->is_searchプロパティを見るより関数で書こう

$query->is_search() → ○

63

Page 87: これからのpre_get_postsの話をしよう

function set_post_per_page( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( $query->is_home() ) { $query->set( 'posts_per_page', 1 ); return; }

if ( $query->is_post_type_archive( 'movie' ) ) { $query->set( 'posts_per_page', 50 ); return; }}add_action( 'pre_get_posts', 'set_post_per_page');

条件にしたがって表示件数を変更

64

Page 88: これからのpre_get_postsの話をしよう

function set_post_per_page( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( $query->is_home() ) { $query->set( 'posts_per_page', 1 ); return; }

if ( $query->is_post_type_archive( 'movie' ) ) { $query->set( 'posts_per_page', 50 ); return; }}add_action( 'pre_get_posts', 'set_post_per_page');

条件にしたがって表示件数を変更

メインページでは

1件表示

65

Page 89: これからのpre_get_postsの話をしよう

function set_post_per_page( $query ) { if ( is_admin() || ! $query->is_main_query() ) return;

if ( $query->is_home() ) { $query->set( 'posts_per_page', 1 ); return; }

if ( $query->is_post_type_archive( 'movie' ) ) { $query->set( 'posts_per_page', 50 ); return; }}add_action( 'pre_get_posts', 'set_post_per_page');

条件にしたがって表示件数を変更

‘movie’ 投稿タイプのアーカイブでは

50件表示

66

Page 90: これからのpre_get_postsの話をしよう

注意点あくまでパラメーターの追加固定ページをアーカイブに等根本的に変更するのは厳しい

= サブクエリーを使う

67

Page 91: これからのpre_get_postsの話をしよう

注意点一部の条件分岐は

pre_get_postsのタイミングでは動作しない例:is_front_page()

68

Page 92: これからのpre_get_postsの話をしよう

サブクエリーの作成

=get_posts

69

Page 93: これからのpre_get_postsの話をしよう

global $post;$args = array( 'posts_per_page' => 5, 'cat' => 1 );$myposts = get_posts( $args );foreach( $myposts as $post ) { setup_postdata($post); ?> <h1><?php the_title(); ?></h1> <?php}wp_reset_postdata();

get_posts記述例

70

Page 94: これからのpre_get_postsの話をしよう

global $post;$args = array( 'posts_per_page' => 5, 'cat' => 1 );$myposts = get_posts( $args );foreach( $myposts as $post ) { setup_postdata($post); ?> <h1><?php the_title(); ?></h1> <?php}wp_reset_postdata();

get_posts記述例

テンプレートタグのセットアップ

テンプレートタグのリセット

71

Page 95: これからのpre_get_postsの話をしよう

Codexで get_posts のサンプルの書き方が微妙にまちまちCodexの改善に期待

72

Page 96: これからのpre_get_postsの話をしよう

$args = array( 'posts_per_page' => 5, 'offset' => 0, 'cat' => 0, 'orderby' => 'post_date', 'order' => 'DESC', 'post_type' => 'post', 'post_status' => 'publish', 'suppress_filters' => true, 'ignore_sticky_posts' => true, 'no_found_rows' => true);

WP_Query記述例$the_query = new WP_Query( $args );if ( $the_query->have_posts() ) { while ( $the_query->have_posts() ) { $the_query->the_post(); ?> <h1><?php the_title(); ?></h1> <?php }}wp_reset_postdata();

上級者向けかも

73

Page 97: これからのpre_get_postsの話をしよう

まとめ

74

Page 98: これからのpre_get_postsの話をしよう

メインクエリーの変更はpre_get_posts

サブクエリーの作成はget_posts (or WP_Query)

使い分ける

75

Page 99: これからのpre_get_postsの話をしよう

Thanks!

質問は公式フォーラム

または Twitter: @HissyNC まで

76