WordPress как на ладони
wordpress jino

WP_Query{} WP 1.5

Выбирает записи из базы данных по указанным критериям. На основе WP_Query работают функции get_posts() и query_posts() и все остальные запросы связанные с выбором записей из таблицы wp_posts.

Является основой для: have_comments(), wp_playlist_shortcode()
Хуки из класса:
Возвращает

Объект/массив. Результат запроса в виде массива объектов записей.

Знакомство с WP_Query

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

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

Рассмотрим простой запрос:

$query = new WP_Query( array( 'category_name' => 'news' ) );

Так, WordPress сделает запрос в базу данных, чтобы получить записи из категории "news".

Теперь, переменная $query содержит в себе объект с результатами запроса. Обработаем результат с помощью специальных методов:

while ( $query->have_posts() ) {
	$query->the_post();

	the_title(); // выведем заголовок поста
}

С помощью have_posts() мы проверяем есть ли записи для вывода в объекте $query. the_post() готовит текущую в цикле запись к выводу, делая доступными привычные функции the_title(), the_content() и другие.

WP_Query используется в WordPress всегда. Например, во время генерации любой страницы WP_Query создает глобальную переменную $wp_query где хранится информация о текущем запросе. На основе этой информации WP определяет на какой странице мы сейчас находимся (пост, архив, метка и т.д.). Также при построении базового цикла WordPress, данные берутся из переменной $wp_query и выводятся на экран через вспомогательные функции: the_permalink(), the_content(). Также, $wp_query хранит и другие данные. На разных типах страниц данные разные. Посмотреть какие данные находятся в переменной $wp_query можно так:

global $wp_query;
print_r($wp_query);

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

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

Если в запросе используется the_post(), то обязательно нужно заканчивать цикл функцией wp_reset_postdata().

Еще код цикла может выглядеть следующим образом - это тоже самое что get_post(), только без предустановленных параметров:

// создаем экземпляр
$my_posts = new WP_Query;

// делаем запрос
$myposts = $my_posts->query( array(
	'post_type' => 'page'
) );

// обрабатываем результат
foreach( $myposts as $pst ){
	echo esc_html( $pst->post_title );
}

Для лучшего понимания и визуального восприятия работы функций запроса, изучите картинку:

Как работают функции запросов в WordPress

Шаблоны использования WP_Query

#1 Стандартный цикл:

// задаем нужные нам критерии выборки данных из БД
$args = array(
	'posts_per_page' => 5,
	'orderby' => 'comment_count'
);

$query = new WP_Query( $args );

// Цикл
if ( $query->have_posts() ) {
	while ( $query->have_posts() ) {
		$query->the_post();
		echo '<li>' . get_the_title() . '</li>';
	}
} else {
	// Постов не найдено
}
/* Возвращаем оригинальные данные поста. Сбрасываем $post. */
wp_reset_postdata();

#2 Множественный цикл:

// Запрос к БД
$the_query = new WP_Query( $args );

// Цикл
while ( $the_query->have_posts() ) {
	$the_query->the_post();
	echo '<li>' . get_the_title() . '</li>';
}

/* Восстанавливаем оригинальные данные 
 * Так как мы используем new WP_Query мы не влияем на
 * переменную $wp_query и нет необходимости сбрасывать запрос,
 * поэтому сбрасываем только данные поста.
*/
wp_reset_postdata();

/* Второй запрос (без глобальной переменной) */
$query2 = new WP_Query( $args2 );

// 2-й Цикл
while( $query2->have_posts() ) {
	$query2->next_post();
	echo '<li>' . get_the_title( $query2->post->ID ) . '</li>';
}

// Восстанавливаем оригинальные данные поста
wp_reset_postdata();

#3 Аналог get_posts():

$args = array(
	'post_type' => 'page'
);
$query = new WP_Query;
$my_posts = $query->query($args);

foreach( $my_posts as $my_post ){
	echo '<p>'. $my_post->post_title .'</p>';
}

При создании запросов WP_Query может получать предустановленные параметры, которые нужно учитывать. Например, запрос $query = new WP_Query( 'post_type=func' ); может вернуть только первые 10 записей типа func, а не все, как ожидается. Потому что предустановленный параметр posts_per_page=10, ограничивает количество получаемых записей до 10. Вот список параметров, которые могут быть предустановлены и которые могут мешать вашему запросу: post_type, posts_per_page, orderby, order, post_status, offset.

Параметры Категорий (рубрик)

Получает посты относящиеся к определенным категориям.

cat(число/строка/массив)
ID категории. Можно указать несколько ID в строке через запятую или в массиве. Чтобы исключить рубрики укажите минус (-) перед ID категории - это исключит и все вложенные рубрики. Чтобы не исключить вложенные, используйте параметр category__not_in.
category_name(строка)
Имя категории. Используйте слаг (альтернативное имя), а не само название категории.
category__and(массив)
Получить посты, которые входят одновременно в несколько категорий.
category__in(массив)
Получить посты, которые входят в одну из указанных категорий.
category__not_in(массив)

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

Этот параметр не учитывает вложенные рубрики. Чтобы исключить рубрику и вложенные, укажите ID рубрик через запятую со знаком минус в параметре cat: -25,-32.

Посты из одной категории

Вывод постов из одной категории (записи из дочерних категорий так же будут выбраны):

$query = new WP_Query('cat=4');

вывод постов из одной категории по ярлыку (альтернативному названию категории):

$query = new WP_Query('category_name=staff');

Выведем посты только из категории 4 (дочерние категории не затрагиваются):

$query = new WP_Query( 'category__in=4' );

Посты из нескольких категорий

Вывод постов из категорий по ID категорий:

$query = new WP_Query('cat=2,6,17,38');

Выведем посты из категорий по слагу категорий:

$query = new WP_Query( 'category_name=staff,news' );

Исключим посты принадлежащие категориям

Выведем все посты, кроме постов из категорий 12,34,56:

$query = new WP_Query( 'cat=-12,-34,-56' );

Показать все посты, кроме тех, что принадлежать категории 3:

$query = new WP_Query('cat=-3');

Нескольких категорий одновременно

Показать посты, которые находятся сразу в двух категориях:

$query = new WP_Query( array( 'category__and' => array(2,6) ) );

Показать посты, которые находятся хотя бы в одной из категорий (дочерние категории не будут учитываться):

$query = new WP_Query(array('category__in' => array(2,6)));

Можно исключить несколько категорий, таким образом:

$query = new WP_Query( array('category__not_in' => array(2,6)) );

Параметры Меток

Получает посты относящиеся к определенным меткам.

tag(строка)
slug метки.
tag_id(число)
ID метки.
tag__and(массив)
Посты одновременно из нескольких меток. Нужно указывать ID.
tag__in(массив)
Посты из хотя бы одной указанной метки. Нужно указывать ID.
tag__not_in(массив)
Посты не относящиеся к указанным меткам. Нужно указывать ID.
tag_slug__and(массив)
Тоже что и tag__and, только указываются альт. названия (slug) меток.
tag_slug__in(массив)
тоже что и tag__in, только указываются альт. названия меток.

Посты с одной меткой

Получить посты с меткой:

$query = new WP_Query('tag=cooking');

Указывать нужно альтернативное название метки.

Получить посты, имеющие хотя бы одну указанную метку:

$query = new WP_Query('tag=bread,baking');

Посты с несколькими метками

Получить посты имеющие любую из меток:

$query = new WP_Query( 'tag=bread,baking' );

Получить посты, имеющие сразу все указанные метки:

$query = new WP_Query('tag=bread+baking+recipe');

Получить посты, имеющие сразу две метки (37 и 47):

$query = new WP_Query( array('tag__and' => array(37,47)) );

Этот вариант более предпочтителен вышеприведенному из-за быстродействия.

Получить посты, имеющие хотя бы одно метку 37 или 47:

$query = new WP_Query( array('tag__in' => array(37,47)) );

Этот вариант предпочтительнее т.к. указываются сразу ID.

Получить посты, НЕ связанные с метками 37 или 47:

$query = new WP_Query(array( 'tag__not_in'=>array(37,47) ));

Параметры Таксономий

Выводит посты связанные с определенной таксономией.

{tax}(строка)
Использовался в версиях ниже 3.1 для которого нужно было указывать "название термина" ( array('taxonomy_name'=>'categoriya') ). Запрещен с версии 3.1.
tax_query(массив)

С версий 3.1 и выше используется аргумент tax_query, который имеет ряд вложенных аргументов, это:

  • relation (строка)
    Как выбирать записи из указанных таксономий. Может быть:

    • AND - записи которые одновременно входят в указанные таксономии;
    • OR - записи принадлежащие любой из указанных таксономий.

    Указывается в первом массиве, а термины во вложенных массивах, которые могут иметь следующие параметры:

    • taxonomy (строка)
      Название таксономии.

    • field (строка)
      Поле которое будет указывать в параметре terms. Может быть:

      • id или term_id - в terms указываем id терминов.
      • name - в terms указываем заголовок термина.
      • slug - в terms указываем ярлык термина.

        По умолчанию: 'term_id'

    • terms (число/строка/массив)
      Термины таксономии, из которых нужно вывести записи.

    • operator (строка)
      Оператор, указывающий как сравнивать указанные термины в параметре terms. Может быть:

      • IN - записи из указанных терминов (по умолчанию);
      • NOT IN - записи из всех терминов, кроме указанных;
      • AND - записи одновременно принадлежащие всем указанным терминам;
      • EXISTS - (с версии 4.1) существует;
      • NOT EXISTS - (с версии 4.1) не существует.

        По умолчанию: 'IN'

    • include_children (логический)
      Включать или нет посты из дочерних терминов (для древовидных таксономий). true -включить.
      По умолчанию: true

tax_query это массив, элементами которого являются другие массивы, в каждом из которых указывается таксономия, её термины и то как использовать эти термины. Оператор relation указывается в первом массиве tax_query и определяет как сравнивать вложенные массивы между собой. Такая конструкция позволяет создавать запрос одновременно к нескольким таксономиям.

#1 Вывод записей из одной таксономии

Выведем записи из раздела (термина) bob, который является элементом таксономии people:

$query = new WP_Query( array( 'people' => 'bob' ) );

#2 Выведем посты прикрепленные к термину bob из таксономии people:

$args = array(
	'post_type' => 'post',
	'people'    => 'bob'
);
$query = new WP_Query( $args );

Сделаем тоже самое что и в примере выше, только с использованием аргумента tax_query:

$query = new WP_Query( array(
	'tax_query' => array(
		array(
			'taxonomy' => 'people',
			'field'    => 'slug',
			'terms'    => 'bob'
		)
	)
) );

#3 Вывод из нескольких таксономий

Выведем посты из нескольких произвольных таксономий:

$query = new WP_Query( array(
	'post_type' => 'post',
	'people'    => 'bob',
	'language'  => 'english'
) );

Аналог примера выше. Выведем записи, который одновременно относятся к нескольким произвольным таксономиям через tax_query:

$query = new WP_Query( array(
	'tax_query' => array(
		'relation' => 'AND',
		array(
			'taxonomy' => 'movie_janner',
			'field'    => 'slug',
			'terms'    => array( 'action', 'comedy' ),
		),
		array(
			'taxonomy' => 'actor',
			'field'    => 'id',
			'terms'    => array( 103, 115, 206 ),
			'operator' => 'NOT IN',
		)
	)
) );

#4 Использование аргумента relation=OR

Выведем посты, которые находятся в рубрике quotes или которые имеют формат quote (форматы введены в версии 3.1). Для этого используем аргумент relation:

$args = array(
	'post_type' => 'post',
	'tax_query' => array(
		'relation' => 'OR',
		array(
			'taxonomy' => 'category',
			'field' => 'slug',
			'terms' => array( 'quotes' )
		),
		array(
			'taxonomy' => 'post_format',
			'field' => 'slug',
			'terms' => array( 'post-format-quote' )
		)
	)
);
$query = new WP_Query( $args );

#5 Многоуровневый сложный запрос с использование оператора relation=OR

Допустим, нам нужно получить записи одной из групп элементов таксономии.

Например, надо получить автомобили марки ford черного цвета или автомобили марки bmw белого цвета:

$query = new WP_Query(
	array(
		'tax_query' => array(
			'relation' => 'OR',
			array(
				'relation' => 'AND',
				array(
					'taxonomy' => 'brand',
					'field'    => 'slug',
					'terms'    => array( 'ford' )
				),
				array(
					'taxonomy' => 'color',
					'field'    => 'slug',
					'terms'    => array( 'black' )
				)
			),
			array(
				'relation' => 'AND',
				array(
					'taxonomy' => 'brand',
					'field'    => 'slug',
					'terms'    => array( 'bmw' )
				),
				array(
					'taxonomy' => 'color',
					'field'    => 'slug',
					'terms'    => array( 'white' )

				)
			)
		)
	)
);

$query = new WP_Query( $args );

Тут первый оператор relation=OR влиял бы на все вложенные массивы, если бы во вложенных массивах он не перебивался дополнительным оператором relation=AND

Использование get_posts()

#6 Выведем заголовки всех типов записей countries из всех подрубрик термина 62, который относится к таксономии country:

$args = array(
	'tax_query' => array(
		array(
			'taxonomy' => 'country',
			'field'    => 'id',
			'terms'    => array( 62 )
		)
	),
	'post_type' => 'countries',
	'posts_per_page' => -1
);
$posts = get_posts( $args );

foreach( $posts as $pst ){
	echo $pst->post_title .'<br>';
}

#7 Выведем все записи произвольного типа (article) не относящиеся к указанным терминам ('term-slug', 'term-slug-two', 'term-slug-three') таксономии (artictag):

// получим все посты не относящиеся к указанным терминам

$post_type = 'article';
$tax   = 'artictag';
$terms = array('term-slug', 'term-slug-two', 'term-slug-three');

$psts  = get_posts( array(
	'posts_per_page' => -1,
	'post_type' => $post_type,
	'tax_query' => array(
			'relation' => 'AND',
			array(
				'taxonomy' => $tax,
				'terms' => $terms,
				'field' => 'slug',
				'operator' => 'NOT IN',
			)
		),
	'' => '',
) );

$i = 0;
foreach( $psts as $pst ){
	echo ++$i . ' <a href="'. get_permalink( $pst->ID ) .'">'. $pst->post_title .'</a><br>';
}

Параметры Авторов

Получает посты принадлежащие определенным авторам.

author(число)
ID автора.
author_name(строка)
Ник автора. Нужно указывать значение поля user_nicename.
author__in(массив)
Массив ID авторов, записи которых нужно получить.
author__not_in(массив)
Массив ID авторов, записи которых нужно исключить.

#1 Выведем посты для одного автора

Посты по ID автора:

$query = new WP_Query( 'author=123' );

Посты по нику автора:

$query = new WP_Query( 'author_name=rami' );

#2 Выведем посты нескольких авторов сразу

Посты четырех авторов по ID:

$query = new WP_Query( 'author=2,6,17,38' );

#3 Исключим посты автора

Исключим посты автора 12 и покажем все посты, кроме его:

$query = new WP_Query( 'author=-12' );

#4 Еще пример

Показать все страницы автора 1 (author=1), отсортировать по заголовку (orderby=title) в алфавитном порядке (order=ASC) и не показывать прикрепленные посты вверху.

$query = new WP_Query('caller_get_posts=1&author=1&post_type=page&post_status=publish&orderby=title&order=ASC');

#5 Несколько авторов одновременно

Получим все записи авторов с ID 2 и 6:

$query = new WP_Query( array( 'author__in' => array( 2, 6 ) ) );

Получим записи всех авторов, кроме авторов с ID 2 и 6:

$query = new WP_Query( array( 'author__not_in' => array( 2, 6 ) ) );

Параметры Постов и Страниц

Получает отдельные страницы или посты.

p(число)
ID поста который нужно получить (p=27).
name(строка)
Альт. название поста (name=o-saite).
page_id(число)
ID постоянной страницы, которую нужно получить (page_id=27)
pagename(строка)
Альт. название постоянной страницы (pagename=o-saite)
post_parent(число)
Вернет только дочерние страницы.
post_parent__in(массив)
Выберет посты родители которых указанны в массиве.
post_parent__not_in(массив)
Выберет посты родители которых не указанны в массиве.
post__in(массив)

Укажите через запятую ID постов, которые нужно получить (post__in=5,12,2,14,7).

Заметка: если есть прилепленные записи, они будут включены автоматом. Отключить их можно параметром ignore_sticky_posts

post__not_in(массив)
Выведет все посты кроме указанных.

Посты/страницы по ID

Выведем пост по ID:

$query = new WP_Query('p=7');

Выведем страницу по ID:

$query = new WP_Query( 'page_id=7' );

Посты/страницы по Слагу

Выведем пост по Слагу:

$query = new WP_Query( 'name=about-my-life' );

Выведем страницу по Слагу:

$query = new WP_Query( 'pagename=contact' );

Дочерние посты/страницы

Выведем дочернюю страницу, используя слаг родительской и дочерней страницы разделенные слэшом: parent_slug/child_slug

$query = new WP_Query( 'pagename=contact_us/canada&post_type=page' );

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

$query = new WP_Query( 'post_parent=93&post_type=page' );

Выведем страницы верхнего уровня, исключим все дочерние:

$query = new WP_Query( 'post_parent=0&post_type=page' );

Выведем посты родители которых указаны в массиве:

$query = new WP_Query( array( 'post_parent__in' => array( 2, 5, 12, 14, 20 ) ) );

Множественные выводы постов/страниц

Выведем только указанные посты:

$query = new WP_Query( 
	array( 'post_type'=>'page', 'post__in' => array( 2, 5, 12, 14, 20 ) ) 
);

Выведем все посты, кроме указанных:

$query = new WP_Query( array(
	'post_type' => 'post',
	'post__not_in' => array( 2, 5, 12, 14, 20 )
) );

Заметка: нельзя объединять post__in и post__not_in в одном запросе.

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

// не правильно
$exclude_ids = '1,2,3';
$query = new WP_Query( array( 'post__not_in' => array( $exclude_ids ) ) );

// Правильно
$exclude_ids = array( 1, 2, 3 );
$query = new WP_Query( array( 'post__not_in' => $exclude_ids ) );

Параметры Типов записей

Показывает посты указанного типа.

post_type(строка/массив)

Записи какого типа нужно показывать. По умолчанию: post. Но если указан параметр tax_query, то по умолчанию ставиться any.

Может быть:

  • any - включает все типы, кроме revision и типов у которых указан параметр exclude_from_search=true.
  • attachment - по умолчанию WP_Query ставит статус 'post_status'=>'publish', а вложения имеют статус 'post_status'=>'inherit', поэтому чтобы вывести вложения нужно еще изменить параметр post_status на 'inherit' или 'any'.
  • page - страница.
  • post - пост.
  • revision - ревизия.
  • custom_type - название (ярлык) произвольного типа записи.
  • array('post','page') - сразу несколько типов в массиве.

По умолчанию: post

Посты по типу

Выведем только страницы:

$query = new WP_Query( 'post_type=page' );

Выведем все посты, кроме ревизий и типов постов у которых при регистрации параметр exclude_from_search выставлен в true:

$query = new WP_Query( 'post_type=any' );

Выведем 4 типа постов одновременно:

$query = new WP_Query( array(
	'post_type' => array( 'post', 'page', 'movie', 'book' )
) );

Параметры Произвольных полей (postmeta)

Основным параметром для работы с мета-данными в WP_Query является meta_query, который получает записи (посты) по существующим у них произвольным полям и их значениям. По принципу использования, meta_query похож на tax_query - массив, где каждый элемент в свою очередь является массивом с параметрами запроса, т.е. meta_query - это массив массивов:

$args = array(
	'meta_query' => array(
		'relation' => 'OR',
		array(
			'key' => 'color',
			'value' => 'blue'
		),
		array(
			'key' => 'price',
			'value' => 20
		)
	)
);

Такая конструкция позволяет использовать множественные запросы. Первый параметр relation во "внешнем" массиве описывает логическую связь между запросами. Он может принимать значения AND (используется по умолчанию. Совпадение со всеми запросами) или OR (совпадение с любым из запросов).

Старые переменные запроса мета-данных: meta_key, meta_value, meta_value_nummeta_compare по прежнему поддерживаются и могут быть использованы для простых запросов связанных с произвольными полями.

Список всех параметров связанных с мета-данными:

meta_key(строка)
Ключ(название) произвольного поля.
meta_value(строка)
Значение произвольного поля.
meta_value_num(число)
Значение произвольного поля, число.
meta_compare(строка)
Оператор для проверки значения произвольного поля. Может быть: =, !=, >, >=, <, <=, LIKE, NOT LIKE, IN, NOT IN, BETWEEN, NOT BETWEEN, EXISTS (с версии 3.5), NOT EXISTS (3.5), REGEXP (3.7), NOT REGEXP (3.7) и RLIKE (3.7);
По умолчанию '='
meta_query(массив)

Массив параметров мета-данных определяющих вывод (этот параметр включает в себя meta_keymeta_value и meta_compare и заменяет их). С версии 3.1.
В массиве можно указать следующие параметры:

  • relation (строка)
    Этот параметр указывается как строка в главном массиве meta_query и указывает как сравнивать между собой несколько массивов с параметрами запроса, указанных в этом главном массиве.
    Параметр может принимать два значение:
    OR - выбрать мета-поля подходящие хоты бы под один массив с параметрами запроса;
    AND (по умолчанию) - выбрать мета поля подходящие для всех массивов с параметрами запроса.

    • key (строка)
      Ключ поля.

    • value (строка/массив)
      Значение поля. Указывать не нужно, если при сравнении используется: 'EXISTS' или 'NOT EXISTS' (с версии 3.9).

    • compare (строка)
      Как сравнивать указанное в value значение. Может быть: 

      • = - равно.
      • != - не равно.
      • > - больше.
      • >= - больше или равно.
      • < - меньше.
      • <= - меньше или равно.
      • LIKE - указанная в value подстрока имеется в строке. Как '%значение%' в sql запросе.
      • NOT LIKE - тоже что LIKE только наоборот.
      • IN - в value указываются несколько значений в массиве и поиск идет хотя бы по одному из значений.
      • NOT IN - любое значение, кроме тех что указанны в виде массива в value.
      • BETWEEN - в value указываются 2 значения в массиве: большее и меньшее и поиск идет между этих значений. , например: 'value' => array(5, 25) - от 5 до 25 (включительно).
      • NOT BETWEEN - любое значение, за пределами диапазона указанного в value, например: 'value' => array(5, 25) - меньше 5 и больше 25.
      • EXISTS - выведет всё где существует указанный в 'key' ключ. 'value' не указывается в этом случае. (с версии 3.5)
      • NOT EXISTS - выведет всё где указанный в 'key' ключ не существует. 'value' не указывается в этом случае. (с версии 3.5)
      • REGEXP - в value указывается регулярное выражение для поиска, например: 'value' => '^bar', (найдет строку: 'bar is'). (с версии 3.7)
      • NOT REGEXP - в value указывается регулярное выражение для поиска, найдет все что не входит в это выражение. (с версии 3.7)
      • RLIKE - синоним REGEXP. (с версии 3.7)

    По умолчанию 'IN', если value массив, '=' в других случаях.

    • type (строка)
      тип произвольного поля (если, например в поле указываются только числа то нужно использовать NUMERIC, чтобы числа не сравнивались как строки). Может быть:

      • NUMERIC - целые числа
      • DECIMAL - дробные числа
      • SIGNED - целые числа, положительные и отрицательные
      • UNSIGNED - целые числа, только положительные
      • CHAR - строка не чувствительна к регистру
      • BINARY - строка чувствительная к регистру
      • DATETIME - дата и время
      • DATE - только дата
      • TIME - только время

      По умолчанию: CHAR.

    Тип DATE работает при сравнении BETWEEN только если дата указывается в формате YYYY-MM-DD и сравнивается с аналогичным форматом.

Смотрите также отдельное описание класса мета запросов: WP_Meta_Query

Сортировка по произвольному полю

Для сортировки по полю, нужно указать ключ данных поля, и затем в параметре 'orderby' указать название этого ключа, например:

'meta_query' => array(
	'book_color' => array(
		'key'     => 'color',
		'value'   => 'blue',
		'compare' => 'NOT LIKE',
	),
),
'orderby' => 'book_color',
'order'   => 'DESC',

Если произвольное поле указывается через параметр meta_key и meta_value, то для сортировки по этому полю в параметре orderby укажите значения: meta_value или meta_value_num (для чисел). См. ниже описание параметра orderby.

'meta_key=color&meta_value=blue&orderby=meta_value&order=ASC'

Базовые примеры (без meta_query)

#1 Посты с ключом произвольного поля color, не обращая внимание на значение этого поля.

$query = new WP_Query( 'meta_key=color' );

#2 Посты со значением произвольно поля blue, не обращая внимание на название ключа.

$query = new WP_Query( 'meta_value=blue' );

#3 Посты с ключом поля color и значением этого поля blue:

$query = new WP_Query( array( 'meta_key' => 'color', 'meta_value' => 'blue' ) );

#4 Посты у которых ключ равен color и значение поля не равно blue:

$query = new WP_Query( 
	 array( 'meta_key' => 'color', 'meta_value' => 'blue', 'meta_compare' => '!=' ) 
);

#5 Продукты с ключом price и значение произвольно поля меньше или равно 22.

При использовании параметра "meta_value" значение 99 будет больше 100, так как эти значения распознаются как строки, а не числа. Для того чтобы числа понимались как числа нужно использовать параметр "meta_value_num":

$query = new WP_Query( 
	 array( 'meta_key' => 'price', 'meta_value_num' => '22', 'meta_compare' => '<=', 'post_type' => 'product' ) 
);

#6 Посты со значением произвольного поля равным 0, не важно какой ключ.

$query = new WP_Query( array ( 'meta_value' => '_wp_zero_value' ) );

Примеры с использованием meta_query

#1 Записи с одним произвольным полем

Выведем продукты (product) у которых ключ равен color и значение поля не равно blue:

$args = array(
	'post_type'  => 'product',
	'meta_query' => array(
		array(
			'key'     => 'color',
			'value'   => 'blue',
			'compare' => 'NOT LIKE'
		)
	)
);
$query = new WP_Query( $args );

Заметка: для meta_query нужно указывать массив в массиве, даже если вы задаете один запрос.

#2 Записи имеющие одновременно два произвольных поля

Пример вывода постов с несколькими произвольными полями и указанием различных условий для значений этих произвольных полей:

$args = array(
	'post_type'  => 'product',
	'meta_query' => array(
		array(
			'key'     => 'color',
			'value'   => 'blue',
			'compare' => 'NOT LIKE'
		),
		array(
			'key'     => 'price',
			'value'   => array( 20, 100 ),
			'type'    => 'numeric',
			'compare' => 'BETWEEN'
		)
	)
 );
$query = new WP_Query( $args );

#3 Записи имеющие хотя бы одно поле

Выведем посты с ключом color и значением не (NOT LIKE) blue или (OR) посты с ключом price со значениями поля от 20 до 100:

$args = array(
	'post_type'    => 'product',
	'meta_query'   => array(
		'relation' => 'OR',
		array(
			'key'     => 'color',
			'value'   => 'blue',
			'compare' => 'NOT LIKE'
		),
		array(
			'key'     => 'price',
			'value'   => array( 20, 100 ),
			'type'    => 'numeric',
			'compare' => 'BETWEEN'
		)
	)
);
$query = new WP_Query( $args );

#4 Записи с двумя полями отсортированные по третьему полю

Предположим у нас есть тип записей toys - игрушки, а в произвольных полях мы указываем материал: твердая мягкая и вес игрушки в граммах: 100 300 500.

Получим мягкие игрушки вес которых от 200 до 500 грамм и отсортируем их по цене по убыванию:

$args = array(
	'post_type'  => 'toys',
	'meta_query' => array(
		array(
			'key'   => 'type',
			'value' => 'soft',
		),
		array(
			'key'     => 'weight',
			'value'   => array( 200, 500 ),
			'compare' => 'BETWEEN',
			'type'    => 'NUMERIC',
		),
	),
	'meta_key' => 'price',
	'orderby'  => 'meta_value_num',
	'order'    => 'DESC'
);
$query = new WP_Query( $args );

#5 Получим записи у которые есть произвольное поле

Этот пример показывает, как получить записи для которых установлены миниатюры (у которых есть произвольное поле _thumbnail_id):

$args = array(
	'posts_per_page' => 3,
	'post_type'  => 'post',
	'meta_query' => array(
		array(
			'key' => '_thumbnail_id',
			'compare' => 'EXISTS'
		)
	)
);
$query = new WP_Query( $args );

#6 Вложенные сложные запросы

С версии 4.1 можно создавать вложенные запросы. Например, выполним такое условие: нужно показать продукты оранжевого цвета (color=orange) ИЛИ маленькие (size=small) продукты красного цвета (color=red):

$args = array(
	'post_type'  => 'product',
	'meta_query' => array(
		'relation' => 'OR',
		array(
			'key'     => 'color',
			'value'   => 'orange',
			'compare' => '=',
		),
		array(
				'relation' => 'AND',
				array(
						'key'     => 'color',
						'value'   => 'red',
						'compare' => '=',
				),
				array(
						'key'     => 'size',
						'value'   => 'small',
						'compare' => '=',
				),
		),
	),
);
$query = new WP_Query( $args );

#7 Сортировка по произвольному полю

С версии 4.2 массивам в meta_query можно указывать ключи, чтобы затем сортировать по этому ключу:

$args = array(
	'post_type'  => 'book',
	'meta_query' => array(
		'book_color' => array(
			'key'     => 'color',
			'value'   => 'blue',
			'compare' => 'NOT LIKE',
		),
	),
	'orderby' => 'book_color',
);
$query = new WP_Query( $args );

Параметры MIME Типов записей

Выбирает вложения с указанным миме типом. Список миме типов смотрите в описании wp_get_mime_types().

post_mime_type(строка/массив)

Миме тип записи. Используется только для вложений - записей с типом 'attachment'.

Этот параметр будет работать только когда параметр post_type = attachment и post_status = inherit. Т.е. миме-тип может быть только у вложений.

Получим только картинки любого типа

$query = new WP_Query( array(
	'post_mime_type' => 'image',
	'post_type'      => 'attachment',
	'post_status'    => 'inherit',
) );

Получим только картинки gif типа

$query = new WP_Query( array(
	'post_mime_type' => 'image/gif',
	'post_type'      => 'attachment',
	'post_status'    => 'inherit',
) );

Получим все типы вложений, кроме картинок

$query = new WP_Query( array(
	'post_mime_type' => array('application','text','video','audio'),
	'post_type'      => 'attachment',
	'post_status'    => 'inherit',
) );

Параметры Статусов

Получает посты с указанным статусом.

post_status(строка/массив)

Статус поста.

По умолчанию publish, а если пользователь авторизован добавляется еще и private. Если запрос запущен из админ части, добавляются еще и защищенные типы статусов: future, draft и pending. Все типы статусов:

  • publish - опубликованный пост;
  • pending - пост на модерации;
  • draft - черновик;
  • auto-draft - черновик, сохраненный самим WordPress (авто-сохранение);
  • future - запланированный пост;
  • private - личный пост;
  • inherit - ревизия;
  • trash - удаленный пост (в корзине). С версии 2.9;
  • any - все статусы, кроме типов постов с "exclude_from_search=true".

По умолчанию: 'publish'

Посты по статусам

Получим только черновики:

$query = new WP_Query( 'post_status=draft' );

Получим посты с разными статусами:

$query = new WP_Query( 
	 array( 'post_status' => array( 'pending', 'draft', 'future' ) ) 
);

Получим все виды вложений:

$query = new WP_Query( 
	  array( 'post_status' => 'any', 'post_type' => 'attachment' ) 
);

Параметры Даты (времени)

Выводит посты принадлежащие определенному периоду времени.

year(число)
4 цифры года (2013)
monthnum(число)
Номер месяцы (1 - 12)
w(число)
Неделя в году (с 0 до 53)
day(число)
День месяца (1 - 31)
hour(число)
Час (0 - 23)
minute(число)
Минута (0 - 60)
second(число)
Секунда (0 - 60)
m(число)
ГодМесяц (201306)
date_query(массив)

Параметры по которым будет отстроиться запрос. Работает на основе отдельного класса: WP_Date_Query.

Этот параметр указывается как массив, который может содержать вложенные массивы. Параметры: column, compare, relation для основного массива работают как параметры по умолчанию для вложенных массивов (если они есть).

Возможные форматы дат смотрите в документации PHP.

  • column — поле в базе данных для запроса. Может быть:
    post_date
    post_date_gmt
    post_modified
    post_modified_gmt
    comment_date
    comment_date_gmt
    user_registered
    По умолчанию: 'post_date'

  • compare — Оператор сравнения для всех вложенных массивов по умолчанию. Может быть: Может быть: =, !=, >, >=, <, <=, IN, NOT IN, BETWEEN, NOT BETWEEN.
    По умолчанию: '='

  • relation — оператор, если указаны несколько массивов с датами:
    AND (учитывать одновременно все указанные массивы).
    OR (если есть совпадения хотя бы с одним указанным массивом).
    По умолчанию - OR

    Параметры ниже должны использоваться во вложенных массивах. Они определяют запрос для отдельной даты.

    Также все параметры ниже, могут быть использованы в основном массиве.

    • before (строка/массив) — Дата записи "до" которой будут получены. Принимает строку которую поймет функция strtotime(): все возможные форматы. Или можно передать массив с индексами: year, month, day: array('year'=>'2015', 'month'=>'5', 'day'=>'28' )
      Относительно текущего времени сайта (не UTC).

    • after (строка/массив) — Дата записи "после" которой будут получены. Принимает строку которую поймет функция strtotime(): все возможные форматы. Или можно передать массив с индексами: year, month, day: array('year' => '2015', 'month' => '5', 'day' => '28' )
      Относительно текущего времени сайта (не UTC).

    • column (строка) — см. выше, только для конкретной даты. По умолчанию: значение верхнего массива.

    • compare (строка) — см. выше, только для конкретной даты. По умолчанию '='.

    • inclusive (логический) — аргументы before и after обрабатываются включительно, если true. По умолчанию: false.

    • year (число/массив) — год, например 2013
    • dayofyear (число/массив) — номер дня в году, 1-366.
    • month (число/массив) — месяц, 1-12
    • week (число/массив) — неделя, 0-53
    • day (число/массив) — день, 1-31
    • dayofweek (число/массив) — день недели, 1-7, где 1 - воскресенье
    • dayofweek_iso (число/массив) — день недели, 1-7, где 1 - понедельник
    • hour (число/массив) — час, 0-23
    • minute (число/массив) — минута, 0-60
    • second (число/массив) — секунда, 0-60

    В параметрах: year, month, week, dayofyear, day, dayofweek, dayofweek_iso, hour, minute, second можно указать несколько значений, в виде массива, если параметр compare соответствует.

#1. Получим посты за сегодня:

$today = getdate();
$query = new WP_Query( 'year=' . $today["year"] . '&monthnum=' . $today["mon"] . '&day=' . $today["mday"] );

#2. Получим посты за последнюю неделю:

$week = date('W');
$year = date('Y');
$query = new WP_Query( 'year=' . $year . '&w=' . $week );

#3. Получим посты за 20 Декабря:

$query = new WP_Query( 'monthnum=12&day=20' );

Заметка: запросы выше возвращают посты за указанный период в истории: "Посты за Х месяц, Х день". Они не могут получать посты за произвольный промежуток времени по отношению к настоящему. Поэтому запросы типа "Посты за последние 30 дней" или "Посты за последний год" не возможны в базовом варианте, для таких запросов нужно использовать фильтр "posts_where". Примеры ниже показывают как это делать.

#4. Получим посты за промежуток времени с 1 марта по 15 марта 2010 года:

// Создадим новую функцию которая добавит условие where в запрос
function filter_where( $where = '' ) {
	// с 1 марта по 15 марта 2010 года
	$where .= " AND post_date >= '2010-03-01' AND post_date < '2010-03-16'";
	return $where;
}

add_filter( 'posts_where', 'filter_where' );
$query = new WP_Query( $query_string );
remove_filter( 'posts_where', 'filter_where' );

#5. Получим посты за последние 30 дней:

// Создадим новую функцию которая добавит условие where в запрос
function filter_where( $where = '' ) {
	// за последние 30 дней
	$where .= " AND post_date > '" . date('Y-m-d', strtotime('-30 days')) . "'";
	return $where;
}

add_filter( 'posts_where', 'filter_where' );
$query = new WP_Query( $query_string );
remove_filter( 'posts_where', 'filter_where' );

#6. Получим посты за промежуток от 30 до 60 дней, до настоящего:

// Создадим новую функцию которая добавит условие where в запрос
function filter_where( $where = '' ) {
	// от 30 до 60 дней
	$where .= " AND post_date >= '" . date('Y-m-d', strtotime('-60 days')) . "'" . " AND post_date <= '" . date('Y-m-d', strtotime('-30 days')) . "'";
	return $where;
}

add_filter( 'posts_where', 'filter_where' );
$query = new WP_Query( $query_string );
remove_filter( 'posts_where', 'filter_where' );

Параметр "m" может быть установлен только в списке постов в админ-панели. Он полезен когда вы выбираете из выпадающего списка select где дата установлена как число YYYYmm.

Примеры с параметром date_query

#1. Получим посты между 9 и 17 часами:

$args = array(
	'date_query' => array(
		array(
			'hour'      => 9,
			'compare'   => '>=',
		),
		array(
			'hour'      => 17,
			'compare'   => '<=',
		),
		array(
			'dayofweek' => array( 2, 6 ),
			'compare'   => 'BETWEEN',
		),
	),
	'posts_per_page' => -1,
);
$query = new WP_Query( $args );

#2. Получим посты за промежуток времени: 1 января по 28 февраля:

$args = array(
	'date_query' => array(
		array(
			'after'     => 'January 1st, 2013',
			'before'    => array(
				'year'  => 2013,
				'month' => 2,
				'day'   => 28,
			),
			'inclusive' => true,
		),
	),
	'posts_per_page' => -1,
);
$query = new WP_Query( $args );

Даты можно указывать цифрами и строками, как видно из этого примера, потому что аргументы before и after обрабатываются функцией PHP strtotime(), а она понимает строки.

#3. Получим посты опубликованные год назад, но измененные в последний месяц:

$args = array(
	'date_query' => array(
		array(
			'column' => 'post_date_gmt',
			'before' => '1 year ago',
		),
		array(
			'column' => 'post_modified_gmt',
			'after'  => '1 month ago',
		),
	),
	'posts_per_page' => -1,
);
$query = new WP_Query( $args );

#4. Получим посты за последние 2 недели, использовав строку '2 weeks ago':

$query = new WP_Query( array(
	'date_query' => array(
		'after' => '2 weeks ago',
	),
) );

#5. Получим записи за последние 2 месяца, опубликованные в будние дни:

$query = new WP_Query( array(
	'date_query' => array(
		'after' => '2 months ago',
		array(
			'dayofweek' => array( 1, 5 ),
			'compare' => 'BETWEEN',
		),
	),
) );

Аргумент date_query работает и с классом WP_Comment_Query, поэтому его точно также можно использовать в функции: get_comments().

Параметры Отступов

Можно установить отступ от первого поста в результатах запроса. Например, стандартно запрос возвращает 6 постов, а если в тот же запрос добавить параметр offset=1, то будут возвращены 5 постов (первый пост из запроса будет пропущен).

offset(число)
Сколько постов из результатов запроса пропустить.

Пример использования

Пропустим первый/один пост (offset=1) и вернем следующие 5:

$query = new WP_Query('posts_per_page=5&offset=1');

Параметры Сортировки и порядка

Сортирует и устанавливает направление сортировки.

order(строка)

Направление сортировки по параметру orderby, может быть:

  • ASC - по порядку, от меньшего к большему (1, 2, 3; a, b, c).
  • DESC - в обратном порядке, от большего к меньшему (3, 2, 1; c, b, a) .
orderby(строка)

Поля по которым можно сортировать посты. Может быть

  • none - не сортировать, выводить как есть в БД. Равносильно сортировке по ID. С версии 2.8.
  • ID - сортировка по ID.
  • author - сортировка по ID авторов.
  • title - сортировка по заголовку.
  • name - по названию поста (ярлык, слаг поста).
  • date - сортировка по дате публикации.
  • modified - сортировка по дате изменения.
  • type - по типу поста (post_type). С версии 4.0
  • parent - сортировка по значению поля parent.
  • rand - случайный порядок.
  • RAND(x) - в случайном порядке для числовых значений. Тут "x" - это целое число.
  • comment_count - сортировка по количеству комментариев. С версии 2.9.
  • menu_order - стандартно используется для страниц и вложений. Порядковый номер указывается на странице редактирования поста.
  • meta_value - по значения произвольного поля.

    Важно: параметр meta_key так же должен быть определен. Заметка: сортировка будет алфавитной и будет не логична, если значения
    произвольных полей числа (будет, например, так 1, 3, 34, 4, 56, 6 и т.д., а не 1, 3, 4, 6, 34, 56).

  • meta_value_num - сортировка по произвольным полям, значения которых являются числами. С версии 2.8.
  • ключ массива из meta_query - в этом случае сортировка будет по значению произвольного поля указанного в массиве meta_query.
  • post__in - учитывает порядок указанных ID в параметре post__in.
orderby = array()

С версии WordPress 4.0 в orderby можно указывать массив сочетающий в себе оба параметра: orderby и order. Сделано это для сортировки по нескольким колонкам одновременною Синтаксис такой:

'orderby' => array( 'title' => 'DESC', 'menu_order' => 'ASC' )

#1 Сортировка по заголовку

$query = new WP_Query( array ( 'orderby' => 'title', 'order' => 'DESC' ) );

Отсортируем по порядку в меню, а затем по заголовку

$query = new WP_Query( array ( 'orderby' => 'menu_order title', 'order' => 'DESC' ) );

#2 Выведем один случайный пост:

$query = new WP_Query( array ( 'orderby' => 'rand', 'posts_per_page' => '1' ) );

#3 Отсортируем посты по количеству комментариев:

$query = new WP_Query( array( 'orderby' => 'comment_count' ) );

#4 Отсортируем продукты по цене (произвольное поле price):

$query = new WP_Query( 
	 array ( 'post_type' => 'product', 'orderby' => 'meta_value', 'meta_key' => 'price' ) 
);

#5 Множественная сортировка

Выведем посты отсортированные по двум полям: 'title' и 'menu_order' (title первостепенен):

$query = new WP_Query( 
	array( 'post_type' => 'page', 'orderby' => 'title menu_order', 'order' => 'ASC' ) 
);

#6 Множественная сортировка с использованием массива (с версии 4.0)

Получим страницы отсортированные по заголовку (title) и номеру меню (menu_order) в разном порядке (ASC/DESC):

$query = new WP_Query( array( 'orderby' => array( 'title' => 'DESC', 'menu_order' => 'ASC' ) ) );

#7 Сортировка по 'meta_value' для нового типа поста (post_type)

Выведем посты типа 'my_custom_post_type' отсортированные по ключу произвольного поля "age" и отфильтрованные, чтобы показывались только посты со значением поля 3 и 4:

$args = array(
   'post_type' => 'my_custom_post_type',
   'meta_key' => 'age',
   'orderby' => 'meta_value_num',
   'order' => 'ASC',
   'meta_query' => array(
	   array(
		   'key' => 'age',
		   'value' => array(3, 4),
		   'compare' => 'IN',
	   )
   )
 );
 $query = new WP_Query($args);

Параметры Пагинации

nopaging(логический)
Выключит пагинацию, выведет все посты на одной странице.
posts_per_page(число)

Количество постов на одной странице. Если выставить -1, то будут выведены все посты (без пагинации).

С версии 2.1 заменяет параметр showposts. Установите параметр paged, если пагинация не работает, после использования этого параметра.

Заметка: если запрос в feed части, WP перезаписывает этот параметр опцией posts_per_rss. Чтобы повлиять на вывод постов в фиде используйте фильтры post_limits или pre_option_posts_per_rss.

posts_per_archive_page(число)
Количество постов для страниц архивов: для страниц, которые удовлетворяют условиям is_archive() или is_search(). Этот параметр перезаписывает параметры "posts_per_page" и "showposts".
offset(число)
Сколько постов пропустить сверху выборки (верхний отступ).
Внимание: Установка этого параметра переписывает/игнорирует параметр "paged" и ломает пагинацию (решение проблемы).
paged(число)
Номер страницы пагинации. Показывает посты, которые в обычном режиме должны были быть показаны на странице пагинации Х. Переписывает параметр posts_per_page
page(число)
Номер для статической домашней страницы. Показывает записи, которые в обычном режиме должны были быть показаны на странице пагинации Х главной статической странице (front page).
ignore_sticky_posts(логический)

Игнорировать прилепленные посты или нет (true/false). С версии 3.1. Заменяет параметр caller_get_posts.

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

#1 Посты на странице

Выведем 3 поста на странице:

$query = new WP_Query( 'posts_per_page=3' );

Выведем все посты на странице:

$query = new WP_Query( 'posts_per_page=-1' );

Выведем все посты и отключим пагинацию:

$query = new WP_Query( 'nopaging=true' );

#2 Отступы сверху

Выведем посты начиная с четвертого (пропустим первые 3):

$query = new WP_Query( 'offset=3' ) );

Выведем 5 постов которые идет за тремя последними:

$query = new WP_Query( array( 'posts_per_page' => 5, 'offset' => 3 ) );

#3 Записи со страницы пагинации 6

$query = new WP_Query( 'paged=6' );

#4 Записи с текущей страницы

Покажем посты с текущей страницы пагинации. Полезно при построении произвольной пагинации:

$query = new WP_Query( array( 'paged' => get_query_var( 'paged' ) ) );

Выведем посты с текущей страницы и установим параметр paged в 1, когда переменная не определена на первой странице пагинации:

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$query = new WP_Query( array( 'paged' => $paged ) );

Используйте get_query_var('page'); если нужно получить номер страницы пагинации для статической главной страницы сайта (is_front_page()). Переменная "page" раже содержит номер пагинации на отдельных страницах типа post, когда в контенте используется тег <!--nextpage--> для разбиения контента на страницы.

Вывод текущей страницы пагинации на статической главной странице:

$paged = (get_query_var('page')) ? get_query_var('page') : 1;
$query = new WP_Query( array( 'paged' => $paged ) );

#5 Прилепленные записи (посты)

# Все прилепленные записи
$sticky = get_option( 'sticky_posts' );
$query = new WP_Query( ('post__in'=>$sticky );
# Только первый прилепленный пост
$sticky = get_option( 'sticky_posts' );
$query = new WP_Query( 'p=' . $sticky[0] );
# Первый прилепленный пост, если такого поста нет, то последний опубликованный
$args = array(
	'posts_per_page' => 1,
	'post__in'  => get_option( 'sticky_posts' ),
	'ignore_sticky_posts' => 1
);
$query = new WP_Query( $args );
# Первый прилепленный пост, если такого поста нет, то ничего не выводим
$sticky = get_option( 'sticky_posts' );
$args = array(
	'posts_per_page' => 1,
	'post__in'  => $sticky,
	'ignore_sticky_posts' => 1
);
$query = new WP_Query( $args );
if ( $sticky[0] ) {
	// формируем вывод...
}
# 5 последних прилепленных записей
$sticky = get_option( 'sticky_posts' ); // все Sticky записи

rsort( $sticky ); // отсортируем - новые вверху

$sticky = array_slice( $sticky, 0, 5 ); // получим первые 5

$query = new WP_Query( array( 'post__in'=>$sticky, 'ignore_sticky_posts'=>1 ) );

#6 Скрытие прилепленных постов

Исключим все прилепленные посты из запроса:

$query = new WP_Query( array( 'post__not_in' => get_option( 'sticky_posts' ) ) );

Исключим прилепленные посты из категории. Вернет все посты рубрики, но прилепленные посты не будут сверху, они будут выводится как обычные посты (по дате):

$query = new WP_Query( array( 'ignore_sticky_posts' => 1, 'posts_per_page' => 3, 'cat' => 6 );

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

$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
$sticky = get_option( 'sticky_posts' );
$args = array(
	'cat' => 3,
	'ignore_sticky_posts' => 1,
	'post__not_in' => $sticky,
	'paged' => $paged
);
$query = new WP_Query( $args );

Параметры Комментариев

В объект WP_Query добавляются данные комментариев записи, если это отдельная запись. В параметрах ниже, указывается как нужно получать комментарии в таких случаях.

comment_status(строка)
Статус комментария.
ping_status(число)
Статус пинга.
comments_per_page(число)
Число комментариев для получения на отдельной странице комментариев. По умолчанию опция: comments_per_page.

Параметры Поиска

s(строка)
поисковая фраза.
exact(логический)
true - искать по точной фразе указанной в параметре s.
По умолчанию: false

Посты найденные по поисковой фразе.

$query = new WP_Query( 's=keyword' );

Параметры Доступа

Показывает посты если пользователь имеет достаточные права.

perm(строка)
Доступ пользователя.

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

$query = new WP_Query( 
	  array( 'post_status' => array( 'publish', 'private' ), 'perm' => 'readable' ) 
);

Параметры Кэширования

Не добавляет данные в кэш при выполнении запросов.

cache_results(логический)
Кэшировать ли информацию о посте.
update_post_meta_cache(логический)
Кэшировать ли информацию о мета данных поста.
update_post_term_cache(логический)
Кэшировать ли информацию о привязке поста к терминам и таксономиям.

#1 Выведем 50 постов, но не будет добавлять информацию о постах в кэш:

$query = new WP_Query( array( 'posts_per_page' => 50, 'cache_results' => false ) );

#2 Выведем 50 постов, но не будем добавлять мета данные поста в кэш

$query = new WP_Query( array( 'posts_per_page' => 50, 'update_post_meta_cache' => false ) );

#3 Выведем 50 постов, но не будем добавлять в кэш информацию о терминах постов

$query = new WP_Query( array( 'posts_per_page' => 50, 'update_post_term_cache' => false ) );

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

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

Параметры Возвращаемых данных

Устанавливает какие данные должен возвращать запрос.

fields(строка/массив)

Какие данные возвращать. По умолчанию возвращаются все.

  • ids - вернет массив с ID постов.
  • id=>parent - вернет ассоциативный массив [ parent => ID, … ].
  • Вставка любых других параметров, вернет все поля (по умолчанию) - массив объектов постов.
no_found_rows(логический)
true - не подсчитывать количество найденных строк. В некоторых случаях может ускорить запрос.
По умолчанию: false

Комбинирование параметров

#1. Комбинирование в строке

Вы наверняка заметили, что параметры соединяются между собой символом амперсанд - &, именно этим символом параметры комбинируются (объединяются).

$query = new WP_Query('cat=3&year=2004');

#2. Комбинирование с переменными

Посты из категории 13 за текущий месяц на главной странице блога:

if (is_home()) {
$query = new WP_Query($query_string . '&cat=13&monthnum=' . date('n',current_time('timestamp')));
}

#3. Комбинирование массивом

Вернет только 2 поста, из категории 1 и 3, отсортированные в обратном порядке по заголовку:

$query = new WP_Query( array(
   'category__and'=>array(1,3),
   'posts_per_page'=>2,
   'orderby'=>title,
   'order'=>DESC
));

#4. Записи из категории и с меткой

Вывести все посты из категории 1, имеющие метку apples:

$query = new WP_Query('cat=1&tag=apples');

Примеры

#1. На главной, исключим посты из рубрики 3

Чтобы на главной странице блога исключить посты, которые находятся в категории 3, нужно вставить следующий код в файл index.php перед началом Цикла WordPress:

<?php
   if (is_home()) {
	  $query = new WP_Query("cat=-3");
   }
?>

#1.2. Можно добавить еще несколько категорий к исключению:

<?php
   if (is_home()) {
	  $query = new WP_Query("cat=-1,-2,-3");
   }
?>

#2. Получим определенный пост (пост с ID = 5):

<?php
// retrieve one post with an ID of 5
$query = new WP_Query('p=5');
?>

#3. Если нужно использовать функцию "читать дальше" (read more) с новым запросом, то нужно переключить глобальную переменную $more на 0:

<?php
// retrieve one post with an ID of 5
$query = new WP_Query('p=5');

global $more;
// set $more to 0 in order to only get the first part of the post
$more = 0; 

// the Loop
while (have_posts()) : the_post();
  // the content of the post
  the_content('Read the full post »');
endwhile;
?>

#4. Получаем определенную страницу (страницу 7):

<?php
$query = new WP_Query('page_id=7');      // получит только страницу с ID 7
?>

или

<?php
$query = new WP_Query('pagename=o-saite'); // получит только страницу "o-saite"
?>

#4.1. Для дочерних страниц нужно указывать имя родительской страницы и самой дочерней страницы. Имена разделяются слэшем (/). Пример:

<?php
$query = new WP_Query('pagename=o-saite/avtori'); // получит страницу "avtori", которая является дочерней к "o-saite"
?>

Вставка переменных в параметры запроса

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

#1. Сборка запроса с использованием одинарных кавычек ' ':
<?php
 $categoryvariable=$cat; // задаем переменной $categoryvariable ID текущей категории
 $query= 'cat=' . $categoryvariable. '&orderby=date&order=ASC'; // собираем запрос
 $query = new WP_Query($query); // запускаем запрос к БД
 ?>
#2. Сборка запроса с использованием двойных кавычек " "

Переменные внутри двойных кавычек интерпретируются PHP как переменные, а не как простой текст):

<?php
$current_month = date('m');
$current_year = date('Y');

$query = new WP_Query("cat=22&year=$current_year&monthnum=$current_month&order=ASC");
?>
<!-- здесь идет Цикл WordPress -->
#3. Использование глобальной переменной $query_string

Которая содержит в себе базовый запрос для функции query_posts. Если нам нужно не нарушать стандартный вывод постов WordPress (например, на странице категорий), но при этом убрать пагинацию (вывести все посты на одной странице), то мы может дополнить базовый запрос функции query_posts, параметром posts_per_page=-1:

<?php
global $wp_query;
$wp_query = new WP_Query( $query_string . '&posts_per_page=-1');
while( have_posts() ){
	the_post();
	// здесь идет Цикл WordPress
}

wp_reset_query(); // сброс глобальной $wp_query
?>

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

#4. Параметры также можно передать в виде массива

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

$query = new WP_Query(array(
	'cat'      => 22,
	'year'     => $current_year,
	'monthnum' => $current_month,
	'order'    => 'ASC',
));

Как видите тут можно поставить каждую переменную на отдельную строку, а это более понятно и читаемо.

Добавление параметров в запрос

Сохранение базового запроса текущей страницы и добавление в него своих параметров

функция query_posts полностью переписывает запрос, если например, мы напишем query_posts ('cat=1'), то другие параметры запроса, которые используются для текущей страницы (например, сортировка, пагинация и т.д.), будут потеряны и будут выведены посты категории 1 с остальными параметрами по умолчанию. Чтобы сохранить базовые параметры запроса и дополнить/заменить их своими нужно использовать PHP функцию array_merge (объединяет 2 массива в один):

global $wp_query;
$query = new WP_Query(
	array_merge(
		array('cat' => 1), // это параметр который добавили мы
		$wp_query->query // это массив базового запроса текущей страницы
	)
);

Этот пример по сути тоже самое что и пример 3 (Использование глобальной переменной $query_string), только с использованием массивов.

Методы и свойства класса

Свойства класса WP_Query

$query
Хранит строку запроса.
$query_vars
Ассоциативные массив с данными запроса.
$tax_query
Запрос для таксономии, объект который передается в get_tax_sql().
$meta_query
Запрос для метаполей.
$date_query
Запрос для дат.
$queried_object
Применяется в запросах типа: рубрика, автор, пост или страница. Содержит информацию о категории, авторе, посте или странице.
$queried_object_id
Если запрос относится к рубрике, автору, посте или странице, содержит соответствующий ID.
$request
Полный SQL запрос, который был построен на основе переданных параметров запроса.
$posts
Заполняется данными постов полученными из Базы Данных.
$post_count
Количество постов выводимых на странице.
$current_post
Доступно во время цикла. Индекс текущего поста, которые выводиться.
$in_the_loop
Логическая переменная. Определяет начат ли цикл и находится ли вызываемый объект в цикле.
$post
Доступно во время цикла. Пост который выводится в текущий момент.
$comments
Список комментариев для текущего поста.
$comment_count
Количество комментариев для постов.
$current_comment
Текущий комментарий в цикле комментариев.
$comment
ID текущего комментария.
$found_posts
Количество всех найденных постов.
$max_num_pages
Количество страниц пагинации: $found_posts / $posts_per_page
$is_single, $is_page, $is_archive, $is_preview, $is_date, $is_year, $is_month, $is_time, $is_author, $is_category, $is_tag, $is_tax, $is_search, $is_feed, $is_comment_feed, $is_trackback, $is_home, $is_404, $is_comments_popup, $is_admin, $is_attachment, $is_singular, $is_robots, $is_posts_page, $is_paged
Логические значения. Определяют к какому из типа страницы относится текущий запрос.
$stopwords
Кэшированный список стопслов для поиска.

Методы класса WP_Query

Амперсанд (&) перед методом, вызывает его как ссылку.

init()
Активирует объект, выставляет все значение свойств в null, 0 или false.
parse_query( $query )
Получает параметры запроса, анализирует их и выставляет базовые свойства класса: $posts, $post_count, $post и $current_post.
parse_query_vars()
Анализирует старый запрос заново.
get( $query_var )
Получает переменную запроса по имени.
set( $query_var, $value )
Устанавливает переменную запроса. Указываются: название переменной и её значение.
&get_posts()
Получает требуемые посты из БД. Также заполняет свойства $posts и $post_count.
next_post()
Используется во время цикла. Переходит к следующему посту в массиве $posts. Устанавливает $current_post и $post. Метод не устанавливает глобальную переменную $post, а влияет на переменную внутри класса. Возвращает данные текущего поста (объект).
the_post()
Используется во время цикла. Переходит к следующему посту и меняет глобальную переменную $post.
have_posts()
Используется прям перед циклом. Проверяет есть ли посты для вывода.
rewind_posts()
Сбрасывает переменные $current_post и $post.
&query( $query )
Вызывает методы: parse_query() и get_posts(). Возвращает результат get_posts().
get_queried_object()
Заполняет переменную $queried_object, если она еще не заполнена и возвращает её.
get_queried_object_id()
Заполняет переменную $queried_object_id , если она еще не заполнена и возвращает её.
__construct($query = '')
Конструктор класса. Если переданы данные запроса, вызывает метод query() и передает ему данные.

Заметки по фильтрам

Можно использовать следующие фильтры для внедрения непосредственно в сам SQL запрос.

Фильтры срабатывающие до установки запроса пагинации:
Фильтры срабатывающие после установки запроса пагинации:
  • posts_where_paged - изменяет SQL 'WHERE' во время пагинации
  • posts_groupby - изменяет SQL 'GROUP BY'
  • posts_join_paged - изменяет SQL 'JOIN' во время пагинации
  • posts_orderby - изменяет SQL 'ORDER BY'
  • posts_distinct - изменяет SQL 'DISTINCTROW'
  • post_limits - изменяет SQL 'LIMIT'
  • posts_fields - изменяет получаемые поля таблицы
  • posts_clauses - позволяет изменять все части одновременно, передает массив:

    Array (
    	[where]    =>  AND 1 = 1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
    	[groupby]  => wp_posts.ID
    	[join]     => INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
    	[orderby]  => wp_posts.post_date DESC
    	[distinct] => 
    	[fields]   => wp_posts.*
    	[limits]   => LIMIT 0, 10
    )

Код WP_Query: wp-includes/class-wp-query.php VER 4.9.8

<?php
class WP_Query {

	/**
	 * Query vars set by the user
	 *
	 * @since 1.5.0
	 * @var array
	 */
	public $query;

	/**
	 * Query vars, after parsing
	 *
	 * @since 1.5.0
	 * @var array
	 */
	public $query_vars = array();

	/**
	 * Taxonomy query, as passed to get_tax_sql()
	 *
	 * @since 3.1.0
	 * @var object WP_Tax_Query
	 */
	public $tax_query;

	/**
	 * Metadata query container
	 *
	 * @since 3.2.0
	 * @var object WP_Meta_Query
	 */
	public $meta_query = false;

	/**
	 * Date query container
	 *
	 * @since 3.7.0
	 * @var object WP_Date_Query
	 */
	public $date_query = false;

	/**
	 * Holds the data for a single object that is queried.
	 *
	 * Holds the contents of a post, page, category, attachment.
	 *
	 * @since 1.5.0
	 * @var object|array
	 */
	public $queried_object;

	/**
	 * The ID of the queried object.
	 *
	 * @since 1.5.0
	 * @var int
	 */
	public $queried_object_id;

	/**
	 * Get post database query.
	 *
	 * @since 2.0.1
	 * @var string
	 */
	public $request;

	/**
	 * List of posts.
	 *
	 * @since 1.5.0
	 * @var array
	 */
	public $posts;

	/**
	 * The amount of posts for the current query.
	 *
	 * @since 1.5.0
	 * @var int
	 */
	public $post_count = 0;

	/**
	 * Index of the current item in the loop.
	 *
	 * @since 1.5.0
	 * @var int
	 */
	public $current_post = -1;

	/**
	 * Whether the loop has started and the caller is in the loop.
	 *
	 * @since 2.0.0
	 * @var bool
	 */
	public $in_the_loop = false;

	/**
	 * The current post.
	 *
	 * @since 1.5.0
	 * @var WP_Post
	 */
	public $post;

	/**
	 * The list of comments for current post.
	 *
	 * @since 2.2.0
	 * @var array
	 */
	public $comments;

	/**
	 * The amount of comments for the posts.
	 *
	 * @since 2.2.0
	 * @var int
	 */
	public $comment_count = 0;

	/**
	 * The index of the comment in the comment loop.
	 *
	 * @since 2.2.0
	 * @var int
	 */
	public $current_comment = -1;

	/**
	 * Current comment ID.
	 *
	 * @since 2.2.0
	 * @var int
	 */
	public $comment;

	/**
	 * The amount of found posts for the current query.
	 *
	 * If limit clause was not used, equals $post_count.
	 *
	 * @since 2.1.0
	 * @var int
	 */
	public $found_posts = 0;

	/**
	 * The amount of pages.
	 *
	 * @since 2.1.0
	 * @var int
	 */
	public $max_num_pages = 0;

	/**
	 * The amount of comment pages.
	 *
	 * @since 2.7.0
	 * @var int
	 */
	public $max_num_comment_pages = 0;

	/**
	 * Signifies whether the current query is for a single post.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_single = false;

	/**
	 * Signifies whether the current query is for a preview.
	 *
	 * @since 2.0.0
	 * @var bool
	 */
	public $is_preview = false;

	/**
	 * Signifies whether the current query is for a page.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_page = false;

	/**
	 * Signifies whether the current query is for an archive.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_archive = false;

	/**
	 * Signifies whether the current query is for a date archive.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_date = false;

	/**
	 * Signifies whether the current query is for a year archive.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_year = false;

	/**
	 * Signifies whether the current query is for a month archive.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_month = false;

	/**
	 * Signifies whether the current query is for a day archive.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_day = false;

	/**
	 * Signifies whether the current query is for a specific time.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_time = false;

	/**
	 * Signifies whether the current query is for an author archive.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_author = false;

	/**
	 * Signifies whether the current query is for a category archive.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_category = false;

	/**
	 * Signifies whether the current query is for a tag archive.
	 *
	 * @since 2.3.0
	 * @var bool
	 */
	public $is_tag = false;

	/**
	 * Signifies whether the current query is for a taxonomy archive.
	 *
	 * @since 2.5.0
	 * @var bool
	 */
	public $is_tax = false;

	/**
	 * Signifies whether the current query is for a search.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_search = false;

	/**
	 * Signifies whether the current query is for a feed.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_feed = false;

	/**
	 * Signifies whether the current query is for a comment feed.
	 *
	 * @since 2.2.0
	 * @var bool
	 */
	public $is_comment_feed = false;

	/**
	 * Signifies whether the current query is for trackback endpoint call.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_trackback = false;

	/**
	 * Signifies whether the current query is for the site homepage.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_home = false;

	/**
	 * Signifies whether the current query couldn't find anything.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_404 = false;

	/**
	 * Signifies whether the current query is for an embed.
	 *
	 * @since 4.4.0
	 * @var bool
	 */
	public $is_embed = false;

	/**
	 * Signifies whether the current query is for a paged result and not for the first page.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_paged = false;

	/**
	 * Signifies whether the current query is for an administrative interface page.
	 *
	 * @since 1.5.0
	 * @var bool
	 */
	public $is_admin = false;

	/**
	 * Signifies whether the current query is for an attachment page.
	 *
	 * @since 2.0.0
	 * @var bool
	 */
	public $is_attachment = false;

	/**
	 * Signifies whether the current query is for an existing single post of any post type
	 * (post, attachment, page, custom post types).
	 *
	 * @since 2.1.0
	 * @var bool
	 */
	public $is_singular = false;

	/**
	 * Signifies whether the current query is for the robots.txt file.
	 *
	 * @since 2.1.0
	 * @var bool
	 */
	public $is_robots = false;

	/**
	 * Signifies whether the current query is for the page_for_posts page.
	 *
	 * Basically, the homepage if the option isn't set for the static homepage.
	 *
	 * @since 2.1.0
	 * @var bool
	 */
	public $is_posts_page = false;

	/**
	 * Signifies whether the current query is for a post type archive.
	 *
	 * @since 3.1.0
	 * @var bool
	 */
	public $is_post_type_archive = false;

	/**
	 * Stores the ->query_vars state like md5(serialize( $this->query_vars ) ) so we know
	 * whether we have to re-parse because something has changed
	 *
	 * @since 3.1.0
	 * @var bool|string
	 */
	private $query_vars_hash = false;

	/**
	 * Whether query vars have changed since the initial parse_query() call. Used to catch modifications to query vars made
	 * via pre_get_posts hooks.
	 *
	 * @since 3.1.1
	 */
	private $query_vars_changed = true;

	/**
	 * Set if post thumbnails are cached
	 *
	 * @since 3.2.0
	 * @var bool
	 */
	 public $thumbnails_cached = false;

	/**
	 * Cached list of search stopwords.
	 *
	 * @since 3.7.0
	 * @var array
	 */
	private $stopwords;

	private $compat_fields = array( 'query_vars_hash', 'query_vars_changed' );

	private $compat_methods = array( 'init_query_flags', 'parse_tax_query' );

	/**
	 * Resets query flags to false.
	 *
	 * The query flags are what page info WordPress was able to figure out.
	 *
	 * @since 2.0.0
	 */
	private function init_query_flags() {
		$this->is_single = false;
		$this->is_preview = false;
		$this->is_page = false;
		$this->is_archive = false;
		$this->is_date = false;
		$this->is_year = false;
		$this->is_month = false;
		$this->is_day = false;
		$this->is_time = false;
		$this->is_author = false;
		$this->is_category = false;
		$this->is_tag = false;
		$this->is_tax = false;
		$this->is_search = false;
		$this->is_feed = false;
		$this->is_comment_feed = false;
		$this->is_trackback = false;
		$this->is_home = false;
		$this->is_404 = false;
		$this->is_paged = false;
		$this->is_admin = false;
		$this->is_attachment = false;
		$this->is_singular = false;
		$this->is_robots = false;
		$this->is_posts_page = false;
		$this->is_post_type_archive = false;
	}

	/**
	 * Initiates object properties and sets default values.
	 *
	 * @since 1.5.0
	 */
	public function init() {
		unset($this->posts);
		unset($this->query);
		$this->query_vars = array();
		unset($this->queried_object);
		unset($this->queried_object_id);
		$this->post_count = 0;
		$this->current_post = -1;
		$this->in_the_loop = false;
		unset( $this->request );
		unset( $this->post );
		unset( $this->comments );
		unset( $this->comment );
		$this->comment_count = 0;
		$this->current_comment = -1;
		$this->found_posts = 0;
		$this->max_num_pages = 0;
		$this->max_num_comment_pages = 0;

		$this->init_query_flags();
	}

	/**
	 * Reparse the query vars.
	 *
	 * @since 1.5.0
	 */
	public function parse_query_vars() {
		$this->parse_query();
	}

	/**
	 * Fills in the query variables, which do not exist within the parameter.
	 *
	 * @since 2.1.0
	 * @since 4.4.0 Removed the `comments_popup` public query variable.
	 *
	 * @param array $array Defined query variables.
	 * @return array Complete query variables with undefined ones filled in empty.
	 */
	public function fill_query_vars($array) {
		$keys = array(
			'error'
			, 'm'
			, 'p'
			, 'post_parent'
			, 'subpost'
			, 'subpost_id'
			, 'attachment'
			, 'attachment_id'
			, 'name'
			, 'static'
			, 'pagename'
			, 'page_id'
			, 'second'
			, 'minute'
			, 'hour'
			, 'day'
			, 'monthnum'
			, 'year'
			, 'w'
			, 'category_name'
			, 'tag'
			, 'cat'
			, 'tag_id'
			, 'author'
			, 'author_name'
			, 'feed'
			, 'tb'
			, 'paged'
			, 'meta_key'
			, 'meta_value'
			, 'preview'
			, 's'
			, 'sentence'
			, 'title'
			, 'fields'
			, 'menu_order'
			, 'embed'
		);

		foreach ( $keys as $key ) {
			if ( !isset($array[$key]) )
				$array[$key] = '';
		}

		$array_keys = array( 'category__in', 'category__not_in', 'category__and', 'post__in', 'post__not_in', 'post_name__in',
			'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'post_parent__in', 'post_parent__not_in',
			'author__in', 'author__not_in' );

		foreach ( $array_keys as $key ) {
			if ( !isset($array[$key]) )
				$array[$key] = array();
		}
		return $array;
	}

	/**
	 * Parse a query string and set query type booleans.
	 *
	 * @since 1.5.0
	 * @since 4.2.0 Introduced the ability to order by specific clauses of a `$meta_query`, by passing the clause's
	 *              array key to `$orderby`.
	 * @since 4.4.0 Introduced `$post_name__in` and `$title` parameters. `$s` was updated to support excluded
	 *              search terms, by prepending a hyphen.
	 * @since 4.5.0 Removed the `$comments_popup` parameter.
	 *              Introduced the `$comment_status` and `$ping_status` parameters.
	 *              Introduced `RAND(x)` syntax for `$orderby`, which allows an integer seed value to random sorts.
	 * @since 4.6.0 Added 'post_name__in' support for `$orderby`. Introduced the `$lazy_load_term_meta` argument.
	 * @since 4.9.0 Introduced the `$comment_count` parameter.
	 *
	 * @param string|array $query {
	 *     Optional. Array or string of Query parameters.
	 *
	 *     @type int          $attachment_id           Attachment post ID. Used for 'attachment' post_type.
	 *     @type int|string   $author                  Author ID, or comma-separated list of IDs.
	 *     @type string       $author_name             User 'user_nicename'.
	 *     @type array        $author__in              An array of author IDs to query from.
	 *     @type array        $author__not_in          An array of author IDs not to query from.
	 *     @type bool         $cache_results           Whether to cache post information. Default true.
	 *     @type int|string   $cat                     Category ID or comma-separated list of IDs (this or any children).
	 *     @type array        $category__and           An array of category IDs (AND in).
	 *     @type array        $category__in            An array of category IDs (OR in, no children).
	 *     @type array        $category__not_in        An array of category IDs (NOT in).
	 *     @type string       $category_name           Use category slug (not name, this or any children).
	 *     @type array|int    $comment_count           Filter results by comment count. Provide an integer to match
	 *                                                 comment count exactly. Provide an array with integer 'value'
	 *                                                 and 'compare' operator ('=', '!=', '>', '>=', '<', '<=' ) to
	 *                                                 compare against comment_count in a specific way.
	 *     @type string       $comment_status          Comment status.
	 *     @type int          $comments_per_page       The number of comments to return per page.
	 *                                                 Default 'comments_per_page' option.
	 *     @type array        $date_query              An associative array of WP_Date_Query arguments.
	 *                                                 See WP_Date_Query::__construct().
	 *     @type int          $day                     Day of the month. Default empty. Accepts numbers 1-31.
	 *     @type bool         $exact                   Whether to search by exact keyword. Default false.
	 *     @type string|array $fields                  Which fields to return. Single field or all fields (string),
	 *                                                 or array of fields. 'id=>parent' uses 'id' and 'post_parent'.
	 *                                                 Default all fields. Accepts 'ids', 'id=>parent'.
	 *     @type int          $hour                    Hour of the day. Default empty. Accepts numbers 0-23.
	 *     @type int|bool     $ignore_sticky_posts     Whether to ignore sticky posts or not. Setting this to false
	 *                                                 excludes stickies from 'post__in'. Accepts 1|true, 0|false.
	 *                                                 Default 0|false.
	 *     @type int          $m                       Combination YearMonth. Accepts any four-digit year and month
	 *                                                 numbers 1-12. Default empty.
	 *     @type string       $meta_compare            Comparison operator to test the 'meta_value'.
	 *     @type string       $meta_key                Custom field key.
	 *     @type array        $meta_query              An associative array of WP_Meta_Query arguments. See WP_Meta_Query.
	 *     @type string       $meta_value              Custom field value.
	 *     @type int          $meta_value_num          Custom field value number.
	 *     @type int          $menu_order              The menu order of the posts.
	 *     @type int          $monthnum                The two-digit month. Default empty. Accepts numbers 1-12.
	 *     @type string       $name                    Post slug.
	 *     @type bool         $nopaging                Show all posts (true) or paginate (false). Default false.
	 *     @type bool         $no_found_rows           Whether to skip counting the total rows found. Enabling can improve
	 *                                                 performance. Default false.
	 *     @type int          $offset                  The number of posts to offset before retrieval.
	 *     @type string       $order                   Designates ascending or descending order of posts. Default 'DESC'.
	 *                                                 Accepts 'ASC', 'DESC'.
	 *     @type string|array $orderby                 Sort retrieved posts by parameter. One or more options may be
	 *                                                 passed. To use 'meta_value', or 'meta_value_num',
	 *                                                 'meta_key=keyname' must be also be defined. To sort by a
	 *                                                 specific `$meta_query` clause, use that clause's array key.
	 *                                                 Accepts 'none', 'name', 'author', 'date', 'title',
	 *                                                 'modified', 'menu_order', 'parent', 'ID', 'rand',
	 *                                                 'relevance', 'RAND(x)' (where 'x' is an integer seed value),
	 *                                                 'comment_count', 'meta_value', 'meta_value_num', 'post__in',
	 *                                                 'post_name__in', 'post_parent__in', and the array keys
	 *                                                 of `$meta_query`. Default is 'date', except when a search
	 *                                                 is being performed, when the default is 'relevance'.
	 *
	 *     @type int          $p                       Post ID.
	 *     @type int          $page                    Show the number of posts that would show up on page X of a
	 *                                                 static front page.
	 *     @type int          $paged                   The number of the current page.
	 *     @type int          $page_id                 Page ID.
	 *     @type string       $pagename                Page slug.
	 *     @type string       $perm                    Show posts if user has the appropriate capability.
	 *     @type string       $ping_status             Ping status.
	 *     @type array        $post__in                An array of post IDs to retrieve, sticky posts will be included
	 *     @type string       $post_mime_type          The mime type of the post. Used for 'attachment' post_type.
	 *     @type array        $post__not_in            An array of post IDs not to retrieve. Note: a string of comma-
	 *                                                 separated IDs will NOT work.
	 *     @type int          $post_parent             Page ID to retrieve child pages for. Use 0 to only retrieve
	 *                                                 top-level pages.
	 *     @type array        $post_parent__in         An array containing parent page IDs to query child pages from.
	 *     @type array        $post_parent__not_in     An array containing parent page IDs not to query child pages from.
	 *     @type string|array $post_type               A post type slug (string) or array of post type slugs.
	 *                                                 Default 'any' if using 'tax_query'.
	 *     @type string|array $post_status             A post status (string) or array of post statuses.
	 *     @type int          $posts_per_page          The number of posts to query for. Use -1 to request all posts.
	 *     @type int          $posts_per_archive_page  The number of posts to query for by archive page. Overrides
	 *                                                 'posts_per_page' when is_archive(), or is_search() are true.
	 *     @type array        $post_name__in           An array of post slugs that results must match.
	 *     @type string       $s                       Search keyword(s). Prepending a term with a hyphen will
	 *                                                 exclude posts matching that term. Eg, 'pillow -sofa' will
	 *                                                 return posts containing 'pillow' but not 'sofa'. The
	 *                                                 character used for exclusion can be modified using the
	 *                                                 the 'wp_query_search_exclusion_prefix' filter.
	 *     @type int          $second                  Second of the minute. Default empty. Accepts numbers 0-60.
	 *     @type bool         $sentence                Whether to search by phrase. Default false.
	 *     @type bool         $suppress_filters        Whether to suppress filters. Default false.
	 *     @type string       $tag                     Tag slug. Comma-separated (either), Plus-separated (all).
	 *     @type array        $tag__and                An array of tag ids (AND in).
	 *     @type array        $tag__in                 An array of tag ids (OR in).
	 *     @type array        $tag__not_in             An array of tag ids (NOT in).
	 *     @type int          $tag_id                  Tag id or comma-separated list of IDs.
	 *     @type array        $tag_slug__and           An array of tag slugs (AND in).
	 *     @type array        $tag_slug__in            An array of tag slugs (OR in). unless 'ignore_sticky_posts' is
	 *                                                 true. Note: a string of comma-separated IDs will NOT work.
	 *     @type array        $tax_query               An associative array of WP_Tax_Query arguments.
	 *                                                 See WP_Tax_Query->queries.
	 *     @type string       $title                   Post title.
	 *     @type bool         $update_post_meta_cache  Whether to update the post meta cache. Default true.
	 *     @type bool         $update_post_term_cache  Whether to update the post term cache. Default true.
	 *     @type bool         $lazy_load_term_meta     Whether to lazy-load term meta. Setting to false will
	 *                                                 disable cache priming for term meta, so that each
	 *                                                 get_term_meta() call will hit the database.
	 *                                                 Defaults to the value of `$update_post_term_cache`.
	 *     @type int          $w                       The week number of the year. Default empty. Accepts numbers 0-53.
	 *     @type int          $year                    The four-digit year. Default empty. Accepts any four-digit year.
	 * }
	 */
	public function parse_query( $query =  '' ) {
		if ( ! empty( $query ) ) {
			$this->init();
			$this->query = $this->query_vars = wp_parse_args( $query );
		} elseif ( ! isset( $this->query ) ) {
			$this->query = $this->query_vars;
		}

		$this->query_vars = $this->fill_query_vars($this->query_vars);
		$qv = &$this->query_vars;
		$this->query_vars_changed = true;

		if ( ! empty($qv['robots']) )
			$this->is_robots = true;

		if ( ! is_scalar( $qv['p'] ) || $qv['p'] < 0 ) {
			$qv['p'] = 0;
			$qv['error'] = '404';
		} else {
			$qv['p'] = intval( $qv['p'] );
		}

		$qv['page_id'] =  absint($qv['page_id']);
		$qv['year'] = absint($qv['year']);
		$qv['monthnum'] = absint($qv['monthnum']);
		$qv['day'] = absint($qv['day']);
		$qv['w'] = absint($qv['w']);
		$qv['m'] = is_scalar( $qv['m'] ) ? preg_replace( '|[^0-9]|', '', $qv['m'] ) : '';
		$qv['paged'] = absint($qv['paged']);
		$qv['cat'] = preg_replace( '|[^0-9,-]|', '', $qv['cat'] ); // comma separated list of positive or negative integers
		$qv['author'] = preg_replace( '|[^0-9,-]|', '', $qv['author'] ); // comma separated list of positive or negative integers
		$qv['pagename'] = trim( $qv['pagename'] );
		$qv['name'] = trim( $qv['name'] );
		$qv['title'] = trim( $qv['title'] );
		if ( '' !== $qv['hour'] ) $qv['hour'] = absint($qv['hour']);
		if ( '' !== $qv['minute'] ) $qv['minute'] = absint($qv['minute']);
		if ( '' !== $qv['second'] ) $qv['second'] = absint($qv['second']);
		if ( '' !== $qv['menu_order'] ) $qv['menu_order'] = absint($qv['menu_order']);

		// Fairly insane upper bound for search string lengths.
		if ( ! is_scalar( $qv['s'] ) || ( ! empty( $qv['s'] ) && strlen( $qv['s'] ) > 1600 ) ) {
			$qv['s'] = '';
		}

		// Compat. Map subpost to attachment.
		if ( '' != $qv['subpost'] )
			$qv['attachment'] = $qv['subpost'];
		if ( '' != $qv['subpost_id'] )
			$qv['attachment_id'] = $qv['subpost_id'];

		$qv['attachment_id'] = absint($qv['attachment_id']);

		if ( ('' != $qv['attachment']) || !empty($qv['attachment_id']) ) {
			$this->is_single = true;
			$this->is_attachment = true;
		} elseif ( '' != $qv['name'] ) {
			$this->is_single = true;
		} elseif ( $qv['p'] ) {
			$this->is_single = true;
		} elseif ( ('' !== $qv['hour']) && ('' !== $qv['minute']) &&('' !== $qv['second']) && ('' != $qv['year']) && ('' != $qv['monthnum']) && ('' != $qv['day']) ) {
			// If year, month, day, hour, minute, and second are set, a single
			// post is being queried.
			$this->is_single = true;
		} elseif ( '' != $qv['static'] || '' != $qv['pagename'] || !empty($qv['page_id']) ) {
			$this->is_page = true;
			$this->is_single = false;
		} else {
			// Look for archive queries. Dates, categories, authors, search, post type archives.

			if ( isset( $this->query['s'] ) ) {
				$this->is_search = true;
			}

			if ( '' !== $qv['second'] ) {
				$this->is_time = true;
				$this->is_date = true;
			}

			if ( '' !== $qv['minute'] ) {
				$this->is_time = true;
				$this->is_date = true;
			}

			if ( '' !== $qv['hour'] ) {
				$this->is_time = true;
				$this->is_date = true;
			}

			if ( $qv['day'] ) {
				if ( ! $this->is_date ) {
					$date = sprintf( '%04d-%02d-%02d', $qv['year'], $qv['monthnum'], $qv['day'] );
					if ( $qv['monthnum'] && $qv['year'] && ! wp_checkdate( $qv['monthnum'], $qv['day'], $qv['year'], $date ) ) {
						$qv['error'] = '404';
					} else {
						$this->is_day = true;
						$this->is_date = true;
					}
				}
			}

			if ( $qv['monthnum'] ) {
				if ( ! $this->is_date ) {
					if ( 12 < $qv['monthnum'] ) {
						$qv['error'] = '404';
					} else {
						$this->is_month = true;
						$this->is_date = true;
					}
				}
			}

			if ( $qv['year'] ) {
				if ( ! $this->is_date ) {
					$this->is_year = true;
					$this->is_date = true;
				}
			}

			if ( $qv['m'] ) {
				$this->is_date = true;
				if ( strlen($qv['m']) > 9 ) {
					$this->is_time = true;
				} elseif ( strlen( $qv['m'] ) > 7 ) {
					$this->is_day = true;
				} elseif ( strlen( $qv['m'] ) > 5 ) {
					$this->is_month = true;
				} else {
					$this->is_year = true;
				}
			}

			if ( '' != $qv['w'] ) {
				$this->is_date = true;
			}

			$this->query_vars_hash = false;
			$this->parse_tax_query( $qv );

			foreach ( $this->tax_query->queries as $tax_query ) {
				if ( ! is_array( $tax_query ) ) {
					continue;
				}

				if ( isset( $tax_query['operator'] ) && 'NOT IN' != $tax_query['operator'] ) {
					switch ( $tax_query['taxonomy'] ) {
						case 'category':
							$this->is_category = true;
							break;
						case 'post_tag':
							$this->is_tag = true;
							break;
						default:
							$this->is_tax = true;
					}
				}
			}
			unset( $tax_query );

			if ( empty($qv['author']) || ($qv['author'] == '0') ) {
				$this->is_author = false;
			} else {
				$this->is_author = true;
			}

			if ( '' != $qv['author_name'] )
				$this->is_author = true;

			if ( !empty( $qv['post_type'] ) && ! is_array( $qv['post_type'] ) ) {
				$post_type_obj = get_post_type_object( $qv['post_type'] );
				if ( ! empty( $post_type_obj->has_archive ) )
					$this->is_post_type_archive = true;
			}

			if ( $this->is_post_type_archive || $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax )
				$this->is_archive = true;
		}

		if ( '' != $qv['feed'] )
			$this->is_feed = true;

		if ( '' != $qv['embed'] ) {
			$this->is_embed = true;
		}

		if ( '' != $qv['tb'] )
			$this->is_trackback = true;

		if ( '' != $qv['paged'] && ( intval($qv['paged']) > 1 ) )
			$this->is_paged = true;

		// if we're previewing inside the write screen
		if ( '' != $qv['preview'] )
			$this->is_preview = true;

		if ( is_admin() )
			$this->is_admin = true;

		if ( false !== strpos($qv['feed'], 'comments-') ) {
			$qv['feed'] = str_replace('comments-', '', $qv['feed']);
			$qv['withcomments'] = 1;
		}

		$this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;

		if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) )
			$this->is_comment_feed = true;

		if ( !( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots ) )
			$this->is_home = true;

		// Correct is_* for page_on_front and page_for_posts
		if ( $this->is_home && 'page' == get_option('show_on_front') && get_option('page_on_front') ) {
			$_query = wp_parse_args($this->query);
			// pagename can be set and empty depending on matched rewrite rules. Ignore an empty pagename.
			if ( isset($_query['pagename']) && '' == $_query['pagename'] )
				unset($_query['pagename']);

			unset( $_query['embed'] );

			if ( empty($_query) || !array_diff( array_keys($_query), array('preview', 'page', 'paged', 'cpage') ) ) {
				$this->is_page = true;
				$this->is_home = false;
				$qv['page_id'] = get_option('page_on_front');
				// Correct <!--nextpage--> for page_on_front
				if ( !empty($qv['paged']) ) {
					$qv['page'] = $qv['paged'];
					unset($qv['paged']);
				}
			}
		}

		if ( '' != $qv['pagename'] ) {
			$this->queried_object = get_page_by_path( $qv['pagename'] );

			if ( $this->queried_object && 'attachment' == $this->queried_object->post_type ) {
				if ( preg_match( "/^[^%]*%(?:postname)%/", get_option( 'permalink_structure' ) ) ) {
					// See if we also have a post with the same slug
					$post = get_page_by_path( $qv['pagename'], OBJECT, 'post' );
					if ( $post ) {
						$this->queried_object = $post;
						$this->is_page = false;
						$this->is_single = true;
					}
				}
			}

			if ( ! empty( $this->queried_object ) ) {
				$this->queried_object_id = (int) $this->queried_object->ID;
			} else {
				unset( $this->queried_object );
			}

			if  ( 'page' == get_option('show_on_front') && isset($this->queried_object_id) && $this->queried_object_id == get_option('page_for_posts') ) {
				$this->is_page = false;
				$this->is_home = true;
				$this->is_posts_page = true;
			}
		}

		if ( $qv['page_id'] ) {
			if  ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) {
				$this->is_page = false;
				$this->is_home = true;
				$this->is_posts_page = true;
			}
		}

		if ( !empty($qv['post_type']) ) {
			if ( is_array($qv['post_type']) )
				$qv['post_type'] = array_map('sanitize_key', $qv['post_type']);
			else
				$qv['post_type'] = sanitize_key($qv['post_type']);
		}

		if ( ! empty( $qv['post_status'] ) ) {
			if ( is_array( $qv['post_status'] ) )
				$qv['post_status'] = array_map('sanitize_key', $qv['post_status']);
			else
				$qv['post_status'] = preg_replace('|[^a-z0-9_,-]|', '', $qv['post_status']);
		}

		if ( $this->is_posts_page && ( ! isset($qv['withcomments']) || ! $qv['withcomments'] ) )
			$this->is_comment_feed = false;

		$this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
		// Done correcting is_* for page_on_front and page_for_posts

		if ( '404' == $qv['error'] )
			$this->set_404();

		$this->is_embed = $this->is_embed && ( $this->is_singular || $this->is_404 );

		$this->query_vars_hash = md5( serialize( $this->query_vars ) );
		$this->query_vars_changed = false;

		/**
		 * Fires after the main query vars have been parsed.
		 *
		 * @since 1.5.0
		 *
		 * @param WP_Query $this The WP_Query instance (passed by reference).
		 */
		do_action_ref_array( 'parse_query', array( &$this ) );
	}

	/**
	 * Parses various taxonomy related query vars.
	 *
	 * For BC, this method is not marked as protected. See [28987].
	 *
	 * @since 3.1.0
	 *
	 * @param array $q The query variables. Passed by reference.
	 */
	public function parse_tax_query( &$q ) {
		if ( ! empty( $q['tax_query'] ) && is_array( $q['tax_query'] ) ) {
			$tax_query = $q['tax_query'];
		} else {
			$tax_query = array();
		}

		if ( !empty($q['taxonomy']) && !empty($q['term']) ) {
			$tax_query[] = array(
				'taxonomy' => $q['taxonomy'],
				'terms' => array( $q['term'] ),
				'field' => 'slug',
			);
		}

		foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t ) {
			if ( 'post_tag' == $taxonomy )
				continue;	// Handled further down in the $q['tag'] block

			if ( $t->query_var && !empty( $q[$t->query_var] ) ) {
				$tax_query_defaults = array(
					'taxonomy' => $taxonomy,
					'field' => 'slug',
				);

 				if ( isset( $t->rewrite['hierarchical'] ) && $t->rewrite['hierarchical'] ) {
					$q[$t->query_var] = wp_basename( $q[$t->query_var] );
				}

				$term = $q[$t->query_var];

				if ( is_array( $term ) ) {
					$term = implode( ',', $term );
				}

				if ( strpos($term, '+') !== false ) {
					$terms = preg_split( '/[+]+/', $term );
					foreach ( $terms as $term ) {
						$tax_query[] = array_merge( $tax_query_defaults, array(
							'terms' => array( $term )
						) );
					}
				} else {
					$tax_query[] = array_merge( $tax_query_defaults, array(
						'terms' => preg_split( '/[,]+/', $term )
					) );
				}
			}
		}

		// If querystring 'cat' is an array, implode it.
		if ( is_array( $q['cat'] ) ) {
			$q['cat'] = implode( ',', $q['cat'] );
		}

		// Category stuff
		if ( ! empty( $q['cat'] ) && ! $this->is_singular ) {
			$cat_in = $cat_not_in = array();

			$cat_array = preg_split( '/[,\s]+/', urldecode( $q['cat'] ) );
			$cat_array = array_map( 'intval', $cat_array );
			$q['cat'] = implode( ',', $cat_array );

			foreach ( $cat_array as $cat ) {
				if ( $cat > 0 )
					$cat_in[] = $cat;
				elseif ( $cat < 0 )
					$cat_not_in[] = abs( $cat );
			}

			if ( ! empty( $cat_in ) ) {
				$tax_query[] = array(
					'taxonomy' => 'category',
					'terms' => $cat_in,
					'field' => 'term_id',
					'include_children' => true
				);
			}

			if ( ! empty( $cat_not_in ) ) {
				$tax_query[] = array(
					'taxonomy' => 'category',
					'terms' => $cat_not_in,
					'field' => 'term_id',
					'operator' => 'NOT IN',
					'include_children' => true
				);
			}
			unset( $cat_array, $cat_in, $cat_not_in );
		}

		if ( ! empty( $q['category__and'] ) && 1 === count( (array) $q['category__and'] ) ) {
			$q['category__and'] = (array) $q['category__and'];
			if ( ! isset( $q['category__in'] ) )
				$q['category__in'] = array();
			$q['category__in'][] = absint( reset( $q['category__and'] ) );
			unset( $q['category__and'] );
		}

		if ( ! empty( $q['category__in'] ) ) {
			$q['category__in'] = array_map( 'absint', array_unique( (array) $q['category__in'] ) );
			$tax_query[] = array(
				'taxonomy' => 'category',
				'terms' => $q['category__in'],
				'field' => 'term_id',
				'include_children' => false
			);
		}

		if ( ! empty($q['category__not_in']) ) {
			$q['category__not_in'] = array_map( 'absint', array_unique( (array) $q['category__not_in'] ) );
			$tax_query[] = array(
				'taxonomy' => 'category',
				'terms' => $q['category__not_in'],
				'operator' => 'NOT IN',
				'include_children' => false
			);
		}

		if ( ! empty($q['category__and']) ) {
			$q['category__and'] = array_map( 'absint', array_unique( (array) $q['category__and'] ) );
			$tax_query[] = array(
				'taxonomy' => 'category',
				'terms' => $q['category__and'],
				'field' => 'term_id',
				'operator' => 'AND',
				'include_children' => false
			);
		}

		// If querystring 'tag' is array, implode it.
		if ( is_array( $q['tag'] ) ) {
			$q['tag'] = implode( ',', $q['tag'] );
		}

		// Tag stuff
		if ( '' != $q['tag'] && !$this->is_singular && $this->query_vars_changed ) {
			if ( strpos($q['tag'], ',') !== false ) {
				$tags = preg_split('/[,\r\n\t ]+/', $q['tag']);
				foreach ( (array) $tags as $tag ) {
					$tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
					$q['tag_slug__in'][] = $tag;
				}
			} elseif ( preg_match('/[+\r\n\t ]+/', $q['tag'] ) || ! empty( $q['cat'] ) ) {
				$tags = preg_split('/[+\r\n\t ]+/', $q['tag']);
				foreach ( (array) $tags as $tag ) {
					$tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
					$q['tag_slug__and'][] = $tag;
				}
			} else {
				$q['tag'] = sanitize_term_field('slug', $q['tag'], 0, 'post_tag', 'db');
				$q['tag_slug__in'][] = $q['tag'];
			}
		}

		if ( !empty($q['tag_id']) ) {
			$q['tag_id'] = absint( $q['tag_id'] );
			$tax_query[] = array(
				'taxonomy' => 'post_tag',
				'terms' => $q['tag_id']
			);
		}

		if ( !empty($q['tag__in']) ) {
			$q['tag__in'] = array_map('absint', array_unique( (array) $q['tag__in'] ) );
			$tax_query[] = array(
				'taxonomy' => 'post_tag',
				'terms' => $q['tag__in']
			);
		}

		if ( !empty($q['tag__not_in']) ) {
			$q['tag__not_in'] = array_map('absint', array_unique( (array) $q['tag__not_in'] ) );
			$tax_query[] = array(
				'taxonomy' => 'post_tag',
				'terms' => $q['tag__not_in'],
				'operator' => 'NOT IN'
			);
		}

		if ( !empty($q['tag__and']) ) {
			$q['tag__and'] = array_map('absint', array_unique( (array) $q['tag__and'] ) );
			$tax_query[] = array(
				'taxonomy' => 'post_tag',
				'terms' => $q['tag__and'],
				'operator' => 'AND'
			);
		}

		if ( !empty($q['tag_slug__in']) ) {
			$q['tag_slug__in'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__in'] ) );
			$tax_query[] = array(
				'taxonomy' => 'post_tag',
				'terms' => $q['tag_slug__in'],
				'field' => 'slug'
			);
		}

		if ( !empty($q['tag_slug__and']) ) {
			$q['tag_slug__and'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__and'] ) );
			$tax_query[] = array(
				'taxonomy' => 'post_tag',
				'terms' => $q['tag_slug__and'],
				'field' => 'slug',
				'operator' => 'AND'
			);
		}

		$this->tax_query = new WP_Tax_Query( $tax_query );

		/**
		 * Fires after taxonomy-related query vars have been parsed.
		 *
		 * @since 3.7.0
		 *
		 * @param WP_Query $this The WP_Query instance.
		 */
		do_action( 'parse_tax_query', $this );
	}

	/**
	 * Generates SQL for the WHERE clause based on passed search terms.
	 *
	 * @since 3.7.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @param array $q Query variables.
	 * @return string WHERE clause.
	 */
	protected function parse_search( &$q ) {
		global $wpdb;

		$search = '';

		// added slashes screw with quote grouping when done early, so done later
		$q['s'] = stripslashes( $q['s'] );
		if ( empty( $_GET['s'] ) && $this->is_main_query() )
			$q['s'] = urldecode( $q['s'] );
		// there are no line breaks in <input /> fields
		$q['s'] = str_replace( array( "\r", "\n" ), '', $q['s'] );
		$q['search_terms_count'] = 1;
		if ( ! empty( $q['sentence'] ) ) {
			$q['search_terms'] = array( $q['s'] );
		} else {
			if ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $q['s'], $matches ) ) {
				$q['search_terms_count'] = count( $matches[0] );
				$q['search_terms'] = $this->parse_search_terms( $matches[0] );
				// if the search string has only short terms or stopwords, or is 10+ terms long, match it as sentence
				if ( empty( $q['search_terms'] ) || count( $q['search_terms'] ) > 9 )
					$q['search_terms'] = array( $q['s'] );
			} else {
				$q['search_terms'] = array( $q['s'] );
			}
		}

		$n = ! empty( $q['exact'] ) ? '' : '%';
		$searchand = '';
		$q['search_orderby_title'] = array();

		/**
		 * Filters the prefix that indicates that a search term should be excluded from results.
		 *
		 * @since 4.7.0
		 *
		 * @param string $exclusion_prefix The prefix. Default '-'. Returning
		 *                                 an empty value disables exclusions.
		 */
		$exclusion_prefix = apply_filters( 'wp_query_search_exclusion_prefix', '-' );

		foreach ( $q['search_terms'] as $term ) {
			// If there is an $exclusion_prefix, terms prefixed with it should be excluded.
			$exclude = $exclusion_prefix && ( $exclusion_prefix === substr( $term, 0, 1 ) );
			if ( $exclude ) {
				$like_op  = 'NOT LIKE';
				$andor_op = 'AND';
				$term     = substr( $term, 1 );
			} else {
				$like_op  = 'LIKE';
				$andor_op = 'OR';
			}

			if ( $n && ! $exclude ) {
				$like = '%' . $wpdb->esc_like( $term ) . '%';
				$q['search_orderby_title'][] = $wpdb->prepare( "{$wpdb->posts}.post_title LIKE %s", $like );
			}

			$like = $n . $wpdb->esc_like( $term ) . $n;
			$search .= $wpdb->prepare( "{$searchand}(({$wpdb->posts}.post_title $like_op %s) $andor_op ({$wpdb->posts}.post_excerpt $like_op %s) $andor_op ({$wpdb->posts}.post_content $like_op %s))", $like, $like, $like );
			$searchand = ' AND ';
		}

		if ( ! empty( $search ) ) {
			$search = " AND ({$search}) ";
			if ( ! is_user_logged_in() ) {
				$search .= " AND ({$wpdb->posts}.post_password = '') ";
			}
		}

		return $search;
	}

	/**
	 * Check if the terms are suitable for searching.
	 *
	 * Uses an array of stopwords (terms) that are excluded from the separate
	 * term matching when searching for posts. The list of English stopwords is
	 * the approximate search engines list, and is translatable.
	 *
	 * @since 3.7.0
	 *
	 * @param array $terms Terms to check.
	 * @return array Terms that are not stopwords.
	 */
	protected function parse_search_terms( $terms ) {
		$strtolower = function_exists( 'mb_strtolower' ) ? 'mb_strtolower' : 'strtolower';
		$checked = array();

		$stopwords = $this->get_search_stopwords();

		foreach ( $terms as $term ) {
			// keep before/after spaces when term is for exact match
			if ( preg_match( '/^".+"$/', $term ) )
				$term = trim( $term, "\"'" );
			else
				$term = trim( $term, "\"' " );

			// Avoid single A-Z and single dashes.
			if ( ! $term || ( 1 === strlen( $term ) && preg_match( '/^[a-z\-]$/i', $term ) ) )
				continue;

			if ( in_array( call_user_func( $strtolower, $term ), $stopwords, true ) )
				continue;

			$checked[] = $term;
		}

		return $checked;
	}

	/**
	 * Retrieve stopwords used when parsing search terms.
	 *
	 * @since 3.7.0
	 *
	 * @return array Stopwords.
	 */
	protected function get_search_stopwords() {
		if ( isset( $this->stopwords ) )
			return $this->stopwords;

		/* translators: This is a comma-separated list of very common words that should be excluded from a search,
		 * like a, an, and the. These are usually called "stopwords". You should not simply translate these individual
		 * words into your language. Instead, look for and provide commonly accepted stopwords in your language.
		 */
		$words = explode( ',', _x( 'about,an,are,as,at,be,by,com,for,from,how,in,is,it,of,on,or,that,the,this,to,was,what,when,where,who,will,with,www',
			'Comma-separated list of search stopwords in your language' ) );

		$stopwords = array();
		foreach ( $words as $word ) {
			$word = trim( $word, "\r\n\t " );
			if ( $word )
				$stopwords[] = $word;
		}

		/**
		 * Filters stopwords used when parsing search terms.
		 *
		 * @since 3.7.0
		 *
		 * @param array $stopwords Stopwords.
		 */
		$this->stopwords = apply_filters( 'wp_search_stopwords', $stopwords );
		return $this->stopwords;
	}

	/**
	 * Generates SQL for the ORDER BY condition based on passed search terms.
	 *
	 * @since 3.7.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @param array $q Query variables.
	 * @return string ORDER BY clause.
	 */
	protected function parse_search_order( &$q ) {
		global $wpdb;

		if ( $q['search_terms_count'] > 1 ) {
			$num_terms = count( $q['search_orderby_title'] );

			// If the search terms contain negative queries, don't bother ordering by sentence matches.
			$like = '';
			if ( ! preg_match( '/(?:\s|^)\-/', $q['s'] ) ) {
				$like = '%' . $wpdb->esc_like( $q['s'] ) . '%';
			}

			$search_orderby = '';

			// sentence match in 'post_title'
			if ( $like ) {
				$search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_title LIKE %s THEN 1 ", $like );
			}

			// sanity limit, sort as sentence when more than 6 terms
			// (few searches are longer than 6 terms and most titles are not)
			if ( $num_terms < 7 ) {
				// all words in title
				$search_orderby .= 'WHEN ' . implode( ' AND ', $q['search_orderby_title'] ) . ' THEN 2 ';
				// any word in title, not needed when $num_terms == 1
				if ( $num_terms > 1 )
					$search_orderby .= 'WHEN ' . implode( ' OR ', $q['search_orderby_title'] ) . ' THEN 3 ';
			}

			// Sentence match in 'post_content' and 'post_excerpt'.
			if ( $like ) {
				$search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_excerpt LIKE %s THEN 4 ", $like );
				$search_orderby .= $wpdb->prepare( "WHEN {$wpdb->posts}.post_content LIKE %s THEN 5 ", $like );
			}

			if ( $search_orderby ) {
				$search_orderby = '(CASE ' . $search_orderby . 'ELSE 6 END)';
			}
		} else {
			// single word or sentence search
			$search_orderby = reset( $q['search_orderby_title'] ) . ' DESC';
		}

		return $search_orderby;
	}

	/**
	 * Converts the given orderby alias (if allowed) to a properly-prefixed value.
	 *
	 * @since 4.0.0
	 *
	 * @global wpdb $wpdb WordPress database abstraction object.
	 *
	 * @param string $orderby Alias for the field to order by.
	 * @return string|false Table-prefixed value to used in the ORDER clause. False otherwise.
	 */
	protected function parse_orderby( $orderby ) {
		global $wpdb;

		// Used to filter values.
		$allowed_keys = array(
			'post_name', 'post_author', 'post_date', 'post_title', 'post_modified',
			'post_parent', 'post_type', 'name', 'author', 'date', 'title', 'modified',
			'parent', 'type', 'ID', 'menu_order', 'comment_count', 'rand',
		);

		$primary_meta_key = '';
		$primary_meta_query = false;
		$meta_clauses = $this->meta_query->get_clauses();
		if ( ! empty( $meta_clauses ) ) {
			$primary_meta_query = reset( $meta_clauses );

			if ( ! empty( $primary_meta_query['key'] ) ) {
				$primary_meta_key = $primary_meta_query['key'];
				$allowed_keys[] = $primary_meta_key;
			}

			$allowed_keys[] = 'meta_value';
			$allowed_keys[] = 'meta_value_num';
			$allowed_keys   = array_merge( $allowed_keys, array_keys( $meta_clauses ) );
		}

		// If RAND() contains a seed value, sanitize and add to allowed keys.
		$rand_with_seed = false;
		if ( preg_match( '/RAND\(([0-9]+)\)/i', $orderby, $matches ) ) {
			$orderby = sprintf( 'RAND(%s)', intval( $matches[1] ) );
			$allowed_keys[] = $orderby;
			$rand_with_seed = true;
		}

		if ( ! in_array( $orderby, $allowed_keys, true ) ) {
			return false;
		}

		switch ( $orderby ) {
			case 'post_name':
			case 'post_author':
			case 'post_date':
			case 'post_title':
			case 'post_modified':
			case 'post_parent':
			case 'post_type':
			case 'ID':
			case 'menu_order':
			case 'comment_count':
				$orderby_clause = "{$wpdb->posts}.{$orderby}";
				break;
			case 'rand':
				$orderby_clause = 'RAND()';
				break;
			case $primary_meta_key:
			case 'meta_value':
				if ( ! empty( $primary_meta_query['type'] ) ) {
					$orderby_clause = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})";
				} else {
					$orderby_clause = "{$primary_meta_query['alias']}.meta_value";
				}
				break;
			case 'meta_value_num':
				$orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
				break;
			default:
				if ( array_key_exists( $orderby, $meta_clauses ) ) {
					// $orderby corresponds to a meta_query clause.
					$meta_clause = $meta_clauses[ $orderby ];
					$orderby_clause = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})";
				} elseif ( $rand_with_seed ) {
					$orderby_clause = $orderby;
				} else {
					// Default: order by post field.
					$orderby_clause = "{$wpdb->posts}.post_" . sanitize_key( $orderby );
				}

				break;
		}

		return $orderby_clause;
	}

	/**
	 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
	 *
	 * @since 4.0.0
	 *
	 * @param string $order The 'order' query variable.
	 * @return string The sanitized 'order' query variable.
	 */
	protected function parse_order( $order ) {
		if ( ! is_string( $order ) || empty( $order ) ) {
			return 'DESC';
		}

		if ( 'ASC' === strtoupper( $order ) ) {
			return 'ASC';
		} else {
			return 'DESC';
		}
	}

	/**
	 * Sets the 404 property and saves whether query is feed.
	 *
	 * @since 2.0.0
	 */
	public function set_404() {
		$is_feed = $this->is_feed;

		$this->init_query_flags();
		$this->is_404 = true;

		$this->is_feed = $is_feed;
	}

	/**
	 * Retrieve query variable.
	 *
	 * @since 1.5.0
	 * @since 3.9.0 The `$default` argument was introduced.
	 *
	 *
	 * @param string $query_var Query variable key.
	 * @param mixed  $default   Optional. Value to return if the query variable is not set. Default empty.
	 * @return mixed Contents of the query variable.
	 */
	public function get( $query_var, $default = '' ) {
		if ( isset( $this->query_vars[ $query_var ] ) ) {
			return $this->query_vars[ $query_var ];
		}

		return $default;
	}

	/**
	 * Set query variable.
	 *
	 * @since 1.5.0
	 *
	 * @param string $query_var Query variable key.
	 * @param mixed  $value     Query variable value.
	 */
	public function set($query_var, $value) {
		$this->query_vars[$query_var] = $value;
	}

	/**
	 * Retrieve the posts based on query variables.
	 *
	 * There are a few filters and actions that can be used to modify the post
	 * database query.
	 *
	 * @since 1.5.0
	 *
	 * @return array List of posts.
	 */
	public function get_posts() {
		global $wpdb;

		$this->parse_query();

		/**
		 * Fires after the query variable object is created, but before the actual query is run.
		 *
		 * Note: If using conditional tags, use the method versions within the passed instance
		 * (e.g. $this->is_main_query() instead of is_main_query()). This is because the functions
		 * like is_main_query() test against the global $wp_query instance, not the passed one.
		 *
		 * @since 2.0.0
		 *
		 * @param WP_Query $this The WP_Query instance (passed by reference).
		 */
		do_action_ref_array( 'pre_get_posts', array( &$this ) );

		// Shorthand.
		$q = &$this->query_vars;

		// Fill again in case pre_get_posts unset some vars.
		$q = $this->fill_query_vars($q);

		// Parse meta query
		$this->meta_query = new WP_Meta_Query();
		$this->meta_query->parse_query_vars( $q );

		// Set a flag if a pre_get_posts hook changed the query vars.
		$hash = md5( serialize( $this->query_vars ) );
		if ( $hash != $this->query_vars_hash ) {
			$this->query_vars_changed = true;
			$this->query_vars_hash = $hash;
		}
		unset($hash);

		// First let's clear some variables
		$distinct = '';
		$whichauthor = '';
		$whichmimetype = '';
		$where = '';
		$limits = '';
		$join = '';
		$search = '';
		$groupby = '';
		$post_status_join = false;
		$page = 1;

		if ( isset( $q['caller_get_posts'] ) ) {
			_deprecated_argument( 'WP_Query', '3.1.0',
				/* translators: 1: caller_get_posts, 2: ignore_sticky_posts */
				sprintf( __( '%1$s is deprecated. Use %2$s instead.' ),
					'<code>caller_get_posts</code>',
					'<code>ignore_sticky_posts</code>'
				)
			);

			if ( ! isset( $q['ignore_sticky_posts'] ) ) {
				$q['ignore_sticky_posts'] = $q['caller_get_posts'];
			}
		}

		if ( !isset( $q['ignore_sticky_posts'] ) )
			$q['ignore_sticky_posts'] = false;

		if ( !isset($q['suppress_filters']) )
			$q['suppress_filters'] = false;

		if ( !isset($q['cache_results']) ) {
			if ( wp_using_ext_object_cache() )
				$q['cache_results'] = false;
			else
				$q['cache_results'] = true;
		}

		if ( !isset($q['update_post_term_cache']) )
			$q['update_post_term_cache'] = true;

		if ( ! isset( $q['lazy_load_term_meta'] ) ) {
			$q['lazy_load_term_meta'] = $q['update_post_term_cache'];
		}

		if ( !isset($q['update_post_meta_cache']) )
			$q['update_post_meta_cache'] = true;

		if ( !isset($q['post_type']) ) {
			if ( $this->is_search )
				$q['post_type'] = 'any';
			else
				$q['post_type'] = '';
		}
		$post_type = $q['post_type'];
		if ( empty( $q['posts_per_page'] ) ) {
			$q['posts_per_page'] = get_option( 'posts_per_page' );
		}
		if ( isset($q['showposts']) && $q['showposts'] ) {
			$q['showposts'] = (int) $q['showposts'];
			$q['posts_per_page'] = $q['showposts'];
		}
		if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) )
			$q['posts_per_page'] = $q['posts_per_archive_page'];
		if ( !isset($q['nopaging']) ) {
			if ( $q['posts_per_page'] == -1 ) {
				$q['nopaging'] = true;
			} else {
				$q['nopaging'] = false;
			}
		}

		if ( $this->is_feed ) {
			// This overrides posts_per_page.
			if ( ! empty( $q['posts_per_rss'] ) ) {
				$q['posts_per_page'] = $q['posts_per_rss'];
			} else {
				$q['posts_per_page'] = get_option( 'posts_per_rss' );
			}
			$q['nopaging'] = false;
		}
		$q['posts_per_page'] = (int) $q['posts_per_page'];
		if ( $q['posts_per_page'] < -1 )
			$q['posts_per_page'] = abs($q['posts_per_page']);
		elseif ( $q['posts_per_page'] == 0 )
			$q['posts_per_page'] = 1;

		if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 )
			$q['comments_per_page'] = get_option('comments_per_page');

		if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
			$this->is_page = true;
			$this->is_home = false;
			$q['page_id'] = get_option('page_on_front');
		}

		if ( isset($q['page']) ) {
			$q['page'] = trim($q['page'], '/');
			$q['page'] = absint($q['page']);
		}

		// If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present.
		if ( isset($q['no_found_rows']) )
			$q['no_found_rows'] = (bool) $q['no_found_rows'];
		else
			$q['no_found_rows'] = false;

		switch ( $q['fields'] ) {
			case 'ids':
				$fields = "{$wpdb->posts}.ID";
				break;
			case 'id=>parent':
				$fields = "{$wpdb->posts}.ID, {$wpdb->posts}.post_parent";
				break;
			default:
				$fields = "{$wpdb->posts}.*";
		}

		if ( '' !== $q['menu_order'] ) {
			$where .= " AND {$wpdb->posts}.menu_order = " . $q['menu_order'];
		}
		// The "m" parameter is meant for months but accepts datetimes of varying specificity
		if ( $q['m'] ) {
			$where .= " AND YEAR({$wpdb->posts}.post_date)=" . substr($q['m'], 0, 4);
			if ( strlen($q['m']) > 5 ) {
				$where .= " AND MONTH({$wpdb->posts}.post_date)=" . substr($q['m'], 4, 2);
			}
			if ( strlen($q['m']) > 7 ) {
				$where .= " AND DAYOFMONTH({$wpdb->posts}.post_date)=" . substr($q['m'], 6, 2);
			}
			if ( strlen($q['m']) > 9 ) {
				$where .= " AND HOUR({$wpdb->posts}.post_date)=" . substr($q['m'], 8, 2);
			}
			if ( strlen($q['m']) > 11 ) {
				$where .= " AND MINUTE({$wpdb->posts}.post_date)=" . substr($q['m'], 10, 2);
			}
			if ( strlen($q['m']) > 13 ) {
				$where .= " AND SECOND({$wpdb->posts}.post_date)=" . substr($q['m'], 12, 2);
			}
		}

		// Handle the other individual date parameters
		$date_parameters = array();

		if ( '' !== $q['hour'] )
			$date_parameters['hour'] = $q['hour'];

		if ( '' !== $q['minute'] )
			$date_parameters['minute'] = $q['minute'];

		if ( '' !== $q['second'] )
			$date_parameters['second'] = $q['second'];

		if ( $q['year'] )
			$date_parameters['year'] = $q['year'];

		if ( $q['monthnum'] )
			$date_parameters['monthnum'] = $q['monthnum'];

		if ( $q['w'] )
			$date_parameters['week'] = $q['w'];

		if ( $q['day'] )
			$date_parameters['day'] = $q['day'];

		if ( $date_parameters ) {
			$date_query = new WP_Date_Query( array( $date_parameters ) );
			$where .= $date_query->get_sql();
		}
		unset( $date_parameters, $date_query );

		// Handle complex date queries
		if ( ! empty( $q['date_query'] ) ) {
			$this->date_query = new WP_Date_Query( $q['date_query'] );
			$where .= $this->date_query->get_sql();
		}


		// If we've got a post_type AND it's not "any" post_type.
		if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) {
			foreach ( (array)$q['post_type'] as $_post_type ) {
				$ptype_obj = get_post_type_object($_post_type);
				if ( !$ptype_obj || !$ptype_obj->query_var || empty($q[ $ptype_obj->query_var ]) )
					continue;

				if ( ! $ptype_obj->hierarchical ) {
					// Non-hierarchical post types can directly use 'name'.
					$q['name'] = $q[ $ptype_obj->query_var ];
				} else {
					// Hierarchical post types will operate through 'pagename'.
					$q['pagename'] = $q[ $ptype_obj->query_var ];
					$q['name'] = '';
				}

				// Only one request for a slug is possible, this is why name & pagename are overwritten above.
				break;
			} //end foreach
			unset($ptype_obj);
		}

		if ( '' !== $q['title'] ) {
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_title = %s", stripslashes( $q['title'] ) );
		}

		// Parameters related to 'post_name'.
		if ( '' != $q['name'] ) {
			$q['name'] = sanitize_title_for_query( $q['name'] );
			$where .= " AND {$wpdb->posts}.post_name = '" . $q['name'] . "'";
		} elseif ( '' != $q['pagename'] ) {
			if ( isset($this->queried_object_id) ) {
				$reqpage = $this->queried_object_id;
			} else {
				if ( 'page' != $q['post_type'] ) {
					foreach ( (array)$q['post_type'] as $_post_type ) {
						$ptype_obj = get_post_type_object($_post_type);
						if ( !$ptype_obj || !$ptype_obj->hierarchical )
							continue;

						$reqpage = get_page_by_path($q['pagename'], OBJECT, $_post_type);
						if ( $reqpage )
							break;
					}
					unset($ptype_obj);
				} else {
					$reqpage = get_page_by_path($q['pagename']);
				}
				if ( !empty($reqpage) )
					$reqpage = $reqpage->ID;
				else
					$reqpage = 0;
			}

			$page_for_posts = get_option('page_for_posts');
			if  ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) {
				$q['pagename'] = sanitize_title_for_query( wp_basename( $q['pagename'] ) );
				$q['name'] = $q['pagename'];
				$where .= " AND ({$wpdb->posts}.ID = '$reqpage')";
				$reqpage_obj = get_post( $reqpage );
				if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) {
					$this->is_attachment = true;
					$post_type = $q['post_type'] = 'attachment';
					$this->is_page = true;
					$q['attachment_id'] = $reqpage;
				}
			}
		} elseif ( '' != $q['attachment'] ) {
			$q['attachment'] = sanitize_title_for_query( wp_basename( $q['attachment'] ) );
			$q['name'] = $q['attachment'];
			$where .= " AND {$wpdb->posts}.post_name = '" . $q['attachment'] . "'";
		} elseif ( is_array( $q['post_name__in'] ) && ! empty( $q['post_name__in'] ) ) {
			$q['post_name__in'] = array_map( 'sanitize_title_for_query', $q['post_name__in'] );
			$post_name__in = "'" . implode( "','", $q['post_name__in'] ) . "'";
			$where .= " AND {$wpdb->posts}.post_name IN ($post_name__in)";
		}

		// If an attachment is requested by number, let it supersede any post number.
		if ( $q['attachment_id'] )
			$q['p'] = absint($q['attachment_id']);

		// If a post number is specified, load that post
		if ( $q['p'] ) {
			$where .= " AND {$wpdb->posts}.ID = " . $q['p'];
		} elseif ( $q['post__in'] ) {
			$post__in = implode(',', array_map( 'absint', $q['post__in'] ));
			$where .= " AND {$wpdb->posts}.ID IN ($post__in)";
		} elseif ( $q['post__not_in'] ) {
			$post__not_in = implode(',',  array_map( 'absint', $q['post__not_in'] ));
			$where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
		}

		if ( is_numeric( $q['post_parent'] ) ) {
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_parent = %d ", $q['post_parent'] );
		} elseif ( $q['post_parent__in'] ) {
			$post_parent__in = implode( ',', array_map( 'absint', $q['post_parent__in'] ) );
			$where .= " AND {$wpdb->posts}.post_parent IN ($post_parent__in)";
		} elseif ( $q['post_parent__not_in'] ) {
			$post_parent__not_in = implode( ',',  array_map( 'absint', $q['post_parent__not_in'] ) );
			$where .= " AND {$wpdb->posts}.post_parent NOT IN ($post_parent__not_in)";
		}

		if ( $q['page_id'] ) {
			if  ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
				$q['p'] = $q['page_id'];
				$where = " AND {$wpdb->posts}.ID = " . $q['page_id'];
			}
		}

		// If a search pattern is specified, load the posts that match.
		if ( strlen( $q['s'] ) ) {
			$search = $this->parse_search( $q );
		}

		if ( ! $q['suppress_filters'] ) {
			/**
			 * Filters the search SQL that is used in the WHERE clause of WP_Query.
			 *
			 * @since 3.0.0
			 *
			 * @param string   $search Search SQL for WHERE clause.
			 * @param WP_Query $this   The current WP_Query object.
			 */
			$search = apply_filters_ref_array( 'posts_search', array( $search, &$this ) );
		}

		// Taxonomies
		if ( !$this->is_singular ) {
			$this->parse_tax_query( $q );

			$clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' );

			$join .= $clauses['join'];
			$where .= $clauses['where'];
		}

		if ( $this->is_tax ) {
			if ( empty($post_type) ) {
				// Do a fully inclusive search for currently registered post types of queried taxonomies
				$post_type = array();
				$taxonomies = array_keys( $this->tax_query->queried_terms );
				foreach ( get_post_types( array( 'exclude_from_search' => false ) ) as $pt ) {
					$object_taxonomies = $pt === 'attachment' ? get_taxonomies_for_attachments() : get_object_taxonomies( $pt );
					if ( array_intersect( $taxonomies, $object_taxonomies ) )
						$post_type[] = $pt;
				}
				if ( ! $post_type )
					$post_type = 'any';
				elseif ( count( $post_type ) == 1 )
					$post_type = $post_type[0];

				$post_status_join = true;
			} elseif ( in_array('attachment', (array) $post_type) ) {
				$post_status_join = true;
			}
		}

		/*
		 * Ensure that 'taxonomy', 'term', 'term_id', 'cat', and
		 * 'category_name' vars are set for backward compatibility.
		 */
		if ( ! empty( $this->tax_query->queried_terms ) ) {

			/*
			 * Set 'taxonomy', 'term', and 'term_id' to the
			 * first taxonomy other than 'post_tag' or 'category'.
			 */
			if ( ! isset( $q['taxonomy'] ) ) {
				foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
					if ( empty( $queried_items['terms'][0] ) ) {
						continue;
					}

					if ( ! in_array( $queried_taxonomy, array( 'category', 'post_tag' ) ) ) {
						$q['taxonomy'] = $queried_taxonomy;

						if ( 'slug' === $queried_items['field'] ) {
							$q['term'] = $queried_items['terms'][0];
						} else {
							$q['term_id'] = $queried_items['terms'][0];
						}

						// Take the first one we find.
						break;
					}
				}
			}

			// 'cat', 'category_name', 'tag_id'
			foreach ( $this->tax_query->queried_terms as $queried_taxonomy => $queried_items ) {
				if ( empty( $queried_items['terms'][0] ) ) {
					continue;
				}

				if ( 'category' === $queried_taxonomy ) {
					$the_cat = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'category' );
					if ( $the_cat ) {
						$this->set( 'cat', $the_cat->term_id );
						$this->set( 'category_name', $the_cat->slug );
					}
					unset( $the_cat );
				}

				if ( 'post_tag' === $queried_taxonomy ) {
					$the_tag = get_term_by( $queried_items['field'], $queried_items['terms'][0], 'post_tag' );
					if ( $the_tag ) {
						$this->set( 'tag_id', $the_tag->term_id );
					}
					unset( $the_tag );
				}
			}
		}

		if ( !empty( $this->tax_query->queries ) || !empty( $this->meta_query->queries ) ) {
			$groupby = "{$wpdb->posts}.ID";
		}

		// Author/user stuff

		if ( ! empty( $q['author'] ) && $q['author'] != '0' ) {
			$q['author'] = addslashes_gpc( '' . urldecode( $q['author'] ) );
			$authors = array_unique( array_map( 'intval', preg_split( '/[,\s]+/', $q['author'] ) ) );
			foreach ( $authors as $author ) {
				$key = $author > 0 ? 'author__in' : 'author__not_in';
				$q[$key][] = abs( $author );
			}
			$q['author'] = implode( ',', $authors );
		}

		if ( ! empty( $q['author__not_in'] ) ) {
			$author__not_in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__not_in'] ) ) );
			$where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
		} elseif ( ! empty( $q['author__in'] ) ) {
			$author__in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__in'] ) ) );
			$where .= " AND {$wpdb->posts}.post_author IN ($author__in) ";
		}

		// Author stuff for nice URLs

		if ( '' != $q['author_name'] ) {
			if ( strpos($q['author_name'], '/') !== false ) {
				$q['author_name'] = explode('/', $q['author_name']);
				if ( $q['author_name'][ count($q['author_name'])-1 ] ) {
					$q['author_name'] = $q['author_name'][count($q['author_name'])-1]; // no trailing slash
				} else {
					$q['author_name'] = $q['author_name'][count($q['author_name'])-2]; // there was a trailing slash
				}
			}
			$q['author_name'] = sanitize_title_for_query( $q['author_name'] );
			$q['author'] = get_user_by('slug', $q['author_name']);
			if ( $q['author'] )
				$q['author'] = $q['author']->ID;
			$whichauthor .= " AND ({$wpdb->posts}.post_author = " . absint($q['author']) . ')';
		}

		// Matching by comment count.
		if ( isset( $q['comment_count'] ) ) {
			// Numeric comment count is converted to array format.
			if ( is_numeric( $q['comment_count'] ) ) {
				$q['comment_count'] = array(
					'value' => intval( $q['comment_count'] ),
				);
			}

			if ( isset( $q['comment_count']['value'] ) ) {
				$q['comment_count'] = array_merge( array(
					'compare' => '=',
				), $q['comment_count'] );

				// Fallback for invalid compare operators is '='.
				$compare_operators = array( '=', '!=', '>', '>=', '<', '<=' );
				if ( ! in_array( $q['comment_count']['compare'], $compare_operators, true ) ) {
					$q['comment_count']['compare'] = '=';
				}

				$where .= $wpdb->prepare( " AND {$wpdb->posts}.comment_count {$q['comment_count']['compare']} %d", $q['comment_count']['value'] );
			}
		}

		// MIME-Type stuff for attachment browsing

		if ( isset( $q['post_mime_type'] ) && '' != $q['post_mime_type'] ) {
			$whichmimetype = wp_post_mime_type_where( $q['post_mime_type'], $wpdb->posts );
		}
		$where .= $search . $whichauthor . $whichmimetype;

		if ( ! empty( $this->meta_query->queries ) ) {
			$clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
			$join   .= $clauses['join'];
			$where  .= $clauses['where'];
		}

		$rand = ( isset( $q['orderby'] ) && 'rand' === $q['orderby'] );
		if ( ! isset( $q['order'] ) ) {
			$q['order'] = $rand ? '' : 'DESC';
		} else {
			$q['order'] = $rand ? '' : $this->parse_order( $q['order'] );
		}

		// Order by.
		if ( empty( $q['orderby'] ) ) {
			/*
			 * Boolean false or empty array blanks out ORDER BY,
			 * while leaving the value unset or otherwise empty sets the default.
			 */
			if ( isset( $q['orderby'] ) && ( is_array( $q['orderby'] ) || false === $q['orderby'] ) ) {
				$orderby = '';
			} else {
				$orderby = "{$wpdb->posts}.post_date " . $q['order'];
			}
		} elseif ( 'none' == $q['orderby'] ) {
			$orderby = '';
		} elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
			$orderby = "FIELD( {$wpdb->posts}.ID, $post__in )";
		} elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
			$orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
		} elseif ( $q['orderby'] == 'post_name__in' && ! empty( $post_name__in ) ) {
			$orderby = "FIELD( {$wpdb->posts}.post_name, $post_name__in )";
		} else {
			$orderby_array = array();
			if ( is_array( $q['orderby'] ) ) {
				foreach ( $q['orderby'] as $_orderby => $order ) {
					$orderby = addslashes_gpc( urldecode( $_orderby ) );
					$parsed  = $this->parse_orderby( $orderby );

					if ( ! $parsed ) {
						continue;
					}

					$orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
				}
				$orderby = implode( ', ', $orderby_array );

			} else {
				$q['orderby'] = urldecode( $q['orderby'] );
				$q['orderby'] = addslashes_gpc( $q['orderby'] );

				foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
					$parsed = $this->parse_orderby( $orderby );
					// Only allow certain values for safety.
					if ( ! $parsed ) {
						continue;
					}

					$orderby_array[] = $parsed;
				}
				$orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );

				if ( empty( $orderby ) ) {
					$orderby = "{$wpdb->posts}.post_date " . $q['order'];
				} elseif ( ! empty( $q['order'] ) ) {
					$orderby .= " {$q['order']}";
				}
			}
		}

		// Order search results by relevance only when another "orderby" is not specified in the query.
		if ( ! empty( $q['s'] ) ) {
			$search_orderby = '';
			if ( ! empty( $q['search_orderby_title'] ) && ( empty( $q['orderby'] ) && ! $this->is_feed ) || ( isset( $q['orderby'] ) && 'relevance' === $q['orderby'] ) )
				$search_orderby = $this->parse_search_order( $q );

			if ( ! $q['suppress_filters'] ) {
				/**
				 * Filters the ORDER BY used when ordering search results.
				 *
				 * @since 3.7.0
				 *
				 * @param string   $search_orderby The ORDER BY clause.
				 * @param WP_Query $this           The current WP_Query instance.
				 */
				$search_orderby = apply_filters( 'posts_search_orderby', $search_orderby, $this );
			}

			if ( $search_orderby )
				$orderby = $orderby ? $search_orderby . ', ' . $orderby : $search_orderby;
		}

		if ( is_array( $post_type ) && count( $post_type ) > 1 ) {
			$post_type_cap = 'multiple_post_type';
		} else {
			if ( is_array( $post_type ) )
				$post_type = reset( $post_type );
			$post_type_object = get_post_type_object( $post_type );
			if ( empty( $post_type_object ) )
				$post_type_cap = $post_type;
		}

		if ( isset( $q['post_password'] ) ) {
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_password = %s", $q['post_password'] );
			if ( empty( $q['perm'] ) ) {
				$q['perm'] = 'readable';
			}
		} elseif ( isset( $q['has_password'] ) ) {
			$where .= sprintf( " AND {$wpdb->posts}.post_password %s ''", $q['has_password'] ? '!=' : '=' );
		}

		if ( ! empty( $q['comment_status'] ) ) {
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.comment_status = %s ", $q['comment_status'] );
		}

		if ( ! empty( $q['ping_status'] ) )  {
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.ping_status = %s ", $q['ping_status'] );
		}

		if ( 'any' == $post_type ) {
			$in_search_post_types = get_post_types( array('exclude_from_search' => false) );
			if ( empty( $in_search_post_types ) ) {
				$where .= ' AND 1=0 ';
			} else {
				$where .= " AND {$wpdb->posts}.post_type IN ('" . join( "', '", array_map( 'esc_sql', $in_search_post_types ) ) . "')";
			}
		} elseif ( !empty( $post_type ) && is_array( $post_type ) ) {
			$where .= " AND {$wpdb->posts}.post_type IN ('" . join("', '", esc_sql( $post_type ) ) . "')";
		} elseif ( ! empty( $post_type ) ) {
			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s", $post_type );
			$post_type_object = get_post_type_object ( $post_type );
		} elseif ( $this->is_attachment ) {
			$where .= " AND {$wpdb->posts}.post_type = 'attachment'";
			$post_type_object = get_post_type_object ( 'attachment' );
		} elseif ( $this->is_page ) {
			$where .= " AND {$wpdb->posts}.post_type = 'page'";
			$post_type_object = get_post_type_object ( 'page' );
		} else {
			$where .= " AND {$wpdb->posts}.post_type = 'post'";
			$post_type_object = get_post_type_object ( 'post' );
		}

		$edit_cap = 'edit_post';
		$read_cap = 'read_post';

		if ( ! empty( $post_type_object ) ) {
			$edit_others_cap = $post_type_object->cap->edit_others_posts;
			$read_private_cap = $post_type_object->cap->read_private_posts;
		} else {
			$edit_others_cap = 'edit_others_' . $post_type_cap . 's';
			$read_private_cap = 'read_private_' . $post_type_cap . 's';
		}

		$user_id = get_current_user_id();

		$q_status = array();
		if ( ! empty( $q['post_status'] ) ) {
			$statuswheres = array();
			$q_status = $q['post_status'];
			if ( ! is_array( $q_status ) )
				$q_status = explode(',', $q_status);
			$r_status = array();
			$p_status = array();
			$e_status = array();
			if ( in_array( 'any', $q_status ) ) {
				foreach ( get_post_stati( array( 'exclude_from_search' => true ) ) as $status ) {
					if ( ! in_array( $status, $q_status ) ) {
						$e_status[] = "{$wpdb->posts}.post_status <> '$status'";
					}
				}
			} else {
				foreach ( get_post_stati() as $status ) {
					if ( in_array( $status, $q_status ) ) {
						if ( 'private' == $status ) {
							$p_status[] = "{$wpdb->posts}.post_status = '$status'";
						} else {
							$r_status[] = "{$wpdb->posts}.post_status = '$status'";
						}
					}
				}
			}

			if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) {
				$r_status = array_merge($r_status, $p_status);
				unset($p_status);
			}

			if ( !empty($e_status) ) {
				$statuswheres[] = "(" . join( ' AND ', $e_status ) . ")";
			}
			if ( !empty($r_status) ) {
				if ( !empty($q['perm'] ) && 'editable' == $q['perm'] && !current_user_can($edit_others_cap) ) {
					$statuswheres[] = "({$wpdb->posts}.post_author = $user_id " . "AND (" . join( ' OR ', $r_status ) . "))";
				} else {
					$statuswheres[] = "(" . join( ' OR ', $r_status ) . ")";
				}
			}
			if ( !empty($p_status) ) {
				if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can($read_private_cap) ) {
					$statuswheres[] = "({$wpdb->posts}.post_author = $user_id " . "AND (" . join( ' OR ', $p_status ) . "))";
				} else {
					$statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
				}
			}
			if ( $post_status_join ) {
				$join .= " LEFT JOIN {$wpdb->posts} AS p2 ON ({$wpdb->posts}.post_parent = p2.ID) ";
				foreach ( $statuswheres as $index => $statuswhere ) {
					$statuswheres[$index] = "($statuswhere OR ({$wpdb->posts}.post_status = 'inherit' AND " . str_replace( $wpdb->posts, 'p2', $statuswhere ) . "))";
				}
			}
			$where_status = implode( ' OR ', $statuswheres );
			if ( ! empty( $where_status ) ) {
				$where .= " AND ($where_status)";
			}
		} elseif ( !$this->is_singular ) {
			$where .= " AND ({$wpdb->posts}.post_status = 'publish'";

			// Add public states.
			$public_states = get_post_stati( array('public' => true) );
			foreach ( (array) $public_states as $state ) {
				if ( 'publish' == $state ) // Publish is hard-coded above.
					continue;
				$where .= " OR {$wpdb->posts}.post_status = '$state'";
			}

			if ( $this->is_admin ) {
				// Add protected states that should show in the admin all list.
				$admin_all_states = get_post_stati( array('protected' => true, 'show_in_admin_all_list' => true) );
				foreach ( (array) $admin_all_states as $state ) {
					$where .= " OR {$wpdb->posts}.post_status = '$state'";
				}
			}

			if ( is_user_logged_in() ) {
				// Add private states that are limited to viewing by the author of a post or someone who has caps to read private states.
				$private_states = get_post_stati( array('private' => true) );
				foreach ( (array) $private_states as $state ) {
					$where .= current_user_can( $read_private_cap ) ? " OR {$wpdb->posts}.post_status = '$state'" : " OR {$wpdb->posts}.post_author = $user_id AND {$wpdb->posts}.post_status = '$state'";
				}
			}

			$where .= ')';
		}

		/*
		 * Apply filters on where and join prior to paging so that any
		 * manipulations to them are reflected in the paging by day queries.
		 */
		if ( !$q['suppress_filters'] ) {
			/**
			 * Filters the WHERE clause of the query.
			 *
			 * @since 1.5.0
			 *
			 * @param string   $where The WHERE clause of the query.
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			$where = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );

			/**
			 * Filters the JOIN clause of the query.
			 *
			 * @since 1.5.0
			 *
			 * @param string   $join  The JOIN clause of the query.
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			$join = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
		}

		// Paging
		if ( empty($q['nopaging']) && !$this->is_singular ) {
			$page = absint($q['paged']);
			if ( !$page )
				$page = 1;

			// If 'offset' is provided, it takes precedence over 'paged'.
			if ( isset( $q['offset'] ) && is_numeric( $q['offset'] ) ) {
				$q['offset'] = absint( $q['offset'] );
				$pgstrt = $q['offset'] . ', ';
			} else {
				$pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
			}
			$limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
		}

		// Comments feeds
		if ( $this->is_comment_feed && ! $this->is_singular ) {
			if ( $this->is_archive || $this->is_search ) {
				$cjoin = "JOIN {$wpdb->posts} ON ({$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID) $join ";
				$cwhere = "WHERE comment_approved = '1' $where";
				$cgroupby = "{$wpdb->comments}.comment_id";
			} else { // Other non singular e.g. front
				$cjoin = "JOIN {$wpdb->posts} ON ( {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID )";
				$cwhere = "WHERE ( post_status = 'publish' OR ( post_status = 'inherit' AND post_type = 'attachment' ) ) AND comment_approved = '1'";
				$cgroupby = '';
			}

			if ( !$q['suppress_filters'] ) {
				/**
				 * Filters the JOIN clause of the comments feed query before sending.
				 *
				 * @since 2.2.0
				 *
				 * @param string   $cjoin The JOIN clause of the query.
				 * @param WP_Query $this The WP_Query instance (passed by reference).
				 */
				$cjoin = apply_filters_ref_array( 'comment_feed_join', array( $cjoin, &$this ) );

				/**
				 * Filters the WHERE clause of the comments feed query before sending.
				 *
				 * @since 2.2.0
				 *
				 * @param string   $cwhere The WHERE clause of the query.
				 * @param WP_Query $this   The WP_Query instance (passed by reference).
				 */
				$cwhere = apply_filters_ref_array( 'comment_feed_where', array( $cwhere, &$this ) );

				/**
				 * Filters the GROUP BY clause of the comments feed query before sending.
				 *
				 * @since 2.2.0
				 *
				 * @param string   $cgroupby The GROUP BY clause of the query.
				 * @param WP_Query $this     The WP_Query instance (passed by reference).
				 */
				$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( $cgroupby, &$this ) );

				/**
				 * Filters the ORDER BY clause of the comments feed query before sending.
				 *
				 * @since 2.8.0
				 *
				 * @param string   $corderby The ORDER BY clause of the query.
				 * @param WP_Query $this     The WP_Query instance (passed by reference).
				 */
				$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );

				/**
				 * Filters the LIMIT clause of the comments feed query before sending.
				 *
				 * @since 2.8.0
				 *
				 * @param string   $climits The JOIN clause of the query.
				 * @param WP_Query $this    The WP_Query instance (passed by reference).
				 */
				$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
			}
			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';

			$comments = (array) $wpdb->get_results("SELECT $distinct {$wpdb->comments}.* FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits");
			// Convert to WP_Comment
			$this->comments = array_map( 'get_comment', $comments );
			$this->comment_count = count($this->comments);

			$post_ids = array();

			foreach ( $this->comments as $comment )
				$post_ids[] = (int) $comment->comment_post_ID;

			$post_ids = join(',', $post_ids);
			$join = '';
			if ( $post_ids ) {
				$where = "AND {$wpdb->posts}.ID IN ($post_ids) ";
			} else {
				$where = "AND 0";
			}
		}

		$pieces = array( 'where', 'groupby', 'join', 'orderby', 'distinct', 'fields', 'limits' );

		/*
		 * Apply post-paging filters on where and join. Only plugins that
		 * manipulate paging queries should use these hooks.
		 */
		if ( !$q['suppress_filters'] ) {
			/**
			 * Filters the WHERE clause of the query.
			 *
			 * Specifically for manipulating paging queries.
			 *
			 * @since 1.5.0
			 *
			 * @param string   $where The WHERE clause of the query.
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			$where = apply_filters_ref_array( 'posts_where_paged', array( $where, &$this ) );

			/**
			 * Filters the GROUP BY clause of the query.
			 *
			 * @since 2.0.0
			 *
			 * @param string   $groupby The GROUP BY clause of the query.
			 * @param WP_Query $this    The WP_Query instance (passed by reference).
			 */
			$groupby = apply_filters_ref_array( 'posts_groupby', array( $groupby, &$this ) );

			/**
			 * Filters the JOIN clause of the query.
			 *
			 * Specifically for manipulating paging queries.
			 *
			 * @since 1.5.0
			 *
			 * @param string   $join  The JOIN clause of the query.
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			$join = apply_filters_ref_array( 'posts_join_paged', array( $join, &$this ) );

			/**
			 * Filters the ORDER BY clause of the query.
			 *
			 * @since 1.5.1
			 *
			 * @param string   $orderby The ORDER BY clause of the query.
			 * @param WP_Query $this    The WP_Query instance (passed by reference).
			 */
			$orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );

			/**
			 * Filters the DISTINCT clause of the query.
			 *
			 * @since 2.1.0
			 *
			 * @param string   $distinct The DISTINCT clause of the query.
			 * @param WP_Query $this     The WP_Query instance (passed by reference).
			 */
			$distinct = apply_filters_ref_array( 'posts_distinct', array( $distinct, &$this ) );

			/**
			 * Filters the LIMIT clause of the query.
			 *
			 * @since 2.1.0
			 *
			 * @param string   $limits The LIMIT clause of the query.
			 * @param WP_Query $this   The WP_Query instance (passed by reference).
			 */
			$limits = apply_filters_ref_array( 'post_limits', array( $limits, &$this ) );

			/**
			 * Filters the SELECT clause of the query.
			 *
			 * @since 2.1.0
			 *
			 * @param string   $fields The SELECT clause of the query.
			 * @param WP_Query $this   The WP_Query instance (passed by reference).
			 */
			$fields = apply_filters_ref_array( 'posts_fields', array( $fields, &$this ) );

			/**
			 * Filters all query clauses at once, for convenience.
			 *
			 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
			 * fields (SELECT), and LIMITS clauses.
			 *
			 * @since 3.1.0
			 *
			 * @param array    $clauses The list of clauses for the query.
			 * @param WP_Query $this    The WP_Query instance (passed by reference).
			 */
			$clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );

			$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
			$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
			$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
			$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
			$distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
			$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
			$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
		}

		/**
		 * Fires to announce the query's current selection parameters.
		 *
		 * For use by caching plugins.
		 *
		 * @since 2.3.0
		 *
		 * @param string $selection The assembled selection query.
		 */
		do_action( 'posts_selection', $where . $groupby . $orderby . $limits . $join );

		/*
		 * Filters again for the benefit of caching plugins.
		 * Regular plugins should use the hooks above.
		 */
		if ( !$q['suppress_filters'] ) {
			/**
			 * Filters the WHERE clause of the query.
			 *
			 * For use by caching plugins.
			 *
			 * @since 2.5.0
			 *
			 * @param string   $where The WHERE clause of the query.
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			$where = apply_filters_ref_array( 'posts_where_request', array( $where, &$this ) );

			/**
			 * Filters the GROUP BY clause of the query.
			 *
			 * For use by caching plugins.
			 *
			 * @since 2.5.0
			 *
			 * @param string   $groupby The GROUP BY clause of the query.
			 * @param WP_Query $this    The WP_Query instance (passed by reference).
			 */
			$groupby = apply_filters_ref_array( 'posts_groupby_request', array( $groupby, &$this ) );

			/**
			 * Filters the JOIN clause of the query.
			 *
			 * For use by caching plugins.
			 *
			 * @since 2.5.0
			 *
			 * @param string   $join  The JOIN clause of the query.
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			$join = apply_filters_ref_array( 'posts_join_request', array( $join, &$this ) );

			/**
			 * Filters the ORDER BY clause of the query.
			 *
			 * For use by caching plugins.
			 *
			 * @since 2.5.0
			 *
			 * @param string   $orderby The ORDER BY clause of the query.
			 * @param WP_Query $this    The WP_Query instance (passed by reference).
			 */
			$orderby = apply_filters_ref_array( 'posts_orderby_request', array( $orderby, &$this ) );

			/**
			 * Filters the DISTINCT clause of the query.
			 *
			 * For use by caching plugins.
			 *
			 * @since 2.5.0
			 *
			 * @param string   $distinct The DISTINCT clause of the query.
			 * @param WP_Query $this     The WP_Query instance (passed by reference).
			 */
			$distinct = apply_filters_ref_array( 'posts_distinct_request', array( $distinct, &$this ) );

			/**
			 * Filters the SELECT clause of the query.
			 *
			 * For use by caching plugins.
			 *
			 * @since 2.5.0
			 *
			 * @param string   $fields The SELECT clause of the query.
			 * @param WP_Query $this   The WP_Query instance (passed by reference).
			 */
			$fields = apply_filters_ref_array( 'posts_fields_request', array( $fields, &$this ) );

			/**
			 * Filters the LIMIT clause of the query.
			 *
			 * For use by caching plugins.
			 *
			 * @since 2.5.0
			 *
			 * @param string   $limits The LIMIT clause of the query.
			 * @param WP_Query $this   The WP_Query instance (passed by reference).
			 */
			$limits = apply_filters_ref_array( 'post_limits_request', array( $limits, &$this ) );

			/**
			 * Filters all query clauses at once, for convenience.
			 *
			 * For use by caching plugins.
			 *
			 * Covers the WHERE, GROUP BY, JOIN, ORDER BY, DISTINCT,
			 * fields (SELECT), and LIMITS clauses.
			 *
			 * @since 3.1.0
			 *
			 * @param array    $pieces The pieces of the query.
			 * @param WP_Query $this   The WP_Query instance (passed by reference).
			 */
			$clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );

			$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
			$groupby = isset( $clauses[ 'groupby' ] ) ? $clauses[ 'groupby' ] : '';
			$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
			$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
			$distinct = isset( $clauses[ 'distinct' ] ) ? $clauses[ 'distinct' ] : '';
			$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
			$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
		}

		if ( ! empty($groupby) )
			$groupby = 'GROUP BY ' . $groupby;
		if ( !empty( $orderby ) )
			$orderby = 'ORDER BY ' . $orderby;

		$found_rows = '';
		if ( !$q['no_found_rows'] && !empty($limits) )
			$found_rows = 'SQL_CALC_FOUND_ROWS';

		$this->request = $old_request = "SELECT $found_rows $distinct $fields FROM {$wpdb->posts} $join WHERE 1=1 $where $groupby $orderby $limits";

		if ( !$q['suppress_filters'] ) {
			/**
			 * Filters the completed SQL query before sending.
			 *
			 * @since 2.0.0
			 *
			 * @param string   $request The complete SQL query.
			 * @param WP_Query $this    The WP_Query instance (passed by reference).
			 */
			$this->request = apply_filters_ref_array( 'posts_request', array( $this->request, &$this ) );
		}

		/**
		 * Filters the posts array before the query takes place.
		 *
		 * Return a non-null value to bypass WordPress's default post queries.
		 *
		 * Filtering functions that require pagination information are encouraged to set
		 * the `found_posts` and `max_num_pages` properties of the WP_Query object,
		 * passed to the filter by reference. If WP_Query does not perform a database
		 * query, it will not have enough information to generate these values itself.
		 *
		 * @since 4.6.0
		 *
		 * @param array|null $posts Return an array of post data to short-circuit WP's query,
		 *                          or null to allow WP to run its normal queries.
		 * @param WP_Query   $this  The WP_Query instance (passed by reference).
		 */
		$this->posts = apply_filters_ref_array( 'posts_pre_query', array( null, &$this ) );

		if ( 'ids' == $q['fields'] ) {
			if ( null === $this->posts ) {
				$this->posts = $wpdb->get_col( $this->request );
			}

			$this->posts = array_map( 'intval', $this->posts );
			$this->post_count = count( $this->posts );
			$this->set_found_posts( $q, $limits );

			return $this->posts;
		}

		if ( 'id=>parent' == $q['fields'] ) {
			if ( null === $this->posts ) {
				$this->posts = $wpdb->get_results( $this->request );
			}

			$this->post_count = count( $this->posts );
			$this->set_found_posts( $q, $limits );

			$r = array();
			foreach ( $this->posts as $key => $post ) {
				$this->posts[ $key ]->ID = (int) $post->ID;
				$this->posts[ $key ]->post_parent = (int) $post->post_parent;

				$r[ (int) $post->ID ] = (int) $post->post_parent;
			}

			return $r;
		}

		if ( null === $this->posts ) {
			$split_the_query = ( $old_request == $this->request && "{$wpdb->posts}.*" == $fields && !empty( $limits ) && $q['posts_per_page'] < 500 );

			/**
			 * Filters whether to split the query.
			 *
			 * Splitting the query will cause it to fetch just the IDs of the found posts
			 * (and then individually fetch each post by ID), rather than fetching every
			 * complete row at once. One massive result vs. many small results.
			 *
			 * @since 3.4.0
			 *
			 * @param bool     $split_the_query Whether or not to split the query.
			 * @param WP_Query $this            The WP_Query instance.
			 */
			$split_the_query = apply_filters( 'split_the_query', $split_the_query, $this );

			if ( $split_the_query ) {
				// First get the IDs and then fill in the objects

				$this->request = "SELECT $found_rows $distinct {$wpdb->posts}.ID FROM {$wpdb->posts} $join WHERE 1=1 $where $groupby $orderby $limits";

				/**
				 * Filters the Post IDs SQL request before sending.
				 *
				 * @since 3.4.0
				 *
				 * @param string   $request The post ID request.
				 * @param WP_Query $this    The WP_Query instance.
				 */
				$this->request = apply_filters( 'posts_request_ids', $this->request, $this );

				$ids = $wpdb->get_col( $this->request );

				if ( $ids ) {
					$this->posts = $ids;
					$this->set_found_posts( $q, $limits );
					_prime_post_caches( $ids, $q['update_post_term_cache'], $q['update_post_meta_cache'] );
				} else {
					$this->posts = array();
				}
			} else {
				$this->posts = $wpdb->get_results( $this->request );
				$this->set_found_posts( $q, $limits );
			}
		}

		// Convert to WP_Post objects.
		if ( $this->posts ) {
			$this->posts = array_map( 'get_post', $this->posts );
		}

		if ( ! $q['suppress_filters'] ) {
			/**
			 * Filters the raw post results array, prior to status checks.
			 *
			 * @since 2.3.0
			 *
			 * @param array    $posts The post results array.
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			$this->posts = apply_filters_ref_array( 'posts_results', array( $this->posts, &$this ) );
		}

		if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
			/** This filter is documented in wp-includes/query.php */
			$cjoin = apply_filters_ref_array( 'comment_feed_join', array( '', &$this ) );

			/** This filter is documented in wp-includes/query.php */
			$cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );

			/** This filter is documented in wp-includes/query.php */
			$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( '', &$this ) );
			$cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';

			/** This filter is documented in wp-includes/query.php */
			$corderby = apply_filters_ref_array( 'comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
			$corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';

			/** This filter is documented in wp-includes/query.php */
			$climits = apply_filters_ref_array( 'comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );

			$comments_request = "SELECT {$wpdb->comments}.* FROM {$wpdb->comments} $cjoin $cwhere $cgroupby $corderby $climits";
			$comments = $wpdb->get_results($comments_request);
			// Convert to WP_Comment
			$this->comments = array_map( 'get_comment', $comments );
			$this->comment_count = count($this->comments);
		}

		// Check post status to determine if post should be displayed.
		if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) {
			$status = get_post_status($this->posts[0]);
			if ( 'attachment' === $this->posts[0]->post_type && 0 === (int) $this->posts[0]->post_parent ) {
				$this->is_page = false;
				$this->is_single = true;
				$this->is_attachment = true;
			}
			$post_status_obj = get_post_status_object($status);

			// If the post_status was specifically requested, let it pass through.
			if ( !$post_status_obj->public && ! in_array( $status, $q_status ) ) {

				if ( ! is_user_logged_in() ) {
					// User must be logged in to view unpublished posts.
					$this->posts = array();
				} else {
					if  ( $post_status_obj->protected ) {
						// User must have edit permissions on the draft to preview.
						if ( ! current_user_can($edit_cap, $this->posts[0]->ID) ) {
							$this->posts = array();
						} else {
							$this->is_preview = true;
							if ( 'future' != $status )
								$this->posts[0]->post_date = current_time('mysql');
						}
					} elseif ( $post_status_obj->private ) {
						if ( ! current_user_can($read_cap, $this->posts[0]->ID) )
							$this->posts = array();
					} else {
						$this->posts = array();
					}
				}
			}

			if ( $this->is_preview && $this->posts && current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
				/**
				 * Filters the single post for preview mode.
				 *
				 * @since 2.7.0
				 *
				 * @param WP_Post  $post_preview  The Post object.
				 * @param WP_Query $this          The WP_Query instance (passed by reference).
				 */
				$this->posts[0] = get_post( apply_filters_ref_array( 'the_preview', array( $this->posts[0], &$this ) ) );
			}
		}

		// Put sticky posts at the top of the posts array
		$sticky_posts = get_option('sticky_posts');
		if ( $this->is_home && $page <= 1 && is_array($sticky_posts) && !empty($sticky_posts) && !$q['ignore_sticky_posts'] ) {
			$num_posts = count($this->posts);
			$sticky_offset = 0;
			// Loop over posts and relocate stickies to the front.
			for ( $i = 0; $i < $num_posts; $i++ ) {
				if ( in_array($this->posts[$i]->ID, $sticky_posts) ) {
					$sticky_post = $this->posts[$i];
					// Remove sticky from current position
					array_splice($this->posts, $i, 1);
					// Move to front, after other stickies
					array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
					// Increment the sticky offset. The next sticky will be placed at this offset.
					$sticky_offset++;
					// Remove post from sticky posts array
					$offset = array_search($sticky_post->ID, $sticky_posts);
					unset( $sticky_posts[$offset] );
				}
			}

			// If any posts have been excluded specifically, Ignore those that are sticky.
			if ( !empty($sticky_posts) && !empty($q['post__not_in']) )
				$sticky_posts = array_diff($sticky_posts, $q['post__not_in']);

			// Fetch sticky posts that weren't in the query results
			if ( !empty($sticky_posts) ) {
				$stickies = get_posts( array(
					'post__in' => $sticky_posts,
					'post_type' => $post_type,
					'post_status' => 'publish',
					'nopaging' => true
				) );

				foreach ( $stickies as $sticky_post ) {
					array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
					$sticky_offset++;
				}
			}
		}

		// If comments have been fetched as part of the query, make sure comment meta lazy-loading is set up.
		if ( ! empty( $this->comments ) ) {
			wp_queue_comments_for_comment_meta_lazyload( $this->comments );
		}

		if ( ! $q['suppress_filters'] ) {
			/**
			 * Filters the array of retrieved posts after they've been fetched and
			 * internally processed.
			 *
			 * @since 1.5.0
			 *
			 * @param array    $posts The array of retrieved posts.
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			$this->posts = apply_filters_ref_array( 'the_posts', array( $this->posts, &$this ) );
		}

		// Ensure that any posts added/modified via one of the filters above are
		// of the type WP_Post and are filtered.
		if ( $this->posts ) {
			$this->post_count = count( $this->posts );

			$this->posts = array_map( 'get_post', $this->posts );

			if ( $q['cache_results'] )
				update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);

			$this->post = reset( $this->posts );
		} else {
			$this->post_count = 0;
			$this->posts = array();
		}

		if ( $q['lazy_load_term_meta'] ) {
			wp_queue_posts_for_term_meta_lazyload( $this->posts );
		}

		return $this->posts;
	}

	/**
	 * Set up the amount of found posts and the number of pages (if limit clause was used)
	 * for the current query.
	 *
	 * @since 3.5.0
	 *
	 * @param array  $q      Query variables.
	 * @param string $limits LIMIT clauses of the query.
	 */
	private function set_found_posts( $q, $limits ) {
		global $wpdb;
		// Bail if posts is an empty array. Continue if posts is an empty string,
		// null, or false to accommodate caching plugins that fill posts later.
		if ( $q['no_found_rows'] || ( is_array( $this->posts ) && ! $this->posts ) )
			return;

		if ( ! empty( $limits ) ) {
			/**
			 * Filters the query to run for retrieving the found posts.
			 *
			 * @since 2.1.0
			 *
			 * @param string   $found_posts The query to run to find the found posts.
			 * @param WP_Query $this        The WP_Query instance (passed by reference).
			 */
			$this->found_posts = $wpdb->get_var( apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) ) );
		} else {
			if ( is_array( $this->posts ) ) {
				$this->found_posts = count( $this->posts );
			} else {
				if ( null === $this->posts ) {  
					$this->found_posts = 0;
				} else {
					$this->found_posts = 1;
				}
			}
		}

		/**
		 * Filters the number of found posts for the query.
		 *
		 * @since 2.1.0
		 *
		 * @param int      $found_posts The number of posts found.
		 * @param WP_Query $this        The WP_Query instance (passed by reference).
		 */
		$this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );

		if ( ! empty( $limits ) )
			$this->max_num_pages = ceil( $this->found_posts / $q['posts_per_page'] );
	}

	/**
	 * Set up the next post and iterate current post index.
	 *
	 * @since 1.5.0
	 *
	 * @return WP_Post Next post.
	 */
	public function next_post() {

		$this->current_post++;

		$this->post = $this->posts[$this->current_post];
		return $this->post;
	}

	/**
	 * Sets up the current post.
	 *
	 * Retrieves the next post, sets up the post, sets the 'in the loop'
	 * property to true.
	 *
	 * @since 1.5.0
	 *
	 * @global WP_Post $post
	 */
	public function the_post() {
		global $post;
		$this->in_the_loop = true;

		if ( $this->current_post == -1 ) // loop has just started
			/**
			 * Fires once the loop is started.
			 *
			 * @since 2.0.0
			 *
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			do_action_ref_array( 'loop_start', array( &$this ) );

		$post = $this->next_post();
		$this->setup_postdata( $post );
	}

	/**
	 * Determines whether there are more posts available in the loop.
	 *
	 * Calls the {@see 'loop_end'} action when the loop is complete.
	 *
	 * @since 1.5.0
	 *
	 * @return bool True if posts are available, false if end of loop.
	 */
	public function have_posts() {
		if ( $this->current_post + 1 < $this->post_count ) {
			return true;
		} elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
			/**
			 * Fires once the loop has ended.
			 *
			 * @since 2.0.0
			 *
			 * @param WP_Query $this The WP_Query instance (passed by reference).
			 */
			do_action_ref_array( 'loop_end', array( &$this ) );
			// Do some cleaning up after the loop
			$this->rewind_posts();
		} elseif ( 0 === $this->post_count ) {
			/**
			 * Fires if no results are found in a post query.
			 *
			 * @since 4.9.0
			 *
			 * @param WP_Query $this The WP_Query instance.
			 */
			do_action( 'loop_no_results', $this );
		}

		$this->in_the_loop = false;
		return false;
	}

	/**
	 * Rewind the posts and reset post index.
	 *
	 * @since 1.5.0
	 */
	public function rewind_posts() {
		$this->current_post = -1;
		if ( $this->post_count > 0 ) {
			$this->post = $this->posts[0];
		}
	}

	/**
	 * Iterate current comment index and return WP_Comment object.
	 *
	 * @since 2.2.0
	 *
	 * @return WP_Comment Comment object.
	 */
	public function next_comment() {
		$this->current_comment++;

		$this->comment = $this->comments[$this->current_comment];
		return $this->comment;
	}

	/**
	 * Sets up the current comment.
	 *
	 * @since 2.2.0
	 * @global WP_Comment $comment Current comment.
	 */
	public function the_comment() {
		global $comment;

		$comment = $this->next_comment();

		if ( $this->current_comment == 0 ) {
			/**
			 * Fires once the comment loop is started.
			 *
			 * @since 2.2.0
			 */
			do_action( 'comment_loop_start' );
		}
	}

	/**
	 * Whether there are more comments available.
	 *
	 * Automatically rewinds comments when finished.
	 *
	 * @since 2.2.0
	 *
	 * @return bool True, if more comments. False, if no more posts.
	 */
	public function have_comments() {
		if ( $this->current_comment + 1 < $this->comment_count ) {
			return true;
		} elseif ( $this->current_comment + 1 == $this->comment_count ) {
			$this->rewind_comments();
		}

		return false;
	}

	/**
	 * Rewind the comments, resets the comment index and comment to first.
	 *
	 * @since 2.2.0
	 */
	public function rewind_comments() {
		$this->current_comment = -1;
		if ( $this->comment_count > 0 ) {
			$this->comment = $this->comments[0];
		}
	}

	/**
	 * Sets up the WordPress query by parsing query string.
	 *
	 * @since 1.5.0
	 *
	 * @param string|array $query URL query string or array of query arguments.
	 * @return array List of posts.
	 */
	public function query( $query ) {
		$this->init();
		$this->query = $this->query_vars = wp_parse_args( $query );
		return $this->get_posts();
	}

	/**
	 * Retrieve queried object.
	 *
	 * If queried object is not set, then the queried object will be set from
	 * the category, tag, taxonomy, posts page, single post, page, or author
	 * query variable. After it is set up, it will be returned.
	 *
	 * @since 1.5.0
	 *
	 * @return object
	 */
	public function get_queried_object() {
		if ( isset($this->queried_object) )
			return $this->queried_object;

		$this->queried_object = null;
		$this->queried_object_id = null;

		if ( $this->is_category || $this->is_tag || $this->is_tax ) {
			if ( $this->is_category ) {
				if ( $this->get( 'cat' ) ) {
					$term = get_term( $this->get( 'cat' ), 'category' );
				} elseif ( $this->get( 'category_name' ) ) {
					$term = get_term_by( 'slug', $this->get( 'category_name' ), 'category' );
				}
			} elseif ( $this->is_tag ) {
				if ( $this->get( 'tag_id' ) ) {
					$term = get_term( $this->get( 'tag_id' ), 'post_tag' );
				} elseif ( $this->get( 'tag' ) ) {
					$term = get_term_by( 'slug', $this->get( 'tag' ), 'post_tag' );
				}
			} else {
				// For other tax queries, grab the first term from the first clause.
				if ( ! empty( $this->tax_query->queried_terms ) ) {
					$queried_taxonomies = array_keys( $this->tax_query->queried_terms );
					$matched_taxonomy = reset( $queried_taxonomies );
					$query = $this->tax_query->queried_terms[ $matched_taxonomy ];

					if ( ! empty( $query['terms'] ) ) {
						if ( 'term_id' == $query['field'] ) {
							$term = get_term( reset( $query['terms'] ), $matched_taxonomy );
						} else {
							$term = get_term_by( $query['field'], reset( $query['terms'] ), $matched_taxonomy );
						}
					}
				}
			}

			if ( ! empty( $term ) && ! is_wp_error( $term ) )  {
				$this->queried_object = $term;
				$this->queried_object_id = (int) $term->term_id;

				if ( $this->is_category && 'category' === $this->queried_object->taxonomy )
					_make_cat_compat( $this->queried_object );
			}
		} elseif ( $this->is_post_type_archive ) {
			$post_type = $this->get( 'post_type' );
			if ( is_array( $post_type ) )
				$post_type = reset( $post_type );
			$this->queried_object = get_post_type_object( $post_type );
		} elseif ( $this->is_posts_page ) {
			$page_for_posts = get_option('page_for_posts');
			$this->queried_object = get_post( $page_for_posts );
			$this->queried_object_id = (int) $this->queried_object->ID;
		} elseif ( $this->is_singular && ! empty( $this->post ) ) {
			$this->queried_object = $this->post;
			$this->queried_object_id = (int) $this->post->ID;
		} elseif ( $this->is_author ) {
			$this->queried_object_id = (int) $this->get('author');
			$this->queried_object = get_userdata( $this->queried_object_id );
		}

		return $this->queried_object;
	}

	/**
	 * Retrieve ID of the current queried object.
	 *
	 * @since 1.5.0
	 *
	 * @return int
	 */
	public function get_queried_object_id() {
		$this->get_queried_object();

		if ( isset($this->queried_object_id) ) {
			return $this->queried_object_id;
		}

		return 0;
	}

	/**
	 * Constructor.
	 *
	 * Sets up the WordPress query, if parameter is not empty.
	 *
	 * @since 1.5.0
	 *
	 * @param string|array $query URL query string or array of vars.
	 */
	public function __construct( $query = '' ) {
		if ( ! empty( $query ) ) {
			$this->query( $query );
		}
	}

	/**
	 * Make private properties readable for backward compatibility.
	 *
	 * @since 4.0.0
	 *
	 * @param string $name Property to get.
	 * @return mixed Property.
	 */
	public function __get( $name ) {
		if ( in_array( $name, $this->compat_fields ) ) {
			return $this->$name;
		}
	}

	/**
	 * Make private properties checkable for backward compatibility.
	 *
	 * @since 4.0.0
	 *
	 * @param string $name Property to check if set.
	 * @return bool Whether the property is set.
	 */
	public function __isset( $name ) {
		if ( in_array( $name, $this->compat_fields ) ) {
			return isset( $this->$name );
		}
	}

	/**
	 * Make private/protected methods readable for backward compatibility.
	 *
	 * @since 4.0.0
	 *
	 * @param callable $name      Method to call.
	 * @param array    $arguments Arguments to pass when calling.
	 * @return mixed|false Return value of the callback, false otherwise.
	 */
	public function __call( $name, $arguments ) {
		if ( in_array( $name, $this->compat_methods ) ) {
			return call_user_func_array( array( $this, $name ), $arguments );
		}
		return false;
	}

	/**
 	 * Is the query for an existing archive page?
 	 *
 	 * Month, Year, Category, Author, Post Type archive...
	 *
 	 * @since 3.1.0
 	 *
 	 * @return bool
 	 */
	public function is_archive() {
		return (bool) $this->is_archive;
	}

	/**
	 * Is the query for an existing post type archive page?
	 *
	 * @since 3.1.0
	 *
	 * @param mixed $post_types Optional. Post type or array of posts types to check against.
	 * @return bool
	 */
	public function is_post_type_archive( $post_types = '' ) {
		if ( empty( $post_types ) || ! $this->is_post_type_archive )
			return (bool) $this->is_post_type_archive;

		$post_type = $this->get( 'post_type' );
		if ( is_array( $post_type ) )
			$post_type = reset( $post_type );
		$post_type_object = get_post_type_object( $post_type );

		return in_array( $post_type_object->name, (array) $post_types );
	}

	/**
	 * Is the query for an existing attachment page?
	 *
	 * @since 3.1.0
	 *
	 * @param mixed $attachment Attachment ID, title, slug, or array of such.
	 * @return bool
	 */
	public function is_attachment( $attachment = '' ) {
		if ( ! $this->is_attachment ) {
			return false;
		}

		if ( empty( $attachment ) ) {
			return true;
		}

		$attachment = array_map( 'strval', (array) $attachment );

		$post_obj = $this->get_queried_object();

		if ( in_array( (string) $post_obj->ID, $attachment ) ) {
			return true;
		} elseif ( in_array( $post_obj->post_title, $attachment ) ) {
			return true;
		} elseif ( in_array( $post_obj->post_name, $attachment ) ) {
			return true;
		}
		return false;
	}

	/**
	 * Is the query for an existing author archive page?
	 *
	 * If the $author parameter is specified, this function will additionally
	 * check if the query is for one of the authors specified.
	 *
	 * @since 3.1.0
	 *
	 * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
	 * @return bool
	 */
	public function is_author( $author = '' ) {
		if ( !$this->is_author )
			return false;

		if ( empty($author) )
			return true;

		$author_obj = $this->get_queried_object();

		$author = array_map( 'strval', (array) $author );

		if ( in_array( (string) $author_obj->ID, $author ) )
			return true;
		elseif ( in_array( $author_obj->nickname, $author ) )
			return true;
		elseif ( in_array( $author_obj->user_nicename, $author ) )
			return true;

		return false;
	}

	/**
	 * Is the query for an existing category archive page?
	 *
	 * If the $category parameter is specified, this function will additionally
	 * check if the query is for one of the categories specified.
	 *
	 * @since 3.1.0
	 *
	 * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
	 * @return bool
	 */
	public function is_category( $category = '' ) {
		if ( !$this->is_category )
			return false;

		if ( empty($category) )
			return true;

		$cat_obj = $this->get_queried_object();

		$category = array_map( 'strval', (array) $category );

		if ( in_array( (string) $cat_obj->term_id, $category ) )
			return true;
		elseif ( in_array( $cat_obj->name, $category ) )
			return true;
		elseif ( in_array( $cat_obj->slug, $category ) )
			return true;

		return false;
	}

	/**
	 * Is the query for an existing tag archive page?
	 *
	 * If the $tag parameter is specified, this function will additionally
	 * check if the query is for one of the tags specified.
	 *
	 * @since 3.1.0
	 *
	 * @param mixed $tag Optional. Tag ID, name, slug, or array of Tag IDs, names, and slugs.
	 * @return bool
	 */
	public function is_tag( $tag = '' ) {
		if ( ! $this->is_tag )
			return false;

		if ( empty( $tag ) )
			return true;

		$tag_obj = $this->get_queried_object();

		$tag = array_map( 'strval', (array) $tag );

		if ( in_array( (string) $tag_obj->term_id, $tag ) )
			return true;
		elseif ( in_array( $tag_obj->name, $tag ) )
			return true;
		elseif ( in_array( $tag_obj->slug, $tag ) )
			return true;

		return false;
	}

	/**
	 * Is the query for an existing custom taxonomy archive page?
	 *
	 * If the $taxonomy parameter is specified, this function will additionally
	 * check if the query is for that specific $taxonomy.
	 *
	 * If the $term parameter is specified in addition to the $taxonomy parameter,
	 * this function will additionally check if the query is for one of the terms
	 * specified.
	 *
	 * @since 3.1.0
	 *
	 * @global array $wp_taxonomies
	 *
	 * @param mixed $taxonomy Optional. Taxonomy slug or slugs.
	 * @param mixed $term     Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
	 * @return bool True for custom taxonomy archive pages, false for built-in taxonomies (category and tag archives).
	 */
	public function is_tax( $taxonomy = '', $term = '' ) {
		global $wp_taxonomies;

		if ( !$this->is_tax )
			return false;

		if ( empty( $taxonomy ) )
			return true;

		$queried_object = $this->get_queried_object();
		$tax_array = array_intersect( array_keys( $wp_taxonomies ), (array) $taxonomy );
		$term_array = (array) $term;

		// Check that the taxonomy matches.
		if ( ! ( isset( $queried_object->taxonomy ) && count( $tax_array ) && in_array( $queried_object->taxonomy, $tax_array ) ) )
			return false;

		// Only a Taxonomy provided.
		if ( empty( $term ) )
			return true;

		return isset( $queried_object->term_id ) &&
			count( array_intersect(
				array( $queried_object->term_id, $queried_object->name, $queried_object->slug ),
				$term_array
			) );
	}

	/**
	 * Whether the current URL is within the comments popup window.
	 *
	 * @since 3.1.0
	 * @deprecated 4.5.0
	 *
	 * @return bool
	 */
	public function is_comments_popup() {
		_deprecated_function( __FUNCTION__, '4.5.0' );

		return false;
	}

	/**
	 * Is the query for an existing date archive?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_date() {
		return (bool) $this->is_date;
	}

	/**
	 * Is the query for an existing day archive?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_day() {
		return (bool) $this->is_day;
	}

	/**
	 * Is the query for a feed?
	 *
	 * @since 3.1.0
	 *
	 * @param string|array $feeds Optional feed types to check.
	 * @return bool
	 */
	public function is_feed( $feeds = '' ) {
		if ( empty( $feeds ) || ! $this->is_feed )
			return (bool) $this->is_feed;
		$qv = $this->get( 'feed' );
		if ( 'feed' == $qv )
			$qv = get_default_feed();
		return in_array( $qv, (array) $feeds );
	}

	/**
	 * Is the query for a comments feed?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_comment_feed() {
		return (bool) $this->is_comment_feed;
	}

	/**
	 * Is the query for the front page of the site?
	 *
	 * This is for what is displayed at your site's main URL.
	 *
	 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
	 *
	 * If you set a static page for the front page of your site, this function will return
	 * true when viewing that page.
	 *
	 * Otherwise the same as @see WP_Query::is_home()
	 *
	 * @since 3.1.0
	 *
	 * @return bool True, if front of site.
	 */
	public function is_front_page() {
		// most likely case
		if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
			return true;
		elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
			return true;
		else
			return false;
	}

	/**
	 * Is the query for the blog homepage?
	 *
	 * This is the page which shows the time based blog content of your site.
	 *
	 * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
	 *
	 * If you set a static page for the front page of your site, this function will return
	 * true only on the page you set as the "Posts page".
	 *
	 * @see WP_Query::is_front_page()
	 *
	 * @since 3.1.0
	 *
	 * @return bool True if blog view homepage.
	 */
	public function is_home() {
		return (bool) $this->is_home;
	}

	/**
	 * Is the query for an existing month archive?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_month() {
		return (bool) $this->is_month;
	}

	/**
	 * Is the query for an existing single page?
	 *
	 * If the $page parameter is specified, this function will additionally
	 * check if the query is for one of the pages specified.
	 *
	 * @see WP_Query::is_single()
	 * @see WP_Query::is_singular()
	 *
	 * @since 3.1.0
	 *
	 * @param int|string|array $page Optional. Page ID, title, slug, path, or array of such. Default empty.
	 * @return bool Whether the query is for an existing single page.
	 */
	public function is_page( $page = '' ) {
		if ( !$this->is_page )
			return false;

		if ( empty( $page ) )
			return true;

		$page_obj = $this->get_queried_object();

		$page = array_map( 'strval', (array) $page );

		if ( in_array( (string) $page_obj->ID, $page ) ) {
			return true;
		} elseif ( in_array( $page_obj->post_title, $page ) ) {
			return true;
		} elseif ( in_array( $page_obj->post_name, $page ) ) {
			return true;
		} else {
			foreach ( $page as $pagepath ) {
				if ( ! strpos( $pagepath, '/' ) ) {
					continue;
				}
				$pagepath_obj = get_page_by_path( $pagepath );

				if ( $pagepath_obj && ( $pagepath_obj->ID == $page_obj->ID ) ) {
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * Is the query for paged result and not for the first page?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_paged() {
		return (bool) $this->is_paged;
	}

	/**
	 * Is the query for a post or page preview?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_preview() {
		return (bool) $this->is_preview;
	}

	/**
	 * Is the query for the robots file?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_robots() {
		return (bool) $this->is_robots;
	}

	/**
	 * Is the query for a search?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_search() {
		return (bool) $this->is_search;
	}

	/**
	 * Is the query for an existing single post?
	 *
	 * Works for any post type excluding pages.
	 *
	 * If the $post parameter is specified, this function will additionally
	 * check if the query is for one of the Posts specified.
	 *
	 * @see WP_Query::is_page()
	 * @see WP_Query::is_singular()
	 *
	 * @since 3.1.0
	 *
	 * @param int|string|array $post Optional. Post ID, title, slug, path, or array of such. Default empty.
	 * @return bool Whether the query is for an existing single post.
	 */
	public function is_single( $post = '' ) {
		if ( !$this->is_single )
			return false;

		if ( empty($post) )
			return true;

		$post_obj = $this->get_queried_object();

		$post = array_map( 'strval', (array) $post );

		if ( in_array( (string) $post_obj->ID, $post ) ) {
			return true;
		} elseif ( in_array( $post_obj->post_title, $post ) ) {
			return true;
		} elseif ( in_array( $post_obj->post_name, $post ) ) {
			return true;
		} else {
			foreach ( $post as $postpath ) {
				if ( ! strpos( $postpath, '/' ) ) {
					continue;
				}
				$postpath_obj = get_page_by_path( $postpath, OBJECT, $post_obj->post_type );

				if ( $postpath_obj && ( $postpath_obj->ID == $post_obj->ID ) ) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Is the query for an existing single post of any post type (post, attachment, page,
	 * custom post types)?
	 *
	 * If the $post_types parameter is specified, this function will additionally
	 * check if the query is for one of the Posts Types specified.
	 *
	 * @see WP_Query::is_page()
	 * @see WP_Query::is_single()
	 *
	 * @since 3.1.0
	 *
	 * @param string|array $post_types Optional. Post type or array of post types. Default empty.
	 * @return bool Whether the query is for an existing single post of any of the given post types.
	 */
	public function is_singular( $post_types = '' ) {
		if ( empty( $post_types ) || !$this->is_singular )
			return (bool) $this->is_singular;

		$post_obj = $this->get_queried_object();

		return in_array( $post_obj->post_type, (array) $post_types );
	}

	/**
	 * Is the query for a specific time?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_time() {
		return (bool) $this->is_time;
	}

	/**
	 * Is the query for a trackback endpoint call?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_trackback() {
		return (bool) $this->is_trackback;
	}

	/**
	 * Is the query for an existing year archive?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_year() {
		return (bool) $this->is_year;
	}

	/**
	 * Is the query a 404 (returns no results)?
	 *
	 * @since 3.1.0
	 *
	 * @return bool
	 */
	public function is_404() {
		return (bool) $this->is_404;
	}

	/**
	 * Is the query for an embedded post?
	 *
	 * @since 4.4.0
	 *
	 * @return bool
	 */
	public function is_embed() {
		return (bool) $this->is_embed;
	}

	/**
	 * Is the query the main query?
	 *
	 * @since 3.3.0
	 *
	 * @global WP_Query $wp_query Global WP_Query instance.
	 *
	 * @return bool
	 */
	public function is_main_query() {
		global $wp_the_query;
		return $wp_the_query === $this;
	}

	/**
	 * Set up global post data.
	 *
	 * @since 4.1.0
	 * @since 4.4.0 Added the ability to pass a post ID to `$post`.
	 *
	 * @global int             $id
	 * @global WP_User         $authordata
	 * @global string|int|bool $currentday
	 * @global string|int|bool $currentmonth
	 * @global int             $page
	 * @global array           $pages
	 * @global int             $multipage
	 * @global int             $more
	 * @global int             $numpages
	 *
	 * @param WP_Post|object|int $post WP_Post instance or Post ID/object.
	 * @return true True when finished.
	 */
	public function setup_postdata( $post ) {
		global $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages;

		if ( ! ( $post instanceof WP_Post ) ) {
			$post = get_post( $post );
		}

		if ( ! $post ) {
			return;
		}

		$id = (int) $post->ID;

		$authordata = get_userdata($post->post_author);

		$currentday = mysql2date('d.m.y', $post->post_date, false);
		$currentmonth = mysql2date('m', $post->post_date, false);
		$numpages = 1;
		$multipage = 0;
		$page = $this->get( 'page' );
		if ( ! $page )
			$page = 1;

		/*
		 * Force full post content when viewing the permalink for the $post,
		 * or when on an RSS feed. Otherwise respect the 'more' tag.
		 */
		if ( $post->ID === get_queried_object_id() && ( $this->is_page() || $this->is_single() ) ) {
			$more = 1;
		} elseif ( $this->is_feed() ) {
			$more = 1;
		} else {
			$more = 0;
		}

		$content = $post->post_content;
		if ( false !== strpos( $content, '<!--nextpage-->' ) ) {
			$content = str_replace( "\n<!--nextpage-->\n", '<!--nextpage-->', $content );
			$content = str_replace( "\n<!--nextpage-->", '<!--nextpage-->', $content );
			$content = str_replace( "<!--nextpage-->\n", '<!--nextpage-->', $content );

			// Ignore nextpage at the beginning of the content.
			if ( 0 === strpos( $content, '<!--nextpage-->' ) )
				$content = substr( $content, 15 );

			$pages = explode('<!--nextpage-->', $content);
		} else {
			$pages = array( $post->post_content );
		}

		/**
		 * Filters the "pages" derived from splitting the post content.
		 *
		 * "Pages" are determined by splitting the post content based on the presence
		 * of `<!-- nextpage -->` tags.
		 *
		 * @since 4.4.0
		 *
		 * @param array   $pages Array of "pages" derived from the post content.
		 *                       of `<!-- nextpage -->` tags..
		 * @param WP_Post $post  Current post object.
		 */
		$pages = apply_filters( 'content_pagination', $pages, $post );

		$numpages = count( $pages );

		if ( $numpages > 1 ) {
			if ( $page > 1 ) {
				$more = 1;
			}
			$multipage = 1;
		} else {
	 		$multipage = 0;
	 	}

		/**
		 * Fires once the post data has been setup.
		 *
		 * @since 2.8.0
		 * @since 4.1.0 Introduced `$this` parameter.
		 *
		 * @param WP_Post  $post The Post object (passed by reference).
		 * @param WP_Query $this The current Query object (passed by reference).
		 */
		do_action_ref_array( 'the_post', array( &$post, &$this ) );

		return true;
	}
	/**
	 * After looping through a nested query, this function
	 * restores the $post global to the current post in this query.
	 *
	 * @since 3.7.0
	 *
	 * @global WP_Post $post
	 */
	public function reset_postdata() {
		if ( ! empty( $this->post ) ) {
			$GLOBALS['post'] = $this->post;
			$this->setup_postdata( $this->post );
		}
	}

	/**
	 * Lazyload term meta for posts in the loop.
	 *
	 * @since 4.4.0
	 * @deprecated 4.5.0 See wp_queue_posts_for_term_meta_lazyload().
	 *
	 * @param mixed $check
	 * @param int   $term_id
	 * @return mixed
	 */
	public function lazyload_term_meta( $check, $term_id ) {
		_deprecated_function( __METHOD__, '4.5.0' );
		return $check;
	}

	/**
	 * Lazyload comment meta for comments in the loop.
	 *
	 * @since 4.4.0
	 * @deprecated 4.5.0 See wp_queue_comments_for_comment_meta_lazyload().
	 *
	 * @param mixed $check
	 * @param int   $comment_id
	 * @return mixed
	 */
	public function lazyload_comment_meta( $check, $comment_id ) {
		_deprecated_function( __METHOD__, '4.5.0' );
		return $check;
	}
}

Cвязанные функции

Из метки: query (запрос)

Еще из раздела: Классы

195 комментов
Полезные 10 Вопросы 9 Все
  • Дмитрий

    Надо сделать, что бы товары выводились по убыванию цены. Я пытался сделать и получилось, то, что выводит, только те товары, которые меньше или равно заданному значению, а как из сделать, что бы они выводились по убыванию?

    $arr = [
    				'id' => '5',
    				'meta_query' => [
    					[
    						'key' => 'price',
    						'value' => '10000',
    						'compare' => '<=',
    						'type' => 'NUMERIC',
    					]
    				],
    				'order' => 'DESC',
    			 ];
    
    			$recent = new WP_Query($arr); 
    
  • Оставлю это здесь, может кто потестирует: оптимизация WP_Query https://drujoopress.wordpress.com/2013/06/27/how-to-optimize-wordpress-query-to-get-results-faster/

  • Что-то подрасстроила меня WP_Query в плане производительности. Пишу сложную выборку из метаполей.

    array(
    	'relation' => 'AND',
    	array(
    		'value'   => array(100, 6999),
    		'type'    => 'numeric',
    		'compare' => 'BETWEEN',
    		'key'     => 'price',
    	),
    	array(
    		'value'   => array(3, 95),
    		'type'    => 'numeric',
    		'compare' => 'BETWEEN',
    		'key'     => 'size',
    	),
    	array(
    		'value'   => array(100, 500),
    		'type'    => 'numeric',
    		'compare' => 'BETWEEN',
    		'key'     => 'weight',
    	),
    	array(
    		'value'   => array('0-1', '1-2'),
    		'key'     => 'old',
    	),
    	array(
    		'value'   => 'нет',
    		'key'     => 'interactive',
    	),
    	array(
    		'value'   => array('Беларусь', 'Россия'),
    		'key'     => 'country',
    	),
    	array(
    		'value'   => array('Baby', 'Disnay'),
    		'key'     => 'brend',
    	)
    );

    Скорость загрузки - 20 секунд, без этого куска кода - 0.2сек. Это из 1000 записей.

    • campusboy2947 cайт: www.youtube.com/c/wpplus

      За удобство всегда приходилось платить. Напиши аналог такого запроса на wpdb, сколько будет выполнение?

      • Хех... легко сказать. Знать бы еще как это делается smile

        • campusboy2947 cайт: www.youtube.com/c/wpplus

          Ну ты же образно говоря обвиняешь WP_Query в медленности, хотя этот класс всего лишь формирует запрос, который выполнит база данных. Если предполагаешь, что она это делает крайне медленно, то надо написать запрос без WP_Query, который будет делать тоже самое и сравнить скорости. Иначе обвинения ложны smile

          1
          • Пардон. Это похоже я с базой данных напортачил. Тестирую на другом, с теми же параметрами. Все довольно быстро - 0.1-0.2 секунды. Беру свои слова обратно

            • В продолжение темы. Не могу понять, по какой причине растет время ответа запроса WP_Query. Стартует хорошо, 0.1-0.2 секунды. Затем, с каждой итерацией, время растет. Доходит аж до 10-20 секунд. Подскажите, в чем может быть причина?

              • campusboy2947 cайт: www.youtube.com/c/wpplus

                Она пытается всё кешировать. Я думаю дело в этом. Попробуй выставить параметры кеширования у неё или используй wp_suspend_cache_addition(). Это лишь моё предположение.

                2
                • Да, так и оказалось. Отключил кеш:

                  'no_found_rows'          => true,
                  'update_post_term_cache' => false,
                  'update_post_meta_cache' => false,
                  'cache_results'          => false

                  И все залетало smile

                  2
                  • campusboy2947 cайт: www.youtube.com/c/wpplus

                    Спасибо за активность и конструктивные обсуждения, желание экспериментировать и искать истину. И делиться этим с другими! И всё это в уважительном тоне. Редкость для рунета. Спасибо ещё раз.

                    2
    • Kama6693

      Такую выборку надо кэшировать - это сложный запрос, оптимизировать его особо не получится, даже если прямой запрос делать. Структура БД для таких запросов слаба...

      Кэшируй результат в транзитные опции или в файлы...

      2
  • Нашел крайне серьезный и неприятный баг WP_Query. В WP можно сказать что гуру, и написал на нем не один десяток сайтов, но теперь просто в шоке от того что обнаружил. В общем, если юзать вызов WP_Query сразу с аргументами, т.е.:

    $query = new WP_Query($args);

    то после этого массив постов забирайте в

    $query->posts

    но ни в коем случае (!!!), не делайте этого с помощью

    $query->get_posts()

    (как я всегда делал). Вообще не юзайте $query->get_posts().
    Результаты в массиве $query->posts и $query->get_posts() отличаются!!
    Посмотрев код wp-includes/class-wp-query.php увидел что при вызове WP_Query с аргументами, вызывается метод get_posts(), и когда мы вручную делаем последующий его вызов, результаты стают другими (не правильными).
    Если хотите, могу привести простой пример (пробовал на чистом WP разных версий).

    1
    • Kama6693

      Откуда такая техника, через $query->get_posts(). В начале этой статьи написано как надо юзать WP_Query... А вообще лучше почти всегда юзать get_posts()...

  • Дмитрий

    Подскажите как сортировать по произвольным полям, если это поля sub_field. Т.е. поля созданы с помощью ACF и объеденены в группу и соответственно это не просто get_field, а группа get_field с полями get_sub_field собственно вопрос как сортировать по этим полям?

    пробую так, но ...

    $group = get_field('name');
    $single = $group['single_name'];
    	$query = new WP_Query(
    		array(
    		'meta_query' => array(
    			array(
    			'key' => $single,
    			'value' => 'параметр'
    		)),
  • Константин cайт: yandex.ru

    Добрый день! Пытаюсь, чтобы в каталоге статей, каждая статья была обернута в тег "cтатья" и чтобы текст в "зе эксцерпт" был обернут в тег "параграф". Помогите пожалуйста

    <section class="articles-catalog">
    <?php    query_posts('cat=5');
     while (have_posts()) : the_post();?>
     <article>
    <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
    <div class="thumbnail"><?php echo get_the_post_thumbnail(); ?></div> 
    	<p><?php the_excerpt();  </p>
    	endwhile; 
    	wp_reset_query();?>
    	</article>   
    			</section>
    Ответить4 месяца назад #
    • newbie32 cайт: yumchief.com
      <section class="articles-catalog">
      <?php query_posts('cat=5');
      while (have_posts()) : the_post();?>
      <article><h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
      <div class="thumbnail"><?php echo get_the_post_thumbnail(); ?></div> 
      <p><?php the_excerpt(); ?></p>
      <?php endwhile; 
      wp_reset_query(); ?>
      </article>   
      </section>
      1
      Ответить4 месяца назад #
  • Андрей

    Потребовалось сделать на аяксе выборку записей по датам из произвольных полей (по сути афиша) с помощью ряда условий в meta_query. Записи получал через WP_Query. Так вот все работало кроме сортировки. Я уже и так и сяк - параметры в query передаются, а сам SQL запрос неизменен. 4 часа бился, пока не передал параметры запроса в get_posts и о чудо - заработало! Все дело оказалось в параметре 'suppress_filters' => true, который get_posts принудительно указывает и тем самым отключает внутренние фильтры WP. Это я к чему - может быть в описании WP_Query сделать сноску, что в случае неадекватного поведения работы WP_Query надо указать 'suppress_filters' => true. Ни в одном мануале про это не написано ((

    2
    Ответить4 месяца назад #
  • богдан

    Хочу в стандартный поиск включить результаты по meta_value в таблице postmeta. Написал след код, но он не работает. Как правильно?

    add_action('pre_get_posts', 'dt_search_filter');
    function dt_search_filter( $query ){
    	$meta_query = $query->get('meta_query');
    	$meta_query = array(
    		'key' => 'fw_options',
    		'value' => $query,
    		'compare' =>  'LIKE'
    	);
    
    	$query->set('meta_query', array('relation' => 'OR', $meta_query));
    }
    Ответитьмесяц назад #
    • campusboy2947 cайт: www.youtube.com/c/wpplus

      У вас ошибка, надо так:

      function search_filter( WP_Query $query ) {
      	if ( ! is_admin() && $query->is_main_query() && $query->is_search() ) {
      		$query->set( 'meta_query', array(
      			'relation' => 'OR',
      			array(
      				'key'     => 'fw_options',
      				'value'   => $query->query_vars['s'],
      				'compare' => 'LIKE'
      			)
      		) );
      	}
      }
      
      add_action( 'pre_get_posts', 'search_filter' );

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

      Взято со статьи Search WordPress by Custom Fields without a Plugin:

      <?php
      /**
       * Extend WordPress search to include custom fields
       *
       * https://adambalee.com
       */
      
      /**
       * Join posts and postmeta tables
       *
       * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_join
       */
      function cf_search_join( $join ) {
      	global $wpdb;
      
      	if ( is_search() ) {    
      		$join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
      	}
      
      	return $join;
      }
      add_filter('posts_join', 'cf_search_join' );
      
      /**
       * Modify the search query with posts_where
       *
       * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
       */
      function cf_search_where( $where ) {
      	global $pagenow, $wpdb;
      
      	if ( is_search() ) {
      		$where = preg_replace(
      			"/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
      			"(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
      	}
      
      	return $where;
      }
      add_filter( 'posts_where', 'cf_search_where' );
      
      /**
       * Prevent duplicates
       *
       * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
       */
      function cf_search_distinct( $where ) {
      	global $wpdb;
      
      	if ( is_search() ) {
      		return "DISTINCT";
      	}
      
      	return $where;
      }
      add_filter( 'posts_distinct', 'cf_search_distinct' );
      Ответитьмесяц назад #
Здравствуйте, !     Войти . Зарегистрироваться