Сучасний шлях — block.json і register_block_type з шляхом до директорії блоку: метадані, скрипти й стилі описуються декларативно, а PHP-рендер задається через render або render_callback.
Як питають
Динамічний чи статичний блок: у чому різниця?
Як передати дані з PHP у редактор блоку?
Чому блок є в редакторі, але не рендериться на фронтенді?
Gutenbergблокиblock.json
Пояснення
Сучасна реєстрація блоку починається з block.json. У ньому описано все: назва й категорія, схема атрибутів, supports, скрипт редактора, стилі, скрипт фронтенду і, з WordPress 6.1, файл render.php для серверного рендеру. PHP-код зводиться до register_block_type зі шляхом до директорії: WordPress сам прочитає метадані, зареєструє ассети й підключить їх лише там, де блок реально використаний.
Ключове рішення при проєктуванні — статичний чи динамічний блок. Статичний зберігає готовий HTML у post_content через save(): швидко, не залежить від плагіна, але контент застигає. Динамічний повертає з save() null, а розмітку будує PHP на кожен показ: правильний вибір для списків, цін, будь-чого, що змінюється або залежить від користувача.
Атрибути статичних блоків живуть у коментарях розмітки, тому зміна схеми чи save() без масиву deprecated ламає всі вже вставлені блоки. Дані з PHP у редактор передають через REST API або inline-скрипт до editorScript, а вивід у render.php обовʼязково екранують. Для інтерактивності на фронтенді замість власного React-бандла зараз використовують Interactivity API з viewScriptModule.
Що block.json є єдиним джерелом метаданих: назва, атрибути, supports, editorScript, style, viewScript, а PHP лише реєструє директорію.
Різницю між статичним блоком, у якого HTML зберігається в post_content із save(), і динамічним, який рендериться PHP на кожен показ.
Що атрибути блоку зберігаються в коментарі-розмітці, тому зміна їхньої схеми потребує deprecations у JS, інакше редактор покаже block validation error.
Що дані з PHP у редактор передаються через REST API, wp_localize_script або wp_add_inline_script на editorScript, а не через глобальні змінні в шаблоні.
Що збірка йде через @wordpress/scripts, а render.php у block.json з WP 6.1 замінює render_callback.
Типові помилки
Реєструвати блок лише в JS через registerBlockType без block.json: WordPress не знає про ассети й не може лениво їх завантажити.
Робити статичний блок для контенту, який змінюється: список останніх постів, курси, ціни, бо збережений HTML застаріває.
Змінювати атрибути або розмітку save() без deprecated-версій і ламати всі вже вставлені блоки.
Виводити через render_callback необроблений HTML з атрибутів без esc_html і wp_kses_post.
Підключати editorScript на фронтенді або viewScript в адмінці, роздуваючи обидва бандли.
ПОРАДА
Уточніть, що туторіали з wp.blocks.registerBlockType у JS без block.json уже вважаються застарілими. Згадайте render.php і Interactivity API як актуальний напрям.
Додаткові питанняЗ ВІДПОВІДЯМИ
Статичний блок генерує фінальний HTML у save() і зберігає його в post_content; на фронтенді PHP лише віддає цей HTML. Динамічний блок має save() що повертає null, а розмітку будує PHP через render.php або render_callback на кожен показ. Статичний швидший і не залежить від плагіна, динамічний потрібен для даних, що змінюються, і для всього, що залежить від контексту користувача.
Найчистіше через REST API: редактор запитує дані через apiFetch, це працює й для динамічних селекторів. Для невеликих статичних налаштувань є wp_add_inline_script на handle editorScript із JSON, або wp_localize_script. Серверні атрибути можна також задати у block.json як default і перекривати через фільтр block_type_metadata.
Масив попередніх версій save() і атрибутів у JS-визначенні блоку. Коли редактор бачить блок, чия збережена розмітка не збігається з поточним save(), він пробує старі версії й мігрує атрибути. Без цього користувач отримує «This block contains unexpected or invalid content» на кожному старому пості після оновлення плагіна.
Через Interactivity API з WP 6.5: у block.json задається viewScriptModule, розмітка отримує директиви data-wp-interactive, data-wp-on--click, data-wp-bind, а стан описується в store. Це дає легкий рантайм без окремого бандла React на фронтенді й серверний рендер із гідрацією.