Как гибко управлять контентом на WordPress: Custom Post Types и Custom Fields
Несколько лет назад я столкнулся с задачей, которая заставила меня по-новому взглянуть на WordPress. Клиент хотел каталог недвижимости с десятками параметров для каждого объекта: площадь, этаж, тип отопления, наличие балкона. Стандартные посты и страницы явно не справлялись. Именно тогда я по-настоящему разобрался в Custom Post Types и Custom Fields — и с тех пор эти инструменты стали основой моей работы с WordPress.
Почему обычных постов недостаточно
WordPress из коробки предлагает посты и страницы — универсальные, но безликие сущности. Пытаться впихнуть в них товары, отзывы, портфолио или объекты недвижимости — это как хранить гвозди в холодильнике: технически можно, но неудобно и нелогично.
Custom Post Types (CPT) решают эту проблему, позволяя создавать собственные типы контента со своей структурой, иконками в админке и логикой отображения.
Создаём Custom Post Type правильно
Первое, что я советую: никогда не редактируйте функционал через плагины типа CPT без понимания кода — это ограничивает вас в будущем. Регистрируйте типы записей программно.
Вот базовый код для регистрации CPT «Недвижимость», который я использую как отправную точку:
function register_property_post_type() {
$labels = array(
'name' => 'Объекты недвижимости',
'singular_name' => 'Объект недвижимости',
'add_new' => 'Добавить объект',
'add_new_item' => 'Добавить новый объект',
'edit_item' => 'Редактировать объект',
'new_item' => 'Новый объект',
'view_item' => 'Просмотреть объект',
'search_items' => 'Искать объекты',
'not_found' => 'Объекты не найдены',
'menu_name' => 'Недвижимость'
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-admin-home',
'supports' => array('title', 'editor', 'thumbnail'),
'rewrite' => array('slug' => 'property'),
'show_in_rest' => true,
);
register_post_type('property', $args);
}
add_action('init', 'register_property_post_type');
Обратите внимание на show_in_rest — этот параметр я включаю всегда, даже если сейчас не планирую использовать REST API. Опыт показывает, что потребность появляется внезапно, а переделывать архитектуру постфактум — боль.
Custom Fields: где хранить дополнительные данные
Теперь самое интересное — как добавить те самые параметры: площадь, этаж, отопление. Здесь у меня есть чёткая позиция: используйте ACF (Advanced Custom Fields), если проект не требует крайней оптимизации, и пишите meta boxes руками, если нужен полный контроль.
Вариант 1: с ACF
ACF — это плагин, который экономит десятки часов разработки. Создаёте группу полей через удобный интерфейс, привязываете к нужному типу записи — и всё, поля появляются в редакторе.
Для вывода данных на фронтенде код простой:
$area = get_field('area');
$floor = get_field('floor');
$heating_type = get_field('heating_type');
echo '<div class="property-details">';
echo '<p>Площадь: ' . esc_html($area) . ' м²</p>';
echo '<p>Этаж: ' . esc_html($floor) . '</p>';
echo '<p>Отопление: ' . esc_html($heating_type) . '</p>';
echo '</div>';
Вариант 2: ручные Meta Boxes
Когда важна производительность или клиент принципиально не хочет зависеть от сторонних плагинов, я пишу meta boxes самостоятельно в functions.php:
function add_property_meta_box() {
add_meta_box(
'property_details',
'Детали объекта',
'render_property_meta_box',
'property',
'normal',
'high'
);
}
add_action('add_meta_boxes', 'add_property_meta_box');
function render_property_meta_box($post) {
wp_nonce_field('save_property_meta', 'property_meta_nonce');
$area = get_post_meta($post->ID, '_property_area', true);
$floor = get_post_meta($post->ID, '_property_floor', true);
?>
<p>
<label>Площадь (м²):</label>
<input type="number" name="property_area" value="<?php echo esc_attr($area); ?>" />
</p>
<p>
<label>Этаж:</label>
<input type="number" name="property_floor" value="<?php echo esc_attr($floor); ?>" />
</p>
<?php
}
function save_property_meta($post_id) {
if (!isset($_POST['property_meta_nonce']) ||
!wp_verify_nonce($_POST['property_meta_nonce'], 'save_property_meta')) {
return;
}
if (isset($_POST['property_area'])) {
update_post_meta($post_id, '_property_area', sanitize_text_field($_POST['property_area']));
}
if (isset($_POST['property_floor'])) {
update_post_meta($post_id, '_property_floor', sanitize_text_field($_POST['property_floor']));
}
}
add_action('save_post', 'save_property_meta');
Да, это больше кода, но зато без зависимости от плагина, который может измениться в новой версии или вовсе прекратить поддержку.
Не забываем про группировку
CPT редко работают в изоляции — их нужно классифицировать. Для недвижимости логично добавить таксономии «Тип объекта» и «Район»:
function register_property_taxonomies() {
register_taxonomy('property_type', 'property', array(
'labels' => array(
'name' => 'Типы объектов',
'singular_name' => 'Тип объекта'
),
'hierarchical' => true,
'show_in_rest' => true,
));
}
add_action('init', 'register_property_taxonomies');
Практические советы из опыта
- Всегда используйте префиксы для метаполей. _property_area вместо просто
area— это спасёт от конфликтов с другими плагинами. - Не переусердствуйте с количеством полей. Если у вас 30+ Custom Fields, задумайтесь: может, часть данных лучше хранить как JSON в одном поле, а не создавать десятки записей в таблице wp_postmeta.
- Индексируйте важные метаполя. Если вы часто фильтруете записи по определённому полю через WP_Query с meta_query, добейтесь роста производительности через register_meta() с параметром show_in_rest и продуманную структуру индексов в БД.
- Тестируйте на больших объёмах данных. Архитектура, которая летает на 50 записях, может тормозить на 5000. Я всегда генерирую тестовые данные через WP-CLI перед сдачей проекта.
Заключение
Custom Post Types и Custom Fields — это не просто технические возможности WordPress, а полноценный инструмент архитектурного мышления. Когда вы правильно структурируете контент с их помощью, WordPress превращается из простого блога-движка в мощную CMS, способную решать задачи любой сложности — от каталогов и портфолио до сложных бизнес-приложений.
Главный урок, который я вынес: не бойтесь писать код руками, но и не изобретайте велосипед там, где готовые решения вроде ACF экономят время без потери качества. Баланс между гибкостью и эффективностью — вот что отличает опытного разработчика от новичка.