WP_Query - Сортировка результатов по значению мета-поля
Я проверил различные варианты, но пока не нашел работающего решения. У меня есть WP_Query со следующими аргументами:
$args = array(
'post_status' => 'publish',
'post_type' => 'listing',
'meta_key' => 'client_feedback_score',
'orderby' => 'client_feedback_score',
'order' => 'DESC'
);
$query = new WP_Query($args);
Я хочу отсортировать результаты по произвольному полю записи client_feedback_score
, от меньшего к большему. Но это не работает... может кто-нибудь подсказать правильное решение?
РЕДАКТИРОВАНИЕ (РЕШЕНО):
Благодаря ответу Milo, вот рабочий код для сортировки по числовому значению мета-поля:
$args = array(
'post_status' => 'publish',
'post_type' => 'listing',
'meta_key' => 'client_feedback_score',
'orderby' => 'meta_value_num',
'order' => 'DESC'
);

Параметр orderby
должен быть meta_value_num
или meta_value
, а не именем ключа. Смотрите Параметры orderby в WP_Query.

Спасибо! Вы мой спаситель времени! Нигде в WPCodex не упоминается про 'meta_value_num'.

Маленькое замечание: если meta_key
ещё не существует для записи, то запись будет проигнорирована.

Является ли meta_value_num
произвольным метаполем (custom post meta), которое можно назначить типам записей? Мне нужно иметь возможность редактировать это значение для каждой записи.

@RobBenz Смотрите Произвольные поля, чтобы узнать о метаполях записей.

Спасибо, я знаком с произвольными метаполями. Я хочу добавить метабокс к товарам WooCommerce с названием search_order
или что-то подобное, чтобы при отображении результатов поиска у меня была возможность контролировать порядок их вывода. Должен ли я назвать добавляемое произвольное метаполе meta_value_num

или meta_value_num
просто берет значение того, что указано в 'meta_key' => 'search_order' для поста

@RobBenz meta_value_num
указывает WordPress сортировать результаты по числовому значению метаполя. Это не название ключа.

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

@RobBenz Возможно, вам стоит создать новый вопрос по этой теме. Шаг 1: Назначьте любое значение вашему мета-ключу, назовём его my_meta_key
, для каждой записи, чтобы сгенерировать нужный вам порядок. Шаг 2: Установите meta_key
в вашем запросе как my_meta_key
. Это указывает WordPress запрашивать записи, имеющие этот ключ. Шаг 3: Установите orderby
в вашем запросе как meta_value_num
. Это указывает WordPress не только запрашивать записи с my_meta_key
, но и сортировать их численно по этому ключу. Этот аргумент запроса — единственное место, где вы увидите или используете meta_value_num
.

@adamj Есть ли какой-то обходной путь? Мне нужно отсортировать все записи, независимо от того, существует ли meta_key для записи или нет.

Если ваше мета-значение не является числовым, например, если это значение даты, то вы можете добавить параметр meta_type => DATE
.
Возможные значения: 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'
.
Запрос с указанием типа мета-поля будет выглядеть так:
$args = array(
'post_status' => 'publish',
'post_type' => 'listing',
'meta_key' => 'client_feedback_score',
'orderby' => 'meta_value_num',
'meta_type' => 'DATE',
'order' => 'DESC'
);

Чтобы ответить на замечание @adamj в принятом ответе
если meta_key ещё не существует для записи, эта запись будет проигнорирована.
Вот решение, которое будет включать даже записи, у которых отсутствует значение client_feedback_score
. Вы можете создать простой запрос для всех записей типа "listing". Затем вручную left join соединить его с таблицей postmeta
, где meta_value
равен client_feedback_score
. После этого отсортировать с помощью условия orderby
.
$args = array(
'post_status' => 'publish',
'post_type' => 'listing',
);
add_filter('post_clauses','post_meta_sort',10,1);
function post_meta_sort( $sql_clauses ) {
global $wpdb;
remove_filter( 'posts_clauses', 'post_meta_sort' ); // Остановить выполнение этой функции для других запросов.
$sql_clauses['join'] .= "LEFT JOIN $wpdb->postmeta AS sort_score_postmeta ON $wpdb->posts.ID = sort_score_postmeta.post_id
AND sort_score_postmeta.meta_key = 'client_feedback_score'";
$sql_clauses['orderby'] = 'sort_score_postmeta.meta_value+0 DESC';
return $sql_clauses;
}
$query = new WP_Query($args);
