Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Everything You Need to Know About WP_Query, WordCamp Russia 2014

2,318 views

Published on

http://2014.russia.wordcamp.org/

Published in: Internet
  • Be the first to comment

Everything You Need to Know About WP_Query, WordCamp Russia 2014

  1. 1. Всё, что нужно знать о WP_Query Сергей Бирюков WordCamp Russia 2014
  2. 2. Обо мне Сергей Бирюков ● Разработчик ядра WordPress http://core.trac.wordpress.org ● Локализатор WP в России http://ru.wordpress.org http://sergeybiryukov.ru @flash_usb
  3. 3. Что мы знаем о WP_Query?
  4. 4. Условные теги is_author(), is_category(), is_home() и т. д.
  5. 5. Кто сталкивался с query_posts()?
  6. 6. Способы получения записей ● query_posts() ● new WP_Query() ● get_posts()
  7. 7. Цикл WordPress while ( have_posts() ) : the_post(); endwhile;
  8. 8. Вторичный цикл $query = new WP_Query( … ); while ( $query->have_posts() ) : $query->the_post(); endwhile;
  9. 9. Массив записей $result = get_posts( … ); foreach ( $result as $post_obj ) { ... }
  10. 10. Что мы не знаем?
  11. 11. У каждого объекта запроса есть методы is_author() — то же самое, что $wp_query->is_author().
  12. 12. function is_author() { global $wp_query; return $wp_query->is_author(); }
  13. 13. Обычный цикл while ( have_posts() ) : the_post(); if ( is_author() ) echo 'Страница автора'; endwhile;
  14. 14. Обычный цикл while ( have_posts() ) : the_post(); if ( $wp_query->is_author() ) echo 'Страница автора'; endwhile;
  15. 15. Вторичный цикл $query = new WP_Query( … ); while ( $query->have_posts() ) : $query->the_post(); if ( $query->is_author() ) echo 'Страница автора.'; endwhile;
  16. 16. Вторичный цикл $query = new WP_Query( … ); while ( $query->have_posts() ) : $query->the_post(); if ( $query->is_author() ) echo 'Страница автора.'; endwhile;
  17. 17. Вторичный цикл $query = new WP_Query( … ); while ( $query->have_posts() ) : $query->the_post(); if ( $query->is_author() ) echo 'Страница автора.'; endwhile;
  18. 18. Если мы создаём новый объект: $my_query = new WP_Query( $query ); то можем вызывать его методы: while ( $my_query->have_posts() ) : $my_query->the_post(); endwhile; wp_reset_postdata();
  19. 19. ● Зачем нужны wp_reset_postdata() и wp_reset_query()? ● Что насчёт query_posts()? ● Как изменить запрос? ● Как изменить основной запрос?
  20. 20. Что такое основной запрос, и почему это важно?
  21. 21. wp-blog-header.php // Загружаем окружение WordPress require './wp-load.php'; // Определяем, какие файлы шаблонов подключить require WPINC . '/template-loader.php';
  22. 22. Что происходит при загрузке? $wp_the_query = new WP_Query(); $wp_query =& $wp_the_query;
  23. 23. Немного о ссылках в PHP $a = 4; $b =& $a; $b = 2; var_dump( $a ); // int(2) $a = 6; var_dump( $b ); // int(6)
  24. 24. ● Основной запрос хранится в $wp_the_query. ● Его копия хранится в $wp_query.
  25. 25. wp-blog-header.php // Загружаем окружение WordPress require './wp-load.php'; // Определяем, какие файлы шаблонов подключить require WPINC . '/template-loader.php';
  26. 26. wp-blog-header.php // Загружаем окружение WordPress require './wp-load.php'; // Всё происходит здесь wp(); // Определяем, какие файлы шаблонов подключить require WPINC . '/template-loader.php';
  27. 27. Что делает вызов wp()? function wp( $query_vars = '' ) { global $wp; $wp->main( $query_vars ); }
  28. 28. Что это было?!
  29. 29. При загрузке $wp = new WP(); Есть функция wp() и класс WP.
  30. 30. class WP { … function main() { $this->init(); $this->parse_request(); $this->send_headers(); $this->query_posts(); $this->handle_404(); $this->register_globals(); ...
  31. 31. class WP { … function main() { $this->init(); $this->parse_request(); $this->send_headers(); $this->query_posts(); $this->handle_404(); $this->register_globals(); ...
  32. 32. WP::parse_request() ● Разбирает URL с помощью WP_Rewrite ● Задаёт переменные запроса для WP_Query WP::query_posts() { global $wp_the_query; $wp_the_query->query( $this->query_vars ); }
  33. 33. SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND wp_posts.post_status = 'publish' ORDER BY wp_posts.post_date DESC LIMIT 0, 10
  34. 34. wp-blog-header.php // Загружаем окружение WordPress require './wp-load.php'; // Определяем, какие записи нужны, затем запрашиваем их wp(); // Загружаем тему оформления require WPINC . '/template-loader.php';
  35. 35. Когда загружается тема оформления, мы уже получили записи.
  36. 36. Тогда зачем делать так? query_posts( 'author=-5' ); get_header(); while ( have_posts() ) : the_post(); endwhile; get_footer();
  37. 37. Получается в два раза больше запросов! ● Первый, который WordPress сделал по умолчанию. ● Второй, который мы будем использовать.
  38. 38. * В общем случае WP_Query выполняет не один запрос, а четыре.
  39. 39. 1. Получаем записи: SELECT SQL_CALC_FOUND_ROWS … FROM wp_posts LIMIT 0, 10 2. Сколько найдено записей? SELECT FOUND_ROWS() 3. Получаем метаданные для этих записей. 4. Получаем элементы таксономий для этих записей.
  40. 40. (Эти запросы можно выборочно отключить...) $my_query = new WP_Query( array( 'no_found_rows' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ) );
  41. 41. Запрос неиспользуемых данных снижает производительность.
  42. 42. Другие проблемы query_posts()
  43. 43. Не работает постраничная навигация Параметры навигации WordPress вычисляет для основного запроса, а не дополнительного.
  44. 44. query_posts( array( 'author' => -5, 'posts_per_page' => 25, ) ); Этот код проблематичен.
  45. 45. Переопределяются глобальные переменные Это может нарушить работу виджетов, комментариев и т.д.
  46. 46. query_posts() — это плохо Согласимся?
  47. 47. Действие pre_get_posts class WP_Query { … function get_posts() { $this->parse_query(); // Ура! do_action_ref_array( 'pre_get_posts', array( &$this ) ); …
  48. 48. function alter_my_home_query( $query ) { if ( $query->is_home() ) $query->set( 'author', '-5' ); } add_action( 'pre_get_posts', 'alter_my_home_query' );
  49. 49. Здесь начинаются сложности.
  50. 50. 'pre_get_posts' выполняется для каждого запроса ● get_posts() ● new WP_Query ● Виджет последних записей, установленный клиентом без вашего ведома. ● И т.д.
  51. 51. Как изменить только основной запрос?
  52. 52. Триумфальное возвращение $wp_the_query
  53. 53. Метод WP_Query::is_main_query() class WP_Query { … function is_main_query() { global $wp_the_query; return $wp_the_query === $this; } …
  54. 54. Только главный запрос! function alter_my_home_query( $query ) { if ( $query->is_home() && $query->is_main_query() ) $query->set( 'author', '-5' ); } add_action( 'pre_get_posts', 'alter_my_home_query' );
  55. 55. function alter_my_home_query( $query ) { if ( is_admin() || ! $query->is_main_query() ) return; if ( $query->is_home() ) $query->set( 'author', '-5' ); } add_action( 'pre_get_posts', 'alter_my_home_query' );
  56. 56. Как работает WP_Query::is_main_query()? ● $wp_the_query никогда не меняется и всегда содержит основной запрос. ● В $wp_query хранится ссылка на $wp_the_query, если только не используется query_posts(). ● Не путать с функцией is_main_query().
  57. 57. query_posts( 'author=-5' ); while ( have_posts() ) : the_post(); endwhile; wp_reset_query();
  58. 58. query_posts( 'author=-5' ); while ( have_posts() ) : the_post(); endwhile; wp_reset_query();
  59. 59. function query_posts( $query ) { // Убираем ссылку на $wp_the_query unset( $wp_query ); $wp_query =& new WP_Query( $query ); return $wp_query; }
  60. 60. query_posts( 'author=-5' ); while ( have_posts() ) : the_post(); endwhile; wp_reset_query();
  61. 61. function wp_reset_query() { // Восстанавливаем ссылку на $wp_the_query unset( $wp_query ); $wp_query =& $wp_the_query; // Восстанавливаем глобальные переменные wp_reset_postdata(); }
  62. 62. ● Вызываете the_post()? wp_reset_query() восстановит $wp_query и глобальные переменные. ● Вызываете $my_query->the_post()? wp_reset_postdata() восстановит глобальные переменные.
  63. 63. Как быть с шаблонами страниц?
  64. 64. /* Template: My Template */ query_posts( $query_string . '&author=-5&posts_per_page=25' ); get_header(); while ( have_posts() ) : the_post(); endwhile;
  65. 65. function alter_my_template( $query ) { if ( ! $query->is_main_query() ) return; if ( ! is_page_template( 'my-template.php' ) ) return; $query->set( 'author', '-5' ); $query->set( 'posts_per_page', 25 ); } add_action( 'pre_get_posts', 'alter_my_template' );
  66. 66. Выводы ● У каждого объекта WP_Query есть методы, соответствующие глобальным условным тегам. ● Глобальные условные теги используют $wp_query — основной или текущий запрос. ● $wp_query — это основной запрос, если не используется query_posts(). Восстанавливайте его с помощью wp_reset_query().
  67. 67. В заключение ● 'pre_get_posts' — мощный и гибкий инструмент (при правильном использовании). ● Всегда проверяйте с помощью $query->is_main_query(), что меняете именно основной запрос.
  68. 68. http://sergeybiryukov.ru @flash_usb Спасибо! Вопросы?

×