Interactivity API в WordPress — полное руководство

Interactivity API — это стандартная система директив для добавления интерактивности на фронтенд блоков WordPress. Она позволяет разработчикам создавать богатый пользовательский интерфейс (от простых счетчиков до корзин покупок и мгновенной навигации) стандартным способом, который легко поддерживать.

Interactivity API превращает WordPress в современный реактивный фреймворк, сохраняя при этом все преимущества классического PHP-движка.

Interactivity API доступен в WordPress 6.5 и выше.

Концепция (Декларативность и Реактивность)

Раньше для интерактивности использовался императивный подход (например, jQuery): вы вручную искали элемент в DOM и говорили ему, что делать. Это приводило к ошибкам при усложнении логики.

Interactivity API работает декларативно:

  1. Вы описываете состояние (state) данных.
  2. Вы размечаете HTML специальными атрибутами — директивами.
  3. Система сама следит за изменениями: как только данные меняются, 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(). Хранилище состоит из нескольких элементов:

  1. Global State (Глобальное состояние): Данные, общие для всех блоков на странице.

  2. Context (Локальный контекст): Данные, специфичные для конкретного экземпляра блока.

  3. Actions (Действия): Функции, которые меняют состояние или контекст (обычно вызываются через data-wp-on).

  4. Derived State (Вычисляемое состояние): Геттеры, которые возвращают значения, рассчитанные на основе других данных. Они обновляются автоматически при изменении зависимостей.

  5. 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 } не сработает.

Видео