Вопрос или проблема
Это скорее вопрос псевдокода, чем фактического кода. У меня есть пользовательские метаданные, прикрепленные к вложениям, и я создал колонку в списке таблицы для этих метаданных. Метаданные могут быть либо 1, либо null (не установлено), но я пытаюсь включить сортировку для этой колонки.
Есть ли способ использовать meta_query
для WP_Query, чтобы фактически выполнить LEFT JOIN, где я получаю все значения (1 или null), и затем могу использовать orderby=meta_value_num
для сортировки?
Очевидный способ — это подключиться к posts_clauses, добавить JOIN и также сделать orderby — просто интересно, возможно ли это сделать, используя функциональность WP_Query напрямую!
Спасибо.
Вы можете использовать pre_get_posts
с обратным вызовом:
<?php
defined( 'ABSPATH' ) OR exit;
/** Название плагина: (#102854) Сортировка записей по Foo */
add_filter( 'pre_get_posts', 'wpse_102854_orderby_foo' );
function wpse_102854_orderby_foo( $query )
{
if (
! $query->is_main_query()
OR ! is_admin()
OR 'edit.php?post_type=YOUR_POST_TYPE' !== $GLOBALS['parent_file']
// Другие условия для принудительной отмены, например:
// OR 'foo' !== $query->get( 'some_query_var' )
)
return $query;
$query->set( 'orderby', 'meta_value_num' );
// и т.д.
return $query;
}
Вы можете сделать это любым из способов!
Используя posts_clauses
, вручную напишите ваше JOIN выражение (используя $wpdb->prepare() – будьте осторожны!), и добавьте/настраивайте условие orderby
также.
Используя meta_query
, нужно учесть несколько моментов. Во-первых, как упоминает кaiser, вы должны использовать relation
внутри meta_query
, чтобы это работало. Во-вторых, даже если meta_query определен, вам все равно нужно указать аргумент meta_key
, иначе orderby=meta_value не будет работать. Я предполагаю, что это связано с тем, что может происходить несколько соединений сразу, которые могут использовать разные мета-ключи.
Вот как я это осуществил:
function handle_my_sortable_column( $query ) {
global $pagenow;
if( is_admin() && 'upload.php' == $pagenow && 'my_meta_key' == get_query_var( 'orderby' ) ) {
$query->set( 'meta_query', array(
'relation' => 'OR',
array(
'key' => 'my_meta_key',
'value' => null,
'compare' => 'EXISTS'
),
array(
'key' => 'my_meta_key',
'value' => '', // должно быть '' значение, null не работает
'compare' => 'NOT EXISTS'
)
) );
$query->set( 'meta_key', 'my_meta_key' ); // нужно для orderby
$query->set( 'orderby', 'meta_value_num' );
}
}
После WordPress 3.9 вы можете сортировать по мета-ключу, не теряя посты, у которых нет этих метаданных, с помощью:
// Не указывайте 'meta_key'
// иначе посты, у которых нет мета, будут пропущены
// $query->set('meta_key', 'the meta key');
$query->set('orderby', 'meta_value');
$query->set('meta_query', [
'relation' => 'OR',
['key' => 'the meta key', 'compare' => 'EXISTS',],
['key' => 'the meta key', 'compare' => 'NOT EXISTS'],
]);
Ответ или решение
Конечно! Давайте рассмотрим, как можно организовать сортировку по кастомной метаинформации в WordPress, используя WP_Query и оптимальные подходы.
Подход 1: Использование meta_query
В WordPress для сортировки по пользователям определённой метаинформации можно использовать параметр meta_query
вместе с orderby
. Это позволяет эффективно работать с метаданными, включая ситуации, когда метаданные могут отсутствовать.
Вот пример, как настроить сортировку по мета-ключу (предположим, что мета-ключ называется my_meta_key
):
add_filter('pre_get_posts', 'handle_my_sortable_column');
function handle_my_sortable_column($query) {
global $pagenow;
// Проверяем, что это административный запрос на странице загрузки
if (is_admin() && 'upload.php' === $pagenow && 'my_meta_key' === get_query_var('orderby')) {
$query->set('meta_query', array(
'relation' => 'OR',
array(
'key' => 'my_meta_key',
'compare' => 'EXISTS',
),
array(
'key' => 'my_meta_key',
'compare' => 'NOT EXISTS',
)
));
// Указание orderby
$query->set('orderby', 'meta_value_num');
// Обратите внимание, что meta_key здесь не устанавливается.
}
}
Подход 2: Использование posts_clauses
Иногда необходимо более тонкое управление запросами, и для этого можно использовать фильтр posts_clauses
. Это позволяет вручную добавлять JOIN’ы и изменять ORDER BY в запросе.
Пример кода:
add_filter('posts_clauses', 'custom_join_orderby', 10, 2);
function custom_join_orderby($clauses, $query) {
global $wpdb;
// Проверяем, что выполняется нужный запрос
if ($query->is_admin() && $query->get('post_type') === 'YOUR_POST_TYPE') {
// Добавляем JOIN
$clauses['join'] .= " LEFT JOIN {$wpdb->postmeta} AS pm ON ({$wpdb->posts}.ID = pm.post_id AND pm.meta_key = 'my_meta_key')";
// Указываем порядок сортировки
$clauses['orderby'] = "CAST(pm.meta_value AS UNSIGNED) ASC"; // сортировка по числовому значению
}
return $clauses;
}
Важные моменты:
-
Сравнение значений: При использовании
meta_query
убедитесь, что в запросе указываетсяrelation
и правильные условия для сравнения. Если мета данных нет, необходимо правильно обработать эти случаи. -
Эффективность: Избегать JOIN’ов, если можно использовать более простое решение с
meta_query
, которое может быть более производительным для больших баз данных. -
Поддержка разных сценариев: Убедитесь, что ваш код учитывает разные сценарии отображения и может обрабатывать разные типы метаданных.
Использование этих подходов позволит вам гибко работать с сортировкой в WordPress и эффективно управлять метаданными. Если у вас возникнут дополнительные вопросы или нужна помощь, не стесняйтесь обращаться!