Упорядочение по нескольким пользовательским мета-полям
У меня есть пользовательский тип записи в моем плагине с именем members
, а также два пользовательских поля; first_name
и last_name
. Я пытаюсь упорядочить свой список по фамилии, затем по имени. Единственное решение, которое я нашел, - это то, которое использует функцию для извлечения первых двух мета-полей запроса и заменяет их (я следовал учебнику по dotnordic.se). Однако всякий раз, когда я пытаюсь это сделать, мне не возвращаются сообщения. Я опубликовал свой код ниже. Любая помощь в устранении проблемы, которая у меня есть с моим код или предложение другого способа очень ценятся.
// Shortcode Function
function mba_members_list_code() {
// WP_Query arguments
$args = array (
'post_type' => 'member_data',
'post_status' => 'active',
'fields' => 'ids',
'posts_per_page' => -1,
'meta_key' => 'last_name',
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'first_name',
),
array(
'key' => 'last_name',
),
array(
'key' => 'publicly_listed',
'value' => 'true',
),
),
);
// The Query
$posts = get_posts( $args );
// The Loop
if( $posts ) {
echo "Total Members Found: " . count($posts) . "<br>";
foreach ( $posts as $post ) {
$q = get_post_meta($post);
echo "<b>" . $q['first_name'][0] . " " . $q['last_name'][0] . "</b><br>";
echo $q['city'][0] . ", " . $q['state'][0] . " " . $q['zip'][0] . "<br>";
echo "<a href='mailto:" . $q['email'][0] . "'>" . $q['email'][0] . "</a><br>";
echo "<br>";
}
unset( $post );
}else{
echo "<b>Sorry, we found no active members. Please be sure to check back soon.</b>";
}
}
РЕДАКТИРОВАТЬ
function customorder($orderby) {
global $wpdb;
return ' {$wpdb->postmeta}.meta_value, mt1.meta_value';
//return str_replace('menu_order', 'mt1.meta_value, mt2.meta_value', $orderby);
}
Я знаю, что есть и другие вопросы по этому поводу с ответом на реализацию этой же функции; однако всякий раз, когда я ее реализую, у меня нет записей/сообщений.
2 answers
РЕДАКТИРОВАТЬ ( Пожалуйста, ознакомьтесь с оригинальным ответом для полного объяснения кода)
Код в моем первоначальном ответе работает должным образом, но вызывает известную ошибку с usort
(Проверьте отчет об ошибке здесь #50688)
Ошибка предупреждения: [2] usort(): Массив был изменен функцией сравнения пользователей
Эта ошибка срабатывает только тогда, когда параметр fields
задан в аргументах в get_posts
, поэтому единственным приемлемым обходным путем я можно было найти, чтобы удалить параметр fields
и перейти к извлечению полных записей.
Вот рабочая версия без ошибок
<?php
$args = array (
'post_type' => 'member_data',
'post_status' => 'active',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'first_name',
),
array(
'key' => 'last_name',
),
array(
'key' => 'publicly_listed',
'value' => 'true',
),
),
);
$posts = get_posts( $args );
usort( $posts, function( $a, $b ){
// sort first by last name
$compare = strnatcmp(get_post_meta($a->ID, 'last_name', true), get_post_meta($b->ID, 'last_name', true));
// if last names are identical, sort by first name
if(!$compare) {
return strnatcmp(get_post_meta($a->ID, 'first_name', true), get_post_meta($b->ID, 'first_name', true));
}else{
return $compare;
}
});
if( $posts ) {
echo "Total Members Found: " . count($posts) . "<br>";
foreach ( $posts as $post ) {
$q = get_post_meta($post->ID);
echo "<b>" . $q['first_name'][0] . " " . $q['last_name'][0] . "</b><br>";
echo $q['city'][0] . ", " . $q['state'][0] . " " . $q['zip'][0] . "<br>";
echo "<a href='mailto:" . $q['email'][0] . "'>" . $q['email'][0] . "</a><br>";
echo "<br>";
}
unset( $post );
}else{
echo "<b>Sorry, we found no active members. Please be sure to check back soon.</b>";
}
}
ОРИГИНАЛЬНЫЙ ОТВЕТ
К сожалению, нет способа выполнить этот тип сортировки изначально, поэтому здесь вам нужно будет применить другой подход.
Используйте
WP_Query
или даже лучшеget_posts
извлекайте свои сообщения в обычном режиме. На этом этапе нет необходимости применять какую-либо сортировку. По моему личному мнению, это бесполезно поскольку вы можете сортировать только по одномуmeta_value
, а не по двум. Я бы предпочел просто использовать сортировку php для упорядочивания сообщений по мере необходимости. (Если вы собираетесь использовать разбивку на страницы, лучше используйтеWP_Query
).Вы собираетесь использовать
usort
для сортировки своих сообщений, сначала поlast_name
, затем, если два или более человека используют один и тот жеlast_name
, мы будем сортировать в соответствии сfirst_name
.
Вот концепция:
Прежде чем я начну, я хочу указать на несколько вещей
Ваш
meta_query
- это к сожалению, беспорядок. Все находится внутри массива внутри массива внутри массива, где, как и должно быть, 3 отдельных массива внутри одного массиваЯ бы предпочел использовать
get_posts
здесь, а также извлекать только идентификаторы сообщений, поскольку вы не собираетесь использовать какие-либо данные postdata или любые другие данные, возвращаемыеWP_Query
Это довольно сложная операция, так как бд посещается два раза для каждого поста. Вам придется постараться использовать здесь переходные процессы.
Теперь о решении
Как сказано, используйте get_posts
для построения вашего запроса. Мы собираемся получить сообщения, которые соответствуют всем трем meta_key
$args = array (
'post_type' => 'member_data',
'fields' => 'ids',
'post_status' => 'active',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'first_name',
),
array(
'key' => 'last_name',
),
array(
'key' => 'publicly_listed',
'value' => 'true',
),
),
);
$posts = get_posts( $args );
Теперь мы будем сортировать $posts
по last_name
, а затем first_name
с помощью usort
usort( $posts, function( $a, $b ){
// sort first by last name
$compare = strnatcmp(get_post_meta($a, 'last_name', true), get_post_meta($b, 'last_name', true));
// if last names are identical, sort by first name
if(!$compare) {
return strnatcmp(get_post_meta($a, 'first_name', true), get_post_meta($b, 'first_name', true));
}else{
return $compare;
}
});
$posts
теперь должны быть отсортированы в алфавитном порядке по last_name
, и если last_name
одинаковы для двух или более лиц, они будут отсортированы в алфавитном порядке по first_name
.
Теперь ваш цикл будет следовать и выглядит так
if( $posts ) {
echo "Total Members Found: " . count($posts) . "<br>";
foreach ( $posts as $post ) {
$q = get_post_meta($post);
echo "<b>" . $q['first_name'][0] . " " . $q['last_name'][0] . "</b><br>";
echo $q['city'][0] . ", " . $q['state'][0] . " " . $q['zip'][0] . "<br>";
echo "<a href='mailto:" . $q['email'][0] . "'>" . $q['email'][0] . "</a><br>";
echo "<br>";
}
unset( $post );
}else{
echo "<b>Sorry, we found no active members. Please be sure to check back soon.</b>";
}
}
Попробуйте что-то подобное из другого поста:
query_posts(
array(
'post_type' => 'custompost',
'posts_per_page' => 4,
'meta_key' => 'mydate',
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'mydate',
'meta-value' => $value,
'value' => $today,
'compare' => '>=',
'type' => 'CHAR'
)
)
)
);
Хотя вам нужно только отсортировать по фамилии, так как имя будет найдено в цикле в порядке, в котором вы его называете.