Query posts

Несколько примеров использования 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

  • 2777
  • 1
  • Рубрика: WordPress

Query_posts

Доброго времени суток. 🙂

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

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

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

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

  <?php  $paged = (get_query_var('paged')) ? get_query_var('paged') :   query_posts('posts_per_page=3&cat=4&paged=' . $paged);  ?>  

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

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

  <?php  if ( get_query_var('paged') ) { $paged = get_query_var('paged'); }  elseif ( get_query_var('page') ) { $paged = get_query_var('page'); }  else { $paged = 1; }  query_posts('posts_per_page=3&cat=4&paged=' . $paged);  ?>  

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

  <?php  $paged = (get_query_var('paged')) ? get_query_var('paged') :  query_posts('posts_per_page=3&cat=3&paged=' . $paged);  ?>  <?php if (have_posts()) : ?><?php while (have_posts()) : the_post(); ?>    //Вывод миниатюры, тизера и тд    <?php endwhile; ?>  <?php if (function_exists('wp_corenavi')) wp_corenavi(); ?>  <?php else : ?>  <?php include(TEMPLATEPATH . '/404.php');?>  <?php endif; ?>  

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

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

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:

/**<br />  * Set up The Loop with query parameters.<br />  *<br />  * This will override the current WordPress Loop and shouldn't be used more than<br />  * once. This must not be used within the WordPress Loop.<br />  *<br />  * @since 1.5.0<br />  * @uses $wp_query<br />  *<br />  * @param string $query<br />  * @return array List of posts<br />  */<br /> function &amp;query_posts($query) {<br /> 	unset($GLOBALS['wp_query']);<br /> 	$GLOBALS['wp_query'] = new WP_Query();<br /> 	return $GLOBALS['wp_query']-&gt;query($query);<br /> }

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…

<br /> $featured_args = array(<br /> 	'post__in' =&gt; get_option( 'sticky_posts' ),<br /> 	'post_status' =&gt; 'publish',<br /> 	'no_found_rows' =&gt; true<br /> );</p> <p>// The Featured Posts query.<br /> $featured = new WP_Query( $featured_args );</p> <p>// Proceed only if published posts with thumbnails exist<br /> if ( $featured-&gt;have_posts() ) {<br /> 	while ( $featured-&gt;have_posts() ) {<br /> 		$featured-&gt;the_post();<br /> 		if ( has_post_thumbnail( $featured-&gt;post-&gt;ID ) ) {<br /> 			/// do stuff here<br /> 		}<br /> 	}</p> <p>	// Reset the post data<br /> 	wp_reset_postdata();<br /> }<br /> 

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:

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

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?

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

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

You May Also Like

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

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

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