Включение и исключение таксономий из архивов и лент с помощью 'pre_get_posts'

10 мар. 2013 г., 18:44:07
Просмотры: 17.2K
Голосов: 6

Что я пытаюсь сделать?

В моем блоге используется пользовательская таксономия под названием edition с терминами us-canada (6), eu (7) и india (8) — слаг термина (ID).

Я хочу, чтобы записи не назначенные ни к одной конкретной 'edition' отображались под всеми терминами (т.е. если запись не назначена для usa, europe или india, она будет показана на архивных страницах всех этих терминов).

Что я пробовал?

Вот пример кода для одного из терминов, который должен дать представление о том, что я пытаюсь сделать, и где я мог ошибиться.

add_filter('pre_get_posts','better_editions_archive');

function better_editions_archive($query) {

    // Проверяем, является ли запрос главным и относится ли к таксономии edition с ID 6
    if ( $query->is_tax( 'edition', 6 ) && $query->is_main_query() ) {
        $query->set( 'post_type', array( 'post' ) );

        // Настраиваем параметры таксономического запроса
        $query->set( 'tax_query',
            array(
                'relation' => 'AND',
                array(
                    'taxonomy' => 'category',
                    'field' => 'id',
                    'terms' => array( 1, 2, 4, 5 )
                ),
                array(
                    'taxonomy' => 'edition',
                    'field' => 'id',
                    'terms' => array( 7, 8 ),
                    'operator' => 'NOT IN'
                )
            )
        );
    }

    return $query;
}

В чем проблема? Приведенный выше код не работает (другие варианты, которые я пробовал: код-1, код-2), он ничего не меняет. Ошибок отладки тоже нет.

Так что же я делаю не так?

Кроме того, чтобы изменения применялись и к лентам этих терминов, я заменил соответствующую строку в коде на эту:

function better_editions_archive($query) {

    // Проверяем как для архивов, так и для лент
    if ( ( $query->is_tax( 'edition', 6 ) && $query->is_main_query() ) || ( $query->is_feed() && $query->is_tax( 'edition', 6 ) ) ) {

Но это приводит к перенаправлению лент терминов обратно на их архивные страницы. То есть при работе функции example.com/edition/usa/feed/ перенаправляет на example.com/edition/usa/.

Опять же, я не понимаю, что делаю не так.

ОБНОВЛЕНИЕ: Что сработало? (Но...)

add_filter( 'pre_get_posts', 'better_editions_archive' );

function better_editions_archive( $query ) {
    // Проверяем условие для термина с ID 6
    if ( $query->is_tax( 'edition', 6 ) && $query->is_main_query() ) {

        $args = array(
            'post_type' => 'post',

            'tax_query' => array(
                'relation' => 'AND',
                array(
                    'taxonomy' => 'category',
                    'field' => 'id',
                    'terms' => array( 1, 2, 4, 5 )
                ),
                array(
                    'taxonomy' => 'edition',
                    'field' => 'id',
                    'terms' => array( 7, 8 ),
                    'operator' => 'NOT IN'
                )
            )
        );

        // Перезаписываем query_vars
        $query->query_vars = $args;
    }

    return $query;
}

Это работает, но есть проблема. После длительного обсуждения с опытным разработчиком WordPress мне сказали следующее (полный разговор можно посмотреть здесь, но он очень длинный):

Вы присваиваете этот массив как query_vars. Но query_vars — это довольно большой объект. И вы фактически перезаписываете все данные в нем, добавляя только свои пользовательские параметры. Это означает, что вы "сбрасываете" все, что добавлено по умолчанию.

Он настоятельно не рекомендовал использовать это решение, а вместо этого использовать метод $query->set();.

Но, как видно выше, у меня не получилось заставить другой вариант работать. Поэтому я здесь, чтобы узнать, что я делаю не так, в менее технических терминах.

11
Комментарии

Отсутствует закрывающая ) для метода set в $query->set( 'tax_query',

birgire birgire
10 мар. 2013 г. 19:51:41

@birgire Я только заметил ваш комментарий, когда собирался внести правку. Изначально закрывающей ) тоже не было (метод set на самом деле закрыт, а завершающая ); находится в другой строке ниже). Не могли бы вы внимательнее посмотреть код?

its_me its_me
10 мар. 2013 г. 19:56:58

Используйте массив tax_query в методе $query->set. Разработчик прав, вы перезаписываете весь запрос, а лучше его дополнять.

bueltge bueltge
12 мар. 2013 г. 21:08:16

@bueltge Это то, что ты хотел, чтобы я попробовал? Если да, то я попробовал. Не сработало. Если нет, можешь объяснить немного понятнее? Спасибо!

its_me its_me
12 мар. 2013 г. 21:43:18

Можешь уточнить, в каком смысле это не работает? Ты вообще не получаешь результатов? Или просто не ту комбинацию результатов, которую ожидал?

vancoder vancoder
12 мар. 2013 г. 22:32:55

@vancoder да, как я уже сказал, ничего не меняется, т.е. результат одинаковый с функцией и без неё. Я вообще не получаю никаких результатов!

its_me its_me
12 мар. 2013 г. 22:47:53

Первый вложенный массив tax_query указывает таксономию как 'category'. Это правильно? Или должно быть 'edition'?

vancoder vancoder
13 мар. 2013 г. 00:06:15

@vancoder Насколько я понимаю, так и должно быть. Первый массив должен означать "показывать записи из всех категорий", а второй массив должен немного переопределять это и говорить: если запись(и) принадлежит(ат) какому-либо другому термину пользовательской таксономии (edition), кроме архива термина, который вы просматриваете, не показывать его. Уловили суть того, что я пытаюсь сделать? Интересно, если это не ясно из моего вопроса. Дайте знать, если нужно больше информации.

its_me its_me
13 мар. 2013 г. 00:24:32

Я на 100% уверен в том, что вам нужно, но я отредактировал свой ответ, основываясь на обоснованном предположении.

vancoder vancoder
13 мар. 2013 г. 00:32:40

@Thone: Я имею в виду вот это, что сейчас в ответе $query->set( 'tax_query', array() ) ;) Вчера у меня не было возможности написать ответ, я читал с мобильного.

bueltge bueltge
13 мар. 2013 г. 12:18:13

@bueltge Я уже это делаю. Пожалуйста, посмотрите первый блок кода.

its_me its_me
13 мар. 2013 г. 14:17:07
Показать остальные 6 комментариев
Все ответы на вопрос 2
7
17

Я попробую еще раз.

Следующий код должен модифицировать основной запрос таким образом, чтобы он включал в цикл любые записи, которые не принадлежат ни к одному термину пользовательской таксономии Edition.

add_filter('pre_get_posts','better_editions_archive');

function better_editions_archive( $query ) {

    if ( $query->is_tax( 'edition' ) && $query->is_main_query() ) {
        $terms = get_terms( 'edition', array( 'fields' => 'ids' ) );
        $query->set( 'post_type', array( 'post' ) );
        $query->set( 'tax_query', array(
            'relation' => 'OR',
            array(
                'taxonomy' => 'edition',
                'field' => 'id',
                'terms' => $terms,
                'operator' => 'NOT IN'
            )
        ) );
    }

    return $query;
}
12 мар. 2013 г. 21:08:19
Комментарии

Только что попробовал. Ничего не изменилось. Никаких ошибок/подсказок в отладке тоже. Спасибо, что попытались помочь. :)

its_me its_me
12 мар. 2013 г. 21:44:40

В качестве метода отладки, вы можете попробовать print_r($query) в вашем первом примере кода. Где-то в выводе должен быть сгенерированный SQL. Добавьте его сюда, это может быть полезно.

vancoder vancoder
12 мар. 2013 г. 22:25:55

Просто для проверки - у вас WP 3.5 или новее, верно?

vancoder vancoder
12 мар. 2013 г. 22:34:31

Да, последняя версия WordPress (всегда!). И для отладки, вы хотите, чтобы я заменил return $query; на print_r($query);? Это то, что нужно сделать?

its_me its_me
12 мар. 2013 г. 22:38:36

Если да, вот что я получил: http://paste.kde.org/694496/ -- Это что-то говорит? (Я не понял.)

its_me its_me
12 мар. 2013 г. 22:39:52

О боже, это сработало! И без каких-либо дополнительных изменений это также модифицирует фиды пользовательских таксономий так же, как и архивы терминов (что, конечно, мне и нужно). Так это работает или мне это кажется? Разве нам не нужно добавить что-то вроде ( is_feed() && is_.... )?

its_me its_me
13 мар. 2013 г. 07:17:10

Это должно работать на любой странице терминов таксономии Edition. Насчет фидов я не уверен. Но я возьму награду, если это сработает :)

vancoder vancoder
13 мар. 2013 г. 18:28:31
Показать остальные 2 комментариев
0

Заметка для себя: ответ @vancoder — это, по сути, улучшенная (& автоматизированная) версия этого кода:

add_filter('pre_get_posts','better_editions_archive');

function better_editions_archive($query) {

    if ( $query->is_tax( 'edition') && $query->is_main_query() ) {

        $query->set( 'post_type', array( 'post' ) );

        $query->set( 'tax_query',
            array(
                array(
                    'taxonomy' => 'edition',
                    'field' => 'id',
                    'terms' => array( 6, 7, 8 ),
                    'operator' => 'NOT IN'
                )
            )
        );

    }

    return $query;
}

(Что делает код) Если это архив для любого элемента пользовательской таксономии 'edition', то...

  1. Код не мешает стандартной работе архивных страниц элементов, т.е. записи, привязанные к элементу пользовательской таксономии 'edition', будут (как обычно) отображаться в соответствующем архиве элемента.

  2. Но если запись не привязана ни к одному из указанных элементов таксономии (см. 'terms' => array( 6, 7, 8 ) и 'operator' => 'NOT IN'), то такие записи будут отображаться на архивных страницах всех элементов этой таксономии.

  3. Код также влияет на RSS-ленты указанных элементов, поэтому содержимое лент зеркалирует содержимое архивных страниц, что мне и нужно. Если вы не хотите, чтобы изменения затрагивали ленты (т.е. хотите применить изменения только к архивным страницам), замените условие IF на следующее:

    if ( $query->is_tax( 'edition') && $query->is_main_query() && ! $query->is_feed() ) {
    
13 мар. 2013 г. 15:44:27