Лучшие практики – Meta Query против post_clauses для упорядочивания “left join”

Вопрос или проблема

Это скорее вопрос псевдокода, чем фактического кода. У меня есть пользовательские метаданные, прикрепленные к вложениям, и я создал колонку в списке таблицы для этих метаданных. Метаданные могут быть либо 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;
}

Важные моменты:

  1. Сравнение значений: При использовании meta_query убедитесь, что в запросе указывается relation и правильные условия для сравнения. Если мета данных нет, необходимо правильно обработать эти случаи.

  2. Эффективность: Избегать JOIN’ов, если можно использовать более простое решение с meta_query, которое может быть более производительным для больших баз данных.

  3. Поддержка разных сценариев: Убедитесь, что ваш код учитывает разные сценарии отображения и может обрабатывать разные типы метаданных.

Использование этих подходов позволит вам гибко работать с сортировкой в WordPress и эффективно управлять метаданными. Если у вас возникнут дополнительные вопросы или нужна помощь, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...