Свой виджет и блок WordPress: рабочие приёмы
Классический виджет и блок редактора решают разные задачи. Разбираем, что выбрать для WordPress 6.x, как зарегистрировать оба варианта и какие ошибки чаще всего ломают редактор и вывод на сайте.

В WordPress 6.x один и тот же компонент можно добавить двумя способами: классическим виджетом для области сайдбара или блоком для редактора записей и виджетов. Ошибка выбора стоит дорого: виджет плохо управляется в контенте, а блок без серверного рендера легко теряет данные в кэше и на старых шаблонах. Ниже — практическое сравнение, рабочие заготовки и критерии, по которым стоит выбрать один из вариантов.
Сначала определите место компонента
Виджет отвечает за заранее предусмотренную область темы: сайдбар, подвал или другую зарегистрированную область. Администратор выбирает его в разделе «Внешний вид → Виджеты», но не вставляет произвольно между абзацами записи.
Блок живёт внутри редактора Gutenberg. Его можно поставить между заголовком и изображением, повторить несколько раз на одной странице и настроить отдельно для каждой записи. В WordPress 6.x блоки также используются в редакторе виджетов, если активная тема поддерживает соответствующий интерфейс.
Если редактор должен управлять местом компонента, создавайте блок. Если место заранее задано темой, а компонент должен жить в сайдбаре или подвале, виджет всё ещё остаётся практичным решением.
Два подхода и их цена
| Подход | Где работает | Что выигрываете | Чем платите |
|---|---|---|---|
Классический WP_Widget | Сайдбар и зарегистрированные области темы | Простая настройка через админку, не нужен JavaScript | Нельзя свободно вставить компонент в текст записи, интерфейс устаревший |
| Блок Gutenberg | Редактор записей, страниц и блоковых шаблонов | Перетаскивание, повторное использование, отдельные настройки каждого экземпляра | Нужны JavaScript-сборка, схема атрибутов и проверка совместимости с темой |
| Блок с серверным рендером | Те же места, но HTML формируется PHP | Данные обновляются без сохранения разметки в записи, проще контролировать вывод | Каждый вывод обращается к PHP и потенциально к базе данных |
Практическое правило: рекламный или информационный элемент в сайдбаре чаще проще сделать виджетом. Карточку товара, список событий или призыв к действию внутри контента лучше оформлять блоком. Если данные меняются после публикации, рассмотрите серверный рендер.
Классический виджет через WP_Widget
Пример рассчитан на WordPress 6.x и PHP 8.1 или новее. Он выводит заголовок и текст в зарегистрированной области темы. Код лучше размещать в собственном небольшом плагине, а не в файле темы: при смене темы компонент не исчезнет.
<?php
/**
* Plugin Name: Site Notice Widget
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
final class Site_Notice_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'site_notice_widget',
'Уведомление сайта'
);
}
public function widget( $args, $instance ) {
$title = isset( $instance['title'] )
? $instance['title']
: '';
$text = isset( $instance['text'] )
? $instance['text']
: '';
echo $args['before_widget'];
if ( $title !== '' ) {
echo $args['before_title'];
echo esc_html( $title );
echo $args['after_title'];
}
echo '<p>' . esc_html( $text ) . '</p>';
echo $args['after_widget'];
}
public function form( $instance ) {
$title = isset( $instance['title'] )
? $instance['title']
: '';
$text = isset( $instance['text'] )
? $instance['text']
: '';
?>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
Заголовок
</label>
<input class="widefat"
id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
type="text"
value="<?php echo esc_attr( $title ); ?>">
</p>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'text' ) ); ?>">
Текст
</label>
<textarea class="widefat"
id="<?php echo esc_attr( $this->get_field_id( 'text' ) ); ?>"
name="<?php echo esc_attr( $this->get_field_name( 'text' ) ); ?>"><?php
echo esc_textarea( $text );
?></textarea>
</p>
<?php
}
public function update( $new_instance, $old_instance ) {
return array(
'title' => sanitize_text_field( $new_instance['title'] ?? '' ),
'text' => sanitize_textarea_field( $new_instance['text'] ?? '' ),
);
}
}
function register_site_notice_widget() {
register_widget( 'Site_Notice_Widget' );
}
add_action( 'widgets_init', 'register_site_notice_widget' );
После активации плагина откройте «Внешний вид → Виджеты» и добавьте «Уведомление сайта» в доступную область. Проверка простая: виджет появляется в списке, а после сохранения темы выводится обёртка из $args['before_widget'] и текст.
Что важно не пропустить в виджете
- Экранируйте вывод в момент вывода: для обычного текста подходит
esc_html(), для атрибута —esc_attr(). - Очищайте данные формы в
update(). Не сохраняйте пользовательский HTML, если он не нужен компоненту. - Используйте обёртки темы из
$args. Иначе виджет может выглядеть чужеродно или сломать стили сайдбара. - Не привязывайте регистрацию к загрузке конкретной страницы. Хук
widgets_initнужен именно для регистрации виджетов.
Блок Gutenberg с атрибутами
Для блока используйте структуру с block.json. Такой файл описывает имя блока, версию API и подключаемые скрипты. Ниже приведены фрагменты для WordPress 6.x и Block API v3. Сборку JavaScript удобно делать средствами официального пакета @wordpress/scripts; создавать конфигурацию webpack вручную для простого блока не требуется.
{
"apiVersion": 3,
"name": "site/notice",
"title": "Уведомление сайта",
"category": "widgets",
"editorScript": "file:./index.js",
"style": "file:./style.css"
}
Регистрация блока в PHP должна использовать путь к каталогу, где лежит block.json:
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
function site_register_notice_block() {
register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'site_register_notice_block' );
В этом примере сборщик помещает block.json и собранный index.js в каталог build. Проверка: в редакторе по кнопке добавления блока находится «Уведомление сайта», а в консоли браузера нет ошибки загрузки скрипта.
Редактор и сохранённая разметка
Для простого текстового блока достаточно хранить строку в атрибуте. В WordPress 6.x компонент RichText даёт редактору форматируемое поле, а useBlockProps добавляет стандартные свойства блока.
import { registerBlockType } from '@wordpress/blocks';
import { RichText, useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'site/notice', {
attributes: {
text: {
type: 'string',
source: 'html',
selector: 'p',
},
},
edit( { attributes, setAttributes } ) {
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
<RichText
tagName="p"
value={ attributes.text }
onChange={ ( text ) => setAttributes( { text } ) }
placeholder="Введите уведомление"
/>
</div>
);
},
save( { attributes } ) {
const blockProps = useBlockProps.save();
return (
<div { ...blockProps }>
<RichText.Content tagName="p" value={ attributes.text } />
</div>
);
},
} );
Здесь source: "html" означает, что значение извлекается из HTML-элемента p в сохранённой разметке. Если позже изменить структуру HTML или селектор, старые записи могут перестать корректно отображаться. Это не косметическая деталь, а часть обратной совместимости блока.
Когда нужен серверный рендер
Если блок показывает актуальное количество товаров, данные из внешнего сервиса или результат запроса к базе, не записывайте готовый результат в пост. Зарегистрируйте блок с файлом render.php и формируйте HTML на сервере. Так публикация не устареет, но каждый вывод потребует выполнения PHP, а иногда и запроса к базе.
Для публичного блока с динамическими данными заранее определите кэширование, обработку недоступного сервиса и экранирование ответа. Инвалидация кэша — отдельная тема; здесь важно не смешивать её с регистрацией блока.
Типичные ошибки и их цена
- Блок не появляется в редакторе. Чаще всего PHP регистрирует не каталог сборки, отсутствует собранный
index.jsили не активирован плагин. Проверьте путь и вкладку Network в инструментах разработчика. - «This block contains unexpected or invalid content». HTML, который возвращает
save(), больше не совпадает с сохранённой разметкой. Либо сохраните обратную совместимость, либо добавьте механизм миграции атрибутов. - Виджет выводит теги вместо форматирования. Это ожидаемо при использовании
esc_html(). Если компоненту действительно нужен ограниченный HTML, используйте разрешённый набор тегов и отдельную очистку, а не вывод сырого значения. - Стиль блока влияет на весь сайт. Селекторы вроде
pили.noticeбез области блока слишком общие. Ограничивайте CSS классом блока, который возвращаетuseBlockProps. - После обновления темы виджет исчез. Тема могла удалить зарегистрированную область или изменить её идентификатор. Сам виджет при этом остаётся в системе, но ему некуда выводиться.
Когда выбирать каждый вариант
Выбирайте WP_Widget, если компонент нужен только в сайдбаре или подвале, его настройки просты, а редактору не требуется управлять позицией. Это самый короткий путь для уведомления, списка ссылок или небольшого промоблока.
Выбирайте блок, если контент-менеджер должен вставлять компонент в произвольное место записи, менять его параметры и использовать несколько экземпляров с разными значениями. Для динамических данных используйте серверный рендер, но учитывайте нагрузку на PHP и базу.
Не делайте одновременно виджет и блок только ради «универсальности». Две реализации означают два интерфейса настроек, два набора тестов и два места, где может отличаться HTML. Если компонент нужен в сайдбаре и в тексте, вынесите общую бизнес-логику в отдельную PHP-функцию, а вывод каждого интерфейса оставьте специфичным для его API.
Что делать дальше
Сначала проверьте компонент на WordPress 6.x с активной темой, которая используется на продакшене. Для блока протестируйте повторное открытие старой записи после изменения HTML, а для виджета — перенос на другую тему и отсутствие доступной области.
В продакшене смотрите не только на внешний вид. Проверьте ошибки JavaScript, время ответа страницы с динамическим блоком и число запросов к базе. После этого зафиксируйте публичные атрибуты блока и не меняйте их без миграции старого контента.
Сноска. Block API — интерфейс WordPress для регистрации и описания блоков редактора: их имени, атрибутов, скриптов и поведения при сохранении. WP_Widget — базовый класс старой модели виджетов, через который компонент получает форму настроек и вывод в области темы.
Редактор изображений: Убрать лишнее, заменить фон, добавить объект, расширить кадр — на вашем изображении.
Спросить за 20 ₽Источники: WordPress Developer Resources: Block Editor Handbook, WordPress Developer Resources: WP_Widget
Частые вопросы
Можно ли сделать один компонент одновременно виджетом и блоком?
Почему мой блок не появляется в списке редактора?
Что делать с ошибкой «This block contains unexpected or invalid content»?
Нужен ли серверный рендер для каждого собственного блока?
Можно ли использовать пример с другой версией WordPress?
Почему виджет есть в админке, но не выводится на сайте?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.