Запрос для сортировки списка сначала по мета-ключу (если он существует) и отображения оставшихся записей без мета-ключа, упорядоченных по названию
Я работаю над пользовательским шаблоном страницы терминов таксономии, где мы хотим, чтобы элементы, связанные с термином, были отсортированы по дате публикации (настраиваемое поле даты) - и если в один и тот же день есть несколько элементов (в формате ГГГГ-ММ-ДД), затем отсортируйте их по названию и, наконец, отсортируйте по названию, если пользовательское поле не было заполнено (более старые элементы).
Итак, я попробовал сотню разных способов с помощью WP_Query, и он возвращает большинство результатов так, как я хочу - но в этом случае он возвращает только те элементы, у которых есть мета_ключ publication_date. Все остальные элементы игнорируются и не отображаются. Я попробовал мета_запрос, используя отношение "или", и сравнил publication_date как СУЩЕСТВУЮЩИЙ, так и НЕ СУЩЕСТВУЮЩИЙ, но это вернуло мне 0 результатов.
Кроме того, сайт все еще работает под управлением версии 3.5.2, и они не хотят обновляться.
Вот мой последний запрос, который возвращает мне сообщения, в которых пользовательское поле publication_date отображается в правильный порядок:
$term = get_queried_object(); // find the term of the taxonomy page we are on
$wp_query = new WP_Query( array(
'post_type' => 'resource',
'tax_query' => array(
array(
'taxonomy' => 'resource_types',
'field' => 'slug',
'terms' => $term->name,
)),
'meta_key' => 'publication_date',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'paged' => $paged,
'posts_per_page' => '10',
));
Я также пытался использовать wpdb и запускать SQL-запрос, но я действительно не уверен, как выполнить то, что я хочу. Если бы кто-нибудь мог мне помочь, это было бы потрясающе!
Заранее благодарю.
5 answers
Спасибо всем за вашу помощь!
В конце концов, приведенный ниже запрос дал мне желаемые результаты, которые заключались в том, чтобы сначала отобразить и отсортировать сообщения по настраиваемому полю "publication_date", отсортировав их по дате, и если бы было несколько одинаковых дат (скажем, 4 июня 2013 года), он бы отсортировал их по названию. Затем, после того как он просмотрит все записи, в которых указана дата публикации, он снова просмотрит оставшиеся записи в алфавитном порядке по названию.
Это приводит к я получаю результаты, заданные в том же запросе, и сохраняю свою разбивку на страницы:
$term = get_queried_object();
the_post();
$wp_query = new WP_Query( array(
'post_type' => 'resource',
'tax_query' => array(
array(
'taxonomy' => 'resource_types',
'field' => 'slug',
'terms' => $term->name,
)),
'meta_query' => array(
'relation' => 'OR',
array( //check to see if date has been filled out
'key' => 'publication_date',
'compare' => '=',
'value' => date('Y-m-d')
),
array( //if no date has been added show these posts too
'key' => 'publication_date',
'value' => date('Y-m-d'),
'compare' => 'NOT EXISTS'
)
),
'meta_key' => 'publication_date',
'orderby' => 'meta_value title',
'order' => 'ASC',
'paged' => $paged,
'posts_per_page' => '10',
));
Несколько лет спустя код, опубликованный CSSGirl, не работал для меня, потому что были некоторые сообщения, в которых не было мета-ключа, или мета-ключ был пуст, поэтому вот что мне пришлось сделать, чтобы все сообщения были упорядочены по дате и сначала отображались те, у которых значение мета-ключа:
$args = array(
'post_type' => $type,
'post_status' => 'publish',
'nopaging' => TRUE,
'meta_query' => array(
'relation' => 'OR',
array(
'key' => $meta_key,
'compare' => 'NOT EXISTS',
),
array(
'relation' => 'OR',
array(
'key' => $meta_key,
'value' => 'on',
),
array(
'key' => $meta_key,
'value' => 'on',
'compare' => '!=',
),
),
),
'orderby' => array( 'meta_value' => 'DESC', 'date' => 'DESC' ),
);
Я думаю, вам нужно будет сделать 2 отдельных цикла. Вы можете захватить все записи, найденные в первом цикле, и достаточно легко исключить их из вторичного цикла:
$found_posts = array();
while($loop->have_posts()): $loop->the_post();
// loop stuff
$found_posts[] = get_the_id();
endwhile;
wp_reset_query();
$args = array(
// other args
'post__not_in' => $found_posts,
);
Затем запустите второй цикл.
Есть ли какая-либо причина, по которой вы не могли бы заставить мета-ключ publication_date существовать для каждого сообщения только с пустым значением?
Таким образом, в своем действии save_post
вы бы добавили/обновили мета-ключ независимо от того, является ли значение $_POST
пустым или нет.
Вам придется запустить скрипт обновления, чтобы просмотреть ваши старые записи и добавить ключ с пустым значением, например:
add_action( 'admin_init', 'update_old_posts' );
function update_old_posts() {
if ( ! isset( $_GET[ 'update_old_posts' ] ) )
return;
foreach( get_posts() as $post ) {
if ( false === get_post_meta( $post->ID, 'publication_date', true ) ) {
update_post_meta( $post->ID, 'publication_date', '' );
echo "Updated {$post->post_title} <br />";
}
}
die;
}
Запустите его, перейдя к http://example.com/wp-admin/?update_old_posts
Тогда вы можете использовать то же самое запрос, как у вас есть. Возможно, вы захотите добавить дополнительный фильтр, чтобы вы могли упорядочивать по разным столбцам в разных направлениях, мне было бы разумно сортировать по дате в порядке убывания и заголовку в порядке возрастания.
add_filter( 'posts_orderby', 'multicolumn_orderby', 10, 2 );
function multicolumn_orderby( $orderby, $query ) {
global $wpdb;
// check it's the right query
if ( $query->get( 'meta_key' ) == 'publication_date' ) {
$orderby = "$wpdb->postmeta.meta_value+0 DESC, $wpdb->posts.post_title ASC";
}
return $orderby;
}
Я создал пользовательское предложение where. Я протестировал его с помощью $wp_query->request
прямо перед моим основным циклом, я не очень хорошо знаю SQL, но, похоже, это помогло.
add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
if(!$query->is_main_query())
return;
//Overwrite query arguments
$query->set('meta_query', array(
array(
'key' => 'TRENDING',
//'value' => 'asdfasdf',//may need a value for older versions of WordPress
'compare' => 'NOT EXISTS',
)
));
$query->set('orderby', 'meta_value_num date');
$query->set('order', 'DESC');
}
add_filter('posts_where', 'add_trending_where');
function add_trending_where($where = ''){
global $wpdb, $wp_query;
if(!$wp_query->is_main_query())//Not sure if this really works. Should be OK
return $where;
$where .= " OR ( $wpdb->postmeta.meta_key = 'TRENDING' )";
// Don't run this twice
remove_filter('posts_where', 'add_trending_where');
return $where;
}
В качестве альтернативы вы можете установить compare
в 'EXISTS'
и изменить строку в add_trending_where на $where .= " OR ($wpdb->postmeta.post_id IS NULL)";
. Тогда вам нужно будет изменить значение ключа только в одном месте. Опять же, повторите $wp_query->request
и поиграйте, если хотите лучше понять это или настроить.
РЕДАКТИРОВАТЬ: Я только что заметил, что это не работает, если meta_key
устанавливается в запросе. Вы могли бы использовать $query->set('meta_key', NULL);
, если вам нужно.
ПРАВКА 2: Я получил это, работая с описанным выше методом. По какой-то причине сначала этого не было (возможно, был установлен meta_key... Я не знаю).
add_action('pre_get_posts', 'add_trending_sort', 11, 1);
function add_trending_sort($query){
// Bail if not the main "hidden" query, as opposed to a 'new WP_Query()' call
if(!$query->is_main_query())
return;
// Set meta_query to get shares for orderby, and also get non-shared content.
$query->set('meta_query', array(
'relation' => 'OR',
array(
'key' => 'TRENDING',
'compare' => 'NOT EXISTS',
),
array(
'key' => 'TRENDING',
'compare' => 'EXISTS',
)
));
//$query->set('meta_key', NULL);
$query->set('orderby', array('meta_value_num' => 'DESC', 'date' => 'DESC'));
}