Custom Containers
Custom Containers позволяют расширять функционал редактора своими клиентскими контейнерами без разработки отдельного виджета внутри Verstka.
Клиент описывает контейнеры в конфиге: как они называются, какого они размера, какую иконку показывать в панели создания, какой HTML рендерить, какие параметры можно менять в редакторе и какой маркер оставить в итоговом HTML для замены на стороне сайта.
Для чего это нужно
Самый частый сценарий - вставить в статью место под клиентский виджет, а затем заменить это место на сайте клиента обычным строковым replace по HTML-комментарию:
<!-- ReplaceMarker: banner -->Например, редактор расставляет контейнеры banner, article-authors, buy-button, а сайт клиента после получения HTML заменяет маркеры на реальные CMS-виджеты, рекламные блоки, авторские карточки или кнопки покупки.
Другой сценарий - собрать конфиг на стороне клиента уже с реальными данными статьи. Например, если клиентская админка знает авторов статьи, текущую рубрику или товар, она может сразу положить эти данные в html или customProps.
Передача конфига
Конфиг передается в metadata.customContainers при открытии сессии:
- интеграция:
POST /integration/session/open; - staff-страница
/new: backend читаетapp/staff/custom_containers.jsonи кладет его в metadata.
Редактор получает конфиг из GET /session/{id} как поле customContainers.
Формат:
type ClientConfig = {
customContainers: CustomContainerDefinition[]
}Контейнеров может быть любое количество. Каждый контейнер должен иметь уникальный id. Значение — массив определений, не объект и не map.
Конфиг сохраняется в metadata_json при создании сессии. Повторный session/open для уже существующего материала metadata (и customContainers) не обновляет.
Как это работает
- Клиент формирует
customContainersна своей стороне. - Verstka сохраняет массив в
metadataсессии и отдает его вGET /session. - В редакторе появляется отдельная кнопка создания для каждого контейнера.
- Дизайнер размещает контейнер в статье и, если нужно, меняет параметры через правую панель.
- В итоговом HTML рендерится контейнер, его атрибуты, HTML из конфига и, если указан
replaceMarker, комментарий вида<!-- ReplaceMarker: value -->. - Сайт клиента заменяет маркер или использует HTML/атрибуты контейнера для собственной логики.
Access in code
У любого контейнера в редакторе есть отдельная секция Access in code. По умолчанию codeName равен null, поэтому в HTML не появляется лишний атрибут.
Если дизайнер нажимает плюс в этой секции и задает Code name, непустое значение попадает в итоговую разметку как публичный атрибут:
<div data-vrstk-container-code-name="heroImage">...</div>Это удобно для embed-кода и клиентской интеграции, когда нужно найти конкретный контейнер через DOM. Для кода без iframe можно искать в текущем document; для iframe доступ к window.parent.document возможен только при same-origin условиях браузера.
Формат контейнера
type CustomContainerDefinition = {
id: string
name: string
toolIcon: string
width: number
height: number
resizable?: boolean
dummyImageUrl?: string | null
html?: string
replaceMarker?: string | null
attributes?: Record<string, string | number | boolean | null>
customProps?: Record<string, string | number | boolean | null>
tool?: {
sectionsConfig: Record<string, { widgetProperties: string[] }>
controlsConfig: Record<string, CustomControlConfig>
}
}После нормализации в редакторе опциональные поля получают значения по умолчанию: resizable: true, html: '', dummyImageUrl: null, replaceMarker: null, пустые attributes / customProps / tool.
Поля
| Поле | Тип | Описание |
|---|---|---|
id | string | Уникальный технический ID контейнера. Используется в сохраненных данных и маркерах. |
name | string | Название в UI редактора и текст editor-only заглушки внутри пустого контейнера. |
toolIcon | string | Иконка кнопки создания: inline SVG строкой или имя иконки редактора (например version). |
width | number | Стартовая ширина контейнера в редакторе. |
height | number | Стартовая высота контейнера в редакторе. |
resizable | boolean | Можно ли менять размер контейнера в редакторе. Это общее свойство всех контейнеров. По умолчанию true. |
dummyImageUrl | string | null | URL картинки-заглушки для canvas-редактора. В превью и на сайте клиента не рендерится. |
html | string | HTML, который будет отрендерен внутри контейнера. Может включать <style>. |
replaceMarker | string | null | Если задан, в HTML появится <!-- ReplaceMarker: value -->. |
attributes | Record | Статические параметры контейнера. В HTML попадают как data-vrstk-custom-param-*. |
customProps | Record | Начальные значения параметров, которые могут редактироваться через контролы. В HTML — те же data-vrstk-custom-param-*. |
tool | object | Описание контролов правой панели. Если пустой, у контейнера нет настроек. |
Правила рендера
Custom Container ведет себя по тому, какие поля есть в конфиге:
| Что есть в конфиге | Что рендерится |
|---|---|
html непустой | Санитизированный HTML внутри контейнера. |
html пустой (editor) | dummyImageUrl, если задан; иначе placeholder с текстом name. |
html пустой (preview/SSR) | Пустой контейнер без визуальной заглушки. |
replaceMarker задан | HTML-комментарий <!-- ReplaceMarker: value -->. |
tool.controlsConfig задан | Контролы в правой панели редактора (только whitelist типов). |
resizable: false | В редакторе скрываются resize-ручки контейнера. |
HTML очищается перед выводом: удаляются <script>, inline-обработчики событий и небезопасные URL вроде javascript:.
dummyImageUrl и fallback с name нужны только в canvas-редакторе, чтобы дизайнер видел пустой контейнер и мог его выбрать. В превью, SSR и на сайте клиента эти заглушки не попадают в разметку: остается сам контейнер с data-vrstk-custom-id, параметрами и комментарием-маркером.
И attributes, и customProps сериализуются одинаково: data-vrstk-custom-param-{kebab-case}. При совпадении ключей значение из customProps побеждает. null пропускается.
Маркер замены
replaceMarker нужен для простого и надежного server-side replacement на сайте клиента.
Конфиг:
{
id: 'banner',
name: 'Баннер',
replaceMarker: 'banner',
html: '',
dummyImageUrl: null,
width: 970,
height: 250,
resizable: false,
toolIcon: '<svg viewBox="0 0 16 16">...</svg>',
attributes: {},
customProps: {},
tool: {
sectionsConfig: {},
controlsConfig: {}
}
}В HTML появится:
<!-- ReplaceMarker: banner -->На PHP это можно заменить обычным str_replace:
$articleHtml = str_replace(
'<!-- ReplaceMarker: banner -->',
renderBannerWidget($article),
$articleHtml
);HTML с реальными данными
Так как конфиг собирается на клиентской стороне, в html можно положить уже готовую разметку с реальными данными статьи:
- авторы статьи;
- текущая рубрика;
- ID товара;
- название бренда;
- текст дисклеймера;
- HTML, который клиент уже умеет собирать в своей CMS.
Важно: значения из CMS нужно экранировать до вставки в HTML. Verstka дополнительно очищает HTML, но это не заменяет нормальную обработку данных на стороне клиента.
Контролы
Контролы позволяют дать дизайнеру изменить параметры контейнера в редакторе. Эти значения сохраняются в customProps и попадают в итоговый HTML как параметры контейнера.
Подробное описание доступных контролов: Контролы.
Готовые сценарии: Примеры.