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

50,152 views

Published on

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

Published in: Technology
0 Comments
37 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
50,152
On SlideShare
0
From Embeds
0
Number of Embeds
33,772
Actions
Shares
0
Downloads
39
Comments
0
Likes
37
Embeds 0
No embeds

No notes for slide

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

  1. 1. これからの by @HissyNC / WordBench Kobe Group pre_get_posts: What's the Right Way to Use? pre_get_posts の話をしよう 1
  2. 2. query_posts非推奨? 『query_postsを捨てよ、pre_get_postsを 使おう』というブログ記事を公開したとこ ろ、はてブなどでバズる。「いつの間にこ んなことになっていたんだよ…」「非推奨 だなんて!いますぐ直さなきゃ!」「急に 言われても困る」「query_posts使いまく ってたぜマジかよ…」「初心者にこの説明 はキツイでしょ」等々の意見が噴出。 2
  3. 3. pre_get_postsとは何か? 結局、Codexのquery_postsのページに非 推奨の文字が入ったのは一時的なもので、 その後表現が修正され、「query_postsの 代わりにpre_get_postsフィルターを使う ことを強く推奨する」となった。ではなぜ 数多のWordPress本でも紹介されている query_postsが推奨されないのだろうか。 pre_get_postsフィルターとは何なのか。 3
  4. 4. まず テンプレート とは何か 4
  5. 5. データベースから 目的のデータを 取得して 表示するためのもの 5
  6. 6. ではない 6
  7. 7. テンプレートとは 表示するデータを 整形する ためのもの 7
  8. 8. データを取得する 目的には 本来使わない 8
  9. 9. どんなデータを 取得するかを 決定するのは 9
  10. 10. URL 10
  11. 11. ?p=1 ?cat=1 ?cat=1&post_type=book&paged=2 クエリー・ストリングという $query_string 11
  12. 12. URLで どのデータを取得 するかが決まる どんな処理を行う かが決まる 12
  13. 13. ほかのCMS でも同じ 13
  14. 14. URLがページの 内容を表している = インターネットの 基本的な概念 14
  15. 15. ここで疑問 15
  16. 16. Webページには たくさんのデータ が表示されており 各ページで共通の ものもある 16
  17. 17. たとえば サイドバーに 新着記事を5件表示 URLとは関係なく どのページにもある 17
  18. 18. 記事の下に 関連記事を5件表示 URLとは間接的に関係 があるが 直接示しているもの ではない 18
  19. 19. これらを サブクエリー と呼ぶ 19
  20. 20. ?p=1 ?cat=1 ?cat=1&post_type=book&paged=2 クエリー・ストリングと直接対応し ているデータのことを 20
  21. 21. メインクエリー と呼ぶ 21
  22. 22. メインクエリー と サブクエリー 違いを理解しよう 22
  23. 23. トップページの内容と してニュースカテゴリ ーの記事を表示する メインクエリー or サブクエリー? 23
  24. 24. トップページの内容と してニュースカテゴリ ーの記事を表示する メインクエリー or サブクエリー? 24
  25. 25. WordPressでは、フロントページ は新着投稿か、固定ページか、 2択です。CMSとしてはそれだ け?と違和感がありますが、そう いう設計ですので、本来特定のカ テゴリーの記事をトップページで 表示するのはWordPressではでき ません。get_postsを使うか、ウ ィジェットを使いましょう 25
  26. 26. query_posts の 迷宮 26
  27. 27. query_postsとは 本来 メインクエリーを 改変するためのもの 27
  28. 28. http://example.com/?cat=1 28
  29. 29. http://example.com/?cat=1 カテゴリーID が 1 28
  30. 30. http://example.com/?cat=1 have_posts() = 投稿が存在する? カテゴリーID が 1 28
  31. 31. http://example.com/?cat=1 have_posts() = 投稿が存在する? カテゴリーID が 1 the_post() = テンプレートタグを有効化 28
  32. 32. http://example.com/?cat=1 have_posts() = 投稿が存在する? カテゴリーID が 1 the_post() = テンプレートタグを有効化 <a href= <?php the_permalink(); ?> > <h2> <?php the_title(); ?></a> </h2> 28
  33. 33. 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
  34. 34. カテゴリーを指定している が、それ以外は? 表示件数(10件?) 並び順(投稿日が新しい順) 投稿タイプ(投稿) デフォルト設定がある 29
  35. 35. メインクエリーには デフォルト設定 がある 30
  36. 36. メインクエリーの デフォルト設定を 変更したい = query_posts 31
  37. 37. 32
  38. 38. ?cat=1 32
  39. 39. ?cat=1 デフォルト設定 32
  40. 40. ?cat=1 デフォルト設定 クエリーストリングの生成 32
  41. 41. ?cat=1 条件分岐タグの設定 デフォルト設定 クエリーストリングの生成 32
  42. 42. ?cat=1 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 クエリーストリングの生成 32
  43. 43. ?cat=1 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み クエリーストリングの生成 32
  44. 44. ?cat=1 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 <a href= <?php the_permalink(); ?> > <h2> 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み クエリーストリングの生成 32
  45. 45. ?cat=1 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み クエリーストリングの生成 32
  46. 46. ?cat=1 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 クエリーストリングの生成 32
  47. 47. ?cat=1 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 クエリーストリングの生成 32
  48. 48. ?cat=1 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 クエリーストリングの生成 32
  49. 49. ?cat=1 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 クエリーストリングの生成 クエリーストリングの再生成 32
  50. 50. ?cat=1 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 クエリーストリングの生成 クエリーストリングの再生成 条件分岐タグの再設定 32
  51. 51. ?cat=1 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 クエリーストリングの生成 クエリーストリングの再生成 条件分岐タグの再設定 データベースから投稿を再取得 32
  52. 52. ?cat=1 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 条件分岐タグの設定 デフォルト設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 クエリーストリングの生成 クエリーストリングの再生成 条件分岐タグの再設定 データベースから投稿を再取得 query_posts以前のアレコレが消えてしまった! 32
  53. 53. 大丈夫! 戻す手段が あります 33
  54. 54. wp_reset_query() query_posts 発動前の状態に戻す 34
  55. 55. query_posts 何が問題なのか? 35
  56. 56. ページ送りが効かない (頻出) 原因 = $query_string と結合していない global $query_string; query_posts( $query_string . '&order=ASC' ); 36
  57. 57. 条件分岐タグの設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 query_posts()以前の条件で テンプレートが選ばれてしまう =意図せず404になる 37
  58. 58. 条件分岐タグの設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 条件分岐タグの再設定 2回DBから投稿データを取得 =非効率、表示遅速の原因 38
  59. 59. 条件分岐タグの設定 データベースから投稿を取得 使用するテンプレートの読み込み query_posts() = 投稿の再取得 条件分岐タグの再設定 条件分岐タグが上書きされる =混乱のもと 39
  60. 60. 条件分岐タグの上書き と、query_posts()を サブクエリーの取得に 使ってしまう間違いが 重なるとカオス 40
  61. 61. header.php footer.php category.php is_category() = true sidebar.phpで query_posts()を使用 wp_reset_query() 書き忘れ is_category() = false テンプレートファイルをま たいで影響が出る 41
  62. 62. まとめ 42
  63. 63. query_postsは 便利だが、影響範囲が 大きすぎる 43
  64. 64. 条件分岐の上書きは 初心者には分かりにくい 44
  65. 65. これからの 推奨される 方法 45
  66. 66. メインクエリー の改変 = pre_get_posts 46
  67. 67. サブクエリー の作成 = get_posts 47
  68. 68. サブクエリー の作成 = get_posts 条件分岐タグが書き換わらない 47
  69. 69. 用途によって 使いわけよう 48
  70. 70. メインクエリー の改変 = pre_get_posts 49
  71. 71. function 関数( $query ) { if ( is_admin() ¦¦ ! $query->is_main_query() ) return; if ( クエリーの改変を適用する条件 ) { $query->set( パラメーター , 値 ); return; } } add_action( 'pre_get_posts', '関数名' ); pre_get_posts基本文法 50
  72. 72. function 関数( $query ) { if ( is_admin() ¦¦ ! $query->is_main_query() ) return; if ( クエリーの改変を適用する条件 ) { $query->set( パラメーター , 値 ); return; } } add_action( 'pre_get_posts', '関数名' ); pre_get_posts基本文法 管理画面とメインクエリー以外 には適用しない 51
  73. 73. function 関数( $query ) { if ( is_admin() ¦¦ ! $query->is_main_query() ) return; if ( クエリーの改変を適用する条件 ) { $query->set( パラメーター , 値 ); return; } } add_action( 'pre_get_posts', '関数名' ); pre_get_posts基本文法 表示条件を変更したい ページを絞り込む 52
  74. 74. function 関数( $query ) { if ( is_admin() ¦¦ ! $query->is_main_query() ) return; if ( クエリーの改変を適用する条件 ) { $query->set( パラメーター , 値 ); return; } } add_action( 'pre_get_posts', '関数名' ); pre_get_posts基本文法 メインクエリーの パラメーターを設定 53
  75. 75. function 関数( $query ) { if ( is_admin() ¦¦ ! $query->is_main_query() ) return; if ( クエリーの改変を適用する条件 ) { $query->set( パラメーター , 値 ); return; } } add_action( 'pre_get_posts', '関数名' ); pre_get_posts基本文法 関数の名前は 自由につけて良い 54
  76. 76. 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
  77. 77. ?cat=1 デフォルト設定 条件分岐タグの設定 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 <a href= <?php the_permalink(); ?> > <h2> データベースから投稿を取得 使用するテンプレートの読み込み クエリーストリングの生成 56
  78. 78. ?cat=1 デフォルト設定 条件分岐タグの設定 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 データベースから投稿を取得 使用するテンプレートの読み込み クエリーストリングの生成 56
  79. 79. ?cat=1 デフォルト設定 条件分岐タグの設定 have_posts() = 投稿が存在する? the_post() = テンプレートタグを有効化 データベースから投稿を取得 使用するテンプレートの読み込み クエリーストリングの生成 pre_get_posts フィルター = クエリーストリングに無い条件の追加 56
  80. 80. 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
  81. 81. 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
  82. 82. 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
  83. 83. 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
  84. 84. 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
  85. 85. 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
  86. 86. 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
  87. 87. 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
  88. 88. 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
  89. 89. 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
  90. 90. 注意点 あくまでパラメーターの追加 固定ページをアーカイブに等 根本的に変更するのは厳しい = サブクエリーを使う 67
  91. 91. 注意点 一部の条件分岐は pre_get_postsのタイミ ングでは動作しない 例:is_front_page() 68
  92. 92. サブクエリー の作成 = get_posts 69
  93. 93. 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
  94. 94. 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
  95. 95. Codexで get_posts のサンプルの書き方 が微妙にまちまち Codexの改善に期待 72
  96. 96. $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
  97. 97. まとめ 74
  98. 98. メインクエリーの変更は pre_get_posts サブクエリーの作成は get_posts (or WP_Query) 使い分ける 75
  99. 99. Thanks! 質問は公式フォーラム または Twitter: @HissyNC まで 76

×