использование posts_where для метаданны на pre_get_posts

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

Предположим, у вас есть код, который фильтрует посты, используя pre_get_posts

например:

add_action( 'pre_get_posts', 'be_exclude_category_from_blog' );

function be_exclude_category_from_blog( $query ) {

    if( $query->is_main_query() && $query->is_home() ) {
        $query->set( 'cat', '-4' );
    }

}

Я нашел хороший кусок кода, который позволяет вам дополнительно фильтровать эти посты за последние 90 дней:

add_action( 'pre_get_posts', 'be_exclude_category_from_blog' );

function be_exclude_category_from_blog( $query ) {

    if( $query->is_main_query() && $query->is_home() ) {
        add_filter( 'posts_where', 'filter_date' );
        $query->set( 'cat', '-4' );
    }

}

function filter_date( $where="" ) {
    $where .= " AND post_date > '" . date('Y-m-d', strtotime('-90 days')) . "'";
    return $where;
}

Это работает очень хорошо. Но что, если я хочу использовать тот же метод для целевой метаданных поста, а не просто post_date? Это возможно? Из этого ответа похоже, что вам нужно сделать что-то вроде этого:

add_action( 'pre_get_posts', 'be_exclude_category_from_blog' );

function be_exclude_category_from_blog( $query ) {

    if( $query->is_main_query() && $query->is_home() ) {
        add_filter( 'posts_where', 'filter_date' );
        $query->set( 'cat', '-4' );
    }

}

function filter_date( $where="" ) {
    global $wpdb;  
    $where .= " AND ($wpdb->postmeta.meta_key = '_length' AND $wpdb->postmeta.meta_value='61')";
    return $where;
}

Однако это не работает для меня, возвращает ноль результатов. Хотя я знаю, что есть посты с мета-ключом _length со значением 61.

Может кто-то указать мне правильное направление?

Спасибо

Я сомневаюсь, что это когда-либо работало само по себе. WP_Query работает с таблицей базы данных постов. На нижнем уровне SQL, чтобы воспользоваться метаданными поста, вам нужно не только указать, какие метаданные вы ищете, но и указать MySQL, как таблица метаданных соединяется с вашей таблицей постов (JOIN область).

Я бы попытался начать с манипуляции с аргументами запроса, не кажется, что ваши условия столь сложны (по крайней мере, исходя из того, что вы привели).

PS также не забудьте удалить свои фильтры после, иначе вы нарушите другие запросы.

Ответ или решение

Вопрос о том, как использовать posts_where для фильтрации постов на основе метаданных в WordPress, действительно актуален, и в вашей ситуации есть несколько моментов, которые стоит учитывать для достижения нужного результата.

Проблема с текущим кодом

В вашем коде вы пытаетесь использовать posts_where для фильтрации постов на основе значения метаполя _length. Однако, как было упомянуто в ваших исходных материалах, WP_Query работает с таблицей постов, и чтобы правильно использовать метаданные, вам необходимо соединить таблицы posts и postmeta.

Использование JOIN для метаданных

Чтобы корректно фильтровать посты по метаданным, вам нужно сделать следующее:

  1. Использовать JOIN для соединения таблиц постов и метаданных.
  2. Убедиться, что фильтрация происходит на основании корректных условий.

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

add_action( 'pre_get_posts', 'be_exclude_category_from_blog' );

function be_exclude_category_from_blog( $query ) {
    if( $query->is_main_query() && $query->is_home() ) {
        add_filter( 'posts_where', 'filter_meta_length' );
        $query->set( 'cat', '-4' );
    }
}

function filter_meta_length( $where ) {
    global $wpdb;

    // Получаем ID одновременно в натяжке на соединение
    $where .= " AND EXISTS (SELECT * FROM $wpdb->postmeta WHERE $wpdb->postmeta.post_id = $wpdb->posts.ID AND $wpdb->postmeta.meta_key = '_length' AND $wpdb->postmeta.meta_value = '61')";

    return $where;
}

// Не забывайте снимать фильтр, чтобы не влиять на другие запросы
add_action( 'wp', function() {
    remove_filter( 'posts_where', 'filter_meta_length' );
});

Объяснение кода

  1. Фильтрация по метаданным: В функции filter_meta_length используется подзапрос EXISTS, который проверяет наличие метаполей у постов. Это сделано для того, чтобы избежать сложностей с JOIN, которые могут усложнить ваш запрос.

  2. Условия AND: Мы добавляем условия в WHERE, чтобы выбрать посты только в том случае, если существует соответствующее значение метаполя.

  3. Удаление фильтра: Мы убираем фильтр с помощью remove_filter, чтобы это изменение не влияло на остальные запросы в коде. Это повышает чистоту и безопасность вашего кода.

Заключение

Используя указанный метод, вы сможете фильтровать посты на основании метаданных в вашей базе данных WordPress. Обратите внимание, что работа с индексами и подзапросами может значительно повлиять на производительность вашего сайта в зависимости от его объема данных.

Если у вас возникнут дополнительные вопросы или потребуется более сложная фильтрация, обязательно рассмотрите возможность использования плагинов для метаданных, которые улучшают работу с кастомными полями и метаданными.

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

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