Как гибко управлять контентом на WordPress: Custom Post Types и Custom Fields

Как гибко управлять контентом на 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');

Практические советы из опыта

  1. Всегда используйте префиксы для метаполей. _property_area вместо просто area — это спасёт от конфликтов с другими плагинами.
  2. Не переусердствуйте с количеством полей. Если у вас 30+ Custom Fields, задумайтесь: может, часть данных лучше хранить как JSON в одном поле, а не создавать десятки записей в таблице wp_postmeta.
  3. Индексируйте важные метаполя. Если вы часто фильтруете записи по определённому полю через WP_Query с meta_query, добейтесь роста производительности через register_meta() с параметром show_in_rest и продуманную структуру индексов в БД.
  4. Тестируйте на больших объёмах данных. Архитектура, которая летает на 50 записях, может тормозить на 5000. Я всегда генерирую тестовые данные через WP-CLI перед сдачей проекта.

Заключение

Custom Post Types и Custom Fields — это не просто технические возможности WordPress, а полноценный инструмент архитектурного мышления. Когда вы правильно структурируете контент с их помощью, WordPress превращается из простого блога-движка в мощную CMS, способную решать задачи любой сложности — от каталогов и портфолио до сложных бизнес-приложений.

Главный урок, который я вынес: не бойтесь писать код руками, но и не изобретайте велосипед там, где готовые решения вроде ACF экономят время без потери качества. Баланс между гибкостью и эффективностью — вот что отличает опытного разработчика от новичка.