Настройка архивов для рубрик, меток и других таксономий в WordPress

Большинство WordPress-пользователей знакомы с метками и рубриками, а также с тем, как их использовать для организации записей блога. Если вы используете произвольные типы записей в WordPress, вы, возможно, нуждаетесь в определенном методе организации их, как в случае с рубриками и метками. Рубрики и метки – это примеры таксономий, и WordPress позволяет вам создавать столько разных таксономий, сколько вы хотите. Эти произвольные таксономии работают точно так же, как рубрики или метки, однако отделены от них.

В данном руководстве мы разъясним, что представляют собой произвольные таксономии, как создавать их. Мы также затронем то, какие шаблоны в WordPress-темах управляют архивами встроенных и произвольных таксономий, а также покажем некоторые расширенные техники настройки поведения архивов таксономий.

Терминология

Перед тем, как продолжить, давайте обратимся к терминологии. Таксономия в WordPress – это тип контента, который используется для организации контента любого другого существующего типа. Две встроенных таксономии, с которыми вы уже знакомы: рубрики и метки. Мы обычно называем «метками» отдельные элементы таксономии меток, хотя правильнее было бы называть их «термами» (или терминами). В произвольной таксономии элементы обычно называются термами.

Рубрики и метки представляют два типа таксономий: иерархическую и неиерархическую. Как в случае с рубриками, иерархические таксономии могут иметь отношения «parent-child» между своими термами. К примеру, у вас в блоге может иметься рубрика films, которая может иметь несколько дочерних категорий с названиями, такими как foreign и domestic. Произвольные таксономии могут также быть иерархическими, как в случае с рубриками, или неиерархическими, как в случае с метками.

wordpress-categories-taxonomies-opt

Архив таксономий – это список записей в таксономии, который автоматически генерируется WordPress. К примеру, это может быть страница, на которую вы переходите, когда щелкаете по ссылке с рубрикой и видите все записи из этой рубрики. Мы посмотрим, как изменить поведение этих страниц и изучим, какие шаблоны генерируют их.

Как работают архивы рубрик, меток и произвольных таксономий

Для каждой рубрики, метки и произвольной таксономии WordPress автоматически генерирует архив, который перечисляет все записи, связанные с данной таксономией, в обратном хронологическом порядке. Система работает прекрасно, если вы структурировали все ваши записи с помощью рубрик и меток. Если у вас имеется комплексная система структуризации произвольных типов записей с произвольными таксономиями, то в таком случае этот подход может быть не самым лучшим. Мы покажем вам разные способы изменения этих архивов.

Первый шаг по настройке архивов – понимание того, какие файлы в вашей теме используются для вывода архивов. Разные темы имеют разные шаблоны, однако во всех темах существует шаблон index.php. Этот шаблон используется для вывода всего контента, если не существует шаблонов, стоящих выше в иерархии. Иерархия шаблонов в WordPress – это система, которая диктует то, какой шаблон будет использоваться для вывода на экран определенного контента. Мы кратко пробежимся по иерархии шаблонов для рубрик, меток и произвольных таксономий.

Большинство тем обладают шаблоном archive.php, который используется для вывода архивов меток и рубрик, а также архивов дат и авторов. Вы можете добавлять шаблоны для отдельной обработки архивов по меткам и рубрикам. Эти шаблоны носят название category.php и tag.php соответственно. Вы можете также создавать шаблоны для отдельных меток или рубрик, используя ID или слаг рубрики/метки. К примеру, метка с ID=7 будет использовать шаблон tag-7.php, если он существует, вместо стандартных tag.php или archive.php. Метка со слагом avocado может быть выведена, используя шаблон tag-avocado.php.

Одна достаточно интересная вещь, которую нужно держать в памяти, состоит в том, что шаблон, названный с помощью слага, будет перекрывать шаблон, названный с помощью ID. К примеру, если метка со слагом avocado имеет ID =7, то в таком случае tag-avocado.php будет перекрывать собой шаблон tag-7.php, если он существует, т. е. слаг имеет высший приоритет.

Иерархия шаблонов для произвольных таксономий несколько отличается, поскольку существуют шаблоны для всех таксономий, для отдельных таксономий и для отдельных термов в конкретной таксономии. К примеру, представим, что у нас есть две таксономии, fruits и vegetables, и таксономия fruits имеет два терма, apples и oranges, в то время как таксономия vegetables имеет два других терма, carrots и celery. Давайте добавим три шаблона к нашей теме сайта: taxonomy.php, taxonomy-fruits.php и taxonomy-vegetables-carrots.php.

Для термов в таксономии fruits все архивы будут генерироваться на базе taxonomy-fruits.php, поскольку не существует шаблонов под отдельные термы. С другой стороны, терм carrots в архивах таксономии vegetables будет генерироваться на базе taxonomy-vegetables-carrots.php. Шаблон taxonomy-vegetables.php не существует, поэтому все другие термы в vegetables будут генерироваться на базе шаблона taxonomy.php.

Использование условных тегов

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

В WordPress имеются условные функции, позволяющие определить, будет ли выведена на экран произвольная таксономия, рубрика или метка. Чтобы определить, какой архив будет выведен на экран, вы можете использовать is_category() для рубрик, is_tag() для меток и is_tax() для таксономий. Функции is_tag() и is_category() позволяют протестировать вывод определенных меток или рубрик через слаг или ID. К примеру:

<?php
    if ( is_tag() ) {
        echo "True for any tag!";
    }
    if ( is_tag( 'jedis' ) ) {
        echo "True for the tag whose slug is jedi";
    }
    if ( is_tag( array( 'jedi', 'sith' ) ) ) {
        echo "True for tags whose slug is jedi or sith";
    }
    if ( is_tag( 7 ) ) {
        echo "You can also use tag IDs. This is true for tag ID 7";
    }
?>

Для произвольных таксономий функция is_tax() может проверять, будет ли выводиться любая таксономия (кроме рубрик и меток), определенная таксономия или определенный терм в таксономии. К примеру:

<?php
    if ( is_tax() ) {
        echo "True for any custom taxonomy.";
    }
    if ( is_tax( 'vegetable' ) ) {
        echo "True for any term in the vegetable taxonomy.";
    }
    if ( is_tax( 'vegetable', 'celery' ) ) {
        echo "True only for the term celery, in the vegetable taxonomy.";
    }
?>

Создание произвольных таксономий

Добавление произвольной таксономии может быть сделано одним из трех способов: ручного кодирования в соответствии с инструкциями в кодексе, что я не рекомендую делать; генерации кода через GenerateWP; либо использования плагина для произвольных типов контента, такого как Pods или Types. Плагины для произвольных типов контента позволяют вам создавать произвольные таксономии и произвольные типы записей в бэкэнде WordPress без написания какого-либо кода. Использование плагина – самый простой способ добавления произвольной таксономии и получения фреймворка для работы с произвольными типами контента.

Если вы приняли решение воспользоваться одним из первых двух вариантов, то в таком случае вам нужно будет добавить код либо в файл functions.php вашей темы, либо в произвольный плагин. Я настоятельно рекомендую создавать произвольный плагин вместо того, чтобы добавлять код в functions.php. Даже если вы никогда до этого не занимались созданием плагинов, я советую вам сделать это. В то время как добавление кода в functions.php – вполне легитимный способ, при переключении тем (скажем, вы захотите использовать новую тему или диагностировать проблемы) таксономия перестанет работать.

Не важно, напишете ли вы свой код в соответствии с руководством кодекса или сгенерируете его с помощью GenerateWP, просто вставьте этот код в текстовый файл и добавьте единственную строку перед ним, в результате чего вы получите плагин. Загрузите его и установите, как в случае с любым другим плагином.

Та строка, которую вам нужно создать, чтобы получить плагин:

/* Plugin name: Custom Taxonomy */

Ниже представлен плагин, позволяющий зарегистрировать произвольную таксономию под названием vegetables. Этот плагин я создал с помощью GenerateWP, поскольку это заметно проще; к тому же снижается вероятность получить ошибки, часто допускаемые при написании кода вручную:

<?php
    /* Plugin Name: Veggie Taxonomy */
    if ( ! function_exists( 'slug_veggies_tax' ) ) {

    // Register Custom Taxonomy
    function slug_veggies_tax() {

    $labels = array(
    'name'                      	=> _x( 'Vegetables', 'Taxonomy General Name', 'text_domain' ),
    'singular_name'              	=> _x( 'Vegetable', 'Taxonomy Singular Name', 'text_domain' ),
    'menu_name'                  	=> __( 'Taxonomy', 'text_domain' ),
    'all_Veggies'                   => __( 'All Veggies', 'text_domain' ),
    'parent_Veggie'                 => __( 'Parent Veggie', 'text_domain' ),
    'parent_Veggie_colon'           => __( 'Parent Veggie:', 'text_domain' ),
    'new_Veggie_name'               => __( 'New Veggie name', 'text_domain' ),
    'add_new_Veggie'                => __( 'Add new Veggie', 'text_domain' ),
    'edit_Veggie'                   => __( 'Edit Veggie', 'text_domain' ),
    'update_Veggie'                 => __( 'Update Veggie', 'text_domain' ),
    'separate_Veggies_with_commas'  => __( 'Separate Veggies with commas', 'text_domain' ),
    'search_Veggies'                => __( 'Search Veggies', 'text_domain' ),
    'add_or_remove_Veggies'         => __( 'Add or remove Veggies', 'text_domain' ),
    'choose_from_most_used'         => __( 'Choose from the most used Veggies', 'text_domain' ),
    'not_found'                     => __( 'Not Found', 'text_domain' ),
    );
    $args = array(
    'labels'                     => $labels,
    'hierarchical'               => false,
    'public'                     => true,
    'show_ui'                    => true,
    'show_admin_column'          => true,
    'show_in_nav_menus'          => true,
    'show_tagcloud'              => false,
    );
    register_taxonomy( 'vegetable', array( 'post' ), $args );

    }

    // Hook into the 'init' action
    add_action( 'init', 'slug_veggies_tax', 0 );

    }
?>

Я создал этот код с помощью GenerateWP всего за пару минут. Сервис является очень полезным; написание кода вручную вместо того, чтобы сгенерировать его – пустая трата времени. Чтобы сделать этот процесс еще проще, вы можете использовать плагин Pluginception, который позволяет создать чистый плагин для вас, после чего вставить в него код, полученный от GenerateWP, воспользовавшись редактором плагинов в WordPress.

Использование WP_QUERY с произвольными таксономиями

Как только вы добавите произвольную таксономию, вы, возможно, захотите получить все записи с термами в данной таксономии. Чтобы сделать это, мы можем использовать запросы к таксономии, которые реализуются при помощи WP_QUERY.

Запросы к таксономиям могут быть либо очень простыми, либо сложными. Самый простой запрос: получение всех записей с определенным термом. К примеру, если у вас есть тип записей jedi, и связанная с ним произвольная таксономия level, вы можете получить всех джедаев-мастеров (master) следующим образом:

<?php
    $args = array(
        'post_type' => 'jedi',
        'level' => 'master'
    );
    $query = new WP_Query( $args );
?>

Если вы добавите дополнительную произвольную таксономию era, то в таком случае вы можете получить всех джедаев-мастеров (master) Старой Республики (old-republic):

<?php
    $args = array(
        'post_type' => 'jedi',
        'level' => 'master',
        'era' => 'old-republic',
    );
    $query = new WP_Query( $args );
?>

Мы можем также создавать и более сложные сравнения, используя полный аргумент tax_query. Аргумент tax_query позволяет нам искать по ID вместо поиска по слагу (как мы делали ранее), искать более одного терма. Он позволяет нам объединять многочисленные запросы к таксономиям и задавать отношения между ними. Кроме того, мы можем использовать SQL-операторы, такие как NOT IN, для исключения термов.

Возможности здесь безграничны. Изучите раздел «Параметры таксономий» в кодексе для получения дополнительной информации. Фрагмент ниже ищет наш тип записей jedi для мастеров (master) и рыцарей (knight) джедаев, которые не входят в эру Old Republic (old-republic):

<?php
    $args = array(
        'post_type' => 'jedi',
        'tax_query' => array(
        'relation' => 'AND',
            array(
                'taxonomy' => 'level',
                'field' => 'slug',
                'terms' => array( 'master', 'knight' )
            ),
            array(
                'taxonomy' => 'era',
                'field' => 'slug',
                'terms' => array( 'old-republic' ),
                'operator' => 'NOT IN'
                )
        )
    );
    $query = new WP_Query( $args );
?>

Настройка архивов таксономий

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

Знакомимся с PRE_GET_POSTS

Еще до того, как любые записи будут выведены в цикле WordPress, система автоматически получает записи для пользователя в соответствии со страницей, которую он запросил, используя класс WP_QUERY. К примеру, для главной страницы блога запрашиваются самые последние записи. Для архивов таксономии запрашиваются самые последние записи в этой таксономии.

Чтобы изменить запрос, вы можете использовать фильтр pre_get_posts перед тем, как WordPress получит какие-либо записи. Этот фильтр передает объект запроса после того, как он будет задан, однако перед фактическим получением каких-либо записей. Это означает, что вы можете изменять запрос, используя методы класса перед тем, как основной цикл WordPress будет выполнен. Звучит несколько запутанно, но не беспокойтесь – в следующих разделах этой статьи будут приведены реальные примеры работы этой методики.

Добавление произвольного типа записей к архивам рубрик или меток

Прекрасный пример изменения объекта WP_QUERY с помощью pre_get_posts  — добавление записей из произвольного типа записей к архиву рубрик. По умолчанию произвольные типы записей не включены в этот запрос. Если бы мы создавали аргументы, которые передавались бы в WP_Query, и хотели бы включить как регулярные записи, так и записи в произвольном типе jedi, то в таком случае наш аргумент имел бы следующий вид:

<?php
    $args = array( 'post_type' =>
        array(
            'post',
            'jedi'
        )
    );
?>

В обратном вызове для нашего фильтра pre_get_posts нам нужно передать похожий аргумент. Проблема заключается в том, что объект WP_QUERY уже существует, поэтому мы не можем передавать аргумент к нему, как мы делаем это при создании экземпляра класса. Вместо этого мы используем метод класса set(), который позволяет нам изменять любой аргумент после того, как класс будет создан.

Во фрагменте ниже мы использовали set() для изменения аргумента post_type со стандартного значения, которым является post, на массив из типов записей, включающий записи и наш произвольный тип записей jedi. Обратите внимание, что мы использовали условный тег is_category(), чтобы изменение произошло только тогда, когда архивы категорий выводятся на экран.

<?php
    add_filter( 'pre_get_posts', 'slug_cpt_category_archives' );
    function slug_cpt_category_archives( $query ) {
    if ( $query->is_category() && $query->is_main_query()  )  {
        $query->set( 'post_type',
            array(
                'post',
                'jedi'
            )
        );
    }

    return $query;

    }
?>

Параметр $query в функции – это объект WP_QUERY перед тем, как он будет использоваться в основном цикле. Поскольку страница может включать в себя многочисленные циклы (к примеру, для виджетов), мы используем условную функцию is_main_query(), чтобы убедиться в том, что функция затрагивает только основной цикл и не влияет на остальные циклы.

Создание иерархических архивов рубрик или таксономий

По умолчанию архивы рубрик и других иерархических таксономий функционируют так же, как и любые другие архивы таксономий: они выводят все записи в заданной рубрике или с заданным термом таксономии. Чтобы вывести на экран только родительские термы и исключить дочерние термы, вы можете использовать, опять же, фильтр pre_get_posts.

Как и в случае с созданием вашего собственного WP_QUERY для записей в таксономии, WP_QUERY основного цикла использует аргументы tax_query для получения записей в таксономии. tax_query имеет аргумент include_children, который по умолчанию задан как 1 или true. Изменив его на 0 или false, мы можем предотвратить включение в архивы записей с дочерними термами:

<?php
    add_action( 'pre_get_posts', 'slug_cpt_category_archives' );
    function slug_cpt_category_archives( $query ) {
        if ( is_tax( 'TAXONOMY NAME') )  {
            $tax_query = $query->tax_query->queries;
            $tax_query['include_children'] = 0;
            $query->set( 'tax_query', $tax_query );
        }

    }
?>

Результат выглядит желаемым, но здесь имеется несколько недостатков. Это нормально, поскольку если мы исправим эти дефекты, мы сделаем первый шаг на пути к созданию чего-то действительно крутого.

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

Хороший способ решить эту проблему заключается в объединении фильтра pre_get_post с некоторой модификацией шаблона, выводящего рубрики или таксономии. Мы уже говорили ранее о том, как определить, какой шаблон используется для вывода архивов рубрики или произвольной таксономии. Кроме того, имейте в виду, что вы всегда можете обернуть свои изменения в условные теги, такие как is_category() или is_tax(), однако в таком случае код может быстро стать громоздким; поэтому лучше всего создать копию archive.php и удалить из нее весь ненужный код.

Первый шаг, который мы сделаем – это обернем все вещи в одну условную проверку, которая покажет, имеет ли текущий терм таксономии дочерние элементы. Если нет, то тогда мы не будем что-либо выводить. Чтобы сделать это, мы используем функцию get_term_children(), которая вернет пустой массив, если текущий терм не имеет дочерних элементов, что мы можем проверить с помощью !empty().

Чтобы код работал для любой таксономии, нам нужно получить текущую таксономию и терм таксономии из массива query_vars глобального объекта $wp_query. Слаг таксономии содержится в ключе taxonomy, а слаг терма – в ключе tax.

Чтобы использовать get_term_children(), нам нужно иметь ID терма. ID отсутствует в query_vars, однако мы можем передать слаг в get_term_by(), чтобы получить ID.

Внесем всю информацию, которая нам нужна, в переменные:

<?php
    global $wp_query;
    $taxonomy = $wp_query->query_vars['taxonomy'];
    $term = $wp_query->query_vars['tax'];
    $term_id = get_term_by( 'slug', $term, $taxonomy );
    $term_id = $term_id->term_id;
    $terms = get_term_children( $term_id, $taxonomy );
?>

Теперь мы будем продолжать работу только в том случае, если $terms не является пустым массивом. Что понять, пустой он или нет, нам нужно сначала повторно получить термы с помощью get_terms(). Это необходимо, поскольку get_term_children возвращает только массив ID, а нам нужны ID и имена, которые находятся в объекте, возвращаемом get_terms(). Мы можем циклично пройти по этому объекту, выводя имена в виде ссылок. Ссылка может быть сгенерирована путем передачи ID терма в get_term_link().

Вот полный код:

<?php
    global $wp_query;
    $taxonomy = $wp_query->query_vars['taxonomy'];
    $term = $wp_query->query_vars['tax'];
    $term_id = get_term_by( 'slug', $term, $taxonomy );
    $term_id = $term_id->term_id;
    $terms = get_term_children( $term_id, $taxonomy );
    if ( !empty( $terms ) ) {
    $terms = get_terms( $taxonomy, array( 'child_of' => $term_id ) );
    echo '<ul class="child-term-list">';
    foreach ( $terms as $term ) {
    echo '<li><a href="'.$term->term_id.'">'.$term->name.'</a></li>';
    }

    echo '</ul>';

?>

Создание произвольного лендинга под архивы таксономий

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

В этом случае хороший вариант – создать произвольную посадочную страницу для терма. Мы будем использовать query_vars снова для определения того, находится ли пользователь на первой странице архива таксономии; если да, то мы будем использовать фильтр taxonomy_archive для включения отдельного шаблона:

<?php
    add_filter( 'taxonomy_archive ', 'slug_tax_page_one' );
    function slug_tax_page_one( $template ) {
        if ( is_tax( 'TAXONOMY_NAME' ) ) {
             global $wp_query;
             $page = $wp_query->query_vars['paged'];
            if ( $page = 0 ) {
                $template = get_stylesheet_directory(). '/taxonomy-page-one.php';
            }
        }

        return $template;

    }
?>

Этот обратный вызов сначала проверяет, находится ли пользователь в таксономии, которая нам нужна. Мы можем сфокусироваться на всех таксономиях, просто изменив код на is_tax(). Затем функция получает текущую страницу, используя query_var с именем paged, и, если пользователь находится на первой странице, то в таком случае мы получаем адрес нового шаблона. Если нет, то мы получаем стандартный шаблон. Вы можете вставить в этот шаблон все, что вам захочется. Вы можете создать список термов, используя код выше. Вы можете использовать этот код для вывода любого контента; например, вы можете вывести расширенную информацию о терме таксономии, вывести ссылки на отдельные записи.

Источник: smashingmagazine.com

Блог про WordPress
Комментарии: 10
  1. Андрей

    Как по мне от архивов никакого толку нет, год уже как создал сайт на ВП и только недавно о них узнал)

  2. Андрей

    Создать новый раздел с метками, получилось, но после переходя по новой метки перекидывает на страницу 404.

    1. Дмитрий (автор)

      Возможно, что конфликты с каким-либо плагином, который тоже использует метки или как-то их стилизует.

  3. Андрей

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

    Возможно у Вас есть статья, как выводить метки не по алфавиту, а в нужном порядке?

    1. Дмитрий (автор)

      Вообще, значение сортировки для меток orderby может принимать значения (по возрастанию или по убыванию):

      ID name
      Default
      slug
      count
      term_group

      Т.е. вот по этим пунктам сортировать можно.

      1. Алекс

        Антон, спасибо! Несколько часов поиска инфы ради одно этого Вашего коммента — помогло изменение типа постоянных ссылок и обратно. 404 больше не возникает. Спасибо!

  4. Антон

    Добрый день, подскажите, как для дополнительных таксономий прописать уникальный заголовок, и мета данные такие, как ключевые слова и описание. Желательно, чтоб это реализовать без плагинов. У меня установлен плагин «platinum seo pack» и там есть возможность прописать title но только для одной таксономии, а у меня их несколько.

    1. Дмитрий (автор)

      Для добавления метаданных к таксономиям можно воспользоваться таким плагином:

      https://wordpress.org/plugins/taxonomy-metadata/

      А вот тут можете почитать, как вывести заголовок и другие данные для таксономии:

      http://www.wpbeginner.com/wp-themes/how-to-show-the-current-taxonomy-title-url-and-more-in-wordpress/

  5. Антон

    Попробовал, но с приведенными вариантами разобраться не получилось, вот нашел код, но не понимаю, как именно прописать к примеру description. Может подскажите, как использовать комментированные параметры.

    // Для элемента таксономии mytax
    if( is_tax(‘mytax’) ){
    $term = get_queried_object(); // данные элемента текущей таксономии
    // ID храниться тут
    $term_id = $term->term_id;

    /* Все возможные поля
    [term_id] => 452
    [name] => Метка
    [slug] => metka
    [term_group] => 0
    [term_taxonomy_id] => 452
    [taxonomy] => mytax
    [description] =>
    [parent] => 0
    [count] => 14
    [filter] => raw
    */
    }

    1. Дмитрий (автор)

      Сейчас мета-данные уже встроены по умолчанию к таксономиям. Эта возможность появилась в версии WordPress 4.4. Поэтому вполне возможно, что данный код работать не будет.

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

Получать новые комментарии по электронной почте.