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() на странице, они говорят, что это приводит к багам, хотя лично я ничего такого не замечал.

Миша Рудрастых

Впервые познакомился с WordPress в 2009 году. С 2014 года меня можно встретить на WordCamp — официальной конфе по WordPress, иногда там выступаю. Также в настоящее время веду курсы по WordPress в Epic Skills.

Если вам нужна помощь с вашим сайтом или может даже разработка с нуля — пишите мне.

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

  • serj:

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

    вот код --->

  • Roman:

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

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

    max_num_pages > 2 ) : ?>

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

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

  • Roman:

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

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

  • Roman:

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

  • Roman:

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

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

  • Роман:

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

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

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

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

    • Роман:

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

      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х статей, то система обрежет лишнее (

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

      • Миша:

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

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

        • Роман:

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

  • Роман:

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

    • Миша:

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

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

  • Алексей:

    Миша, это снова я.
    Напомню. На вордпрессе создана произвольная таксономия, сделана страница архива этой таксономии, скажем, 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();  ?>

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

    • Миша:

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

      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>';
      • Алексей:

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

        <?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 );
        ?>

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

  • Дмитрий:

    Привет, Михаил. Дублирую из скайпа вопрос:

    В купленной мной теме есть файл портфолио, которое выводит все записи из избранной рубрики. Так же в нем организован фильтр, который переключает записи по подрубрикам для удобства. Это портфолио я приспособил под каталог. Изначально было предусмотрен вывод 60 записей в виде плитки по три в ряд, что вполне смотрибельно. Но в моем каталоге около 200 записей, так что страница долго загружается и имеет длинную прокрутку.

    Я пытался сделать пагинацию посредством wp-pagenavi но ничего не вышло - я не программист. Вероятно, требуется внести более серьезные изменения в код, чем я предполагал.

    Так что сейчас задача такая:

    Сделать пагинацию, чтобы "все записи", которые выводятся при загрузке портфолио, были разбиты, скажем по 18 штук с постраничной навигацией, хотелось бы, чтобы навигация была и в отфильтрованных подкатегориях, если количество записей в них больше 18.

    Сам код ниже.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    
    <!--?php $titan = TitanFramework::getInstance( 'gpress' );?-->
    <div id="7" class="gp-home-container gp-light-bg  gp-clearfix">
    <div class="gp-home-container-inner gp-clearfix"><!-- end isotope-list --> <!--?php endif; ?--></div>
    <!-- end home-container-inner --></div>
    <!-- end home-container --> <!--?php $titan = TitanFramework::getInstance( 'gpress' );?-->
    <div id="7" class="gp-home-container gp-light-bg  gp-clearfix">
    <div class="gp-home-container-inner gp-clearfix">
    <div class="item-action-icons"> <?php $titan = TitanFramework::getInstance( 'gpress' );?></div>
    </div>
    </div>
    <div id="7" class="gp-home-container gp-light-bg gp-clearfix">
     
    <div class="gp-home-container-inner gp-clearfix">
     
    <div class="gp-home-container-title">
     
    <h2><?php echo $titan->getOption( 'filter-title' ); ?></h2>
     
    <span><?php echo $titan->getOption( 'filter-subtitle' ); ?></span>
     
    </div><!-- end home-container title -->
    <ul id="filters" class="gp-clearfix">
     
    <li>Фильтр: </li>
     
    <li><a href="#" data-filter="*" class="selected"><?php _e('Все', 'gpress'); ?></a></li>
     
    <?php
     
    $terms = get_terms('category', array('parent' => $titan->getOption( 'filter-cat' )));
     
    $count = count($terms);
     
    if ( $count > 0 ){
     
    foreach ( $terms as $term ) {
     
    echo "<li><a href='#' data-filter='.".$term->slug."'>" . $term->name . "</a></li>\n";
     
    }
     
    }
     
    ?>
     
    </ul>
     
    <?php
     
    $terms_ID_array = array();
     
    foreach ($terms as $term)
     
    {
     
    $terms_ID_array[] = $term->term_id;
     
    }
     
    $terms_ID_string = implode(',', $terms_ID_array);
    $the_query = new WP_Query( 'posts_per_page=30&cat='.$terms_ID_string );
     
    ?>
     
    <?php if ( $the_query->have_posts() ) : ?>
     
    <div id="isotope-list">
     
    <?php while ( $the_query->have_posts() ) : $the_query->the_post();
     
    $termsArray = get_the_terms( $post->ID, "category" );
     
    $termsString = "";
     
    foreach ( $termsArray as $term ) {
     
    $termsString .= $term->slug.' ';
     
    }
    ?>
     
    <div class="<?php echo $termsString; ?> filter-block grid-item">
     
    <div class="item-wrap">
     
    <?php
     
    $thumb = get_post_thumbnail_id();
     
    $img_url = wp_get_attachment_url( $thumb,'full' );
     
    $image = aq_resize( $img_url, 400, 400, true, true, true );
     
    ?>
     
    <?php if($image) : ?><img src="<?php echo $image ?>" alt="<?php the_title(); ?>"><?php endif; ?>
     
    </div> <!-- end item-wrap -->
     
    <div class="item-inner">
     
    <h2><?php the_title(); ?></h2>
     
    </div><!-- end item inner -->
     
    <div class="item-action-icons">
     
    <?php if($image) : ?> <a rel="lightbox" href="<?php echo $img_url ?>"><i class="fa fa-arrows-alt" aria-hidden="true"></i></a><?php endif; ?>
     
    <a href="<?php the_permalink() ?>"><i class="fa fa-link" aria-hidden="true"></i></a>
     
    </div>
     
    </div> <!-- end item -->
     
    <?php endwhile; ?>
    </div> <!-- end isotope-list -->
     
    <?php endif; ?>
     
    </div><!-- end home-container-inner -->
     
    </div><!-- end home-container -->

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

phpjsHTMLCSSSQLПросто код
  Комментарии закрыты.