Фильтрация по одному произвольному полю и сортировка по другому
У меня есть произвольный тип записи "Listing" и я хочу получить все записи, у которых произвольное поле gateway_value != 'Yes'
, и отсортировать результаты по другому произвольному полю location_level1_value
. Запросы работают по отдельности, но я не могу их объединить:
Запрос 1 (сортировка по местоположению):
$wp_query = new WP_Query( array (
'post_type' => 'listing',
'post_status' => 'publish',
'posts_per_page' => '9',
'meta_key' => 'location_level1_value',
'orderby' => 'location_level1_value',
'order' => 'ASC',
'paged' => $paged
)
);
Запрос 2 (значение произвольного поля != Yes):
$wp_query = new WP_Query( array (
'post_type' => 'listing',
'posts_per_page' => '9',
'post_status' => 'publish',
'meta_key' => 'gateway_value',
'meta_value' => 'Yes',
'meta_compare' => '!=',
'paged' => $paged
)
);
Объединенный запрос:
Я посмотрел документацию для помощи с этим, но следующий запрос не работает:
$wp_query = new WP_Query( array (
'post_type' => 'listing',
'posts_per_page' => '9',
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'gateway_value',
'value' => 'Yes',
'compare' => '!='
),
array(
'key' => 'location_level1_value'
)
),
'orderby' => "location_level1_value",
'order' => 'ASC',
'paged' => $paged
)
);
Что я делаю неправильно в объединенном запросе?
[ОБНОВЛЕНИЕ]: После выхода версии 3.1, объединенный запрос выше все еще не работает. Я получаю результаты, но они неправильно отсортированы.
[ОБНОВЛЕНИЕ]: var_dump($wp_query->request)
выдает следующее:
string(527) " SELECT SQL_CALC_FOUND_ROWS wp_7v1oev_posts.* FROM wp_7v1oev_posts
INNER JOIN wp_7v1oev_postmeta ON (wp_7v1oev_posts.ID = wp_7v1oev_postmeta.post_id)
INNER JOIN wp_7v1oev_postmeta AS mt1 ON (wp_7v1oev_posts.ID = mt1.post_id) WHERE 1=1 AND wp_7v1oev_posts.post_type = 'listing' AND (wp_7v1oev_posts.post_status = 'publish') AND wp_7v1oev_postmeta.meta_key = 'gateway_value' AND CAST(wp_7v1oev_postmeta.meta_value AS CHAR) != 'Yes' AND mt1.meta_key = 'location_level1_value' ORDER BY wp_7v1oev_posts.post_date DESC LIMIT 0, 9"

Вы можете использовать запрос для фильтрации контента, как задумано, с помощью 'meta_query' и параметров фильтрации. Для сортировки просто добавьте/измените следующие параметры:
- 'orderby' => 'meta_value'
- 'meta_key' => 'location_level1_value'
'order' => 'ASC'
$wp_query = new WP_Query( array ( 'post_type' => 'listing', 'posts_per_page' => '9', 'post_status' => 'publish', 'meta_query' => array( array( 'key' => 'gateway_value', 'value' => 'Yes', 'compare' => '!=' ) ), 'orderby' => 'meta_value', // это означает, что мы будем использовать выбранное // мета-поле для сортировки 'meta_key' => 'location_level1_value', // здесь указывается, какое мета-поле // будет использоваться для сортировки, // независимо от фильтров 'order' => 'ASC', 'paged' => $paged ) );

Как уже сказал Jan, в новой WordPress 3.1 можно использовать meta_query
, но пока эта версия не вышла, вы можете использовать ваш первый запрос для сортировки (orderby) и фильтрации внутри вашего цикла, вот так:
Global $my_query;
$my_query = new WP_Query( array (
'post_type' => 'listing',
'post_status' => 'publish',
'posts_per_page' => '9',
'meta_key' => 'location_level1_value',
'orderby' => 'location_level1_value',
'order' => 'ASC',
'paged' => $paged
)
);
while ($my_query->have_posts){
$my_query->the_post();
//делаем нужные операции в цикле
}
и добавить этот код в ваш файл functions.php
//фильтр join
add_filter('posts_join', 'listing_join_865' );
function listing_join_865($join){
Global$ my_query;
if ('listing' = $my_query->query['post_type']){
$restriction1 = 'gateway_value';
return $join .="
LEFT JOIN $wpdb->postmeta AS $restriction1 ON(
$wpdb->posts.ID = $restriction1.post_id
AND $restriction1.meta_key = '$restriction1'
)";
}else {
return $join;
}
}
//фильтр where
add_filter('posts_where', 'listing_where_865' );
function listing_where_865($where){
global $my_query;
if ('listing' = $my_query->query['post_type']){
return $where.= " AND $restriction1.meta_value != 'yes'";
}else{
return $where;
}
}
Теперь это должно работать.

Спасибо за это. Это работает, за исключением странного побочного эффекта - моя пагинация перестала работать правильно. Вместо 9 элементов на странице, в моей сетке появляются "пустые места", где должны были быть кастомные записи с gateway_value == "Yes"
, если бы не было условия... Есть идеи как это исправить?

да, это сломает пагинацию, так что единственный выход - кастомный sql запрос, дай мне пару минут.

Не беспокойся - я просто воспользуюсь вторым запросом и плагином http://wordpress.org/extend/plugins/post-types-order до выхода версии 3.1 :)

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

@בניית אתרים - Если вы сделаете отступы во всём своём коде, его будет проще вставлять в ответы. Например: Поместите код в ваш редактор, выделите всё, затем сделайте отступ один раз, теперь скопируйте и вставьте — и вам не нужно будет добавлять по 4 пробела перед каждой строкой кода (весь код красиво поместится в блок кода без лишних манипуляций).

Ты написал это с телефона... уважаю!.. Я бы даже не попытался писать код на телефоне.. :) +1 за скиллы на телефоне! ;)

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

Копирование и вставка из Notepad++ в Firefox работает нормально.

Apologies for answering my own question:
Looking at [http://core.trac.wordpress.org/ticket/15031][1], seems like this is a known issue. I have fixed (hacked?) it to work using post_filter
, like so (just for anyone's reference who might be searching for the same answer):
In functions.php###
add_filter('posts_orderby', 'EV_locationl1' );
function EV_locationl1 ($orderby) {
global $EV_locationl1_orderby;
if ($EV_locationl1_orderby) $orderby = $EV_locationl1_orderby;
return $orderby;
}
Amended wp_query in template file###
$EV_locationl1_orderby = " mt1.meta_value ASC";
$wp_query = new WP_Query( array (
'post_type' => 'listing',
'posts_per_page' => '9',
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'gateway_value',
'value' => 'Yes',
'compare' => '!='
),
array(
'key' => 'location_level1_value'
)
),
'order' => $EV_locationl1_orderby,
'paged' => $paged
));
