Можно ли исключить записи по meta key используя функцию pre_get_posts?

10 нояб. 2012 г., 01:55:57
Просмотры: 36.3K
Голосов: 33

Я вижу, что многие предпочитают использовать хук pre_get_posts вместо query_posts. Приведенный ниже код работает и показывает все записи, у которых есть мета-ключ "featured"

function show_featured_posts ( $query ) {
    if ( $query->is_main_query() ) {
       $query->set( 'meta_key', 'featured' );
       $query->set( 'meta_value', 'yes' );
    }
}

add_action( 'pre_get_posts', 'show_featured_posts' );

Но я хочу, чтобы записи, имеющие мета-ключ 'featured', были исключены из основного запроса. Есть ли простой способ сделать это?

0
Все ответы на вопрос 3
4
46

Я заметил, что многие предпочитают использовать хук pre_get_posts вместо query_posts

Ура!

Хук pre_get_posts фильтрует объект WP_Query, что означает — всё, что вы можете сделать через query_posts(), можно сделать через $query->set() и $query->get(). В частности, мы можем использовать параметр meta_query (см. Кодекс):

$meta_query = array(
                 array(
                    'key'=>'featured',
                    'value'=>'yes',
                    'compare'=>'!=',
                 ),
);
$query->set('meta_query',$meta_query);

Но... это заменяет оригинальный 'meta query' (если он был). Поэтому, если вы не хотите полностью заменять оригинальный meta query, я предлагаю:

// Получаем оригинальный meta query
$meta_query = $query->get('meta_query');

// Добавляем наш meta query к существующим meta queries
$meta_query[] = array(
                    'key'=>'featured',
                    'value'=>'yes',
                    'compare'=>'!=',
                );
$query->set('meta_query',$meta_query);

Таким образом мы добавляем наш meta query вместе с существующими meta queries.

Вы можете (или нет) установить свойство relation для $meta_query в значение AND или OR (чтобы возвращать записи, удовлетворяющие всем или хотя бы одному из meta queries).

* Примечание: Такой запрос вернёт записи с мета-ключом 'featured', но со значением, отличным от yes. Он не будет включать записи, где мета-ключ 'featured' отсутствует. Это станет возможным в версии 3.5.

10 нояб. 2012 г. 12:32:19
Комментарии

Так что нет способа проверить, существует ли meta_key для записи или нет / пуста она или нет? Придется ждать 3.5. Спасибо за ответ.

Carlisle Carlisle
10 нояб. 2012 г. 14:57:03

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

Carlisle Carlisle
10 нояб. 2012 г. 15:38:45

Кстати, я не уверен, что создавать дополнительный meta_key со значением Да или Нет для всех записей — это хорошая идея. Было бы лучше исключать те записи, у которых просто отсутствует ключ featured.

Carlisle Carlisle
10 нояб. 2012 г. 15:44:55

Эта функция перестала работать на моем сайте после обновления до PHP 7, выдавая ошибку Uncaught Error: [] operator not supported for strings, так как исходный meta_query возвращал значение null. Это можно обойти, используя пустой массив по умолчанию, если значение не существует, заменив $meta_query = $query->get('meta_query'); на $meta_query = ( is_array( $query->get('meta_query') ) ) ? $query->get('meta_query') : [];.

Kevin Nugent Kevin Nugent
22 февр. 2018 г. 13:59:06
0

Я хочу поделиться своим временным решением для избранных записей на случай, если кому-то оно пригодится. Я не использую здесь хук pre_get_posts, но и не применяю query_posts. Проблема в том, что мне нужно работать с основным запросом и выполнять фрагмент SQL-запроса. Буду рад, если эксперты проверят код и скажут, всё ли в порядке и не вызовет ли это проблем с производительностью. Также будет здорово, если у кого-то есть более удачный подход и он поделится им с нами.

Создание запроса для избранных записей:

<?php 

$featured_query = new WP_query( array(
    'meta_key'       =>'featured', 
    'meta_value'     =>'yes', 
    'posts_per_page' => 5, 
    'no_found_rows'  => true
    )
);

while ($featured_query->have_posts()) : 

    $featured_query->the_post(); 
    // Действия с записью...

endwhile; 
wp_reset_postdata(); 

?>

Создание основного запроса, исключающего записи с мета-ключом featured, ограничение исключения 5 самыми последними записями и отображение всех остальных:

<?php 

$excludeposts = $wpdb->get_col( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'featured' AND meta_value != '' ORDER BY post_id DESC LIMIT 0, 5" );

$main_query = new WP_Query( array(
    'post__not_in' => $excludeposts, 
    'paged' => $paged 
    ) 
);  

while ($main_query->have_posts()) : 

    $main_query->the_post();
    // Действия с записью...

endwhile;

?>
10 нояб. 2012 г. 18:27:34
0

В ответ @Carlisle, если вы хотите исключить 5 последних записей, помеченных как избранные, вы можете сделать следующее. Измените posts_per_page на количество записей, которые хотите исключить, и meta_query в соответствии с тем, как у вас обозначается избранная категория.

function cmp_exclude_featured_posts($query) {
    $exclude = array();  // Создаем пустой массив для ID записей, которые нужно исключить
    if ( $query->is_main_query() ) {
            $featured = get_posts(array(
                'post_type' => 'post',
                'meta_query' => array(
                    array(
                        'key' => 'featured',
                        'value' => '1',
                        'compare' => '==',
                    ),
                ),
                'posts_per_page' => 2
            ));

            foreach($featured as $hide) {
                $exclude[] = $hide->ID;
            }   

            $query->set('post__not_in', $exclude);
        }
}

add_filter( 'pre_get_posts', 'cmp_exclude_featured_posts' );
29 апр. 2015 г. 21:21:09