Intereting Posts
Запросы Active DB в WordPress? Присвоение роли определенному типу пользовательских сообщений (и игнорирование других типов сообщений) Удалить li из wp_nav_menu Пользовательская таксономическая разбивка на конечные точки с использованием paginate_links () Фильтр цены WooCommerce не работает? Сумасшедший выход WP не имеет смысла (wp_get_nav_menu_items). Кто угодно? Как узнать, зарегистрирован ли пользователь Отображение страницы профиля зарегистрированного пользователя Плагин WordPress не создает пользовательские таблицы Почему редактор почтового контента всегда расширялся? Есть ли способ прочитать или перечислить содержимое wp_head ()? Как открыть медиаредактор для определенного изображения в интерфейсе WordPress, нажав кнопку вместе с идентификатором изображения? Как организовать категории сеанса the_tags: мы можем вставить класс Как загрузить среду WordPress без загрузки шаблона?

Когда использовать WP_query (), query_posts () и pre_get_posts

Я читал @ nacin, что вы вчера не знаете «Запрос», и мне было отправлено немного запросов на кроличью нору. До вчерашнего дня я (ошибочно) использовал query_posts() для всех моих запросов. Теперь я немного мудрее об использовании WP_Query() , но все же имею некоторые серые области.

Я думаю, что знаю точно:

Если я делаю дополнительные петли в любом месте страницы – на боковой панели, в нижнем колонтитуле, любых «связанных сообщениях» и т. Д. – я хочу использовать WP_Query() . Я могу использовать это повторно на одной странице без какого-либо вреда. (правильно?).

То, что я точно не знаю

  1. Когда я использую pre_get_posts @ pre_get_posts против WP_Query() ? Должен ли я использовать pre_get_posts для всего сейчас?
  2. Когда я хочу изменить цикл на странице шаблона – скажем, я хочу изменить страницу архива таксономии – if have_posts : while have_posts : the_post и написать собственный WP_Query() ? Или я могу изменить вывод с помощью pre_get_posts в моем файле functions.php?

ТЛ; др

Правила tl; dr, которые я хотел бы извлечь из этого:

  1. Никогда не используйте query_posts больше
  2. При запуске нескольких запросов на одной странице используйте WP_Query()
  3. При изменении цикла, сделайте это __________________.

Спасибо за любую мудрость

Терри

ps: Я видел и читал: Когда вы должны использовать WP_Query vs query_posts () vs get_posts ()? Что добавляет другое измерение – get_posts . Но не имеет дело с pre_get_posts вообще.

Solutions Collecting From Web of "Когда использовать WP_query (), query_posts () и pre_get_posts"

Вы имеете право сказать:

Никогда не используйте query_posts больше

pre_get_posts

pre_get_posts – это фильтр для изменения любого запроса. Он чаще всего используется для изменения только «основного запроса»:

 add_action('pre_get_posts','wpse50761_alter_query'); function wpse50761_alter_query($query){ if( $query->is_main_query() ){ //Do something to main query } } 

(Я также хотел бы проверить, что is_admin() возвращает false – хотя это может быть избыточным.). Основной запрос появляется в ваших шаблонах как:

 if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

Если вы когда-нибудь почувствуете необходимость редактировать этот цикл – используйте pre_get_posts . т.е. если у вас возникает соблазн использовать query_posts() – вместо этого используйте pre_get_posts .

WP_Query

Основной запрос является важным экземпляром WP_Query object . WordPress использует его для определения того, какой шаблон использовать, например, и любые аргументы, переданные в URL-адрес (например, разбиение на страницы), все направляются в этот экземпляр объекта WP_Query .

Для вторичных циклов (например, в боковых барах или списках связанных записей) вы захотите создать свой собственный отдельный экземпляр объекта WP_Query . Например

 $my_secondary_loop = new WP_Query(...); if( $my_secondary_loop->have_posts() ): while( $my_secondary_loop->have_posts() ): $my_secondary_loop->the_post(); //The secondary loop endwhile; endif; wp_reset_postdata(); 

Обратите внимание на wp_reset_postdata(); – это потому, что вторичный цикл переопределяет глобальную переменную $post которая идентифицирует «текущую должность». Это существенно сбрасывает это значение на $post мы находимся.

get_posts ()

Это по существу оболочка для отдельного экземпляра объекта WP_Query . Это возвращает массив объектов post. Методы, используемые в вышеприведенном цикле, больше не доступны для вас. Это не «Loop», а просто массив пост-объекта.

 <ul> <?php global $post; $args = array( 'numberposts' => 5, 'offset'=> 1, 'category' => 1 ); $myposts = get_posts( $args ); foreach( $myposts as $post ) : setup_postdata($post); ?> <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li> <?php endforeach; wp_reset_postdata(); ?> </ul> 

Отвечая на ваши вопросы

  1. Используйте pre_get_posts для изменения основного запроса. Используйте отдельный объект WP_Query (метод 2) для вторичных циклов на страницах шаблонов.
  2. Если вы хотите изменить запрос основного цикла, используйте pre_get_posts .

Для циклов существуют два разных контекста:

  • основной цикл, который происходит на основе запроса URL-адреса и обрабатывается до загрузки шаблонов
  • вторичные циклы, которые происходят каким-либо другим способом, вызываются из файлов шаблонов или иным образом

Проблема с query_posts() заключается в том, что это вторичный цикл, который пытается быть основным и терпит неудачу. Таким образом, забудьте о существовании.

Чтобы изменить основной цикл

  • не используйте query_posts()
  • используйте фильтр pre_get_posts с $query->is_main_query()
  • поочередно используйте фильтр request (немного слишком грубый, так что выше лучше)

Чтобы запустить вторичный цикл

Используйте new WP_Query или get_posts() которые в значительной степени взаимозаменяемы (последняя – тонкая оболочка для бывших).

Очистить

Используйте wp_reset_query() если вы использовали query_posts() или запутались с глобальным $wp_query напрямую, поэтому вам почти никогда не понадобится.

Используйте wp_reset_postdata() если вы использовали the_post() или setup_postdata() или перепутались с глобальной $post setup_postdata() и должны восстановить начальное состояние связанных с сообщением вещей.

Существуют законные сценарии использования query_posts($query) , например:

  1. Вы хотите отобразить список сообщений или сообщений на пост-пост-типа на странице (используя шаблон страницы)

  2. Вы хотите сделать разбивку на страницы этих должностей

Теперь почему вы хотите отображать его на странице вместо использования шаблона архива?

  1. Это более интуитивно понятно для администратора (ваш клиент?) – они могут видеть страницу в «Странице»,

  2. Лучше добавить его в меню (без страницы, они должны будут добавить URL напрямую)

  3. Если вы хотите отобразить в шаблоне дополнительный контент (текст, миниатюра сообщения или любой пользовательский метаконтент), вы можете легко получить его со страницы (и все это имеет смысл для клиента). Посмотрите, используете ли вы шаблон архива, вам нужно либо жестко указать дополнительный контент, либо использовать, например, параметры темы / плагина (что делает его менее интуитивным для клиента)

Вот упрощенный примерный код (который будет на вашем шаблоне страницы – например, page-page-of-posts.php):

 /** * Template Name: Page of Posts */ while(have_posts()) { // original main loop - page content the_post(); the_title(); // title of the page the_content(); // content of the page // etc... } // now we display list of our custom-post-type posts // first obtain pagination parametres $paged = 1; if(get_query_var('paged')) { $paged = get_query_var('paged'); } elseif(get_query_var('page')) { $paged = get_query_var('page'); } // query posts and replace the main query (page) with this one (so the pagination works) query_posts(array('post_type' => 'my_post_type', 'post_status' => 'publish', 'paged' => $paged)); // pagination next_posts_link(); previous_posts_link(); // loop while(have_posts()) { the_post(); the_title(); // your custom-post-type post's title the_content(); // // your custom-post-type post's content } wp_reset_query(); // sets the main query (global $wp_query) to the original page query (it obtains it from global $wp_the_query variable) and resets the post data // So, now we can display the page-related content again (if we wish so) while(have_posts()) { // original main loop - page content the_post(); the_title(); // title of the page the_content(); // content of the page // etc... } 

Теперь, чтобы быть совершенно ясным, мы могли бы избежать использования query_posts() здесь тоже и вместо этого использовать WP_Query – вот так:

 // ... global $wp_query; $wp_query = new WP_Query(array('your query vars here')); // sets the new custom query as a main query // your custom-post-type loop here wp_reset_query(); // ... 

Но зачем нам это делать, когда у нас есть такая приятная небольшая функция, доступная для этого?

Я изменяю запрос WordPress из functions.php:

 //unfortunately, "IS_PAGE" condition doesn't work in pre_get_posts (it's WORDPRESS behaviour) //so you can use `add_filter('posts_where', ....);` OR modify "PAGE" query directly into template file add_action( 'pre_get_posts', 'myf88' ); function myf88($query) { if ( ! is_admin() && $query->is_main_query() ) { if ( $query->is_category ) { $query->set( 'post_type', array( 'post', 'page', 'my_postType' ) ); add_filter( 'posts_where' , 'MyFilterFunction_1' ) && $GLOBALS['call_ok']=1; } } } function MyFilterFunction_1($where) { return (empty($GLOBALS['call_ok']) || !($GLOBALS['call_ok']=false) ? $where : $where . " AND ({$GLOBALS['wpdb']->posts}.post_name NOT LIKE 'Journal%')"; } 

Просто для того, чтобы наметить некоторые улучшения в принятом ответе, поскольку WordPress развивался с течением времени, и теперь некоторые вещи разные (пять лет спустя):

pre_get_posts – это фильтр для изменения любого запроса. Он чаще всего используется для изменения только «основного запроса»:

На самом деле это крючок действия. Не фильтр, и это повлияет на любой запрос.

Основной запрос появляется в ваших шаблонах как:

 if( have_posts() ): while( have_posts() ): the_post(); //The loop endwhile; endif; 

Собственно, это также неверно. Функция have_posts выполняет have_posts global $wp_query объекта global $wp_query который не связан только с основным запросом. global $wp_query; также могут быть изменены с помощью вторичных запросов.

 function have_posts() { global $wp_query; return $wp_query->have_posts(); } 

get_posts ()

Это по существу оболочка для отдельного экземпляра объекта WP_Query.

На самом деле, в настоящее время WP_Query является классом, поэтому у нас есть экземпляр класса.


В заключение: В то время @StephenHarris написал, скорее всего, все это было правдой, но с течением времени вещи в WordPress были изменены.