Перейти к содержимому

Плейсхолдеры

Плейсхолдер — место в шаблоне блока, куда подставляется значение: {{ props.title }}. Сами значения живут не в блоке, а в его вхождении на странице — в поле placeholder_values. Один и тот же блок на десяти страницах — десять наборов значений и один шаблон.

В шаблоне Что это Кто заполняет
{{ props.<поле> }} значения полей схемы блока placeholder_values вхождения блока
{{ content }} HTML, полученный из Markdown ключ _markdown в placeholder_values (только markdown-блоки)
{{ data.<слот> }} живые данные витрины привязка слота, см. Биндинги и слоты
@имя переменная сайта настройки сайта

Три первых — переменные Liquid. @имя переменной Liquid не является: подстановка идёт регулярным выражением по уже отрендеренному HTML, поэтому работает и в CSS-части блока, и внутри значений полей. Неизвестное имя заменяется пустой строкой.

Схема блока (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 (dateYYYY-MM-DD, timeHH:MM, datetimeYYYY-MM-DDTHH:MM); серверный валидатор для них требует лишь строку.

Дефолты: когда они подставляются, а когда нет

Заголовок раздела «Дефолты: когда они подставляются, а когда нет»

Дефолты из схемы подставляются при рендере только если placeholder_values пустые целиком. Тогда собирается полный набор значений: default поля, для select/radio — первый options[].value, для switchfalse, для arraymin пустых элементов (по умолчанию один), для 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 — строка в формате 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/.