Плейсхолдеры
Плейсхолдер — место в шаблоне блока, куда подставляется значение: {{ props.title }}.
Сами значения живут не в блоке, а в его вхождении на странице — в поле
placeholder_values. Один и тот же блок на десяти страницах — десять наборов значений
и один шаблон.
Четыре источника данных в шаблоне
Заголовок раздела «Четыре источника данных в шаблоне»| В шаблоне | Что это | Кто заполняет |
|---|---|---|
{{ props.<поле> }} |
значения полей схемы блока | placeholder_values вхождения блока |
{{ content }} |
HTML, полученный из Markdown | ключ _markdown в placeholder_values (только markdown-блоки) |
{{ data.<слот> }} |
живые данные витрины | привязка слота, см. Биндинги и слоты |
@имя |
переменная сайта | настройки сайта |
Три первых — переменные Liquid. @имя переменной Liquid не является: подстановка
идёт регулярным выражением по уже отрендеренному HTML, поэтому работает и в
CSS-части блока, и внутри значений полей. Неизвестное имя заменяется пустой строкой.
Пример: схема, шаблон, payload
Заголовок раздела «Пример: схема, шаблон, payload»Схема блока (schema_content, подробный справочник полей — в разделе
Схема полей):
{ "type": "object", "label": "Промо-баннер", "fields": { "title": { "type": "text", "label": "Заголовок", "required": true, "default": "Скидки" }, "accent": { "type": "color", "label": "Цвет акцента", "default": "#e11d48" }, "links": { "type": "array", "label": "Ссылки", "min": 1, "item": { "type": "object", "fields": { "text": { "type": "text", "label": "Текст" }, "url": { "type": "url", "label": "Адрес" } } } } }}Шаблон:
<section style="border-color: {{ props.accent }}"> <h2>{{ props.title }}</h2> <ul> {% for link in props.links %} <li><a href="{{ link.url }}">{{ link.text }}</a></li> {% endfor %} </ul></section>Значения при добавлении блока на страницу:
{ "block_id": 12, "placeholder_values": { "title": "Чёрная пятница", "accent": "#111827", "links": [ { "text": "Каталог", "url": "/catalog" }, { "text": "Условия", "url": "/terms" } ] }}Соответствие типов полей и значений
Заголовок раздела «Соответствие типов полей и значений»| Тип поля | Значение в placeholder_values |
|---|---|
text, textarea, url, email, image, icon, color, date, time, datetime |
строка |
select, radio |
строка из options[].value |
switch |
true / false |
object |
вложенный объект по fields |
array |
массив объектов по item.fields |
Форматы дат проверяются только публичной JSON Schema (date → YYYY-MM-DD,
time → HH:MM, datetime → YYYY-MM-DDTHH:MM); серверный валидатор для них
требует лишь строку.
Дефолты: когда они подставляются, а когда нет
Заголовок раздела «Дефолты: когда они подставляются, а когда нет»Дефолты из схемы подставляются при рендере только если placeholder_values
пустые целиком. Тогда собирается полный набор значений: default поля, для
select/radio — первый options[].value, для switch — false, для array —
min пустых элементов (по умолчанию один), для object — рекурсивно по вложенным
полям, для остальных типов — пустая строка.
Готовый заведомо валидный набор дефолтов можно не собирать руками — его отдаёт
GET /api/v1/blocks/{id}/placeholder-schema в поле example.
Что проверяется при сохранении
Заголовок раздела «Что проверяется при сохранении»Проверка идёт по полям схемы, а не по присланным ключам:
- тип значения должен соответствовать типу поля;
- значение
select/radioдолжно входить вoptions[].value; - поле с
required: trueобязательно, если у него нетdefault; с дефолтом — необязательно; _markdown, если передан, должен быть строкой.
Неизвестные ключи ошибкой не считаются на любом уровне вложенности: шаблон вправе
использовать переменные, которых нет в fields. Публичная JSON Schema это же
обещает через additionalProperties: true.
Ошибки возвращаются с кодом 400 и массивом errors[], где path указывает на
конкретное поле:
{ "errors": [ { "path": "blocks[0].placeholder_values.title", "message": "поле обязательно — передайте значение либо задайте default в схеме блока" }, { "path": "blocks[0].placeholder_values.links[1].url", "message": "ожидалась строка, получено int" } ]}Контракт под конкретный блок
Заголовок раздела «Контракт под конкретный блок»Вместо разбора schema_content руками попросите готовый контракт:
curl -H "Authorization: Bearer pb_..." \ https://page-craft.4partners.io/api/v1/blocks/12/placeholder-schema{ "block_type": "schema", "schema": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "placeholder_values for block #12", "type": "object", "properties": { "title": { "title": "Заголовок", "type": "string", "default": "Скидки" }, "accent": { "title": "Цвет акцента", "type": "string", "default": "#e11d48" } }, "required": ["title"], "additionalProperties": true }, "example": { "title": "Скидки", "accent": "#e11d48", "links": [{ "_id": "8f1c2ad3", "text": "", "url": "" }] }, "binding_slots": []}example можно отправлять как есть. Служебный _id у элементов массива — маркер
элемента для редактора; он безвреден, но и обязательным не является. binding_slots непустой — блок SSR-овый,
дальше по цепочке идут источники данных.
Markdown-блоки
Заголовок раздела «Markdown-блоки»У блока с типом markdown есть зарезервированный ключ _markdown — строка в
формате GitHub Flavored Markdown (таблицы, ~~зачёркнутый~~, автоссылки). При
рендере она конвертируется в HTML и приходит в шаблон как {{ content }}; сами
props при этом тоже доступны. Таблицы автоматически оборачиваются в контейнер
с горизонтальной прокруткой.
<article class="post"> <h1>{{ props.title }}</h1> {{ content }}</article>Где задаются значения
Заголовок раздела «Где задаются значения»| Действие | Запрос |
|---|---|
| создать страницу сразу с блоками | POST /api/v1/pages, массив blocks[] |
| вставить блоки в существующую страницу | POST /api/v1/pages/{id}/blocks |
| заменить состав блоков | PUT /api/v1/pages/{id} |
| поправить значения одного вхождения | PUT /api/v1/pages/{id}/blocks/{pageBlockId} — полная замена placeholder_values |
Полная замена означает именно замену: не переданные ключи исчезают, а не сливаются с прежними.
Источники: backend/src/Service/Block/BlockPlaceholderValidator.php,
backend/src/Service/Block/BlockPlaceholderSchemaBuilder.php,
backend/src/Publishing/BlockRenderer.php,
backend/src/OpenApi/Schemas/PageBlockInput.php,
backend/src/Controller/V1/Block/ShowBlockPlaceholderSchemaPublicAction.php,
backend/src/Controller/V1/PageBlock/.