Сборка страницы и статическая копия
У страницы с фреймом два способа попасть к посетителю: сборка на запросе (PHP собирает фрейм по шаблону для этой страницы) и статическая копия (готовый HTML лежит файлом, веб-сервер отдаёт его без PHP за миллисекунды). Какой способ выбран, решает не страница и не вы, а содержимое фрейма.
Сборка на запросе
- По адресу находится страница и её язык.
- Тема берёт фрейм страницы (
_onpress_frame) и собирает его из исходника: выполняет каждую вставкуonpress/…для этой страницы и этого языка, подставляетdata-op-bind. Вложенные черезonpress/frameфреймы собираются так же, в том же контексте. - Результат оборачивается в документ темы —
<head>с SEO, иконками, стилями темы, токенами дизайна, собственным CSS и счётчиками. Если фрейм сам является документом (<!doctype html>), обвязка встраивается в его<head>и<body>. - Ответ кладётся в кэш страниц (WP Super Cache).
Всё, что меняется через API (меню, наборы, языки, настройки, вложенные фреймы), попадает на такие страницы на следующем же запросе — API сам сбрасывает кэш затронутых страниц.
Статическая копия
Страница становится файлом, когда выполнены все условия:
| Условие | Причина отказа (reason) |
|---|---|
| страница опубликована и без пароля | not_public |
| у неё есть фрейм | no_frame |
| фрейм не зависит от страницы | renders_on_request |
| у фрейма уже есть собранная копия | no_baked_copy |
| адрес ложится в дерево файлов: латиница без процентов, первый сегмент не зарезервирован WordPress, адрес не занят другим приложением | bad_path |
Когда условие перестаёт выполняться, копия снимается, а не остаётся устаревшей. Копия — это ответ сайта, снятый целиком, вместе с обвязкой <head>, поэтому SEO и счётчики в ней те же, что при сборке на запросе.
Состояние копии видно в трёх местах:
- в ответе публикации —
printed:{"how": "static", "url": "/promo/", "published_by": "php", …}; - в списке и карточке страницы —
static:{"published": true, "url": "/promo/", "app_key": "page-6432"}; - в ответах
PATCH /pages/{ref}иPOST /frames/{ref}/assign—staticс полямиpublished,url,path,bytes,reason,was_published,was_url,removed,changed.
printed.how | Что значит |
|---|---|
static | страница отдаётся копией |
on_request | фрейм зависит от страницы — собирается на каждом запросе |
not_published | у страницы пока нет адреса: черновик, отложена или неопубликованный родитель |
theme | у страницы нет фрейма. На сайте v2 это 404 — см. ниже |
Когда фрейм зависит от страницы
Фрейм получает renders_on_request: true, если в нём есть хоть одно из:
| Признак | Как выглядит в live_reasons |
|---|---|
вставки onpress/content, onpress/pager, onpress/docs-nav, onpress/outline, onpress/share-ai, onpress/featured-image, onpress/terms, onpress/assistant, onpress/faq-schema, onpress/assistant-welcome, onpress/partial | inserts: op/content, … |
data-op-bind с токеном page.* или атрибут вставки, целиком равный токену page.* | data-op-bind uses page.* tokens |
onpress/repeat с match от page.* | op/repeat match uses page.* tokens |
onpress/repeat с limit или offset от page.* | op/repeat limit/offset uses page.* tokens |
повторитель по контекстному источнику: pages.children, pages.siblings, pages.adjacent, breadcrumbs | contextual sources: breadcrumbs |
вложенный через onpress/frame зависимый фрейм | — (правило транзитивное) |
Фрейм с параметрами вызова (onpress/frame {"name":"…","agent":"…"}) и фрейм со слотом собираются на месте вызова из исходника: своей копии с чужими параметрами или чужим содержимым у них нет.
Вызов фрейма в теле страницы собирается вместе с телом. Оглавление onpress/outline в теле собирается после всего тела, поэтому видит те же заголовки и якоря, что и оглавление во фрейме страницы. Если FAQ-фреймов в теле несколько, их схемы FAQPage при сборке тела сливаются в первую, остальные снимаются.
Копия такого фрейма показала бы на всех страницах текст одной, поэтому копий у него не бывает вовсе, а его страницы всегда собираются на запросе. Не делают фрейм зависимым: onpress/faq (вопросы внутри вставки), onpress/repeat по набору без page.*, onpress/repeat {"empty":"frame"}, вложенный повторитель item.<поле>, onpress/lang-switcher, onpress/menu.
Как сделать страницу файлом. Уберите из фрейма всё зависимое. Типичный пример — лендинг: разметка целиком во фрейме, тело страницы пустое, никаких onpress/content и page.*. Оболочка статьи или документации, которая выводит тело через onpress/content, файлом не станет никогда — и это правильно.
Копии по языкам
Фрейм с языкозависимыми вставками (onpress/menu, onpress/lang-switcher, onpress/footer-columns, onpress/repeat, onpress/frame, onpress/content, onpress/socials, onpress/copyright, onpress/docs-nav, onpress/outline, onpress/share-ai, onpress/pager, onpress/partial) собирается отдельно на каждый язык сайта: копия основного языка и копии остальных. Фрейм без таких вставок собирается один раз. Страница получает копию своего языка.
Пересборка
Копии обновляются, когда меняется то, из чего они собраны. API делает это сам после каждой записи и сообщает результат полем rebaked:
| Запись | Кого пересобирает |
|---|---|
POST/PUT/PATCH/DELETE /frames/… | фреймы, вкладывающие изменённый, транзитивно |
| любая запись меню | фреймы с onpress/menu, onpress/footer-columns, повторителями по menu.* |
запись набора данных (PUT, PATCH, DELETE /data/{name}) | фреймы, читающие этот набор, и вкладывающие их |
запись системного источника через /data/… | зависимых от этого источника |
"rebaked": {
"status": "ok",
"total": 2,
"baked": 0,
"not_needed": 2,
"frames": [
{ "id": "838a082b034be249", "slug": "article__faq", "because": ["datasets: faq"], "bake": "not_needed", "detail": "renders on request from the source, has no baked copy" },
{ "id": "e627bf4dbefcc374", "slug": "article", "because": ["contains article__faq"], "bake": "not_needed", "detail": "renders on request from the source, has no baked copy" }
],
"cache": { "status": "ok", "scope": "pages", "pages": [6428], "flushed": { "urls": { "status": "flushed", "urls": ["https://example.onpress.pro/tarify/"] } } }
}
| Поле | Смысл |
|---|---|
status | ok — всё нужное собрано; partial — часть; failed — ничего; nothing — от изменения никто не зависит |
total | сколько фреймов найдено |
baked | сколько сборок сделано: языкозависимый фрейм собирается по разу на язык |
not_needed | фреймы на запросе — копии у них нет, собирать нечего |
frames | по записи на сборку: slug, lang, because (почему попал), bake (ok, not_needed, ошибка), pages (страницы фрейма) |
pages | страницы, у которых зависимая вставка стоит прямо в теле: id и because (datasets: faq, nested frames: …, contains …); есть, только если такие нашлись |
cache | сброс кэша страниц, которые собираются этими фреймами, включая фреймы на запросе, и страниц из pages. scope: "pages" — точечно по адресам; scope: "site" — весь кэш сайта, если зависимых страниц больше 400 |
skipped, cap | за один вызов пересобирается не больше 25 фреймов, остальные перечислены здесь |
Неудачная пересборка никогда не отменяет запись: данные уже сохранены, копию можно пересобрать повтором или вручную.
Зависимые страницы находятся по фрейму страницы и цепочке onpress/frame внутри фреймов, а также по вставкам в теле страницы: onpress/repeat по набору, onpress/frame (и всё, что вложено в этот фрейм), привязки и прочие вставки тела разбираются так же, как во фрейме. Такие страницы приходят в pages, их кэш сбрасывается вместе с остальными.
Ручная пересборка
Нужна, когда изменение прошло мимо API — меню правили в wp-admin, опцию меняли руками — или копии надо обновить после обновления платформы:
# всё
curl -s -X POST "$API/site/$SITE/frames/rebake" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"all": true}' | jq '.rebaked | {status, total, baked, not_needed}'
# только то, что зависит от меню и от набора faq
curl -s -X POST "$API/site/$SITE/frames/rebake" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"menus": true, "datasets": ["faq"]}' | jq '.rebaked.frames[] | {slug, because, bake}'
| Поле тела | Кого пересобирает |
|---|---|
all | все фреймы сайта |
menus | фреймы с меню: onpress/menu, onpress/footer-columns, повторители и бинды по menu.* |
pages | фреймы, выводящие страницы, их заголовки и адреса: меню, зависимые от страницы вставки, повторители по pages.*, breadcrumbs, site.front_page, бинды page.* |
languages | фреймы с языкозависимыми вставками, повторителями по site.languages, биндом site.lang |
settings | фреймы с onpress/socials, onpress/copyright, повторителями по site.settings и site.front_page, биндами site.* и option.* |
datasets | массив имён наборов |
frames | массив слагов или id — фреймы, вкладывающие эти |
Пустое тело — 400 nothing_to_rebake. Изменения, сделанные в wp-admin, платформа ловит и сама (правка меню, сохранение записи, изменение опций ставят в очередь тех же зависимых), ручной вызов — для уверенности.
Кэш страниц
Готовые ответы кэширует WP Super Cache, и отдаются они веб-сервером. Все записи API сбрасывают кэш сами: запись фрейма, меню и набора — кэш зависимых страниц, запись CSS и токенов дизайна — весь кэш сайта, настройки, языки и SEO — весь кэш сайта и объектный кэш. Если правка не видна:
# точечно по адресам или id страниц
curl -s -X POST "$API/site/$SITE/cache/flush" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"urls": ["/tarify/"]}' | jq .flushed
# весь кэш страниц сайта
curl -s -X POST "$API/site/$SITE/cache/flush" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"supercache": true}' | jq .flushed
Подробно — настройки, главная и кэш. Проверяйте результат запросом без кук (curl по адресу страницы): вошедший в WordPress видит страницы мимо кэша.
Страница без фрейма и страница 404
На сайте v2 страницу выводит только её фрейм. Опубликованная страница без фрейма (или с удалённым фреймом) отвечает 404, не попадает в кэш и помечается noindex — чтобы по адресу не жила пустая или чужая разметка.
Ответ «не найдено» собирает страница сайта со слагом 404, если она опубликована и у неё есть фрейм: такой же страницей, как остальные, со своим текстом и оболочкой. Её собственный адрес тоже отвечает 404, чтобы поисковик не принял её за обычную страницу. Нет такой страницы — ответ пустой с кодом 404. Опубликуйте страницу 404 на каждом языке сайта — и все несуществующие адреса получат оформленный ответ.
Отчёт сборки
Ответ записи фрейма несёт bake.response — отчёт сборки на стороне сайта:
| Поле | Смысл |
|---|---|
baked | собрано |
bytes, source_bytes | размер результата и исходника |
renders_on_request | фрейм на запросе — копии не хранится |
lang, default_lang | язык сборки |
inserts, unknown_inserts | сколько вставок выполнено; вставки, которых платформа не знает |
binds, bind_tags | подставленных значений и помеченных тегов |
unresolved | токены без значения |
repeats | что вывели повторители: источник, откуда взят, сколько элементов |
frames | вложенные фреймы: выведен ли, глубина, свои unresolved |
published | копии страниц этого фрейма: pages[] с id, url, published, path, bytes, reason |
bake.status: ok — собрано; unavailable — исполнитель на сайте не установлен, исходник сохранён; failed — исполнитель ответил ошибкой или не ответил (reason); skipped — сборка выключена ("bake": false).