Поля данных
Поля данных выводят во фрейм значения страницы, сайта и элементов списка. Основные примеры — в гайде «Поля данных».
API — https://onpress.pro/api/v2, SITE — id сайта, OP_TOKEN — токен API. Адреса запросов и общие параметры — в общих правилах API, права — в авторизации.
| Раздел | Содержание |
|---|---|
| Поле | значение поля и заглушка |
| Выражения | грамматика, связи и фильтры |
| Атрибуты data-op-* | условия, повтор, HTML и изображения |
| Список полей данных | значения страницы, сайта и элемента |
| Пустое значение | проверка пустого значения |
| Что попадает на страницу | готовый HTML |
| Проверить разметку | пробный прогон разметки |
| Атрибут data-op-bind | пары атрибутов и полей |
Шаблон фрейма — обычный HTML с тремя видами записей. Поле {{поле}} выводит значение в тексте тега или в значении атрибута. Атрибут data-op-* управляет тегом, на котором стоит: условие, повтор, HTML внутри тега, картинка. Вставка <!-- frame/имя /--> выводит другой фрейм, ее описывает справочник «Вставка фрейма». Те же поля и атрибуты работают в тексте страницы.
API хранит разметку фрейма байт в байт, и GET /frames/{ref} отдает ее так, как вы ее записали. Поля и атрибуты сборка обрабатывает при каждой сборке страницы, превью и статической копии, а в выдачу посетителю не попадают ни скобки полей, ни атрибуты data-op-*, ни <template> повторителя. Число обработанных тегов приходит полем binds в отчете о разметке, поля без значения — полем bake.response.unresolved в отчете сборки. Какие поля читает фрейм конкретной страницы, показывает GET /pages/{ref}/data-fields.
Поле
{{поле}} или {{поле || заглушка}} в тексте тега или в значении атрибута выводит значение поля. Например, заголовок с заглушкой:
<h1>{{page.title || Заголовок записи}}</h1>
На странице «Тарифы» получится <h1>Тарифы</h1>, а в превью без страницы — <h1>Заголовок записи</h1>.
Разбор. Поле начинается с {{ и кончается на первой }}. Текст до первого || вне кавычек — имя поля или выражение, после — заглушка, пробелы по краям обоих сборка обрезает. Без || заглушка пустая, остальные || остаются в заглушке. Имя поля — item или путь через точку: первая часть из латиницы, цифр, _ и -, начинается с буквы или _, дальше одна или больше частей через точку. Все остальное, например {{ count + 1 }}, {{ message }} и {{ message | capitalize }}, остается текстом. }} без пары и {{ без конца остаются текстом.
Где стоит поле.
| Где поле | Что выводит сборка |
|---|---|
| весь текст тега, без вложенных тегов, пробелы по краям допустимы | значение вместо текста тега, пробелы вокруг на месте |
| посреди текста, или полей в тексте несколько, или рядом вложенные теги | значение каждого поля в <span> на месте поля |
| все значение атрибута, в кавычках или без | значение атрибута |
часть значения атрибута, одно или несколько полей среди текста: href="/blog/{{item.slug}}/" | значение по шаблону: текст как есть, на месте полей их значения |
обработчики событий on…, атрибуты data-op-* и имена не из латиницы, цифр, _, :, ., - | ничего, скобки остаются текстом |
В обработчики событий сборка поля не подставляет, потому что значение из данных внутри кода обработчика стало бы частью скрипта.
Где скобки остаются как есть. Содержимое <script>, <style> и <textarea>, теги <code> и <pre> вместе с потомками, тег с атрибутом data-op-raw вместе с потомками и HTML-комментарии, в том числе JSON параметров вызова фрейма. Внутри <script> значение выводит блок onpress/value.
Заглушка — текст. Сборка экранирует в ней <, >, ", ' и &, кроме & в начале готовой сущности вроде &, поэтому сборка выводит HTML заглушки как текст. Заглушка заканчивается на первой }}, поэтому в ней не может быть }}.
Экранирование. \{{ выводит {{ без обратной косой, и поле после него сборка не подставляет. Правило действует в тексте тегов и в значениях атрибутов, а внутри кода обратная косая остается на месте.
Текст страницы. Поля в тексте страницы сборка подставляет при каждом выводе: на странице, в превью, в статической копии и внутри фрейма с data-op-html="page.content", значениями той страницы, которой принадлежит текст. Блок кода и инлайн-код Markdown остаются как есть, а запись \{{ в тексте Markdown сохраняет обратную косую при выгрузке и дает {{ при выводе. Поле page.excerpt в тексте страницы выводит только выдержку из свойства excerpt, а без нее на месте поля остается заглушка. Выгрузка GET /pages/{ref}/markdown отдает текст со скобками и \{{ в том виде, в каком вы его записали.
Шаблон значения
Значение атрибута, в котором среди текста стоят поля, — шаблон: href="/blog/{{item.slug}}/". Сборка подставляет значение каждого поля, а текст вокруг оставляет. Поле без значения или с пустым значением дает свою заглушку, без || — пустую подстроку. Если ни одно поле шаблона не дало значения, атрибут остается таким, как в исходнике, с заглушками на месте полей; поля без значения попадают в unresolved. Поле item.* вне повторителя шаблон не трогает, его подставляет повторитель, а frame.<ключ> сборка подставляет из параметров вызова. Готовую строку сборка экранирует так же, как значение одного поля: в href, src и других атрибутах-ссылках адрес проходит ту же проверку, что ссылки страницы, и адрес вида javascript: пропадает. Например, класс карточки по типу и размеру:
<div class="card card--{{item.type || basic}} {{item.size}}">…</div>
У элемента с type: "news" и size: "lg" получится class="card card--news lg", у элемента без полей — class="card card--basic ".
Выражения
Выражение меняет значение поля перед выводом: фильтры после | считают, форматируют и обрезают значение, а ключ в квадратных скобках выбирает запись набора. Выражение работает везде, где работает поле: в {{…}} в тексте тега и в атрибутах, в значениях data-op-html, data-op-md, data-op-picture и в значениях пар data-op-bind. Синтаксис повторяет шаблонизатор Liquid. Например, цена с наценкой, округленная до рубля и с пробелами между разрядами:
<p class="price">{{item.price | times: 1.2 | number_format: 0, ",", " " || цена по запросу}} ₽</p>
У элемента с price: 12500 получится <p class="price">15 000 ₽</p>, у элемента без цены — <p class="price">цена по запросу ₽</p>.
поле = "{{" выражение [ "||" заглушка ] "}}"
выражение = значение { "|" фильтр [ ":" аргумент { "," аргумент } ] }
значение = путь | строка | число | true | false | nil | empty
аргумент = путь | строка | число | true | false | nil
путь = имя { "." ключ | "[" значение "]" }
строка = "'" текст "'" | '"' текст '"'
число = [ "-" ] цифры [ "." цифры ]
Что сборка считает выражением. Значение, которое начинается с имени поля, строки или числа и продолжается фильтром через |, и путь со скобками, например data.authors[page.data.author].name. Если первое слово пути без точки, как в {{ message | capitalize }}, это шаблон другой библиотеки, и скобки остаются текстом. Если выражение начинается с имени поля и фильтра, но дальше в нем ошибка, сборка выводит заглушку и пишет ошибку.
Строки и знаки. Пишите строку в одинарных или двойных кавычках. Внутри строки не бывает ее кавычки и }}, обратная косая в ней не работает. В атрибуте с двойными кавычками пишите строку в одинарных: title="{{item.name | append: ' — автор'}}". Сущности ", ', ', <, > и & в выражении сборка раскрывает, поэтому < и < значат одно и то же.
Порядок и пустое значение. Сборка выполняет фильтры слева направо, каждый получает результат предыдущего. Поле без значения проходит мимо всех фильтров, кроме default, и выводит заглушку. Выражение не вызывает функций и не читает ничего, кроме полей данных из списка: фильтры — закрытый список из таблицы ниже.
Вывод. Число сборка выводит кратчайшей записью без лишних нулей, 1200 и 1199.988, а фиксированное число знаков дает number_format. Логическое значение выводит 1 или пустую строку, список строк и чисел — элементы подряд без разделителя, а запись целиком — ошибку expr_record.
Путь
Путь читает значение по частям: .ключ — поле записи, .0 или [0] — элемент списка по номеру с нуля, ["ключ"] или [поле] — ключ из строки или из другого поля. После списка или строки .size дает длину, а после списка .first и .last — первый и последний элемент, если у записи нет своего поля с таким именем. В выражении data.<набор> — сам список записей набора, поэтому {{data.team | size}} и {{data.team.size}} выводят число записей. Например, {{item.links[0].url}} выводит адрес первой ссылки элемента.
Связи между наборами
Ключ-строка в скобках после списка выбирает запись, у которой поле slug равно ключу, а если такой нет — запись с таким id. Ключ может прийти из поля страницы или элемента повтора, так фрейм выводит запись другого набора. Например, автор статьи из набора authors по слагу в свойстве страницы author:
<a class="byline" href="/authors/{{data.authors[page.data.author].slug}}/">{{data.authors[page.data.author].name || Редакция}}</a>
У статьи с author: anna и записью {"slug": "anna", "name": "Анна Петрова"} в наборе получится <a class="byline" href="/authors/anna/">Анна Петрова</a>. Если записи или ключа нет, значения нет, и сборка выводит заглушку. Запись с известным слагом можно взять и через точку: data.authors.anna.name. Запись по другому полю находят фильтры where и first: {{data.authors | where: "email", page.data.email | first | map: "name"}}. В повторе ключ дает элемент: {{data.authors[item.author].name}}.
Поле с data.<набор> в любом месте выражения, в том числе внутри скобок, делает фрейм и страницу зависимыми от набора: запись набора через PUT /data/{name} пересобирает страницы, где стоит его запись, а поле rebaked ответа называет их с причиной datasets: authors.
Фильтры
Фильтры повторяют фильтры Liquid с теми же именами и параметрами, number_format — из шаблонизатора Twig. Числом фильтры считают число, логическое значение (1 и 0) и строку вида -12 или 3.5 с пробелами по краям или без, другое значение дает ошибку expr_not_number. Длину и позиции в строке фильтры считают в символах. Например, {{item.title | truncate: 30, "…"}} обрезает заголовок до 30 символов вместе с многоточием.
| Фильтр | Параметры | Что делает | Пример |
|---|---|---|---|
plus, minus, times | число | сложение, вычитание, умножение | times: 1.2: 1000 → 1200 |
divided_by | число, true | деление; с true — с округлением вниз | divided_by: 2: 7 → 3.5; divided_by: 2, true: 7 → 3 |
modulo | число | остаток от деления | modulo: 3: 7 → 1 |
round | знаков после запятой, 0 | округление, половина — от нуля | round: 1: 2.675 → 2.7 |
ceil, floor, abs | — | округление вверх, вниз, модуль | ceil: 4.2 → 5 |
at_least, at_most | число | не меньше, не больше | at_least: 5: 3 → 5 |
number_format | знаков 0, дробный разделитель ".", разделитель разрядов "," | число с разрядами и фиксированным числом знаков | number_format: 2, ",", " ": 1234567.891 → 1 234 567,89 |
upcase, downcase | — | верхний и нижний регистр | upcase: seo → SEO |
capitalize | — | первая буква заглавная, остальные строчные | capitalize: москва → Москва |
append, prepend | строка | дописывает в конец или в начало | append: ".pdf": report → report.pdf |
replace, replace_first | что, на что | заменяет все вхождения или первое | replace: "-", " ": a-b-c → a b c |
remove, remove_first | что | убирает все вхождения или первое | remove: "#": #seo → seo |
strip, lstrip, rstrip | — | убирает пробелы и переводы строк по краям, слева, справа | strip: x → x |
strip_html | — | убирает теги, <script>, <style> и комментарии | strip_html: <b>x</b> → x |
strip_newlines | — | убирает переводы строк | |
truncate | длина 50, хвост "..." | обрезает до длины вместе с хвостом | truncate: 8, "…": Длинный заголовок → Длинный… |
truncatewords | слов 15, хвост "..." | оставляет первые слова и хвост | truncatewords: 2, "…": раз два три → раз два… |
slice | начало, длина 1 | часть строки или списка, отрицательное начало — от конца | slice: 0, 3: Привет → При |
split | разделитель | превращает строку в список | split: ",", затем last: a,b → b |
url_encode | — | кодирует для адреса, пробел — + | url_encode: a b → a+b |
size | — | длина строки, число элементов списка или полей записи | size: ["a","b"] → 2 |
default | значение | заменяет пустое значение | default: "Без названия": "" → Без названия |
date | формат | дата в формате strftime, см. ниже | date: "%d.%m.%Y": 2026-10-30 → 30.10.2026 |
first, last | — | первый и последний элемент списка | |
join | разделитель " " | склеивает список в строку | join: ", ": ["a","b"] → a, b |
map | поле | поле каждой записи списка; у одной записи — ее поле | map: "name" |
where | поле, значение | записи, у которых поле равно значению по правилам ==; без значения — записи с непустым полем | where: "role", "CEO" |
sort | поле | по возрастанию: числа как числа, строки по алфавиту кодов, записи без поля в конце | sort: "price" |
reverse, uniq, compact | — | обратный порядок, без повторов, без отсутствующих значений |
Дата
Фильтр date выводит дату по формату strftime. Дату он принимает в виде ISO 8601 (2026-10-30, 2026-10-30 14:05, 2026-10-30T14:05:00+03:00), числом секунд Unix (время UTC) или словами now и today — сейчас и начало дня по часам сайта. Время фильтр выводит таким, как оно записано, без пересчета пояса. Поле page.date приходит в формате сайта, поэтому для фильтра берите page.date_iso. Названия месяцев и дней фильтр пишет на языке сайта: на русском для ru, на английском для остальных языков. Например, {{page.date_iso | date: "%-d %B %Y"}} на русском сайте дает 30 октября 2026.
| Код | Что выводит | Пример |
|---|---|---|
%Y, %y | год, две последние цифры года | 2026, 26 |
%m, %d, %e | месяц, день, день с пробелом вместо нуля | 03, 05, 5 |
%j | день года | 303 |
%H, %I, %p | часы 0–23, часы 1–12, AM или PM | 14, 02, PM |
%M, %S | минуты, секунды | 05, 09 |
%B | месяц словом, на русском в родительном падеже | октября, October |
%OB | месяц словом в именительном падеже | октябрь, October |
%b, %h | месяц коротко | окт, Oct |
%A, %a | день недели полностью и коротко | пятница, пт |
%u, %w | номер дня недели: понедельник 1…воскресенье 7; воскресенье 0…суббота 6 | 5 |
%F, %T, %R | %Y-%m-%d, %H:%M:%S, %H:%M | 2026-10-30, 14:05:09, 14:05 |
%s | секунды Unix | 1793369109 |
%% | знак процента | % |
Флаг - после % убирает ведущий ноль у числовых кодов: %-d, %-m, %-H. Неизвестный код фильтр выводит как есть.
Ошибки выражений
Ошибка в выражении не ломает страницу: поле выводит заглушку, а условие с ошибкой сборка считает невыполненным, поэтому data-op-if снимает тег, а data-op-unless оставляет. Ошибки разбора приходят в warnings отчета о разметке при записи фрейма строкой код: выражение: пояснение, ошибки по данным, например текст в арифметике, — в bake.response.warnings отчета сборки.
| Код | Когда | Что делать |
|---|---|---|
expr_syntax | незакрытая строка или скобка, лишний знак, нет значения после : или оператора | проверьте кавычки, скобки и запятые между параметрами |
expr_unknown_filter | фильтра нет в таблице | исправьте имя фильтра |
expr_filter_args | у фильтра не то число параметров | сверьте параметры с таблицей |
expr_bad_argument | параметр не того вида, например число знаков round не целое от 0 до 15 | передайте целое число в допустимых пределах |
expr_not_number | арифметика над значением, которое не число, или результат вышел за пределы числа | проверьте поле или поставьте default: 0 перед арифметикой |
expr_division_by_zero | деление или остаток на ноль | проверьте делитель |
expr_bad_date | date не разобрал дату | передайте дату ISO 8601 или page.date_iso |
expr_not_text | строковый фильтр получил список или запись | выберите поле через путь или map, склейте список через join |
expr_record | выражение выводит запись или список записей целиком | укажите поле: .name или map: "name" |
Атрибуты data-op-*
Атрибуты управляют тегом шаблона, на котором стоят. Значение атрибута — имя поля или выражение, у data-op-if и data-op-unless — поле или условие, у data-op-repeat — имя набора или JSON с параметрами.
| Атрибут | Значение | Что делает |
|---|---|---|
data-op-if | поле или условие | оставляет тег, если у поля есть значение или условие выполнено, иначе снимает тег со всем содержимым |
data-op-unless | поле или условие | оставляет тег, если у поля нет значения или условие не выполнено |
data-op-repeat | набор или JSON | повторяет тег по разу на каждый элемент списка |
data-op-html | поле | ставит внутрь тега значение как HTML; page.content — текст страницы, frame.content — содержимое вставки |
data-op-md | поле | ставит внутрь тега строчный Markdown значения, остальной HTML экранирует |
data-op-picture | поле | только на <img>: заменяет тег на <picture> с WebP |
data-op-raw | без значения | оставляет скобки в теге и его потомках как есть, атрибуты data-op-* внутри не работают |
Сборка не трогает атрибуты внутри <pre>, <code> и тега с data-op-raw. Если значение data-op-html, data-op-md или data-op-picture не имя поля и не выражение, а у data-op-repeat — не имя и не JSON-объект, атрибут не работает: сборка выводит тег один раз, без условия и повтора, а сборка убирает сам атрибут из готового HTML. Имена атрибутов сборка сравнивает без учета регистра, а data-op-md-url и другие имена, которые только начинаются так же, не трогает. На одном теге атрибуты сочетаются: <li data-op-repeat="team" data-op-if="item.photo"> повторяет тег и убирает элементы без фото.
Условия data-op-if и data-op-unless
data-op-if="поле" оставляет тег, если у поля есть значение. Иначе сборка снимает тег целиком вместе с содержимым, и сборка не подставляет остальные поля тега. data-op-unless работает наоборот. Значения нет, когда поля нет или оно пустое по правилу empty(): пустая строка, 0, "0", false, null, пустой список; строка из пробелов — значение. Поле элемента со списком (item.children) есть, пока список не пуст, а data.<набор> — пока в наборе есть элементы. Если на теге стоят оба атрибута, тег остается, когда выполнены оба условия. Внутри повторителя условие проверяет поле своего элемента, а поле item.* вне повторителя сборка в условии не проверяет. Например, обложка и замена для статьи без обложки:
<img class="cover" src="{{page.thumbnail_url}}" alt="{{page.title}}" data-op-if="page.thumbnail_url">
<div class="cover cover--empty" data-op-unless="page.thumbnail_url">Без обложки</div>
Сравнения в условиях
Значение data-op-if и data-op-unless может сравнивать поле с числом, строкой или другим полем и объединять сравнения словами and, or и not. Например, плашка у дорогих товаров, которые еще в продаже:
<span class="badge" data-op-if="page.data.price >= 1000 and not page.data.sold">Премиум</span>
У страницы с price: 1500 без sold плашка останется, у страницы с price: 500 или с sold: true сборка ее снимет.
условие = или
или = и { "or" и }
и = не { "and" не }
не = "not" не | сравнение
сравнение = операнд [ оператор операнд ]
оператор = "==" | "!=" | "<>" | ">" | "<" | ">=" | "<=" | "contains"
операнд = путь | строка | число | true | false | nil | null | empty | blank | "(" условие ")"
| Запись | Верно, когда |
|---|---|
a == b, a != b, a <> b | значения равны или не равны: оба числа — как числа, иначе как строки |
a > b, a < b, a >= b, a <= b | оба числа — по величине, иначе строки по порядку кодов символов, поэтому даты ISO сравниваются верно |
a contains b | строка a содержит b, список a содержит элемент, равный b, или у записи a есть поле b |
a == empty, a == blank | значение пустое; blank — еще и строка из одних пробелов |
a == nil | у поля нет значения |
not a, a and b, a or b | отрицание, оба условия, хотя бы одно |
a | у поля есть значение, как у data-op-if="поле" |
Числом сравнение считает число и строку вида -12 или 3.5, поэтому page.data.rating > 3 верно для rating: 4 из свойств страницы, которые API принимает как строки. Логическое значение сборка сравнивает как 1 и пустую строку, поэтому item.featured == true верно и для true в наборе, и для 1. Список и запись равны только empty, а > и < с ними, со значением nil и с полем без значения неверны. Сборка выполняет сначала not, потом сравнения, потом and, потом or, а скобки меняют порядок: (a or b) and c. Фильтры в условии не работают, длину списка дает .size: data-op-if="item.tags.size > 2". Строку в условии пишите в одинарных кавычках, потому что значение атрибута стоит в двойных: data-op-if="item.type == 'news'". Ошибка в условии делает его невыполненным, подробности — в разделе «Ошибки выражений».
Повтор data-op-repeat
data-op-repeat выводит тег по разу на каждый элемент списка, внутри поля item.* берут значения своего элемента. Значение — имя списка строкой или JSON-объект с параметрами в одинарных кавычках:
<tr data-op-repeat="team"><td>{{item.name}}</td><td>{{item.role}}</td></tr>
<a class="card" data-op-repeat='{"source":"news","limit":3}' href="{{item.url}}">{{item.title}}</a>
| Форма | Как читается |
|---|---|
data-op-repeat="team" | имя набора, системных данных (pages.children, pages.outline, menu.header, breadcrumbs, site.languages, slot.faq) или item.<поле> во вложенном повторе; латиница, цифры, _, ., - |
data-op-repeat='{"source":"team","limit":3}' | JSON-объект с параметрами повторителя: source, items, lang, match, limit, offset, empty, separator, statuses, page и параметры pages.children |
data-op-repeat="{"source":"team"}" | JSON в двойных кавычках атрибута с " вместо кавычек, сборка раскрывает ", ', ', <, > и & |
Все параметры, источники и правила выбора списка описывает справочник «Повторитель». Пустой список ничего не выводит, а "empty":"frame" снимает весь фрейм, в котором стоит повторитель. Тег без содержимого, например <img data-op-repeat="gallery" src="{{item}}" alt="">, повторяется так же. Вложенный data-op-repeat внутри повторяемого тега берет список из элемента внешнего: data-op-repeat="item.children".
Несколько тегов без обертки. <template data-op-repeat="…"> повторяет свое содержимое, а сам <template> на страницу не попадает. <template> без data-op-repeat остается в разметке как есть. Например:
<dl><template data-op-repeat="slot.faq"><dt>{{item.q_text}}</dt><dd data-op-html="item.a"></dd></template></dl>
HTML и Markdown data-op-html и data-op-md
data-op-html="поле" заменяет все содержимое тега значением поля как HTML, без изменений, поэтому берите его только для своих данных. data-op-md="поле" сначала экранирует HTML значения, потом разбирает строчный Markdown: **жирный**, *курсив*, [ссылка](/адрес/) и код в обратных кавычках. Если у поля нет значения, в теге остается его исходное содержимое, оно работает заглушкой. На тегах без содержимого (img, br, input и других) атрибут не работает. Например:
<p class="hero__lead" data-op-md="item.lead">Подзаголовок</p>
Два поля выводят не значение, а целый текст, и для них data-op-html и data-op-md работают одинаково:
| Поле | Что ставит внутрь тега | Нет значения |
|---|---|---|
page.content | текст страницы, на которой стоит фрейм, с якорями у заголовков; один раз за сборку | у страницы нет текста или фрейм собирается без страницы — исходное содержимое тега |
frame.content | содержимое парной вставки <!-- frame/имя -->…<!-- /frame -->, Markdown превращается в HTML тем же конвертером, что публикует страницы | одиночная вставка или пустое содержимое — исходное содержимое тега |
<article class="article__text" data-op-html="page.content"><p>Текст скоро появится</p></article>
<aside class="callout callout--{{frame.type || info}}" data-op-html="frame.content"></aside>
Фрейм с page.content зависит от страницы, подробности — в гайде «Сборка и копии».
Иллюстрации data-op-picture
data-op-picture="поле" берет адрес картинки из поля и заменяет <img> на <picture> с WebP и вариантами размеров, как у картинки в тексте страницы. С исходного тега переходят class, alt, loading, decoding, fetchpriority, width, height и style; без width и height размеры приходят из медиатеки, без alt — подпись картинки в медиатеке, без loading — lazy. Если картинки нет в медиатеке сайта, это не JPEG и не PNG или WebP на сайте выключен, остается <img> с этим адресом в src. Если у поля нет значения, <img> остается как в исходнике. На другом теге атрибут не работает, и отчет сборки пишет picture ставится только на <img>. Например:
<img class="card__img" loading="lazy" alt="{{item.title}}" data-op-picture="item.image.url">
Без обработки data-op-raw
data-op-raw на теге оставляет скобки {{…}} в нем и во всех потомках как есть, а атрибуты data-op-* внутри не работают. Ставьте его на корень шаблона Vue или Alpine. Сам атрибут на страницу не попадает. Например:
<div id="app" data-op-raw><p>{{ user.name }}</p></div>
Список полей данных
Имя поля данных называет значение. Поля элемента item.* зависят от списка: у системных данных страницы они описаны в «Повторителе». Список закрытый: поле с опечаткой ничего не выводит и попадает в unresolved отчета сборки. Те же поля принимают атрибуты data-op-*, блок onpress/value, а match, limit и offset повторителя — все, кроме параметров вызова frame.<ключ>.
| Поле | Значение |
|---|---|
site.home_url, site.url | адрес главной со слешем на конце |
site.site_url | корневой адрес сайта |
site.name, site.description | название и описание сайта |
site.logo_url | логотип сайта, иначе иконка сайта; нет ни того, ни другого — значения нет |
site.host | домен без схемы |
site.lang | слаг текущего языка |
site.year | текущий год |
site.charset | кодировка |
site.login_url, site.logout_url | адреса входа и выхода |
menu.<область>.name | название меню в области на языке сборки, например menu.footer_1.name; в области нет меню — значения нет |
option.<имя> | значение настройки сайта с этим именем, только строка или число; несуществующая настройка дает пустую строку |
raw:<значение> | значение как есть, без словаря |
| Поле | Значение |
|---|---|
page.id, page.url, page.title | id, полный адрес и название собираемой страницы |
page.slug, page.status, page.type, page.lang | слаг, статус, тип записи и слаг языка |
page.parent_id | id родителя, только если он есть |
page.parent_title, page.parent_url | название и адрес ближайшего родителя, который виден в хлебных крошках |
page.excerpt | выдержка; пустая выдержка дает первые слова текста |
page.description | выдержка без первых слов текста: пустая выдержка дает пустую строку |
page.date, page.date_iso | дата публикации в формате сайта и в ISO 8601 |
page.date_modified, page.date_modified_iso | дата изменения в тех же форматах |
page.thumbnail_id, page.thumbnail_url, page.thumbnail_alt | превью страницы, только если оно есть |
page.author_id, page.author_name | id автора и его отображаемое имя |
page.author_url | адрес архива автора, только если он не раскрывает логин учетной записи |
page.author_avatar | аватар автора, только если файл лежит на домене сайта |
page.categories, page.tags | рубрики и метки через запятую |
page.category_name, page.category_slug, page.category_url | первая рубрика |
page.paged | номер страницы разбивки из адреса ?blog_page=N, без параметра — 1 |
page.data.<ключ> | значение своего ключа из свойств страницы |
page.content | текст страницы, выводится только атрибутом data-op-html или data-op-md |
page.data.<ключ> отдает только ключи, которые пришли из свойств страницы при публикации, кроме ключей на _, и только непустые строки, числа и логические значения. Формы rating: 5, data.rating: 5 и вложенная под data: дают одно поле page.data.rating. Поле page.* делает фрейм зависимым от страницы, подробности — в гайде «Сборка страницы и статическая копия».
| Поле | Значение |
|---|---|
item | сам элемент повторителя, когда список состоит из строк или чисел |
item.<поле> | поле элемента повторителя; вложенные поля через точку, элемент массива — номером с нуля: item.links.0.url |
frame.<ключ> | параметр вызова фрейма; вложенные ключи через точку |
frame.content | содержимое парной вставки, выводится только атрибутом data-op-html или data-op-md |
frame.id, frame.url | заняты платформой, не называйте так параметры вызова |
data.<набор> | число элементов в наборе; пустой набор дает 0, и data-op-if снимает тег |
data.<набор>.<номер>.<поле> | поле одного элемента набора, например data.team.0.name |
data.<набор>[ключ].<поле> | поле записи набора с таким slug или id, ключ — строка или поле: data.authors[page.data.author].name, подробности — в разделе «Связи между наборами» |
item.* берет элемент ближайшего повторителя. Логическое true дает 1, false — пустую строку, объект, массив и null значения не дают. Вне повторителя сборка поле item.* не трогает и в unresolved не пишет. frame.<ключ> сборка подставляет в исходник вызванного фрейма до сборки и снимает эту пару из атрибута, поэтому в готовой разметке ее нет; если атрибут опустел, сборка снимает его целиком. Параметр-объект или параметр-список поле данных не подставляет, такой список выводит повторитель с source frame.<ключ>. Нет параметра — значения нет. Параметр type вызова с именем фрейма поле frame.type выводит как обычный параметр. Подробнее о параметрах — на странице «Вставка фрейма и служебные блоки».
Элементы набора выводит повторитель data-op-repeat, а поля item.* показывают значения элемента. Поле data.<набор> читает тот же набор, что повторитель с source этого имени, на языке страницы, и запись набора через API пересобирает страницы, где оно стоит.
Пустое значение
Пустым поле считает то же, что функция empty() в PHP: пустую строку, 0 строкой или числом, false, null, пустой список и пустой объект; строка из пробелов и "0.0" — значения. С пустым значением или без значения поле ничего не подставляет: текст и атрибуты тега остаются такими, как в исходнике, поэтому исходный текст работает заглушкой. В шаблоне на место пустого поля встает его заглушка. Когда пустое значение должно очищать тег, а 0 печататься нулем, нужен ключ "empty":"clear" атрибута data-op-bind.
| Значение поля | Поле {{…}} и data-op-html, data-op-md, data-op-picture | data-op-if | data-op-unless |
|---|---|---|---|
нет значения: такого поля нет в списке, у страницы нет поля, у элемента нет ключа, ключ равен null | заглушка или исходное содержимое, поле в unresolved | тег снят | тег остается |
пустая строка или false | заглушка или исходное содержимое | тег снят | тег остается |
0 или "0" | заглушка или исходное содержимое | тег снят | тег остается |
| строка из пробелов | пробелы | тег остается | тег снят |
| пустой список или объект | заглушка или исходное содержимое | тег снят | тег остается |
непустой список у поля элемента (item.children) | заглушка или исходное содержимое | тег остается | тег снят |
| поле шаблона без значения или с пустым значением | заглушка поля на его месте, текст вокруг на месте | — | — |
Что попадает на страницу
На страницу, в статическую копию и в превью попадает чистый HTML: значения на месте полей, без скобок, без атрибутов data-op-*, без data-op-bind и без <template> повторителя. Атрибуты, которые сборка не разобрала, тоже снимаются. Скобки остаются только там, где сборка их не трогает: в коде, в <script>, в теге с data-op-raw и там, где в скобках стоит не поле и не выражение.
Проверить разметку
POST /frames с dry_run: true разбирает разметку и возвращает отчет о разметке без записи: binds считает теги с полями и атрибутами data-op-*, sources — списки повторителей, live_reasons называет поля page.*. Например, заголовок героя и список возможностей:
curl -s -X POST "$API/site/$SITE/frames" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"slug": "landing__hero", "dry_run": true, "html": "<section class=\"hero\"><h1>{{page.title || Заголовок}}</h1><li data-op-repeat=\"features\">{{item.name}}</li></section>"}'
{ "success": true, "dry_run": true, "applied": false, "binds": 2, "inserts": { "op/repeat": 1 }, "sources": ["features"],
"renders_on_request": true, "live_reasons": ["data-op-bind uses page.* tokens"], "warnings": [], "…": "…" }
Ошибки разбора выражений отчет о разметке пишет в warnings. Значения и unresolved показывает только сборка: запишите фрейм и смотрите bake.response.binds, bake.response.unresolved и bake.response.warnings в отчете сборки.
Атрибут data-op-bind
Атрибут data-op-bind с JSON-объектом — другая запись тех же возможностей, она работает так же. Поля и атрибуты data-op-* сборка сама переводит в эту запись, поэтому она встречается в старых фреймах и в отчетах. Пишите значение атрибута в одинарных кавычках, а JSON внутри — в двойных. Ключ и значение в каждой паре — строки, значение — имя поля, шаблон или литерал raw:<значение>. Например, логотип со ссылкой на главную:
<a class="logo" data-op-bind='{"href":"site.home_url"}'><img data-op-bind='{"src":"site.logo_url","alt":"site.name"}'></a>
| Ключ | Что делает | Запись без data-op-bind |
|---|---|---|
| имя атрибута | выставляет атрибут тега | href="{{поле}}" |
text | заменяет содержимое тега значением и экранирует HTML | <p>{{поле}}</p> |
html | заменяет содержимое тега значением как HTML | data-op-html |
md | заменяет содержимое тега строчным Markdown | data-op-md |
picture | на <img> заменяет тег на <picture> с WebP | data-op-picture |
if | оставляет тег, если у поля есть значение | data-op-if |
unless | оставляет тег, если у поля нет значения | data-op-unless |
empty | keep или без ключа — пустое значение оставляет исходный текст и атрибуты, clear — записывает значение как есть: пустая строка очищает содержимое или атрибут, 0 печатается нулем | — |
Сначала сборка проверяет условия if и unless, потом подставляет остальные пары по порядку; из ключей text, html и md работает последний. У <img> ключ src с адресом .jpg, .jpeg или .png получает адрес WebP-копии той же картинки, когда такая копия есть на сайте. Битый JSON сборка пропускает и пишет в warnings отчета сборки битый JSON в data-op-bind, пару с нестроковым ключом или значением — пара атрибут/токен должна быть строками, другое значение empty — тоже предупреждение. Атрибут в двойных кавычках обрывается на первой кавычке JSON, об этом предупреждает отчет о разметке.
Если на теге уже стоит data-op-bind в одинарных кавычках, сборка дописывает в него пары от полей и атрибутов data-op-*, а явная пара главнее: <p data-op-bind='{"if":"page.data.a"}' data-op-if="page.data.b"> проверяет page.data.a. Атрибут data-op-bind в двойных кавычках или с битым JSON сборка не дополняет. Например, цена тарифа, у которой 0 — тоже цена:
<b class="price" data-op-bind='{"text":"item.price","empty":"clear"}'></b>
Повтор, текст страницы и содержимое вставки тоже записываются служебными блоками: <!-- onpress/repeat {…} -->…<!-- /onpress/repeat -->, <!-- onpress/content /--> и <!-- onpress/slot /-->, их описывает справочник «Вставка фрейма и служебные блоки».