WordPress query posts


Как упоминалось ранее, если и есть одна вещь, которую нужно понимать для того, чтобы быть реально крутым перцем-разработчиком шаблонов, так это как работает цикл и что вы можете с ним делать. Давайте посвятим наше внимание трем способам заставить WordPress Loop делать все, что нам угодно.

query_posts() https://codex.wordpress.org/Template_Tags/get_posts

Если вы работаете с одиночным циклом записей и просто хотите модифицировать тип записей, которые он возвращает, используйте query_posts(). Это идеально для ограничения количества записей, исключения записей из определенной рубрики и т.д..

WP_Query() https://codex.wordpress.org/Functi on_Reference/WP_Query Для мощной настройки множественных циклов, используйте WP_Query(). Настройкой дополнительных экземпляров WP_Query() в вашем шаблоне можно создать любое количество множественных циклов и настроить вывод каждого из них.

get_posts() https://codex.wordpress.org/Template_Tags/get_posts

Последний, но не худший, get_posts() – позволяет создать дополнительные циклы где угодно в шаблоне. get_posts() принимает те же параметры, что и query_posts() и идеален для вывода дополнительных циклов в сайдбаре, футере или где угодно.

Разберемся с ними подробнее.

Настраиваем query_posts()

Типичный цикл по умолчанию выглядит вот так:

  

<?php // The WordPress Loop if (have_posts()) : while (have_posts()) : the_post(); ... endwhile; else: ... endif; ?>

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

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

 <?php query_posts('cat=-9'); // исключаем категорию с ID = 9 if (have_posts()) : while (have_posts()) : the_post(); ... endwhile; else: ... endif; ?>

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

 <?php  global $query_string;  $posts = query_posts($query_string.'&cat=-9'); if (have_posts()) : while (have_posts()) : the_post(); ... endwhile; else: ... endif; wp_reset_query(); ?>  

Тег wp_reset_query восстанавливает оригинальный запрос query_posts и используется при применении в шаблонах нескольких последовательных циклов.

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

$posts = query_posts($query_string.'&cat=-7,-8,-9&posts_per_page=3&order=ASC');

что значит вывести 3 записи, исключив 7,8,9 категории и отсортировать записи по алфавиту.

Ключ к успешному использованию query_posts заключается в сохранении оригинального формата запроса с помощью $query_string переменных. Будучи однажды подключенными, можно добавить столько параметров, сколько нужно (подробнее тут https://codex.wordpress.org/Function_Reference/WP_Query#Parameters ).

Этот способ хорош, но не лишен недостатков. query_posts использует дополнительные запросы к базе данных и может повлиять на работоспособность других условных тегов, таких как is_page() и is_ single(). Поэтому рекомендуется не использовать этот способ, хотя он и работоспособен, а заменить его на WP_Query с которым точно проблем не будет.

Настраиваем WP_Query

Для полного контроля над любым количеством циклов, WP_Query – самый лучший способ. Если нужно модифицировать дефолтовый цикл, то это выглядит очень похоже на query_posts:

 <?php // The WordPress Loop - customized with WP_Query $custom_query = new WP_Query('cat=-9');  while($custom_query->have_posts()) : $custom_query->the_post(); ... endwhile; wp_reset_postdata(); // reset the query ?>  

Применяются те же параметры, что и для query_posts, поэтому для модификации числа постов, используемыхисключаемых рубрик, порядка сортировки делается все то же самое.

 $custom_query = new WP_Query('cat=-7,-8,-9'); // исключить категории $custom_query = new WP_Query('posts_per_page=3'); // ограничить количество $custom_query = new WP_Query('order=ASC'); // порядок сортировки

А также любые нужные комбинации

 $custom_query = new WP_Query('cat=-7,-8,-9&posts_per_page=3&order=ASC');

В дополнение к сферам применения, мы также можем создавать и настраивать дополнительные множественные циклы, вот типовой пример:

Каждый из этих циклов может быть размещен в любом месте шаблона, не нужно вписывать их последовательно. Например, первый цикл может быть в сайдбаре, второй в футере и т.д.. И каждый выводит свои собственные списки записей, в соответствии с параметрами.

При желании можно комбинировать вместе 3 разных способа query_posts , get_posts и WP_Query в множественных циклах. А в версии вордпресса 3.3 появилась функция is_main_query, позволяющая модифицировать только главные объекты в WP_Query, подробнее на https://codex.wordpress .org/Functi on_Reference/i s_main_query

Настраиваем get_posts

Самый легкий и безопасный способ создать множественные циклы, это get_posts. Просто добавляете в нужном месте шаблона

Этот код создает циклы всех постов за исключением указанной рубрики. Конечно, исключение рубрик не единственный способ применения циклов. Опять же, используя различные параметры можно получить любой нужный результат.

Но есть один момент, get_posts требует передачи параметров в виде массива, т.е.

Также обратите внимание, что мы используем numberposts вместо posts_per_page для ограничения количества записей. В соответствии с кодексом WP параметр posts_per_page все же должен работать, но если нет — то замените его на numberposts.

Стандартный цикл, а также модифицированные с помощью query_posts и WP_Query поддерживают постраничную навигацию, используя next_posts_link и previous_posts_link, а вот get_posts не поддерживает ее, отображая статический список постов, соответствующих выбранному критерию и все.

Подытожим:

  • Чтобы модифицировать стандартный цикл, используйте query_posts()
  • Чтобы модифицировать иили создать множественные циклы, используйте WP_Query()
  • Чтобы создать статический, дополнительный цикл, используйте get_posts()

Цикл не беспокоится о разметке

Это правда. Можно использовать все, что нам в голову придет. Вот пример типового цикла, закрытого в тег <div>

И вот точно такой же цикл, оформленный в стиле нумерованного списка

А вот пример списка определений

Обратите внимание, что не только разметка отличается в этих трех примерах, но и используемые функции разные. Например, в третьем случае использовался the_excerpt() для вывода цитат вместо контента.

По умолчанию the_excerpt() выводит первые 55 слов записи, если не задано поле цитата записи. Поэтому для постов длиной меньше 55 слов будет выведено полное содержание, более 55 слов – только часть.

Мораль такая — циклы WordPress очень удобная, гибкая и мощная штука — вы можете как угодно применять их и где угодно размещать.

Мощь WP_Query

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

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

Как и в предыдущих примерах, изменением параметров в новом WP_Query вы легко настраиваете вывод любого набора записей. Давайте подробно разберем наиболее типичные способы применения.

Отображение разного количества записей

Глобальная настройка количества отображаемых постов настраивается в админке, но мы можем менять это значение прямо в цикле. Например, так мы задаем свое значение вместо значения по умолчанию.

Таким образом мы ограничим количество выводимых постов шестью, вместо десяти (значение по умолчанию). Чтобы вывести абсолютно все записи, нужно указать параметр равный «-1».

Исключаем некоторые категории

Одна из самых популярных задач – исключение записей определенной категории на главной странице сайта. Например, у вас есть несколько записей про хомячков, но вы хотели бы убрать их с главной страницы сайта. Этот контент остается в базе данных, отображается в своей рубрике и RSS ленте, но только не на главной. Есть множество способов сделать это, но мы применим самое простое из решений…да, это WP_Query class:

В общих случаях, знак минус означает исключить данный параметр.

Поэтому мы исключили третью рубрику (про хомячков).                                                   

Другие возможности исключить содержимое этой рубрики — использовать php функцию continue и пропускать записи определенной категории, скрывать контент с помощью css и javascript, править файлы ядра вордпресс и использовать плагины. Согласитесь, WP_Query однозначно лучше.

Изменяем порядок сортировки

WordPress относится к приложениям LIFO типа — last in, first out, т.е. последний пришел, первый вышел. Что означает, что мы видим сначала свеже опубликованные записи, а старички спрятаны глубоко в недрах навигации. Это рационально, т.к. большинство блоговых сайтов стремится первым показать самый свежий контент. Это дает людям смысл периодически возвращаться на сайт, т.к. они смогут найти что-то новенькое прямо на первой странице сайта. Но это не идеальный вариант для каждого типа сайтов.

Допустим, вы используете вордпресс для того, чтобы публиковать свой роман. Это означает, что вы писали и публиковали его хронологически, главу за главой. Поэтому, когда посетители приходят на ваш сайт, вы хотите показать им сначала главу Один, но она является фактически самой старой записью, поэтому вместо этого они увидят самую последнюю опубликованную главу. Но нет проблем, всего навсего изменим порядок сортировки:

Покажем специфические страницы, встраивая страницу в страницу

Другой интересный и полезный цикл, это использовать новый WP_Query class для отображения только одной определенной страницы. Это может быть полезно из разных соображений, например, для встраивания одной страницы в другую. Вот пример запроса, когда содержимое страницы About встраивается в другую страницу:

Обратите внимание, что в pagename нужно использовать не реальное название страницы, а ее слаг.

Пример использования множественных циклов

Ничто не заставляет вас ограничиваться только одним циклом. Вы можете использовать ровно столько, сколько вам нужно. Фактически, это в целом нормально иметь множественные циклы в шаблоне. Простым примером будет главная страница, которая показывает полное содержание трех новых публикаций. А затем в сайдбаре, в втором цикле показывает выдержки из остальных семи публикаций. И все работает чудесным образом.

А вот пример более сложной реализации. Допустим, у нас есть милый четырех колоночный шаблон. В левом сайдбаре мы покажем выдержки из одной категории. Затем в главной центральной части, разбитой на две колонки, мы покажем 10 последних записей по 5 в каждой. И затем в правом сайдбаре, мы покажем еще 10 записей, идущих после первых десяти.

Таким образом у нас получается 4 цикла

1 — Левый сайдбар 2 — Левая колонка 3 — Правая колонка 4 — Правый сайдбар

new WP_Query( 'cat=7&showposts=3');

3 последние записи из рубрики номер 7

new WP_Query( 'cat=-7&showposts=5');

5 последних записей, кроме из рубрики номер 7

new WP_Query( 'cat=-7&showposts=5 &offset=5');

еще 5 последних записей, кроме из рубрики номер 7

new WP_Query( 'cat=-7&showposts=10 &offset=10');

еще 10 последних записей, кроме из рубрики номер 7

которые будут находиться в index.php, но также разместить их можно будет где угодно еще.

Теперь необходимо разобраться с используемыми параметрами, которые помогают отображать именно то, что нам нужно.

Параметр cat

  • Цикл 1 — отображает записи только из 7 рубрики (cat=7)
  • Цикл 2 — отображает записи кроме 7 рубрики (cat=-7)
  • Цикл 3 — отображает записи кроме 7 рубрики (cat=-7)
  • Цикл 4 — отображает записи кроме 7 рубрики (cat=-7)

Параметр showposts

  • Цикл 1 — отображает только 3 записи (showposts=3)
  • Цикл 2 — отображает только 5 записей (showposts=5)
  • Цикл 3 — отображает только 5 записей (showposts=5)
  • Цикл 4 — отображает только 10 записей (showposts=10)

Параметр offset

  • Цикл 1 — не используется Цикл 2 — не используется
  • Цикл 3 — пропускает первые 5 записей (offset=5)
  • Цикл 4 — пропускает первые 10 записей (offset=10)

Таким образом, каждый цикл модифицирован для отображения желаемых записей. Последнее, что останется рассмотреть, это нужна ли нам навигация в одном из этих циклов. В обычных циклах по умолчанию мы используем теги posts_nav_link() для вывода навигационных ссылок на главную, рубрики и архивы.

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

Цикл 1 — Левый сайдбар

Отображает 3 кратких записи.

Цикл 2 — Левая колонка

Отображает 5 полных записей, а после них выводит ссылки на следующие и предыдущие записи.

Цикл 3 — Правая колонка

Цикл 4 — правый сайдбар

Отображает 10 полных записей.

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

iwsm.ru

Несколько примеров использования query_posts
Бывают случаи когда на главную (или какую нибудь другую) страницу нужно вывести записи только из определенной категории, или вообще только определенные записи. Для этого в WordPress и существует query_posts.

Теперь немножко подробнее — для вывода записей в WordPress используется цикл, называемый «The Loop». Обычно он выглядит так:

Если перед циклом «The Loop» поставить функцию query_posts с нужными нам параметрами, то мы добьемся нужного нам результата. Вот пример такого использования:

Такой код выведет на главную записи из всех категорий кроме категорий с ID 1, 2 и 3.

Ниже преведены еще несколько примеров использования query_posts:
query_posts(‘cat=-3’) — Не показывать категорию id которой равно 3;
query_posts(‘cat=-1,-2,-3’) — Не показывать категории, id которых равны 1, 2 и 3;
query_posts(‘cat=2,6,17’) — Вывести категории с id равным 2, 6 и 17;
query_posts(‘category_name=WordPress’) — Вывести категорию с названием “WordPress”;
query_posts(‘name=Hello World’) — Вывести один пост с названием “Hello World”;
query_posts(‘p=5’) — Вывести один пост, id которого равно 5;
query_posts(‘page_id=7’) — Вывести страницу id которой равно 7;
query_posts(‘pagename=about’) — Вывести страницу с названием “about”;
query_posts(‘cat=18&showposts=5’) — Вывести 5 постов из категории с id=18;
query_posts(‘cat=3&orderby=date&order=ASC’) — Вывести посты из категории id которой равно 3, сортировать по дате в хронологическом порядке(DESC — в обратном порядке);
query_posts(‘posts_per_page=10’) — Вывести 10 постов на страницу (при значении -1 выводит все посты);
query_posts(‘cat=3&year=2008’) — Вывести посты из категории с id=3 за 2008 год;
query_posts(‘orderby=rand&showposts=3&cat=3’) — выводин рандомно, т.е. случайно 3 записи из 3 категории;
query_posts(‘orderby=rand&showposts=3’) — выводит случайно 3 записи из всех категорий;
query_posts(‘meta_key=cars&meta_value=volvo’) — выводит список постов с произвольным полем “cars” и значением этого поля volvo.

Если возникнут какие нибудь вопросы, то обязательно спрашивайте ?

Подробное описание функции query_posts смотрите здесь.

www.wp-info.ru

Плагин Different Posts Per Page

Начтем с плагина. На официальном сайте вордпресс он называется cbnet Different Posts Per Page и выполняет единственное действие как раз нужно нам – вывод разного числа постов на страницах категорий, архивов, тегов, главной и многих других. При этом вы можете задавать порядок сортировки при выводе – в сторону уменьшения или увеличения. Круто? – да, возможно, хотя меня лично не сильно впечатляет, и дальше вы поймете почему. Единственная особенность плагина Different Posts Per Page, которая кажется интересной, — возможность вывода различного количества постов для разных категорий.

Итак, для установки плагина Different Posts Per Page нужно скачать архив с официального сайта, разархивировать и залить на ФТП блога в директорию /wp-content/plugins/. Далее в админке WordPress находим модуль и активируем его. После это в меню появится новый пункт для управления настройками.

Wordpress query posts

Здесь найдете некоторые настройки установленные по умолчанию – для главной страницы, категорий, архивов, тегов и поиска. Чуть ниже есть блок для добавления дополнительных параметров. В первом пункте есть на выбор достаточно много опций – страницы авторов, по дате, времени и т.п. Во втором вы можете выбрать конкретную категорию блога для ограничения, что достаточно интересно.

Использование WP_Query

Почему я говорил, что меня плагин не очень впечатлил. В принципе, все эти хитрые хаки вы можете выполнить самостоятельно через правку файлов шаблона. Недавно я рассказывал в блоге про wordpress цикл (loop), где упоминал также функцию запроса к базе данных query_posts, с помощью которой можно задавать некоторые параметры выборки постов блога. В общем, суть метода – для различных файлов шаблона index.php и archive.php в query_posts нужно добавить требуемое число постов через переменную showposts.

Например, находите в файле index.php код, который делает выборку постов

или запись покороче:

После чего заменяете это все на строки:

Теперь на главной вы получите вывод 3-х постов, а на остальных страницах будет работать параметр, заданный в настройках блога.

Нюансы WP_Query и плагина Different Posts Per Page

Вообще лично у меня была задача сделать вывод на главной странице блога по 3 поста, на остальных по 5. Проблема реализации через WP_Query заключалась в навигации. Дело в том, что разбиение по 3 поста касалось не только главной страницы, а и все остальных страниц, куда бы вы переходили по ссылкам в навигации на главной (они тоже считаются как home).

Wordpress query posts

А это не сильно хорошо соответствовало дизайну. Кстати, если кто-то знает как решить эту проблему с помощью WP_Query пишите в комментариях. Чего я лично только не пробовал, начинался много документации с официального сайта, но до финального результата, увы, так и не дошел. Можно, конечно, отказаться от правки кода и воспользоваться плагином Different Posts Per Page, который представляет выход из этой ситуации. Кроме настроек по умолчанию вы можете добавить некоторые другие «состояния», в том числе и когда пользователь переходит по страницам (Paged). Поэтому я указал для главной (Home) отображение 3  постов, а для любых страниц (Paged) – по 5 (смотрим рисунок 1). Как раз то, что мне и нужно было.

Единственное плагин неправильно считает количество страниц при этом. То есть у меня, например 14 постов, по 3 на страницу для главной и по 5 на остальные. Так вот на главной выводится навигация с 5 страницами – 1,2,3,4,5. Но физически 4 и 5ой не существует, потому что мы выбрали вывод по 5 на всех paged. В общем, тоже вроде бы не совсем красивое решение ссылаться на пустые страницы, которые попадут в индекс, проще вообще убрать навигацию с главной.

P.S. Постовой. Пассажирские перевозки: аренда и заказ микроавтобусов москва — отличное обслуживание.

wordpressinside.ru

1. WP_Query PHP код для вывода записей в КАТЕГОРИЯХ

Самый простой вывод постов, исключающий записи из конкретных категорий. Использую его для вывода на главной странице через index.php или home.php.

Также этот код занесен у меня в файл empty.php. Он нужен на тот случай, если человек зашел в категорию, где не должно быть никаких записей, там не будет ничего выводиться, кроме сообщения, что он не должен был попасть на эту страницу (раздел). И предлагаются инструменты для поиска на сайте.

Иногда в код, который выводит все статьи, но исключает определенные рубрики, требуется добавить пагинацию (&paged=’.$paged;), чтобы в последний страницах навигации не было пустых страниц.

В коде ниже выводятся записи с сортировкой по произвольному полю с ДАТОЙ. Выводятся записи с произвольным полем год, затем сортируются от последнего года к предыдущему.

2. WP_Query PHP код для вывода постов в КАТЕГОРИИ с БЮДЖЕТОМ

Следующий вывод WP_Query выводит, в категориях WordPress записи, по произвольному полю «Бюджет». В этом поле находятся цифровые значения.

Допустим требуется вывести в категории «Бюджет» все записи, которые будут сортироваться от большей цифры к меньшей.

3. WP_Query PHP код для вывода постов в разделе РЕЙТИНГ

Нижеследующий код выводит все статьи с произвольным полем год, сортируя по этому произвольному полю (от последнего года, до меньшего). Одновременно с этим исключает все записи из категорий меньше значения рейтинга 9.

4. WP_Query PHP код для вывода постов в КАТЕГОРИИ с ДАТОЙ

В php коде ниже вводятся две переменные с ДАТАМИ. Текущая дата сравнивается с датой, которая будет в будущем.

Для чего это нужно? Например, я хочу вывести ТОВАРЫ, которые только поступят в продажу или ФИЛЬМЫ, которые только выйдут в ближайшем будущем. Если, например, такие ТОВАРЫ или ФИЛЬМЫ или ЧТО-ТО другое существует, то следует вывести ЗАПИСИ с этими произвольными полям. В противном случае в категории ничего не будет выводиться.

5. WP_Query PHP код для вывода записей в разделе ТЕГОВ

Вывод записей в тегах, в отличии от категорий, немного другой. По какой-то причине, в тегах не работает функция исключающая категории из WP_Query:

К счастью, работает другая структура:

И код вывода $wp_query для тегов будет такой:

6. WP_Query PHP код для вывода записей в разделе ПОИСКА

Для вывода WP_Query на странице поиска используем совершенно иной код:

Для специальной обработки запроса WP_Query в файле search.php добавляем в файл functions.php своей темы следующий код:

Он сортирует записи в категории ПОИСК по произвольному полю ГОДЫ.

В заключение. Очень важно.

После любого из перечисленных выше кодов (кроме того что в functions.php) нужно вывести следующую функцию:

Обязательная нужна такая конструкция:

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

7. Код для главной страницы (раздела) для вывода и РАЗДЕЛЕНИЯ записей по ТЕГАМ

Следующая конструкция выводит записи из категории 27. Сортирует их случайно. Выводит 4 записи.

В конструкции выше код отвечающий за вывод поста находится в отдельном файле:

8. PHP для вывода и РАЗДЕЛЕНИЯ записей по РАЗДЕЛАМ

Тот же самый код, но для вывода записей из РАЗДЕЛОВ, а не ТЕГОВ. Значения вывода ($args) изменены на другие. В том числе учтена пагинация (&paged=’.$paged;), в конструкции выше она исключена из работы.

9. Выводим один конкретный пост

Типовые конструкции для вывода одного определенного поста. В данном случае будет выведен пост с номером 1. Под конец wp_reset_postdata сбрасывает вывод WP_Query, так что можно выводить и любые другие посты.

10. Вывод записей с незаполненным произвольным полем

Можно вывести записи с пустым значением в конкретном произвольном поле. Иногда такой способ помогает найти все записи с незаполненными значениями. Как альтернатива поиска данных через MySQL.

11. Выводим одну конкретную страницу

В заключение как можно вывести вместо записи содержимое страницы. Выводим страницу с ID 130:

ploshadka.net

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

Многие сталкиваются с проблемой пагинации на query_posts. В стандартном ее виде, она не работает и все. Искал я долго решение и однажды благодаря всезнающему Гуглу, нашел.

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

Во второй строке задаем параметры query_posts: 3 записи на страницу и выводить только записи с 4 каталога. Меняйте все под себя, параметры query_posts, как я и писал, изучайте в прошлой статье.

Если Вам нужно вывести цикл на статической странице, то код будет немного другим, на две строки больше. Параметры query_posts меняйте в четвертой строке.

В итоге, для первого варианта(для второго по сути то же самое) у меня код получился примерно такого вида:

В 10 строке функция постраничной навигации без плагина, о которой можете прочитать в статье — Постраничная навигация в WordPress без плагина.

Ко мне обратился читатель блога и сообщил, что метод не работает. Я проверил его код и обнаружил, что ошибка была через плагин WP-PageNavi. Так что лучше используйте навигацию из моей статьи.

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

На этом все, спасибо за внимание. ?

gnatkovsky.com.ua

Тема для данной заметки навеяна проблемой, возникшей при переносе одного из блогов на VPS сервер. После переноса отказался работать плагин Advanced Category Excluder, который позволял отключить вывод постов из отдельной категории (или группы категория) в требуемых разделах блога, например, на главной странице или в архивах. В итоге, на главной оказались те публикации, которых там быть не должно. Более того, в общую ленту вылезли ревизии, картинки и файлы. В общем, все, что пишется в таблицу wp_posts, повалило в продакшен. Судя по всему, плагин отказывался работать на более новой версии PHP, хотя это более, чем странно. Выяснять истинные причины я выяснять не стал, так как разбираться в чужом коде не было желания, а просто поискал замену. Альтернатив оказалось не так много и все они показались мне совершенно неудобными в использовании. Было решено обойтись без плагина в принципе.

Я думаю, что решение достаточно верное, так как плагин Advanced Category Excluder не добавляет к движку ничего нового, а служит лишь оберткой для базовых функций WordPress, делающей работу с ними более комфортной.

У WordPress есть функция query_posts(), позволяющая переопределять стандартные запросы к базе данных, а следовательно, влиять на результаты выборки публикаций и страниц. Возможности ее очень богаты и можно без труда добиться практически любого результата.

Так, например, в предыдущей заметке я описывал процесс создания формы поиска и сортировок для каталога на WordPress, реализованного с помощью плагина Magic Fields. Желаемый эффект как раз достигался за счет использования query_posts(). Сегодня постараюсь развить тему.

Вызывать функцию query_posts() следует перед вызовом while (have_posts()). В качестве аргумента передается набор параметров, полным список которых, конечно же, можно найти в документации WordPress.

Так, например, чтобы добиться эффекта, который раньше создавался плагином Advanced Category Excluder, достаточно в индексном файле шаблона привести цикл вывода постов к следующему виду:

Такой вызов query_posts() исключает из выборки посты, принадлежашие к категории с ID равным 3.

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

Для этого достаточно ввести переменную $query_string в текущую область видимости и конкатенировать ее с нашими дополнительными условиями выборки:

Собственно, то, что делал плагин Advanced Category Excluder, я реализовал путем добавления одной единственной строчки кода.

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

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

Также есть возможность вывести посты по имени категории:

Выведет пост из блога, ID которого равен 5

Следующий запрос комбинирует сразу несколько условий. Он выведет 5 постов из категории с ID 7, сортированных по дате (в обратном порядке), опубликованных в 2011 году:

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

Официальная документация функции query_posts() находится в кодексе WordPress

omurashov.ru

Here at WordPress.com, we have over 200 themes (and even more plugins) running inside the biggest WordPress installation around (that we know of anyway!) With all of that code churning around our over 2,000 servers worldwide, there’s one particular WordPress function that we actually try to shy away from; query_posts()

If you think you need to use it, there is most likely a better approach. query_posts() doesn’t do what most of us probably think it does.

We think that it:

  • Resets the main query loop.
  • Resets the main post global.

But it actually:

  • Creates a new WP_Query object with whatever parameters you set.
  • Replaces the existing main query loop with a new one (that is no longer the main query)

Confused yet? It’s okay if you are, thousands of others are, too.

This is what query_posts actually looks like:

Rarely, if ever, should anyone need to do this. The most commonly used scenario is a theme that has featured posts that appear visually before the main content area. Below is a screen-grab of the iTheme2 theme for reference.

Wordpress query posts

The thing to keep in mind, is by the time the theme is starting to display the featured posts, WordPress has already:

  • looked at the URL…
  • parsed out what posts fit the pattern…
  • retrieved those posts from the database (or cache)…
  • Filled the $wp_query and $post globals in PHP.

Let’s think about it like this:
Wordpress query posts

The “Main Loop” consists of 3 globals, 2 of which actually matter.

  • $wp_the_query (does not matter)
  • $wp_query (matters)
  • $post (matters)

The reason $wp_the_query doesn’t matter is because you’ll *never* directly touch it, nor should you try. It’s designed to be the default main query regardless of how poisoned the $wp_query and $post globals might become.

Back to Featured Posts

When you want to query the database to get those featured posts, we all know it’s time to make a new WP_Query and loop through them, like so…

Great! Two queries, no conflicts; all is right in the world. You are remembering to use wp_reset_postdata(), right? ? If not, the reason you do it is because every new WP_Query replaces the $post global with whatever iteration of whatever loop you just ran. If you don’t reset it, you might end up with $post data from your featured posts query, in your main loop query. Yuck.

Remember query_posts()? Look at it again; it’s replacing $wp_query and not looking back to $wp_the_query to do it. Lame, right? It just takes whatever parameters you passed it and assumes it’s exactly what you want.

I’ll let you stew on that for a second; let’s keep going…

What if, after your featured-posts query is done and you’ve dumped out all your featured posts, you want to *exclude* any featured posts from your main loop?

Think about this…

It makes sense that you would want to use query_posts() and replace the main $wp_query loop, right? I mean, how else would you know what to exclude, if you didn’t run the featured posts query BEFORE the main loop query happened?

EXACTLY!

Paradox, and WordPress and WP_Query are designed to handle this extremely gracefully with an action called ‘pre_get_posts‘

Think of it as the way to convince WordPress that what it wants to do, maybe isn’t really what it wants to do. In our case, rather than querying for posts a THIRD time (main loop, featured posts, query_posts() to exclude) we can modify the main query ahead of time, exclude what we don’t want, and run the featured query as usual. Genius!

This is how we’re doing it now in the iTheme2 theme:

  /**   * Filter the home page posts, and remove any featured post ID's from it. Hooked   * onto the 'pre_get_posts' action, this changes the parameters of the query   * before it gets any posts.   *   * @global array $featured_post_id   * @param WP_Query $query   * @return WP_Query Possibly modified WP_query   */  function itheme2_home_posts( $query = false ) {    	// Bail if not home, not a query, not main query, or no featured posts  	if ( ! is_home() || ! is_a( $query, 'WP_Query' ) || ! $query->is_main_query() || ! itheme2_featuring_posts() )  		return;    	// Exclude featured posts from the main query  	$query->set( 'post__not_in', itheme2_featuring_posts() );    	// Note the we aren't returning anything.  	// 'pre_get_posts' is a byref action; we're modifying the query directly.  }  add_action( 'pre_get_posts', 'itheme2_home_posts' );    /**   * Test to see if any posts meet our conditions for featuring posts.   * Current conditions are:   *   * - sticky posts   * - with featured thumbnails   *   * We store the results of the loop in a transient, to prevent running this   * extra query on every page load. The results are an array of post ID's that   * match the result above. This gives us a quick way to loop through featured   * posts again later without needing to query additional times later.   */  function itheme2_featuring_posts() {  	if ( false === ( $featured_post_ids = get_transient( 'featured_post_ids' ) ) ) {    		// Proceed only if sticky posts exist.  		if ( get_option( 'sticky_posts' ) ) {    			$featured_args = array(  				'post__in' => get_option( 'sticky_posts' ),  				'post_status' => 'publish',  				'no_found_rows' => true  			);    			// The Featured Posts query.  			$featured = new WP_Query( $featured_args );    			// Proceed only if published posts with thumbnails exist  			if ( $featured->have_posts() ) {  				while ( $featured->have_posts() ) {  					$featured->the_post();  					if ( has_post_thumbnail( $featured->post->ID ) ) {  						$featured_post_ids[] = $featured->post->ID;  					}  				}    				set_transient( 'featured_post_ids', $featured_post_ids );  			}  		}  	}    	// Return the post ID's, either from the cache, or from the loop  	return $featured_post_ids;  }

It reads like this:

  • Filter the main query.
  • Only proceed if we’re on the home page.
  • Only proceed if our query isn’t somehow messed up.
  • Only proceed if we want to filter the main query.
  • Only proceed if we actually have featured posts.
  • Featured posts? Let’s check for stickies.
  • Query for posts if they exist
  • (At this point, WP_Query runs again, and so does our ‘pre_get_posts’ filter. Thanks to our checks above, our query for featured posts won’t get polluted by our need to exclude things.
  • Take each post ID we get, and store them in an array.
  • Save that array as a transient so we don’t keep doing this on each page load.
  • We’re done with featured posts, and back in our main query filter again.
  • In our main query, exclude the post ID’s we just got.
  • Return the modified main query variables.
  • Let WordPress handle the rest.

With a little foresight into what we want to do, we’re able to architect ourselves a nice bit of logic to avoid creating a third, potentially costly WP_Query object.

Another, more simple example

The Depo Masthead theme wants to limit the home page to only 3 posts. We already learned earlier we *don’t* want to run query_posts() since it will create a new WP_Query object we don’t need. So, what do we do?

/**   * Modify home query to only show 3 posts   *   * @param WP_Query $query   * @return WP_Query   */  function depo_limit_home_posts_per_page( $query = '' ) {    	// Bail if not home, not a query, not main query, or no featured posts  	if ( ! is_home() || ! is_a( $query, 'WP_Query' ) || ! $query->is_main_query() )  		return;    	// Home only gets 3 posts  	$query->set( 'posts_per_page', 3 );  }  add_action( 'pre_get_posts', 'depo_limit_home_posts_per_page' );  

Stop me if you’ve heard this one. We hook onto ‘pre_get_posts’ and return a modified query! Woo woo!

Themes are the most common culprit, but they aren’t alone. More often than not, we all forget to clean up after ourselves, reset posts and queries when we’re done, etc… By avoiding query_posts() all together, we can be confident our code is behaving the way we intended, and that it’s playing nicely with the plugins and themes we’re running too.

developer.wordpress.com

Passing variables to query_posts
You can pass a variable to the query with several methods, depending on your needs. As with other examples, place these above your Loop:

Example 1

In this example, we concatenate the query before running it. First assign the variable, then concatenate and then run it. Here we’re pulling in a category variable from elsewhere.

 // assign the variable as current category $categoryvariable = $cat;  // concatenate the query $args = 'cat=' . $categoryvariable . '&orderby=date&order=ASC';  // run the query query_posts( $args ); 

Example 2

In this next example, the double quotes tell PHP to treat the enclosed as an expression. For this example, we are getting the current month and the current year, and telling query_posts() to bring us the posts for the current month/year, and in this case, listing in ascending order so we get the oldest post at the top of the page.

 $current_year = date('Y'); $current_month = date('m');  query_posts( "cat=22&year=$current_year&monthnum=$current_month&order=ASC" ); 

Example 3

This example explains how to generate a complete list of posts, dealing with pagination. We can use the default $query_string telling query_posts() to bring us a full posts listing. We can also modify the posts_per_page query parameter from -1 to the number of posts you want to show on each page; in this last case, you’ll probably want to use posts_nav_link() to navigate the generated archive.

 query_posts( $query_string . '&posts_per_page=-1' ); 

Example 4

If you don’t need to use the $query_string variable, another method exists that is more clear and readable, in some more complex cases. This method puts the parameters into an array. The same query as in Example 2 above could be done like this:

 $args = array( 	'cat' => 22, 	'year' => $current_year, 	'monthnum' => $current_month, 	'order' => 'ASC' ); query_posts( $args ); 

As you can see, with this approach, every variable can be put on its own line, for easier reading.

Example 5

It is even possible to use the array style (Example 4) to query multiple taxonomies. Simply supply the taxonomy slug with a string of comma-separated values (each value being one term). In the example below, we will get all movie posts starring either Bruce Campbell or Chuck Norris.

 $args = array( 	'post_type'=> 'movie', 	'actor' => 'Bruce Campbell, Chuck Norris', 	'order' => 'ASC' ); query_posts( $args ); 

developer.wordpress.org


You May Also Like

About the Author: admind

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.