Query posts


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

Основной запрос (или основной цикл) в WordPress это тот, который выполняется на раннем этапе загрузки ядра, он строится из запрошенного URL, настроек постоянных ссылок и т.д. Во время основного запроса WordPress определяет такие параметры как количество записей на страницу, используемый шаблон в теме и прочие. Основной запрос делает сам WordPress.

Вторичный запрос это тот, который выполняется дополнительно к основному. Например:

  • Вывести в боковой колонке список самых популярных записей
  • Вывести выделенные записи в слайдере на главной странице
  • Вывести записи из той же категории в блоке «похожие записи»

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

Основным отличием query_posts()


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

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

// Вторичный цикл  $popular = new WP_Query( ... );  while ( $popular->have_posts() ) {   $popular->the_post();     the_title(); // вывести название   the_content(); // вывести содержимое  }

Этот же цикл с помощью query_posts():

// Вторичный цикл  query_posts( ... );  while ( have_posts() ) {   the_post();     the_title(); // вывести название   the_content(); // вывести содержимое  }  

Безусловно второй вариант выглядит немного чище и привычнее, поскольку такая конструкция чаще всего встречается при работе с основным циклом WordPress.

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

$wp_query и $wp_the_query

После выполнения основного запроса WordPress помещает его результат в глобальную переменную $wp_the_query, а в глобальной переменной $wp_query хранится всего лишь ссылка на $wp_the_query


. Функции have_posts(), the_post() и прочие работают именно с глобальным объектом $wp_query.

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

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

Функция query_posts() создает новый вторичный запрос с помощью WP_Query и помещает результат в эту же глобальную переменную $wp_query:

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

Таким образом функции, которые предназначены для работы с основным циклом WordPress начинают работать с нашим вторичным запросом, а основной запрос остался в глобальной переменной $wp_the_query, ссылку на которую можно восстановить с помощью функции wp_reset_query().

function wp_reset_query() {   $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];   wp_reset_postdata();  }

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

Пагинация

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

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


в начале нашего шаблона index.php или archive.php:

global $query_string;  query_posts( $query_string . '&posts_per_page=5' );  

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

Напоминаем, что основной запрос WordPress происходит еще до того, как обрабатываются шаблоны index.php или archive.php, где происходит наша «подмена». В основном запросе количество записей на страницу — десять, и всего две страницы. Третей и четвертой страниц в основном запросе нет.

Именно основной запрос определяет какой шаблон темы будет использоваться, и при запросе третей или четвертой страницы WordPress будет использовать шаблон 404.php.

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

Событие pre_get_posts

Наиболее правильным способом изменить основной цикл WordPress является событие pre_get_posts


, которое происходит перед каждым запросом WP_Query. Работать с этим событием можно в плагине или в файле functions.php вашей темы:

function my_pre_get_posts( $query ) {   if ( ! is_admin() && $query->is_main_query() ) {   $query->set( 'posts_per_page', 5 );   }  }  add_action( 'pre_get_posts', 'my_pre_get_posts' );  

Важно отметить, что pre_get_posts вызывается для каждого запроса WP_Query, включая основной запрос, навигационное меню, вторичные запросы в виджетах и прочее. С помощью метода is_main_query() мы изменяем параметры только основного запроса, а с помощью проверки is_admin() мы меняем запрос только на лицевой части сайта и не в административной панели.

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

Альтернативы query_posts()

Если вам необходимо выполнить вторичный запрос в WordPress, воспользуйтесь функцией get_posts() или конструкцией new WP_Query(). При работе с ними ваш код будет более явным и понятным для читающих.

Когда вам необходимо изменить основной запрос WordPress перед его выполнением, самым простым способом является событие pre_get_posts


, или фильтр request, который выполняется еще раньше, чем pre_get_posts и только для основного запроса.

Если у вас возникли вопросы про query_posts() или WP_Query, оставьте комментарий и мы обязательно вам ответим.

wpmag.ru

Настраиваем 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

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.

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:
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

Тема для данной заметки навеяна проблемой, возникшей при переносе одного из блогов на 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, достаточно в индексном файле шаблона привести цикл вывода постов к следующему виду:

<?php query_posts('cat=-3'); ?>    <?php if (have_posts()) { ?>  	<?php while (have_posts()) { the_post() ?>  		...  	<?php } ?>  <?php } ?>

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

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

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

<?php global $query_string; query_posts($query_string . '&cat=-3'); ?>    <?php if (have_posts()) { ?>  	<?php while (have_posts()) { the_post() ?>  		...  	<?php } ?>  <?php } ?>

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

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

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

<?php  	query_posts('cat=-1,-2,-3');  ?>

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

<?php  	query_posts('category_name=software_news');  ?>

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

<?php  	query_posts('p=13');  ?>

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

<?php  	query_posts('cat=7&year=2011&orderby=date&order=DESC&posts_per_page=5');  ?>

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

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

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

omurashov.ru

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

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

<?php if (have_posts()) : ?>  <?php while (have_posts()) : the_post(); ?>  //Тут Ваш код  <?php endwhile; ?>

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

<?php query_posts('cat=-1,-2,-3'); ?>  <?php if (have_posts()) : ?>  <?php while (have_posts()) : the_post(); ?>  //Тут Ваш код  <?php endwhile; ?>

Такой код выведет на главную записи из всех категорий кроме категорий с 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

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

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

Рассмотрим ситуацию, когда мы захотели, скажем, на всех страницах сайта, в том числе и на странице категории, выводить по 10 записей на страницу, а на страницах подкатегорий выводить по 20 записей на страницу. Вопрос отделения на уровне функций конкретно подкатегорий в этой статье опустим, а рассмотрим только вопрос организации такой постраничной навигации. В данном случае общеизвестный плагин different_posts_per_pages не подойдет, т.к. он умеет задавать произвольное число записей для главной страницы, страниц ВСЕХ категорий (то есть столько записей, сколько мы зададим выводить на странице категорий, будет выводиться и на страницах подкатегорий), страниц архивов и так далее, но не умеет различать категории и подкатегории. На помощь нам приходит query_posts с условиями posts_per_page=20 и cat= $cat (переменная $cat всегда хранит id текущей категории):

<? query_posts('posts_per_page=20&cat=' . $cat); ?>

И действительно, таким образом мы будем получать по 20 записей на странице, однако, при попытке перейти на следующую страницу мы увидим, что выведутся те же самые 20 записей. И действительно, ведь query_post по сути помимо переданных ей параметров все остальные параметры берет дефолтными, т.е. если ей явно не задать, с какой страницы 20 записей вы хотите получить, он все время будет выводить последние 20 записей (первую страницу). Поведение функции вполне логично, осталось передать функции номер страницы. Погуглив немного, на одном форуме о создании сайтов я нашел простое и изящное решение. Делается это с помощью глобальной переменной $paged:

<? $paged = (get_query_var('paged')) ? get_query_var('paged') : 1; query_posts('showposts=20&paged='.$paged.'&cat='.$cat); ?>

Данное условие гласит: если удалось получить номер страницы, то присваиваем переменной $paged номер страницы и передаем ее в качестве параметра функции query_posts. Если не удалось получить номер страницы, то присваиваем переменной $paged единицу и передаем ее в качестве параметра функции query_posts.

Данная строчка кода вставляется непосредственно перед циклом вывода постов:

Вуаля! Постраничная навигация с query_posts() больше не проблема.

http://blogto4ka.ru

blogto4ka.ru

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 для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.