Можно ли объединить 2 запроса WP_Query($variable)?
Я использую мультисайт WordPress и настроил SQL-запрос, который использует switch_to_blog(); для запроса постов.
Есть ли способ объявить запрос внутри нового WP_Query и объединить его с другим запросом?
По сути, если я делаю это:
$number1 = new WP_Query($multisitequery);
Могу ли я объединить его с:
$number2 = new WP_Query($normalquery);
$normalquery
содержит настройки пагинации, количества записей на странице, отрывков, заголовков и т.д. для шорткода портфолио.
Я хотел бы включить запрошенные посты из моего нового запроса $multisite
.
Возможно ли это? Просто хочу избежать создания полностью новой настройки шорткода.
Заранее спасибо. Рори
РЕДАКТИРОВАНИЕ========
То, что у меня есть:
$portfolio = array();
$portfolio = $settings;
Далее в моей функции портфолио "после всех $settings['options']" у меня есть:
$portfolio_query = new WP_Query( $portfolio );
$portfolio_query
использует цикл на шаблоне страницы.
Я хочу добавить дополнительный запрос следующим образом:
global $wpdb, $blog_id, $post;
// Получаем все блоги
$blogs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM wp_blogs ORDER BY blog_id" ) );
$globalcontainer = array();
foreach ($blogs as $blog){
// Переключаемся на блог
switch_to_blog($blog->blog_id);
$globalquery = query_posts($args);
// Объединяем результаты
$globalcontainer = array_merge( $globalcontainer, $globalquery );
// Восстанавливаем текущий блог
restore_current_blog();
}
где я предполагаю, что $globalcontainer
будет массивом для объединения с wp_query();
.
Итак, принимая во внимание то, что вы ответили, теоретически я мог бы просто:
$mergedqueryargs = array_merge($portfolio , $globalcontainer);
$portfolio_query = new WP_query($mergedqueryargs);
Это будет правильно?
Во-вторых, относительно перезаписи ключей массива при array_merge..... Как мне предотвратить перезапись?

Просто объединения аргументов будет недостаточно, вам нужно объединить результирующий массив записей и счетчик post_count. Вот решение, которое работает у меня:
//настраиваем запросы, как вы уже делаете
$query1 = new WP_Query($args_for_query1);
$query2 = new WP_Query($args_for_query2);
//создаем новый пустой запрос и заполняем его двумя другими
$wp_query = new WP_Query();
$wp_query->posts = array_merge( $query1->posts, $query2->posts );
//устанавливаем правильное количество записей для корректной работы цикла
$wp_query->post_count = $query1->post_count + $query2->post_count;

Это выглядит хорошо, но мне нужно решение, которое можно использовать с хуком pre_get_posts - то есть мне нужно модифицировать существующий объект WP_Query. Я пробовал использовать '$wp_query->init();' вместо '$wp_query = new WP_Query();', но это, кажется, всё портит. Есть предложения?

Вам стоит задать отдельный вопрос, так как это другой ответ, но вы можете использовать этот же код, только части query2, модифицируя свойства ->posts и ->post_count объекта $wp_query, чтобы они содержали сумму оригинального запроса, который даёт вам pre_get_posts, и второго запроса, который вы хотите добавить.

Спасибо за это. Были проблемы с meta_query, использующей отношение OR. Разделил запрос с помощью этой техники, и время выполнения сократилось с 41с до 0.01с.

@ban-geoengineering Ты смог разобраться с этим? У меня такая же проблема.

@harvey Извини, не могу найти код, связанный с этим. (Это было несколько лет назад.) Лучше всего создать новый вопрос. Удачи. :-)

Если вы создаете новый массив и удаляете дубликаты с помощью чего-то вроде array_unique()
, вы можете заполнить $wp_query->post_count
с помощью count($wp_query->posts)

Обычно я объединяю их массивы ID и выполняю третий запрос. Чтобы первые запросы были дешевыми, я возвращаю только их ID, используя параметр fields, вот так:
//настраиваем запросы с дополнительным параметром fields => ids
$query1 = new WP_Query(array('fields' => 'ids','other_parameters' => 'etc'));
$query2 = new WP_Query(array('fields' => 'ids','other_parameters'=>'etc'));
//теперь у нас есть ID записей в $query->posts
$allTheIDs = array_merge($query1->posts,$query2->posts);
//новый запрос, используя параметр post__in
$finalQuery = new WP_Query(array('post__in' => $allTheIDs));
Надеюсь, это поможет
---ОБНОВЛЕНИЕ---
После моего ответа исходный вопрос был отредактирован с учетом деталей мультисайта. В случае слияния записей в мультисайте этот метод не работает.

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

Как это может корректно работать, если post_ID не уникальны в рамках мультисайта (они уникальны в пределах блога, но несколько записей могут иметь одинаковые ID в сети)?

@Adal Исходный вопрос был отредактирован после моего ответа, поэтому мой ответ актуален для одиночного сайта. С мультисайтом я никогда не пробовал объединять запросы, и в этом случае, конечно, это не сработает — запросы нужно выполнять отдельно и затем объединять. После объединения можно попробовать отсортировать их с помощью PHP-функций сортировки (например, по дате публикации).

Вы можете сохранить сортировку, используя 'orderby' => 'post__in'
в последнем запросе.

Для пользовательских типов записей, думаю, параметр post_type нужен в любом случае, даже при запросе по id, потому что по умолчанию post_type=post @RobbTe

Убедитесь, что проверяете, не является ли массив объединенных ID пустым. Потому что запрос post__in возвращает результаты, если массив пуст. Это баг, который WP отказывается исправлять: https://core.trac.wordpress.org/ticket/28099

Итак, если у вас есть такой код:
$number1 = new WP_Query($multisitequery);
$number2 = new WP_Query($normalquery);
Я предполагаю, что вы где-то ранее определяете эти переменные?
$multisitequery = array();
$normalquery = array();
...в таком случае, чтобы объединить два запроса, просто используйте array_merge()
для слияния двух массивов перед передачей их в new WP_Query()
:
$merged_query_args = array_merge( $normalquery, $multisitequery );
$merged_query = new WP_Query( $merged_query_args );
Обратите внимание, что порядок аргументов в вызове array_merge()
имеет значение. Если оба массива содержат одинаковые ключи, значения из второго массива перезапишут значения из первого.

Таким образом, можно объединить два запроса WP_Query с разными post_type или другими параметрами сортировки, например, а затем склеить их по ids в один рабочий запрос WP_Query — чтобы сохранить сортировку при склейке, необходимо указать orderby => post__in
Мой пример показывает, как создается новый цикл WP_Query, который может влиять на любой другой цикл вывода записей путем вызова new global_change_of_sorting_posts->change_query_posts() => query_posts(). Этот вызов нужно выполнить до обработки цикла вывода записей!
class global_change_of_sorting_posts
{
public function get_posts_ids()
{
$query1 = new WP_Query([
'fields' => 'ids',
'posts_per_page' => -1,
'post_type' => 'post', // Стандартный тип записи
]);
$query2 = new WP_Query([
'posts_per_page' => -1,
'fields' => 'ids',
'post_type' => 'custom-post', // Пользовательский тип записи
]);
$merge_ids_posts = $query1->posts + $query2->posts; // Объединение ID записей
wp_reset_query();
return $merge_ids_posts;
}
public function get_posts_wp_query()
{
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1; // Получение текущей страницы пагинации
$posts_per_page = 40;
$wp_query = new WP_Query([
'posts_per_page' => $posts_per_page,
'paged' => $paged,
'post__in' => $this->get_posts_ids(), // Используем объединенные ID
'orderby' => 'post__in', // Сохраняем порядок сортировки
]);
while ($wp_query->have_posts()) {
$wp_query->the_post();
var_dump(get_the_ID()); // Выводим ID текущей записи
}
}
public function change_query_posts($query_string)
{
parse_str($query_string, $args); // Разбираем строку запроса
$args['post__in'] = $this->get_posts_ids(); // Добавляем объединенные ID
$args['orderby'] = 'post__in'; // Устанавливаем сортировку
query_posts($args); // Модифицируем основной запрос
}
}
