query_posts() — модификация основного цикла

Когда я писал про циклы, я говорил, что если хотите как-то «по-особому» вывести записи, например в случайном порядке, используйте query_posts().

Итак, query_posts() видоизменяет основной цикл WordPress, то есть, если раньше на главной показывались последние 10 записей с блога, то теперь там может показываться что угодно и сколько угодно.

query_posts( $query )
$query
(строка|массив) все параметры такие же, как и у WP_Query()

Обычные примеры

Этот код выведет заголовки всех записей из рубрики с id=22:

query_posts("cat=22");
while (have_posts()) : the_post();
	echo'<p>'; the_title(); echo'</p>';
endwhile;
wp_reset_query();

Как и в случае с wp_list_categories(), параметры можно указывать в скобках, а можно выносить в отдельную переменную-массив (кстати, советую использовать именно двойные кавычки, как в примере).

Выводим записи из всех рубрик кроме id=1 и id=4:

query_posts("cat=-1,-4");

Выводим записи, опубликованные в текущем месяце.

$curr_year = date('Y'); // текущий год
$curr_month = date('m'); // текущий месяц
query_posts("year=$curr_year&monthnum=$curr_month");

Записи из рубрики с id=2, опубликованные в текущем месяце и отсортированные по заголовкам (в алфавитном порядке) по возрастанию:

$args = array(
	'cat'      => 2,
	'year'     => $curr_year,
	'monthnum' => $curr_month,
	'orderby'  => 'title',
	'order'    => 'ASC'
);
query_posts($args);

Примеры с модификацией основного цикла страницы

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

Сортируем посты на странице по имени:

global $query_string; // глобальные параметры в виде строки
query_posts( $query_string . '&orderby=name' ); // делаем сортировку постов по имени, объединив параметры

Тот же самый пример, но только через массивы:

global $wp_query; // глобальные параметры, которые уже стоят по умолчанию на странице
$args = array_merge( $wp_query->query_vars, array( 'orderby' => 'name' ) ); // добавляем к ним сортировку по имени
query_posts( $args );

Вы наверное понимаете, что таким образом можно вытворять всё, что угодно, например сортировать товары по цене (и по возрастанию и по убыванию).

P.S. в самой документации WordPress не рекомендуется использовать несколько query_posts() на странице, они говорят, что это приводит к багам, хотя лично я ничего такого не замечал.

Комментарии 23

  • serj16 ноября 2012 в 22:11 #

    Привет Миша! Помоги решить задачу.
    На главную нужно вывести из трех кат.(например с id=123,320,405) по три записи(c id=234,345,677), как осуществить, что удалить может. Спасибо.

    вот код --->

  • Roman4 августа 2014 в 21:08 #

    Здравствуйте.
    Собственно, ситуация следующая.
    На главной странице использую плагин для пагинации — PageNavi, все работает корректно.
    Сейчас создал свою страницу для одной из категорий, и решил подключить стандартную пагинацию, т.к. шаблоны страниц слегка отличаются.

    Использовал код —

    max_num_pages > 2 ) : ?>

    На сайте ограничение стоит на 10 записей, всего в базе — 12.
    Пагинация выводит три номера страницы и дублирует одни и те же записи.

    В чем может заключаться проблема?

    • Миша5 августа 2014 в 07:08 #

      Добрый день!
      Если у вас в настройках сайта стоит 10 записей, а выводится другое количество, это значит, что в цикле параметр posts_per_page переопределяется, вам нужно найти где.

  • Roman5 августа 2014 в 09:08 #

    Спасибо большое! Нашел, где идет перераспределение) Одна лишняя страница исчезла, но осталась ещё одна, которая дублирует записи на предыдущей странице.
    В базе - 12 записей, она дубликатом выдает 20.

    Какой здесь подвох? Безумно буду благодарен за совет!)

  • Roman5 августа 2014 в 09:08 #

    Может как-то циклом задать, что если нет постов, не дублировать предыдущие записи?

  • Roman5 августа 2014 в 17:08 #

    Проблема найдена! И она крылась намного глубже)) Дело даже не в posts_per_page, как оказалось, wp_query был лишним и вызывал сбой в работе.

    Михаил, огромное Вам спасибо за наводку. И огромное спасибо за ресурс и статьи!

  • Роман24 ноября 2015 в 01:11 #

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

    <?php if (is_category('club')): {query_posts('category_name=club&showposts=4&orderby=date');} ?>

    // далее идёт цикл

    сама навигация отображается, но при клике на ссылку второй страницы вижу 404 (
    есть решение?

    • Роман24 ноября 2015 в 03:11 #

      сам спросил и сам отвечу )
      временно вопрос решил через функцию:

      function club_post_queries( $query ) {
        if (!is_admin() && $query->is_main_query()){
          if(is_category('club')){
            $query->set('posts_per_page', 4);
          }
        }
      }
      add_action( 'pre_get_posts', 'club_post_queries' );

      но глобально вопрос остался
      если будет опубликовано больше 4х статей, то система обрежет лишнее (

      появилась мысль сделать выборку по дате.
      т.е. выводить на странице посты за одну дату как в архивах, а пагинация должна перебрасывать на следующую страницу с постами у которых общая дата
      как это возможно?

      • Миша24 ноября 2015 в 08:11 #

        но глобально вопрос остался
        если будет опубликовано больше 4х статей, то система обрежет лишнее (

        Разве?
        По-моему вы уже нашли решение через pre_get_posts ?

        • Роман24 ноября 2015 в 16:11 #

          у меня материал публикуется блоками, по несколько постов. они могут публиковаться как сразу в один день так и за пару тройку дней. задача разделить навигацию по дням, но дни идут не подряд. т.е. сегодня и завтра я опубликовал 4 материала и это один блок, а через две недели ещё 5 и это второй блок. мне нужно чтобы в одном блоке показывался весь материал и при этом между ними работала постраничная навигация

          • Миша25 ноября 2015 в 08:11 #

            Разделить по дням? А почему не используете архивы по дням?
            Например http://сайт/2015/02/18 ?

            • Роман25 ноября 2015 в 12:11 #

              на сайте уже есть много другого материала, у которого своя структура.
              дни идут не подряд и материал может быть выложен не сразу в один день.
              как оно будет всё это переваривать?
              пока через кастыли вопрос решил.

  • Роман23 января 2016 в 20:01 #

    Добрый вечер, я вот в wpmag прочитал что query_posts нежелательно использовать т.к. она заменяет основной цикл и что вроде могут быть ошибки. Могут быть с этой функцией проблемы?

    • Миша24 января 2016 в 11:01 #

      Добрый вечер!
      По сути с любой функцией могут :) Что касается query_posts(), то просто следует знать, где её нужно использовать, а где нет.

      Если вы скажите, для каких целей вы хотите её задействовать, я могу вам подсказать — нужно или нет :)

  • Алексей6 мая 2016 в 16:05 #

    Миша, это снова я.
    Напомню. На вордпрессе создана произвольная таксономия, сделана страница архива этой таксономии, скажем, taxonomy-nane.php.
    Нужно написать код, который сделает так, чтобы на странице архива не выводились ссылки на посты, принадлежащие дочерним таксономиям (подтаксономиям).
    мне вот тут посоветовали вот так код построить:
    сначала вот это:

    <?php $the_query = new WP_Query( $args );  
    $args = array(   
    'child_of'     => 0,   
    'parent'       => ''  
    )   
    ?>
    <?php while ($the_query->have_posts()) : $the_query->the_posts();   ?>

    потом тайтлы, контенты
    а потом вот это

    <?php endwhile; ?>
    <?php wp_reset_postdata();  ?>

    куда я только это не втыкал. либо белая страница, либо без результата.
    что-же не так то...

    • Миша7 мая 2016 в 08:05 #

      Окей, по порядку.

      1. query_posts().
      Нужен именно он. В самом начале файла:

      global $wp_query;
      $taxonomy_slug = get_query_var('term');
      $taxonomy = get_query_var('taxonomy');
       
      $args = array_merge( $wp_query->query_vars, array( 'tax_query', array(array(  'taxonomy' => $taxonomy, 'field' => 'slug', 'terms' => array( $taxonomy_slug ), 'include_children' => false ) ) ) ); 
      query_posts( $args );

      2. get_terms()

      $term = get_term_by( 'slug', $taxonomy_slug, $taxonomy );
      $term_id = $term->term_id;
       
      $children = get_terms($taxonomy, array( 'child_of' => $term_id ) ); 
       
      echo '<ul>';
      foreach ($children as $term){
      	echo "<li>{$term->name} ({$term->count})</li>";
      }
      echo '</ul>';
      • Алексей7 мая 2016 в 12:05 #

        вероятно, я не знаю каких-то основ, но я пишу вот это

        <?php 
        global $wp_query;
        $taxonomy_slug = get_query_var('term');
        $taxonomy = get_query_var('taxonomy');
         
        $args = array_merge( $wp_query->query_vars, array( 'tax_query', array(array(  'taxonomy' => $taxonomy, 'field' => 'slug', 'terms' => array( $taxonomy_slug ), 'include_children' => false ) ) ) ); 
        query_posts( $args );
        ?>

        И результата нет
        Когда вставляю второй код - он мне выводит то, что у меня уже с Вашей помощью сделано - подтаксономию.
        Но ссылки выводятся на все записи, не исключая дочерние

        • Миша10 мая 2016 в 14:05 #

          Через обычный while ?

          • Алексей10 мая 2016 в 14:05 #

            Миша, к сожалению, не могу сказать, так как не знаю, что это такое.
            Факт в том, что сделал то, что хотел с помощью одного программиста. Ваши подсказки я ему тоже показывал.

Оставить комментарий / вопрос

phpjsHTMLCSSSQLПросто код
  Для того, чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или авторизуйтесь на сайте.
Получайте новости блога по email или следите за мной в социальных сетях.
  • alex morozov: Ура, спасибо! Все-таки я разобрался ! Сделал:

  • alex morozov: Сделал Класс добаляется даже если поле пустое

  • Vladislav: Лучше бы посоветовали изящное решение имеющейся проблемы.

  • alex morozov: Не очень понял. Я добавляю метабокс через класс, почти как у вас. class Desc_Meta_Box { private $screens = array(...

  • Миша: Метод тыка хорош, но оснвоы нужно знать в любом случае. Рекомендую почитать это.