Кастомные типы записей в WordPress: создание, таксоном…

Кастомные типы записей в WordPress: создание, таксоном…
Быстрый ответ

Кастомные типы записей (Custom Post Types, CPT) — это собственные типы контента в WordPress, которые вы создаёте под свои задачи. Например, «Товары», «Портфолио», «Отзывы», «Акции» или «Кейсы». В отличие от стандартных «Записей» и «Страниц», CPT позволяют хранить разнородный контент отдельно, задавать свою структуру, таксономии и произвольные поля. Создаются через register_post_type() в functions.php или в плагине. Кастомные таксономии (register_taxonomy()) группируют записи внутри CPT — как рубрики и метки, но для вашего типа контента. Вывод на фронтенде делается через шаблоны single-{post_type}.php и archive-{post_type}.php или через WP_Query.

Что такое кастомные типы записей и зачем они нужны

WordPress из коробки предлагает два основных типа контента: Записи (Posts) и Страницы (Pages). Для блога или простого информационного сайта этого достаточно. Но как только проект усложняется, стандартных типов перестаёт хватать.

Представьте, что вы делаете сайт-каталог недвижимости. У вас есть объекты — квартиры, дома, коммерческие помещения. У каждого объекта — цена, площадь, адрес, этаж, планировка, фотографии. Если хранить всё это в обычных «Записях», придётся:

  • Использовать категории для типов недвижимости (но категории — это не структура данных)
  • Забивать произвольные поля для характеристик (но их сложно администрировать)
  • Путать записи блога с объектами каталога (админка превращается в свалку)

Кастомные типы записей решают эту проблему кардинально: вы создаёте отдельный раздел «Объекты» в админке, у каждого объекта — свой набор полей, своя таксономия (например, «Тип недвижимости», «Район»), свой шаблон вывода на сайте. Блог при этом остаётся отдельно.

Когда стоит создавать CPT

  • Каталог товаров/услуг — интернет-магазин, портфолио, кейсы
  • Карточки объектов — недвижимость, автомобили, вакансии
  • Пользовательский контент — отзывы, вопросы, заявки
  • Специфичные разделы — акции, мероприятия, команда, партнёры
  • Любые данные со своей структурой, которые не вписываются в формат «заголовок + текст»

Создание кастомного типа записи: register_post_type()

Стандартный способ создать CPT — вызвать функцию register_post_type() внутри хука init. Лучшая практика — выносить код в отдельный плагин, а не в functions.php темы, потому что при смене темы все CPT пропадут.

Вот минимальный пример создания типа записи «Кейсы»:

<?php
/**
 * Регистрация кастомного типа записи "Кейсы"
 */
add_action('init', function () {
    $labels = [
        'name'               => 'Кейсы',
        'singular_name'      => 'Кейс',
        'add_new'            => 'Добавить кейс',
        'add_new_item'       => 'Добавить новый кейс',
        'edit_item'          => 'Редактировать кейс',
        'new_item'           => 'Новый кейс',
        'view_item'          => 'Просмотреть кейс',
        'search_items'       => 'Искать кейсы',
        'not_found'          => 'Кейсы не найдены',
        'not_found_in_trash' => 'В корзине кейсов нет',
        'all_items'          => 'Все кейсы',
        'menu_name'          => 'Кейсы',
    ];

    $args = [
        'labels'              => $labels,
        'public'              => true,
        'has_archive'         => true,
        'show_in_rest'        => true,  // для Gutenberg
        'menu_icon'           => 'dashicons-portfolio',
        'supports'            => ['title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'],
        'rewrite'             => ['slug' => 'cases'],
        'show_in_menu'        => true,
        'menu_position'       => 5,
    ];

    register_post_type('case', $args);
});

Ключевые параметры register_post_type()

ПараметрОписаниеРекомендация
public Виден ли тип на фронтенде и в админке true для обычных CPT, false для внутренних
has_archive Включает архивную страницу /cases/ true, если нужен список всех записей
show_in_rest Включает поддержку Gutenberg и REST API true — обязательно для современной разработки
supports Какие блоки редактора доступны Минимум ['title', 'editor']
rewrite URL-структура для ЧПУ ['slug' => 'your-slug']
menu_icon Иконка в админ-меню Любой dashicon или SVG
show_in_menu Показывать в боковом меню true — для быстрого доступа
menu_position Позиция в меню (5 — ниже Записей) 5, 10, 15, 20, 25, 60, 65…
taxonomies Привязка стандартных таксономий ['category', 'post_tag'] — если нужны

Регистрация кастомных таксономий

Таксономии — это механизм группировки записей. В WordPress из коробки есть рубрики (category) и метки (post_tag). Для CPT вы можете создать свои таксономии через register_taxonomy().

Добавим к нашему типу «Кейсы» две таксономии: «Тип услуги» (иерархическая, как рубрики) и «Технологии» (плоская, как метки):

<?php
/**
 * Регистрация кастомной таксономии "Тип услуги"
 */
add_action('init', function () {
    $labels = [
        'name'              => 'Типы услуг',
        'singular_name'     => 'Тип услуги',
        'search_items'      => 'Искать типы услуг',
        'all_items'         => 'Все типы',
        'parent_item'       => 'Родительский тип',
        'parent_item_colon' => 'Родительский тип:',
        'edit_item'         => 'Редактировать тип',
        'update_item'       => 'Обновить тип',
        'add_new_item'      => 'Добавить новый тип',
        'new_item_name'     => 'Название нового типа',
        'menu_name'         => 'Типы услуг',
    ];

    $args = [
        'labels'            => $labels,
        'public'            => true,
        'hierarchical'      => true,   // как рубрики — с родителями
        'show_in_rest'      => true,
        'rewrite'           => ['slug' => 'service-type'],
        'show_admin_column' => true,   // колонка в списке записей
    ];

    register_taxonomy('service_type', ['case'], $args);
});
<?php
/**
 * Регистрация плоской таксономии "Технологии"
 */
add_action('init', function () {
    $labels = [
        'name'          => 'Технологии',
        'singular_name' => 'Технология',
        'search_items'  => 'Искать технологии',
        'all_items'     => 'Все технологии',
        'edit_item'     => 'Редактировать',
        'update_item'   => 'Обновить',
        'add_new_item'  => 'Добавить новую',
        'new_item_name' => 'Название',
        'menu_name'     => 'Технологии',
    ];

    $args = [
        'labels'            => $labels,
        'public'            => true,
        'hierarchical'      => false,  // как метки — без иерархии
        'show_in_rest'      => true,
        'rewrite'           => ['slug' => 'tech'],
        'show_admin_column' => true,
    ];

    register_taxonomy('tech', ['case'], $args);
});

После регистрации таксономий не забудьте пересохранить правила перезаписи (flush rewrite rules): зайдите в Настройки → Постоянные ссылки и нажмите «Сохранить изменения».

Сравнение иерархических и плоских таксономий

ПараметрИерархическая (hierarchical: true)Плоская (hierarchical: false)
Аналог в WordPressРубрикиМетки
ВложенностьЕсть (родитель → потомок)Нет
Интерфейс выбораЧекбоксы / выпадающий списокПоле ввода через запятую
URL-структура/service-type/web//tech/php/
Для чего подходитКатегории товаров, разделы портфолиоТеги, технологии, характеристики

Привязка таксономии к CPT разными способами

Есть два способа связать таксономию с типом записи:

Способ 1: при регистрации таксономии

В параметре register_taxonomy() вторым аргументом передаём массив типов записей:

register_taxonomy('service_type', ['case', 'post'], $args);
// Таксономия будет доступна и для CPT 'case', и для стандартных 'post'

Способ 2: через register_taxonomy_for_object_type()

Если таксономия уже зарегистрирована, а привязать её к новому CPT нужно отдельно:

add_action('init', function () {
    register_taxonomy_for_object_type('tech', 'case');
    register_taxonomy_for_object_type('tech', 'portfolio');
});
728x90 11

Вывод кастомных типов записей на сайте

Есть три основных способа вывести CPT на фронтенде:

1. Шаблоны темы

Самый правильный способ. WordPress автоматически подхватывает файлы по иерархии шаблонов:

  • single-case.php — для одной записи (страница кейса)
  • archive-case.php — для архива (список всех кейсов)
  • taxonomy-service_type.php — для страницы таксономии

Пример archive-case.php:

<?php get_header(); ?>

<h1>Наши кейсы</h1>

<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
    <article>
        <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
        <?php the_excerpt(); ?>

        <?php
        $terms = get_the_terms(get_the_ID(), 'service_type');
        if ($terms && !is_wp_error($terms)) :
            $names = wp_list_pluck($terms, 'name');
            echo '<p>Тип: ' . implode(', ', $names) . '</p>';
        endif;
        ?>

        <?php if (has_post_thumbnail()) : ?>
            <?php the_post_thumbnail('medium'); ?>
        <?php endif; ?>
    </article>
<?php endwhile; endif; ?>

<?php get_footer(); ?>

2. WP_Query — вывод в любом месте

Если нужно вывести записи CPT внутри другой страницы (например, блок «Похожие кейсы» на странице услуги):

<?php
$cases = new WP_Query([
    'post_type'      => 'case',
    'posts_per_page' => 4,
    'orderby'        => 'date',
    'order'          => 'DESC',
    'tax_query'      => [
        [
            'taxonomy' => 'service_type',
            'field'    => 'slug',
            'terms'    => 'web-dev',
        ],
    ],
]);

if ($cases->have_posts()) :
    while ($cases->have_posts()) : $cases->the_post();
        // вывод записи
    endwhile;
    wp_reset_postdata();
endif;

3. REST API — для SPA и внешних приложений

Если CPT зарегистрирован с show_in_rest = true, данные доступны через REST API:

// GET https://delai-sait.ru/wp-json/wp/v2/case
// GET https://delai-sait.ru/wp-json/wp/v2/case?categories=15
// GET https://delai-sait.ru/wp-json/wp/v2/service_type

Для расширения REST-ответа своими полями:

<?php
add_action('rest_api_init', function () {
    register_rest_field('case', 'budget', [
        'get_callback' => function ($post) {
            return get_post_meta($post['id'], 'case_budget', true);
        ],
        'schema' => [
            'description' => 'Бюджет проекта',
            'type'        => 'string',
        ],
    ]);
});

Полезные хуки и функции для работы с CPT

<?php
// Изменить заголовки колонок в админке списка CPT
add_filter('manage_case_posts_columns', function ($columns) {
    $columns['service_type'] = 'Тип услуги';
    $columns['budget']       = 'Бюджет';
    return $columns;
});

// Вывести значение кастомной колонки
add_action('manage_case_posts_custom_column', function ($column, $post_id) {
    if ($column === 'budget') {
        echo get_post_meta($post_id, 'case_budget', true) ?: '—';
    }
    if ($column === 'service_type') {
        $terms = get_the_terms($post_id, 'service_type');
        echo $terms ? implode(', ', wp_list_pluck($terms, 'name')) : '—';
    }
}, 10, 2);

// Добавить фильтр по таксономии в админке
add_action('restrict_manage_posts', function () {
    global $typenow;
    if ($typenow === 'case') {
        $taxonomy = 'service_type';
        wp_dropdown_categories([
            'show_option_all' => 'Все типы услуг',
            'taxonomy'        => $taxonomy,
            'name'            => $taxonomy,
            'value_field'     => 'slug',
            'selected'        => $_GET[$taxonomy] ?? '',
        ]);
    }
});

CPT в админке: метабоксы и произвольные поля

Часто вместе с CPT регистрируют произвольные метаполя — через ACF (Advanced Custom Fields) или нативными функциями. Вот пример добавления метабокса «Бюджет проекта» без плагинов:

<?php
/**
 * Добавляем метабокс "Бюджет проекта" для CPT "Кейсы"
 */
add_action('add_meta_boxes', function () {
    add_meta_box(
        'case_budget_meta',
        'Бюджет проекта',
        function ($post) {
            wp_nonce_field('case_budget_nonce', 'case_budget_nonce_field');
            $value = get_post_meta($post->ID, 'case_budget', true);
            ?>
            <input type="text" name="case_budget"
                   value="<?php echo esc_attr($value); ?>"
                   style="width: 100%;" placeholder="Например: 150 000 ₽" />
            <?php
        },
        'case',
        'side'
    );
});

// Сохраняем значение
add_action('save_post_case', function ($post_id) {
    if (!isset($_POST['case_budget_nonce_field']) ||
        !wp_verify_nonce($_POST['case_budget_nonce_field'], 'case_budget_nonce')) {
        return;
    }
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;

    if (isset($_POST['case_budget'])) {
        update_post_meta($post_id, 'case_budget', sanitize_text_field($_POST['case_budget']));
    }
});

CPT vs стандартные записи: что выбрать

КритерийКастомный тип записи (CPT)Стандартная запись
Раздел в админкеОтдельный пункт менюВ разделе «Записи»
Структура данныхСвои поля, метабоксы, таксономииСтандартный набор (заголовок, текст, рубрики)
URL-префиксНастраиваемый (/cases/, /portfolio/)/category/… (привязан к рубрикам)
SEO-потенциалВысокий — отдельный архив, карта сайтаСредний — смешивается с блогом
Сложность настройкиТребует кода / плагинаНе требует — работает из коробки
Для чего подходитКаталоги, портфолио, карточки, кейсыБлог, новости, статьи

Плагины для управления CPT без кода

Если вам нужно создать CPT, но писать код не хочется — вот лучшие плагины:

ПлагинЦенаФишки
Custom Post Type UIБесплатно / Pro $29Удобный интерфейс, экспорт кода, поддержка таксономий
Podcasts — FrameworkБесплатно / Extended $89CPT + ACF-подобные поля, построитель экранов
JetEngine (Crocoblock)От $43/годCPT, метаполя, динамические виджеты, переплетение типов
Toolset TypesОт $69/годВизуальный конструктор, шаблоны, интеграция с поиском

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

Распространённые ошибки и как их избежать

  1. Забыли сбросить rewrite rules — после регистрации CPT и таксономий страницы 404. Решение: зайти в Настройки → Постоянные ссылки и нажать «Сохранить».
  2. Поместили код CPT в functions.php темы — при смене темы данные останутся в БД, но админка и вывод сломаются. Решение: выносите CPT в отдельный плагин.
  3. Пересечение slug с существующими страницами — если у вас уже есть страница /cases/, а для CPT задан slug ‘cases’, будет конфликт. Решение: проверяйте slug перед регистрацией.
  4. Не включили show_in_rest — Gutenberg и REST API не работают. Решение: всегда ставьте show_in_rest = true при регистрации.
  5. Попытка использовать зарезервированные имена — post, page, attachment, revision, nav_menu_item и другие. WordPress просто не зарегистрирует CPT с таким именем.
  6. Не обновляют ЧПУ после деактивации — если удалили CPT-плагин, на сайте остаются 404 на страницах, которые его использовали. Решение: настройте редиректы или заранее продумайте миграцию.

Часто задаваемые вопросы

Можно ли создавать CPT через админку без кода?

Да, с помощью плагинов — Custom Post Type UI или Pods. Они предоставляют графический интерфейс и генерируют код, который можно потом вынести в плагин.

Сколько CPT можно создать на одном сайте?

Ограничений нет. На крупных проектах может быть 10–20 и более кастомных типов записей. Однако каждый CPT добавляет запросы к БД, поэтому следите за производительностью.

В чём разница между CPT и произвольными полями?

CPT — это отдельный тип контента со своей структурой и страницей архива. Произвольные поля (метаполя) — это дополнительные атрибуты внутри записи любого типа. CPT часто используются вместе с произвольными полями.

Как удалить кастомный тип записи и его данные?

Просто удалить код регистрации недостаточно — записи останутся в БД. Нужно либо удалить записи вручную через админку перед удалением CPT, либо использовать функцию wp_delete_post() в цикле через WP-CLI или скрипт.

Нужен ли CPT для интернет-магазина на WooCommerce?

WooCommerce уже регистрирует свой CPT — ‘product’. Вам не нужно создавать его вручную. Но если у магазина есть сопутствующий контент (обзоры, кейсы, акции), для них можно создать отдельные CPT.

Как сделать CPT доступным только для определённой роли пользователя?

Используйте параметр capability_type и capabilities при регистрации CPT. Либо плагины вроде User Role Editor для гибкой настройки прав.

Как добавить CPT в карту сайта (sitemap) для SEO?

Если используете Yoast SEO или Rank Math — они автоматически включают CPT с public = true в sitemap. Убедитесь, что в настройках SEO-плагина галочка стоит на нужном CPT.

Поддерживает ли CPT иерархию, как Страницы?

Да, если при регистрации указать hierarchical = true, CPT будет поддерживать родительские и дочерние записи с вложенной URL-структурой.

Мощный SEO плагин Clearfy

Статья написана для блога delai-sait.ru — разработка и поддержка сайтов на WordPress.

Поделиться:
Telegram ВКонтакте