Successfully reported this slideshow.
Your SlideShare is downloading. ×

Everything You Need to Know About WP_Query, WordCamp Russia 2014

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 68 Ad
Advertisement

More Related Content

Slideshows for you (20)

Advertisement

Similar to Everything You Need to Know About WP_Query, WordCamp Russia 2014 (20)

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 Спасибо! Вопросы?

×