Временно переписывает $ wp_query плохую идею?

Я занимаюсь переписыванием большого количества кода и реструктуризацией многих файлов темы для использования частей шаблона (то есть с помощью get_template_part() ). Я столкнулся с ситуацией, когда я хочу использовать те же части шаблона, независимо от того, использую ли я основной запрос или вторичный пользовательский запрос (используя WP_Query ). Части шаблона также используют основные функции, которые зависят от основного запроса (например, условных выражений).

Я могу обойти проблему, перезаписав основной запрос (или перезаписав глобальный $wp_query содержащий основной запрос, основной запрос все еще существует) с моим пользовательским запросом и сбросом основного запроса, как только я закончу. Это также означает, что я могу использовать один и тот же цикл для основного запроса и моих пользовательских запросов. Например:

 // Query if ( $i_need_a_custom_query ) { $wp_query = new WP_Query($custom_query_args); } // The Loop if ( have_posts() ) : while ( have_posts() ) : the_post(); // Do some loop stuff // and call some functions that rely on the main query // End the loop endwhile; endif; // I'm done so reset the query wp_reset_query(); 

Это работает. Никаких проблем, но для меня это немного взломало. Поэтому мой вопрос:

  • Правильно ли я устал переписывать основной запрос?
  • Есть ли какие-то побочные эффекты?
  • И правильно ли я предполагаю, что вызов wp_reset_query() не является дорогостоящим (т. wp_reset_query() Он фактически не перезапускает запрос, а просто перезагружает глобальные переменные, которые все еще находятся где-то)?

Изменить, чтобы уточнить:

Я использую только специальные запросы в качестве вторичных запросов, вот и весь вопрос. Я хочу использовать один и тот же шаблон. Я использую специальный вторичный запрос или используя основной запрос. Я понимаю, что то, что я делаю, по существу то же самое, что и с использованием query_posts() , что является плохой идеей. Насколько мне известно и в широком смысле, два недостатка в использовании query_posts() – это 1. Производительность, которая не является проблемой, потому что я делаю это только при выполнении вторичного пользовательского запроса и 2. Неумышленные последствия изменения глобальный $ wp_query, который именно то, что я действительно хочу (и, как я сказал, действительно работает отлично).

В общем, я согласен с Howdy_McGee в том, что следует избегать перезаписи основного запроса, если это абсолютно необходимо – чаще всего изменение основного запроса с чем-то вроде 'pre_get_posts' является лучшим решением для таких сценариев.

Ручная перезапись глобальной $wp_query может вызвать все виды непреднамеренного поведения, если вы не слишком осторожны, в том числе разбиваете разбивку на страницы, среди прочего. По сути, это еще более упрощенный эквивалент часто критикуемой функции query_posts() , о которой говорится в кодексе WordPress Code Reference :

Эта функция полностью отменяет основной запрос и не предназначена для использования плагинами или темами. Его чрезмерно упрощенный подход к изменению основного запроса может быть проблематичным и его следует избегать, когда это возможно. В большинстве случаев есть более эффективные и более эффективные варианты для изменения основного запроса, например, посредством действия pre_get_posts в WP_Query.

Однако в этом случае, где вам требуется:

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

то одно решение заключается в том, чтобы хранить «контекстный» экземпляр WP_Query в локальной переменной и вызывать условные методы WP_Query для этой переменной вместо использования их глобально доступных условных тегов функций (которые всегда явно ссылаются на основной запрос, global $wp_query ).

Например, если вы хотите, чтобы ваша «контекстная переменная запроса» ссылалась на пользовательский вторичный запрос в одиночных и архивных шаблонах для вашего настраиваемого типа сообщений, my-custom-post-type , но обратитесь к основному запросу в каждом другом случае, вы может сделать следующее:

Файл functions.php темы или файл плагина:

 function wpse_232115_get_contextual_query() { global $wp_query; static $contextual_query; // A convenient means to check numerous conditionals without a bunch of '||' operations, // ie "if( $i_need_a_custom_query )" if( in_array( true, [ is_singular( 'my-custom-post-type' ), is_post_type_archive( 'my-custom-post-type' ) ] ) ) { // Create the contextual query instance, if it doesn't yet exist if( ! isset( $contextual_query ) ) { $query_args = [ //... ]; $contextual_query = new WP_Query( $query_args ); } return $contextual_query; } return $wp_query; } 

Файлы общих файлов шаблонов «Generic»:

 $query = wpse_232115_get_contextual_query(); // Contextual Query loop (loops through your custom query when 'my-custom-post-type's // are being displayed, the main $wp_query otherwise. if ( $query->have_posts() ) : while ( $query->have_posts() ) : $query->the_post(); // Tags dependent on The Loop will refer to the contextual query if The Loop // was set up with the "$query->" prefix, as above. Without it, they always // refer to the main query. the_title(); // The global conditional tags always refer to the main query if( is_singular() ) { //... Do stuff is the main query result is_singular(); } // Conditional methods on the $query object reference describe either // the main query, or a custom query depending on the context. if( $query->is_archive() ) { //... Do stuff if the $query query result is an archive } // End the loop endwhile; endif; 

Я не уверен, что это лучшее решение, но я думаю, что я подошел бы к этой проблеме.

Я чувствую, что вы должны использовать get_template_part() для разметки. Допустим, у вас есть пользовательский шаблон и блог, который использует тот же get_template_part() . Вы вызывали бы template_part в цикле вместо вызова The Loop в части. Например:

Ваш пользовательский шаблон

 $custom_query = new WP_Query( $args ); if ( $custom_query->have_posts() ) { while ( $custom_query->have_posts() ) { $custom_query->the_post(); get_template_part( $path ); } wp_reset_postdata(); } 

Ваш блог

 if ( have_posts() ) { while ( have_posts() ) { the_post(); get_template_part( $path ); } } 

Это даст как ваш пользовательский шаблон, так и ваш файл блогов доступ к переменным, таким как the_title() и the_permamlink() не обязательно перезаписывая основной запрос. В итоге вышеизложенное даст вам большую гибкость.


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

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

 function query_posts($query) { $GLOBALS['wp_query'] = new WP_Query(); return $GLOBALS['wp_query']->query($query); } 

Помните, что $GLOBALS['wp_query'] === $wp_query . Теперь посмотрите на свой код, и вы обнаружите, что это то же самое.

Есть более чем достаточно query_posts о том, насколько плохи query_posts , поэтому не query_posts и работайте над ними.

Никогда не существует веской причины для замены основного запроса на любой странице. Замена основного запроса ВСЕГДА приведет к некоторой проблеме, она может быть не видна сразу, но вы обязательно увидите ее эффект.

Вы также должны помнить, что если вы после SEO и производительности, то действительно плохая новость заключается в том, что вы определенно делаете это неправильно. Основной запрос всегда выполняется нормально при любой загрузке страницы, т. Е. Он будет запрашивать db и возвращать соответствующие сообщения для страницы. Простое удаление цикла НЕ останавливает основной запрос. Если вы замените цикл на пользовательский, как и в вашем примере, вы снова запросите db, что означает, что вы делаете в два раза больше запросов, а также замедляете страницу из-за этого. Это негативно влияет на SEO, поэтому вам есть о чем подумать.

В заключение, если вам нужно что-то еще из основного запроса, ВСЕГДА используйте pre_get_posts чтобы изменить его. Таким образом, вы не запускаете никаких дополнительных запросов или разбиваете глобальные переменные