Кастомные типы записей (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');
});
Вывод кастомных типов записей на сайте
Есть три основных способа вывести 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 $89 | CPT + ACF-подобные поля, построитель экранов |
| JetEngine (Crocoblock) | От $43/год | CPT, метаполя, динамические виджеты, переплетение типов |
| Toolset Types | От $69/год | Визуальный конструктор, шаблоны, интеграция с поиском |
Но наш совет: если вы разработчик — пишите код сами. Плагины добавляют лишнюю нагрузку, создают зависимость от стороннего кода и часто тормозят админку.
Распространённые ошибки и как их избежать
- Забыли сбросить rewrite rules — после регистрации CPT и таксономий страницы 404. Решение: зайти в Настройки → Постоянные ссылки и нажать «Сохранить».
- Поместили код CPT в functions.php темы — при смене темы данные останутся в БД, но админка и вывод сломаются. Решение: выносите CPT в отдельный плагин.
- Пересечение slug с существующими страницами — если у вас уже есть страница /cases/, а для CPT задан slug ‘cases’, будет конфликт. Решение: проверяйте slug перед регистрацией.
- Не включили show_in_rest — Gutenberg и REST API не работают. Решение: всегда ставьте
show_in_rest = trueпри регистрации. - Попытка использовать зарезервированные имена — post, page, attachment, revision, nav_menu_item и другие. WordPress просто не зарегистрирует CPT с таким именем.
- Не обновляют ЧПУ после деактивации — если удалили 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-структурой.
Статья написана для блога delai-sait.ru — разработка и поддержка сайтов на WordPress.

