Interactivity API в WordPress — полное руководство
Interactivity API — это стандартная система директив для добавления интерактивности на фронтенд блоков WordPress. Она позволяет разработчикам создавать богатый пользовательский интерфейс (от простых счетчиков до корзин покупок и мгновенной навигации) стандартным способом, который легко поддерживать.
Interactivity API превращает WordPress в современный реактивный фреймворк, сохраняя при этом все преимущества классического PHP-движка.
Interactivity API доступен в WordPress 6.5 и выше.
Концепция (Декларативность и Реактивность)
Раньше для интерактивности использовался императивный подход (например, jQuery): вы вручную искали элемент в DOM и говорили ему, что делать. Это приводило к ошибкам при усложнении логики.
Interactivity API работает декларативно:
- Вы описываете состояние (state) данных.
- Вы размечаете HTML специальными атрибутами — директивами.
- Система сама следит за изменениями: как только данные меняются, UI обновляется автоматически.
Преимущества:
- Легкость: ядро системы весит всего ~10 КБ.
- Производительность: быстрая загрузка без блокировки рендеринга.
- SEO-дружелюбность: WordPress обрабатывает директивы на сервере (PHP), поэтому пользователь сразу получает готовый HTML.
- Совместимость: блоки могут легко общаться друг с другом через общее состояние.
Подготовка и создание блока
1. Создание заготовки
Проще всего создать интерактивный блок с помощью официального шаблона:
npx @wordpress/create-block@latest my-block --template @wordpress/create-block-interactive-template
При выборе варианта используйте typescript, если вам нужна типизация.
2. Настройка block.json
Чтобы WordPress понял, что блок интерактивный, добавьте в block.json:
{
"supports": { "interactivity": true },
"viewScriptModule": "file:./view.js"
}
Примечание: скрипты должны быть оформлены как Script Modules.
Директивы — «оживляем» HTML
Директивы — это атрибуты с префиксом data-wp-, которые добавляются в файлы render.php (для динамических блоков) или save.js (для статических).
Основные директивы:
-
data-wp-interactive: «Включает» API для элемента и его дочерних узлов. В значении указывается пространство имен (namespace). -
data-wp-context: Создает локальное состояние, доступное только этому элементу и его детям. Принимает JSON-строку. -
data-wp-bind--[атрибут]: Связывает атрибут HTML (например, hidden или href) со значением из состояния. -
data-wp-class--[имя-класса]: Добавляет или удаляет CSS-класс в зависимости от логического значения (true/false). -
data-wp-on--[событие]: Назначает обработчик события (например,data-wp-on--click). -
data-wp-text: Устанавливает внутренний текст элемента. data-wp-each: Используется в теге<template>для циклического рендеринга списков из массива.
Хранилище (The Store) — «мозг» блока
Логика описывается в файле view.js через функцию store(). Хранилище состоит из нескольких элементов:
-
Global State (Глобальное состояние): Данные, общие для всех блоков на странице.
-
Context (Локальный контекст): Данные, специфичные для конкретного экземпляра блока.
-
Actions (Действия): Функции, которые меняют состояние или контекст (обычно вызываются через
data-wp-on). -
Derived State (Вычисляемое состояние): Геттеры, которые возвращают значения, рассчитанные на основе других данных. Они обновляются автоматически при изменении зависимостей.
- Side Effects (Побочные эффекты): Функции, которые реагируют на изменения данных (например,
data-wp-watch).
Пример структуры view.js:
import { store, getContext } from '@wordpress/interactivity';
const { state } = store('myPlugin', {
state: {
get isDark() { return state.theme === 'dark'; } // Вычисляемое состояние
},
actions: {
toggle: () => {
const context = getContext(); // Получаем локальный контекст
context.isOpen = !context.isOpen;
}
},
callbacks: {
logChange: () => {
console.log("Состояние изменилось!"); // Побочный эффект
}
}
});
Связь с сервером (PHP и SSR)
Interactivity API позволяет инициализировать состояние прямо в PHP через функцию wp_interactivity_state().
Зачем это нужно?
- SEO: Поисковики видят уже заполненный данными HTML.
- Безопасность и переводы: Вы можете использовать PHP-функции для генерации одноразовых кодов (nonces) или перевода строк через __() прямо внутри состояния.
Пример в render.php:
// Устанавливаем начальное состояние на сервере
wp_interactivity_state( 'myPlugin', array(
'counter' => 10,
'message' => __('Привет, мир!', 'textdomain')
));
// Удобный помощник для вывода контекста
$context = array( 'isOpen' => false );
?>
<div data-wp-interactive="myPlugin" <?php echo wp_interactivity_data_wp_context($context); ?>>
<span data-wp-text="state.message"></span>
<button data-wp-on--click="actions.toggle">Кнопка</button>
</div>
Продвинутые возможности
-
Асинхронные действия: Если действие выполняет запрос (например, через fetch), используйте генераторы (
function*) иyieldвместоasync/await. Это необходимо для правильного восстановления контекста после завершения асинхронной операции. -
Приватные хранилища: Вы можете скрыть данные своего плагина от других, используя параметр
lockв функцииstore(). -
TypeScript: API полностью поддерживает типизацию, позволяя автоматически выводить типы свойств хранилища или задавать их вручную.
- Клиентская навигация: Пакет
@wordpress/interactivity-routerпозволяет перемещаться между страницами без полной перезагрузки, сохраняя при этом состояние интерактивных блоков.
В произвольном HTML
Interactivity API не ограничивается только блоками Gutenberg; его можно использовать для добавления интерактивности в любую часть WordPress, включая классические темы или произвольный HTML-код.
Для реализации этого напрямую в HTML вам потребуется выполнить три основных шага:
- подготовить разметку с директивами.
- инициализировать состояние на стороне сервера (PHP).
- описать логику на стороне клиента (JS).
1. Серверная часть (PHP): Подготовка и обработка
В классических темах или произвольных шаблонах вам нужно вручную вызвать процесс обработки директив. Для этого используется функция wp_interactivity_process_directives().
Пример в файле шаблона (например, index.php или footer.php):
<?php // 1. Инициализируем глобальное состояние на сервере wp_interactivity_state( 'myCustomApp', array( 'isCounterVisible' => true, 'count' => 0, 'title' => __( 'Мой интерактивный HTML', 'textdomain' ) )); // 2. Используем буферизацию вывода, чтобы захватить HTML и обработать его ob_start(); ?> <!-- HTML разметка с директивами --> <div data-wp-interactive="myCustomApp" class="my-container"> <h2 data-wp-text="state.title"></h2> <div data-wp-bind--hidden="!state.isCounterVisible"> <p>Счетчик: <span data-wp-text="state.count">0</span></p> <button data-wp-on--click="actions.increment">Увеличить</button> </div> <button data-wp-on--click="actions.toggleVisibility"> <span data-wp-text="state.isCounterVisible ? 'Скрыть' : 'Показать'"></span> </button> </div> <?php $html = ob_get_clean(); // 3. Обрабатываем директивы перед выводом на экран echo wp_interactivity_process_directives( $html ); ?>
2. Клиентская часть (JavaScript): Логика
Даже если вы не используете блоки, логика должна быть оформлена как Script Module, чтобы она могла импортировать зависимости из @wordpress/interactivity.
Пример view.js (зарегистрированного как модуль):
import { store } from '@wordpress/interactivity';
// Создаем хранилище с тем же пространством имен
const { state } = store( 'myCustomApp', {
state: {
// Здесь можно добавить вычисляемые свойства (Derived State)
},
actions: {
increment: () => {
state.count++; // Прямая мутация состояния
},
toggleVisibility: () => {
state.isCounterVisible = !state.isCounterVisible;
}
}
});
Ключевые моменты при работе без блоков:
-
Функция обработки: wp_interactivity_process_directives() — это ядро системы для SSR (Server Side Rendering). Она находит директивы в строке HTML и заменяет их содержимое на актуальные данные из состояния до того, как страница уйдет в браузер.
-
Инициализация данных: Используйте wp_interactivity_state() для глобальных данных или wp_interactivity_data_wp_context() для локальных данных конкретного элемента.
-
SEO и производительность: Благодаря серверной обработке, пользователь получает уже готовый HTML (например, с числом «0» в спане), а не пустые теги, которые заполняются только после загрузки JS.
- Подключение скриптов: Вам нужно убедиться, что ваш JavaScript-файл подключен как модуль (через wp_enqueue_script_module()), иначе import { store } не сработает.