Вставка фрейма и служебные блоки
Вызов <!-- frame/имя /--> выводит фрейм в разметке другого фрейма или в тексте страницы. Основные примеры — в разделе «Вложить фрейм во фрейм».
API — https://onpress.pro/api/v2, SITE — id сайта, OP_TOKEN — токен API. Адреса запросов и общие параметры — в общих правилах API, права — в авторизации.
| Раздел | Содержание |
|---|---|
| Синтаксис вызова | формы записи |
| Параметры вызова | типы и значения параметров |
| Содержимое вставки | текст парной вставки |
| Служебные блоки | текст страницы и значения полей |
| Пределы | глубина и число вызовов |
| Где работает вставка | страница и язык вызова |
| Проверить вставки | проверка до записи |
Вставка фрейма — HTML-комментарий <!-- frame/имя /-->, на месте которого сборка выводит фрейм с этим слагом или id. Служебные блоки своей верстки не имеют, они выводят текст страницы, содержимое вставки, список и одно значение. Первые три вы ставите атрибутом на тег фрейма: data-op-html="page.content", data-op-html="frame.content" и data-op-repeat, а значение без тега вокруг — блоком <!-- onpress/value … /-->. Вызов и блоки работают в разметке фрейма и в тексте страницы.
API хранит разметку фрейма байт в байт, а вызовы разбирает при каждой сборке. Выгрузка текста страницы GET /pages/{ref}/markdown отдает вызовы фреймов в форме frame/имя. Сколько вызовов и блоков в разметке, считает поле inserts отчета о разметке: ключ op/frame — вызовы фреймов, op/content, op/slot, op/value и op/repeat — служебные блоки, в том числе записанные атрибутами data-op-html и data-op-repeat.
Синтаксис вызова
Одиночный вызов <!-- frame/имя /--> выводит фрейм целиком. Парный вызов образуют строки <!-- frame/имя --> и <!-- /frame -->, текст между ними — содержимое вставки. Параметры — JSON-объект через пробел после имени, в обеих формах. Например, врезка с заголовком в тексте страницы:
<!-- frame/callout--warning {"title":"Проверьте перед отправкой"} -->
В черновике могут быть неверные имена и даты.
<!-- /frame -->
| Правило | Как писать |
|---|---|
| пробелы | после <!-- и перед /--> или --> — хотя бы один пробел или перевод строки; <!-- /frame --> — тоже с пробелами |
| имя | слаг или id фрейма: латиница в нижнем регистре, цифры, - и _, первый символ — буква или цифра |
| параметры | JSON-объект, ключи и строки в двойных кавычках |
| закрытие | <!-- /frame --> закрывает последний открытый парный вызов, поэтому парные вызовы поддерживают вложенность |
Двойной дефис внутри строки параметра пишите как \u002d\u002d, тогда значение не закроет комментарий раньше времени. Вызов с ошибкой в JSON сборка не разбирает: в inserts он есть, имени в frame_refs нет, на странице на его месте пусто.
Параметры вызова
Все ключи JSON-объекта, кроме служебных, сборка передает во фрейм параметрами. Значение — строка, число, логическое значение, список или объект. Внутри вызванного фрейма параметр — поле данных frame.<ключ>, вложенный ключ — через точку: frame.data.title. Каждый вызов сборка собирает заново из исходника фрейма на месте вызова, поэтому два вызова с разными параметрами не делят одну копию. Например, одна секция выводит разные наборы, потому что повторитель берет имя набора из вызова:
<!-- frame/site__bento {"source":"home_bento"} /-->
<!-- frame/site__bento {"source":"pricing_bento"} /-->
Во фрейме site__bento:
<h2 data-op-repeat="frame.source">{{item.title}}</h2>
| Служебный ключ | Что делает |
|---|---|
name, ref, frame, slug, id | называют фрейм; в форме frame/имя имя дает адрес вызова. Ключ с другим фреймом дает frame_ref_conflict: запись фрейма отвечает 400, на странице на месте вызова пусто |
class | оборачивает вывод фрейма в <div class="…"> |
lock, metadata, className | заняты платформой, параметрами не уходят |
type | в вызове с именем фрейма — обычный параметр frame.type; в вызове без имени называет фрейм по типу страницы |
Параметр url не называйте: поле frame.url занято платформой, как frame.id.
| Где во фрейме | Что получает frame.<ключ> |
|---|---|
поле данных {{frame.<ключ>}}, атрибуты data-op-* и data-op-bind | строку, число или логическое значение; объект и список поле данных не подставляет |
блок onpress/value | строку, число или логическое значение |
параметр data-op-repeat, служебного блока или вложенного вызова, значение которого целиком frame.<ключ> | значение параметра любого типа; нет параметра — сборка снимает атрибут, и блок берет значение по умолчанию |
source повторителя | список из параметра, объект — список из одного элемента, строка — имя набора, см. повторитель |
Атрибут служебного блока или вложенного вызова, значение которого целиком page.<поле>, сборка тоже заменяет значением поля страницы, а без значения снимает. Строку, которая только похожа на имя поля, пишите с префиксом raw:: сборка снимет префикс и оставит строку. Атрибуты match, limit, offset повторителя и bind блока onpress/value сборка так не заменяет, поля данных в них разбирает сам блок, и frame.<ключ> там не работает.
Внутри повторителя значение атрибута вызова item или item.<поле> сборка заменяет элементом или его полем, сборка передает объект целиком; нет поля — атрибут снят. Например, карточка получает элемент набора одним параметром: <!-- frame/card {"data":"item"} /-->, а во фрейме card поле данных frame.data.title выводит заголовок.
Содержимое вставки
Содержимое вставки — текст между <!-- frame/имя --> и <!-- /frame --> без переводов строки по краям. Фрейм выводит его атрибутом data-op-html="frame.content" или разбирает повторителем с источником slot.faq. В тексте страницы содержимое вставки остается частью текста страницы: выгрузка и повторная публикация возвращают его без изменений. Поля {{…}} в содержимом вставки сборка подставляет значениями страницы. Например, вопросы во фрейме faq:
<!-- frame/faq -->
### Сколько это стоит?
Бесплатно на любом тарифе.
<!-- /frame -->
Служебные блоки
Атрибут тега фрейма выводит текст страницы, содержимое вставки или список, а значение без тега вокруг — блоком onpress/value. Тот же вывод дают и блоки-комментарии <!-- onpress/имя … /-->, парный блок завершает строка <!-- /onpress/имя -->.
| Что выводит | Атрибут на теге | Блок-комментарий |
|---|---|---|
| текст страницы | data-op-html="page.content" | <!-- onpress/content /--> |
| содержимое текущей вставки | data-op-html="frame.content" | <!-- onpress/slot /--> |
| разметку по разу на элемент списка | data-op-repeat="team" | <!-- onpress/repeat {"source":"team"} -->…<!-- /onpress/repeat --> |
| одно значение без тега вокруг | — | <!-- onpress/value {"bind":"page.title"} /--> |
data-op-md вместо data-op-html с этими двумя полями работает так же. Атрибут ставит вывод внутрь тега, а исходное содержимое тега остается заглушкой, если выводить нечего. Все атрибуты data-op-* описывает справочник «Поля данных».
Текст страницы
data-op-html="page.content" выводит внутри тега текст собираемой страницы: оболочка ставит его туда, где должна стоять статья. Текст страницы сборка считает один раз за сборку, а внутри самого текста страницы такой вывод ничего не дает. Заголовки текста получают якоря, по ним же строит ссылки оглавление. Нет страницы в контексте сборки или у страницы нет текста — в теге остается его исходное содержимое. Фрейм с этим выводом зависит от страницы, в отчете о разметке — live_reasons: ["inserts: op/content"] и static_per_page: true: статическую копию получает каждая его страница. Например:
<article class="article__body" data-op-html="page.content"><p>Текст скоро появится</p></article>
Блок <!-- onpress/content /--> выводит то же без заглушки и принимает атрибут page (number) — id другой страницы, чей текст вывести.
Содержимое вставки во фрейме
data-op-html="frame.content" выводит внутри тега содержимое текущей парной вставки. Сборка превращает его из Markdown в HTML тем же конвертером, что публикует страницы, картинки из медиатеки выводит как <picture>, а текст получает ту же типографику, что текст страницы. Вне парного вызова и при пустом содержимом в теге остается его исходное содержимое. Например, фрейм врезки:
<aside class="callout callout--{{frame.type || info}}" data-op-html="frame.content"></aside>
Блок <!-- onpress/slot /--> выводит то же без заглушки, атрибутов у него нет.
onpress/value
Выводит одно значение прямо в текст, без тега вокруг: внутри <script>, в JSON-LD, в тексте без обертки. Сначала блок ищет frame.<ключ> в параметрах текущего вызова, потом — в списке полей данных: site.*, page.*, page.data.*, item.*, menu.<область>.name, option.<имя>, raw:. В тексте страницы ставьте блок отдельной строкой. Например, название страницы в JSON-LD:
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"Article","headline":<!-- onpress/value {"bind":"page.title","format":"json"} /-->}
</script>
| Параметр | Тип | Обязательно | По умолчанию | Описание |
|---|---|---|---|---|
bind | string | да | — | имя поля данных |
format | string | нет | text | text — экранирует HTML; html — как есть; md — строчный Markdown, остальной HTML экранирует; json — строка JSON, безопасная внутри <script>: </ и <!-- экранированы, U+2028 и U+2029 тоже. Другое значение работает как text |
Нет значения — format: "json" выводит null, остальные форматы ничего не выводят. Значение всегда строка: в json число 5 выходит как "5".
Пределы
| Предел | Что происходит |
|---|---|
| 8 фреймов в одной цепочке вызовов, считая фрейм страницы | глубже сборка не выводит, в отчете reason: "max_depth" |
| 64 вызова фреймов за одну сборку страницы | следующие вызовы ничего не выводят, reason: "max_inserts" |
| фрейм уже есть выше в цепочке | второй раз сборка его не выводит, reason: "recursion" |
| фрейма с таким именем на сайте нет | на месте вызова пусто; запись фрейма называет имя в frame_refs_missing |
| у фрейма нет разметки, только файлы | вызов ничего не выводит, а стили фрейма страница получает |
повторитель с "empty":"frame" получил пустой список | вызванный фрейм выводит пустую строку, reason: "empty" |
вызванный фрейм — целый документ с <!doctype> или <html> | сборка выводит его и предупреждает в warnings вызова |
Пояснений сборка в HTML страницы не пишет: причины лежат в bake.response.frames отчета сборки.
Где работает вставка
Вызов фрейма и служебные блоки работают в разметке фрейма и в тексте страницы. Вызванный фрейм получает ту же страницу и тот же язык, что и внешний. Фрейм из текста страницы выходит на страницу как собран, без типографики текста, поэтому скрипты в нем остаются целыми. PATCH /frames/{ref} с новым слагом переписывает вызовы во фреймах сайта и в тексте его страниц.
Проверить вставки
POST /frames с dry_run: true разбирает разметку и возвращает отчет без записи: inserts и inserts_total считают вызовы и блоки, frame_refs перечисляет вызванные фреймы, frame_refs_missing — те, которых на сайте нет. Например, оболочка промо-страницы с шапкой, текстом, секцией и подвалом:
curl -s -X POST "$API/site/$SITE/frames" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"slug": "promo", "dry_run": true, "html": "<main class=\"promo\"><!-- frame/site__header /--><div data-op-html=\"page.content\"></div><!-- frame/site__cta {\"title\":\"Попробуйте\"} /--><!-- frame/site__footer /--></main>"}'
{ "success": true, "dry_run": true, "applied": false,
"inserts": { "op/frame": 3, "op/content": 1 }, "inserts_total": 4,
"frame_refs": ["site__header", "site__cta", "site__footer"], "frame_refs_missing": ["site__cta"],
"renders_on_request": true, "live_reasons": ["inserts: op/content"], "static_per_page": true, "…": "…" }
| Код | HTTP | Когда | Что делать |
|---|---|---|---|
frame_ref_conflict | 400 | ключи имени в вызове называют разные фреймы; conflicts | оставьте одно имя |