Wordpresses

Как добавить свои поля в Gutenberg без плагинов

Если нужно добавить в Gutenberg свои поля для записей, страниц или отдельных блоков, это можно сделать без плагинов — через стандартные возможности WordPress и небольшой код в теме или mu-plugin. На практике есть два разных сценария: поля для всей записи и поля прямо внутри блока. Для каждого подходит свой инструмент, и если их не путать, решение получается аккуратным и предсказуемым.

Ниже разберу оба варианта: как добавить кастомные поля к записи через метабокс и как расширить отдельный блок через block.json и registerBlockType. Это именно тот случай, когда лучше опираться на код, а не на лишний плагин.

Что именно можно добавить в Gutenberg без плагинов

В WordPress под «своими полями» обычно имеют в виду одно из двух:

  • метаполя записи — данные, которые хранятся у поста, страницы или любого другого типа записи;
  • настройки блока — дополнительные поля в боковой панели конкретного блока Gutenberg.

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

Важно понимать ограничение: Gutenberg сам по себе не умеет «из коробки» создавать произвольные интерфейсы для любых полей без кода. Но WordPress даёт для этого нормальные API, и они работают без сторонних расширителей.

Самый простой путь: добавить метаполе к записи

Для полей уровня записи обычно используют register_post_meta() и метабокс в админке. Это надёжнее, чем пытаться хранить данные в произвольных опциях темы, потому что значение привязано к конкретной записи и доступно в шаблонах.

Сначала зарегистрируем метаполе. Код можно положить в functions.php дочерней темы или в отдельный mu-plugin, если не хотите зависеть от темы. Для примера добавим поле _subtitle — дополнительный подзаголовок записи.

add_action( 'init', function () {
    register_post_meta( 'post', '_subtitle', array(
        'type'              => 'string',
        'single'            => true,
        'show_in_rest'      => true,
        'sanitize_callback' => 'sanitize_text_field',
        'auth_callback'     => function () {
            return current_user_can( 'edit_posts' );
        },
    ) );
} );

Здесь ключевой параметр — show_in_rest. Без него Gutenberg не увидит метаполе через REST API, а значит, не сможет нормально работать с ним в редакторе. Для строкового поля обычно хватает sanitize_text_field, чтобы не сохранить мусор или HTML там, где он не нужен.

Теперь добавим сам интерфейс в редакторе. Проще всего сделать метабокс в классической части админки, а значение сохранить через REST-совместимое метаполе. Для этого подойдёт обычный метабокс с полем ввода.

add_action( 'add_meta_boxes', function () {
    add_meta_box(
        'post_subtitle_box',
        'Дополнительный подзаголовок',
        function ( $post ) {
            $value = get_post_meta( $post->ID, '_subtitle', true );
            wp_nonce_field( 'save_post_subtitle', 'post_subtitle_nonce' );
            echo '<p><label for="post_subtitle">Текст подзаголовка</label></p>';
            echo '<input type="text" id="post_subtitle" name="post_subtitle" value="' . esc_attr( $value ) . '" style="width:100%;" />';
        },
        'post',
        'normal',
        'default'
    );
} );

add_action( 'save_post_post', function ( $post_id ) {
    if ( ! isset( $_POST['post_subtitle_nonce'] ) || ! wp_verify_nonce( $_POST['post_subtitle_nonce'], 'save_post_subtitle' ) ) {
        return;
    }

    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        return;
    }

    $value = isset( $_POST['post_subtitle'] ) ? sanitize_text_field( wp_unslash( $_POST['post_subtitle'] ) ) : '';
    update_post_meta( $post_id, '_subtitle', $value );
} );

Этот вариант рабочий, но у него есть нюанс: метабокс живёт в классическом интерфейсе записи, а не в боковой панели Gutenberg. Если вам нужен именно современный интерфейс редактора, лучше подключить поле к панели настроек через JavaScript. Для большинства задач, однако, метабокса достаточно: он простой, понятный и не требует сложной интеграции с редактором.

Как вывести значение в шаблоне

После сохранения поле нужно использовать в теме. Если это подзаголовок, его можно вывести в шаблоне single.php, template-parts или в блоковом шаблоне темы — в зависимости от того, как у вас устроен вывод записи.

<?php
$subtitle = get_post_meta( get_the_ID(), '_subtitle', true );
if ( $subtitle ) :
    echo '<p class="entry-subtitle">' . esc_html( $subtitle ) . '</p>';
endif;
?>

Если поле пустое, блок не выводится. Это нормальная практика: не стоит печатать пустые контейнеры ради формальности.

Если поле нужно именно внутри блока Gutenberg

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

Логика такая: вы добавляете новый атрибут в блок, показываете ему контрол в панели настроек и сохраняете значение вместе с разметкой блока. Для этого используются стандартные скрипты WordPress: wp.hooks, wp.blockEditor, wp.components и wp.element.

Ниже пример для блока core/paragraph, к которому добавим поле customNote. Это демонстрация принципа; в реальном проекте лучше расширять только те блоки, которые вам действительно нужны.

Сначала подключите скрипт в админке:

add_action( 'enqueue_block_editor_assets', function () {
    wp_enqueue_script(
        'my-block-extra-fields',
        get_stylesheet_directory_uri() . '/assets/js/block-extra-fields.js',
        array( 'wp-hooks', 'wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor', 'wp-i18n' ),
        '1.0.0',
        true
    );
} );

Теперь сам JavaScript. Он добавляет атрибут блоку и показывает текстовое поле в инспекторе блока.

( function ( wp ) {
    const { addFilter } = wp.hooks;
    const { createHigherOrderComponent } = wp.compose;
    const { InspectorControls } = wp.blockEditor;
    const { PanelBody, TextControl } = wp.components;
    const { Fragment } = wp.element;

    function addAttributes( settings, name ) {
        if ( name !== 'core/paragraph' ) {
            return settings;
        }

        settings.attributes = Object.assign( {}, settings.attributes, {
            customNote: {
                type: 'string',
                default: '',
            },
        } );

        return settings;
    }

    addFilter(
        'blocks.registerBlockType',
        'my-plugin/add-attributes',
        addAttributes
    );

    const withInspectorControls = createHigherOrderComponent( function ( BlockEdit ) {
        return function ( props ) {
            if ( props.name !== 'core/paragraph' ) {
                return wp.element.createElement( BlockEdit, props );
            }

            const { attributes, setAttributes } = props;

            return wp.element.createElement(
                Fragment,
                {},
                wp.element.createElement( BlockEdit, props ),
                wp.element.createElement(
                    InspectorControls,
                    {},
                    wp.element.createElement(
                        PanelBody,
                        { title: 'Дополнительные настройки', initialOpen: true },
                        wp.element.createElement( TextControl, {
                            label: 'Примечание',
                            value: attributes.customNote,
                            onChange: function ( value ) {
                                setAttributes( { customNote: value } );
                            },
                        } )
                    )
                )
            );
        };
    }, 'withInspectorControls' );

    addFilter(
        'editor.BlockEdit',
        'my-plugin/with-inspector-controls',
        withInspectorControls
    );
} )( window.wp );

Чтобы значение не потерялось при сохранении, его нужно учесть в разметке блока. Для динамических блоков это делается на сервере, а для обычных — через save в JavaScript. Если вы работаете с существующим core-блоком, помните: не все core-блоки одинаково удобно расширять таким способом, и после обновлений WordPress поведение может меняться. Поэтому перед внедрением лучше проверить конкретный блок на тестовом сайте.

Когда лучше выбрать метаполе, а когда — расширение блока

СценарийЧто использоватьПочему
Дополнительный заголовок записиМетаполе записиЗначение относится ко всему контенту
Источник цитаты в конкретном абзацеАтрибут блокаПараметр нужен только одному блоку
Служебный ID для шаблонаМетаполе записиУдобно читать в PHP-шаблоне
Цвет, отступ, примечание для блокаАтрибут блокаЛогичнее хранить вместе с блоком

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

На что обычно спотыкаются при такой настройке

Самая частая ошибка — зарегистрировать метаполе, но забыть show_in_rest. Визуально поле может сохраниться через старый интерфейс, но в Gutenberg оно будет вести себя нестабильно или вообще не появится там, где вы ожидали.

Вторая типичная проблема — отсутствие проверки прав и nonce при сохранении. Если поле редактируют только администраторы, это ещё не повод пропускать защиту. WordPress-редактор работает через AJAX и REST, поэтому проверка доступа должна быть явной.

Третья ошибка — хранить HTML в строковом поле без необходимости. Если вам нужен обычный текст, очищайте его через sanitize_text_field. Если нужен HTML, используйте другой подход и не пытайтесь запихнуть всё в одно поле.

И ещё один практический момент: если вы добавляете код в functions.php, обновление темы может его затереть. Для постоянного решения лучше вынести код в дочернюю тему или небольшой mu-plugin. Это особенно важно, если сайт уже в работе и вы не хотите потерять настройки после обновления.

Как проверить, что всё работает

После добавления кода откройте запись в Gutenberg и проверьте три вещи:

  1. поле отображается в редакторе там, где вы его ожидаете;
  2. значение сохраняется после обновления записи;
  3. данные выводятся на фронтенде через шаблон или блок.

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

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

×
Halloween Game

Сыграй в игру, спаси сайт! Забери приз

Играть