Фреймы
Фрейм — готовая разметка, загруженная через API. Он задаёт вид страницы целиком: оболочку статьи, шапку и подвал внутри неё, блок вопросов, лендинг, выгруженный из конструктора. Разметка хранится ровно такой, какой её прислали — ничего не переписывается и не чистится, инлайновый <script> из конструктора доезжает байт в байт. Подстановки делаются только при сборке страницы: вставки <!-- onpress/… --> и атрибуты data-op-bind.
Не путайте фрейм с iframe: фрейм выводится в саму страницу, а не во встроенное окно.
Три свойства, которых у фрейма нет
- Типа. Нет «шапки», «подвала» и «страницы» как категорий: назначение говорит слаг, место — явная ссылка. Поле
typeво входе игнорируется с предупреждениемtype_ignored. - Адреса. Фрейм — шаблон, сам по себе он не открывается. Всё, что открывается по адресу, — страница, которая называет свой фрейм. Поле
urlво входе —400 frame_url_not_supported: молчаливое игнорирование навело бы на мысль, что лендинг опубликован. - Человеческого имени. Фрейм называется слагом. Поле
nameигнорируется с предупреждениемname_ignored.
Умолчаний сайта («фрейм шапки по умолчанию») тоже нет: GET/PUT /frames/defaults и POST /frames/{ref}/default отвечают 410 gone.
Имя по БЭМ
Слаг — блок__элемент--модификатор. Внутри части слова соединяются одиночным дефисом.
| Слаг | Блок | Элемент | Модификатор |
|---|---|---|---|
article | article | — | — |
article__faq | article | faq | — |
article__faq--simple | article | faq | simple |
site__header | site | header | — |
site-simple__header | site-simple | header | — |
docs__code-cards | docs | code-cards | — |
Блок site — общее для всего сайта (шапка, подвал). Остальные блоки называются по сущности, которой служат: article, docs, landing. Элемент — часть блока, модификатор — его вариант.
Регулярное выражение:
^[a-z0-9]+(?:-[a-z0-9]+)*(?:__[a-z0-9]+(?:-[a-z0-9]+)*)?(?:--[a-z0-9]+(?:-[a-z0-9]+)*)?$
Заглавные буквы приводятся к строчным. Одиночное подчёркивание, второй __ или -- — 400 invalid_slug с подсказкой схемы. Поля block, element, modifier в ответах вычисляются из слага. Старые транслитерированные слаги (shapka-sajta) проходят проверку, но ничего не говорят о месте — переименуйте их.
Загрузить фрейм
curl -s -X POST "$API/site/$SITE/frames" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d "$(jq -n --rawfile html site__header.html '{slug: "site__header", html: $html}')" \
| jq '{success, updated, frame: .frame | {id, slug, block, element}, inserts, binds, renders_on_request, warnings, bake: .bake.status}'
site__header.html:
<header class="site-header">
<a class="site-header__logo" data-op-bind='{"href":"site.home_url"}'>
<img data-op-bind='{"src":"site.logo_url","alt":"site.name"}' width="24" height="24">
<span data-op-bind='{"text":"site.name"}'></span>
</a>
<!-- onpress/lang-switcher {"display":"dropdown"} /-->
<nav class="site-header__nav"><!-- onpress/menu {"place":"header","class":"site-header__menu","depth":1} /--></nav>
</header>
Ответ — отчёт о том, что найдено в разметке, и результат пересборки:
{
"success": true,
"updated": false,
"frame": { "id": "cb7ccee58078d1fb", "slug": "site__header", "block": "site", "element": "header" },
"inserts": { "op/lang-switcher": 1, "op/menu": 1 },
"binds": 3,
"renders_on_request": false,
"warnings": [],
"bake": "ok"
}
| Поле отчёта | Что значит |
|---|---|
inserts, inserts_total | вставки по именам и их общее число |
binds | сколько тегов с data-op-bind |
sources | какие наборы и источники читают повторители |
frame_refs | слаги вложенных фреймов (ссылки по id приводятся к слагам) |
renders_on_request, live_reasons | фрейм зависит от страницы и собирается на каждом запросе; почему — в live_reasons |
has_doctype, has_body | фрейм — целый документ |
warnings | что стоит поправить; запись при этом проходит |
frame_refs_missing | вложенные фреймы, которых на сайте нет — такая вставка выводит пустое место, пока фрейм не появится |
bake | пересборка копии на стороне сайта: ok, unavailable, failed, skipped |
rebaked | какие фреймы, вкладывающие этот, пересобраны вслед за ним |
Предупреждения, на которые стоит реагировать:
data-op-bind is written with double quotes— атрибут в двойных кавычках оборвётся на первой кавычке JSON. Пишите его в одинарных.the frame contains a whole document—<!doctype>или<body>уместны у фрейма-документа, но вложенный черезonpress/frameон даст второй<body>внутри чужой страницы.frame_ref_missing: …— вложенного фрейма нет на сайте.op/frame {"type":…} is legacy— старая форма ссылки, пишите{"name":"слаг"}.400 frame_ref_conflict— не предупреждение, а отказ: в одной вставкеonpress/frameдва ключа ссылки называют разные фреймы. Оставьте одинname.
dry_run: true проверяет разметку и возвращает тот же отчёт, ничего не сохраняя. bake: false сохраняет без пересборки копии.
Предел — 2 МБ разметки на фрейм (413 frame_too_large). Сайт целиком с картинками и скриптами — это не фрейм, а приложение первой версии API.
Слаг занят — 409 slug_taken; менять разметку существующего фрейма нужно через PUT.
Прочитать
# список без разметки; ?block=article — один блок, ?q=head — подстрока слага, ?include_html=1 — с разметкой
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/frames" | jq '.frames[] | {slug, renders_on_request, pages: (.pages // [] | length)}'
# один фрейм с разметкой: ref — слаг или id
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/frames/site__header" | jq '.frame | {slug, referenced_by, pages, html}'
У фрейма в списке и в карточке есть pages — id страниц, которые в нём собираются, и referenced_by — слаги фреймов, которые его вкладывают. Адресов у фрейма нет, его адреса — это адреса его страниц.
Заменить разметку
curl -s -X PUT "$API/site/$SITE/frames/site__header" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d "$(jq -n --rawfile html site__header.html '{html: $html}')" | jq '{updated, warnings, rebaked: .rebaked.status}'
PUT заменяет разметку целиком и может заодно сменить slug (с теми же последствиями, что у PATCH). После записи фреймы, которые вкладывают этот, пересобираются транзитивно — ответ перечисляет их в rebaked.
Переименовать
curl -s -X PATCH "$API/site/$SITE/frames/shapka-sajta" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"slug": "site__header"}' | jq '{frame: .frame.slug, renamed}'
{ "frame": "site__header", "renamed": { "from": "shapka-sajta", "to": "site__header", "frames_updated": ["article", "landing"], "details": [ { "slug": "article", "replaced": 1 } ] } }
Переименование переписывает ссылки: во всех фреймах сайта вставки onpress/frame, ссылавшиеся на старый слаг (любым ключом ссылки, и старая вставка onpress/partial тоже), получают новый слаг. Ссылка, записанная алиасом, переписывается основным ключом name. Остальная разметка не трогается ни на байт, изменённые фреймы пересобираются. Страницы не трогаются вовсе: они хранят id фрейма, а не слаг. Слаг — единственное поле, которое правит PATCH; пустое тело — 400 nothing_to_update.
Поставить на страницу
Три равноправных способа, одна и та же мета страницы:
# при публикации — поле frame во frontmatter
# frame: "article"
# со стороны страницы
curl -s -X PATCH "$API/site/$SITE/pages/tarify" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"frame": "article"}' | jq '{changed, static}'
# со стороны фрейма
curl -s -X POST "$API/site/$SITE/frames/article/assign" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"page": "/tarify/"}' | jq '{page, static, republish}'
У страницы ровно один фрейм; новый заменяет прежний. assign с "clear": true снимает фрейм. Страница хранит id, поэтому переименование фрейма ей не страшно. Ответ несёт static — что стало со статической копией этой страницы после смены фрейма (переписана, снята, не нужна) — подробно в сборке.
Вложить фрейм во фрейм
Единственная связь между фреймами — вставка onpress/frame:
<!-- onpress/frame {"name":"site__header"} /-->
<main class="article">
<h1 data-op-bind='{"text":"page.title"}'></h1>
<!-- onpress/content /-->
<!-- onpress/frame {"name":"article__faq"} /-->
</main>
<!-- onpress/frame {"name":"site__footer"} /-->
name — слаг (читается) или id; ref, frame, slug, id — его алиасы. Вложенный фрейм собирается из своего исходника в контексте той же страницы и того же языка. Кольцо ссылок не зацикливается: фрейм, который уже собирается, второй раз не выводится, на его месте остаётся комментарий с цепочкой. Глубина вложения — до 8, вставок фреймов за одну сборку — до 64. Атрибут class оборачивает вложенный фрейм в <div class="…">.
Другая шапка на одном виде страниц — это другая оболочка, которая ссылается на другой фрейм шапки (landing → site-simple__header), а не переопределение на странице.
Фрейм может исчезнуть, если его список пуст. Повторитель с "empty":"frame" при пустом списке гасит весь фрейм, в котором стоит: article всегда вкладывает article__faq, а на странице без вопросов блока просто нет — ни заголовка, ни пустой секции. Подробно — в повторителе.
onpress/frame работает и в теле страницы: <!-- onpress/frame {"name":"article__cta"} /--> в markdown выводит общий блок, который правится в одном месте.
Параметры и слот
Вызов фрейма может передать ему данные. Параметры — все атрибуты вызова, кроме служебных (name и его алиасы, type, class); внутри фрейма они читаются как frame.<ключ>:
<!-- onpress/frame {"name":"assistant__chat","agent":"canva","agent_view":"profile"} /-->
<div id="ai-assistant-mount" data-op-bind='{"data-agent":"frame.agent"}'></div>
Слот — содержимое парного вызова. Markdown между открытием и закрытием остаётся в теле страницы, а фрейм ставит его вставкой onpress/slot или разбирает на вопросы и ответы источником slot.faq:
<!-- onpress/frame {"name":"faq"} -->
### Сколько это стоит?
Бесплатно.
<!-- /onpress/frame -->
Фрейм с параметрами собирается на месте вызова из исходника — своей копии с чужими параметрами у него нет. Все правила — в справочнике вставок, готовый FAQ — в рецепте FAQ. Как взять готовый фрейм и переделать его разметку под себя — свой фрейм из готового.
Фрейм — целый документ
Фрейм может быть полным HTML-документом с <!doctype html>, <head> и <body> — так выглядит лендинг, выгруженный из конструктора. Страница с таким фреймом отдаётся полноценной страницей сайта: в его <head> и <body> встраивается обвязка сайта — SEO Yoast (canonical, robots, Open Graph, JSON-LD), иконки, счётчики аналитики, hreflang. Если у страницы заполнены seo_title и seo_description, они заменяют <title> и description автора; если нет — авторские остаются. Свой счётчик Метрики или GA4 в разметке не дублируется обвязкой.
Два правила для фрейма-документа:
- не вкладывайте его в другой фрейм через
onpress/frame— получится второй<body>; - держите его независимым от страницы (без
onpress/content, биндовpage.*и прочего из списка в сборке): тогда страница получает статическую копию и отдаётся файлом. Зависимый от страницы фрейм-документ собирается внутри документа темы и даёт два<html>.
Как опубликовать лендинг целиком — рецепт лендинга.
Удалить
curl -s -X DELETE "$API/site/$SITE/frames/article__faq" -H "Authorization: Bearer $OP_TOKEN" | jq '{deleted, unbound_pages, referenced_by, warnings}'
Удаляются разметка и запись реестра, у всех страниц этого фрейма снимается привязка (их id — в unbound_pages), их статические копии снимаются. Такие страницы на сайте v2 после этого отвечают 404 — сначала переставьте их на другой фрейм. Фреймы, которые вкладывали удалённый, не правятся: они перечислены в referenced_by, и вставка выводит пустое место, пока фрейм с таким слагом не появится снова.
Где лежат
В опциях своего сайта: реестр onpress_frames (JSON: id → слаг, отчёт, даты) и исходник каждого фрейма в onpress_frame_<id>. Id — 16 шестнадцатеричных символов, выдаётся при создании. Фреймы не делятся между сайтами: id или слаг чужого сайта здесь не найдётся (404 frame_not_found). Перенос фрейма на другой сайт — GET на одном и POST на другом.
Дальше
- Вставки onpress/ — все вставки с атрибутами.
- Бинды data-op-bind — подстановка значений в атрибуты.
- Сборка страницы и статическая копия — когда фрейм собирается на запросе, когда страница становится файлом, как работает пересборка.
- Свой фрейм из готового — копия фрейма с другой разметкой при той же логике.
- Готовые фреймы — фреймы с живых сайтов: assistant с чатом, article, docs, faq, outline, шапка и подвал.
- Справочник: фреймы — все параметры и коды.