Сайт с нуля
Результат: сайт с шапкой и подвалом, меню, главной, страницами «О компании» и «Контакты», оформленной страницей 404 и своими цветами. Всё — запросами к API, файлы лежат рядом в рабочем каталоге.
0. Сайт
Если сайт уже есть — возьмите его site_id (доступ) и переходите к шагу 1. Новый сайт создаёт суперадмин сети — клоном донора с очисткой содержимого:
curl -s -X POST "$API/sites" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "acme", "title": "Acme", "donor": 233, "empty": true, "copy_files": false, "public": false}' \
| jq '{site_id, blog_id, domain}'
export SITE=… # site_id из ответа
public: false закрывает сайт от поисковиков до запуска (в конце откроем). Подробности — сайты и домены.
1. Язык
curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/languages" | jq '{default, languages: [.languages[].slug]}'
Дальше во всех страницах lang — язык из default. Здесь — ru. Нужен другой основной язык — языки сайта.
2. Фреймы
Три файла.
site__header.html:
<header class="site-header">
<a class="site-header__logo" data-op-bind='{"href":"site.home_url","text":"site.name"}'></a>
<nav class="site-header__nav"><!-- onpress/menu {"place":"header","class":"site-header__menu","depth":1} /--></nav>
<!-- onpress/lang-switcher {"display":"dropdown","show":"slug"} /-->
</header>
site__footer.html:
<footer class="site-footer">
<!-- onpress/footer-columns {"places":"footer_1,footer_2"} /-->
<p class="site-footer__copy"><!-- onpress/copyright {"text":"© {year} {name}"} /--></p>
</footer>
article.html — оболочка страницы, которая вкладывает шапку и подвал:
<!-- onpress/frame {"name":"site__header"} /-->
<main class="article">
<h1 class="article__title" data-op-bind='{"text":"page.title"}'></h1>
<p class="article__lead" data-op-bind='{"text":"page.description"}'></p>
<div class="article__body"><!-- onpress/content /--></div>
</main>
<!-- onpress/frame {"name":"site__footer"} /-->
Загрузите — сначала вложенные, потом оболочку, чтобы ссылки сразу находили фреймы:
for f in site__header site__footer article; do
curl -s -X POST "$API/site/$SITE/frames" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d "$(jq -n --arg slug "$f" --rawfile html "$f.html" '{slug: $slug, html: $html}')" \
| jq -c '{slug: .frame.slug, renders_on_request, warnings}'
done
{"slug":"site__header","renders_on_request":false,"warnings":[]}
{"slug":"site__footer","renders_on_request":false,"warnings":[]}
{"slug":"article","renders_on_request":true,"warnings":[]}
Шапка и подвал от страницы не зависят, оболочка зависит (onpress/content, page.title) — её страницы собираются на запросе. Если слаг занят (409 slug_taken) — фрейм уже есть: замените разметку тем же телом через PUT $API/site/$SITE/frames/<слаг>.
3. Страницы
Четыре файла. home.md:
---
name: "Acme"
slug: "home"
url: "/home/"
lang: "ru"
frame: "article"
excerpt: "Мы делаем сайты, которыми управляют через API."
seo_title: "Acme — сайты через API"
seo_description: "Acme делает сайты на OnPress: страницы из markdown, оформление фреймами, всё через API."
---
## Что мы делаем
Сайты, где страницы публикуются запросом, а вид задаётся фреймами.
## Как с нами связаться
Все способы — на странице [Контакты](/kontakty/).
o-kompanii.md:
---
name: "О компании"
slug: "o-kompanii"
url: "/o-kompanii/"
lang: "ru"
frame: "article"
excerpt: "Кто мы и чем занимаемся."
---
Текст о компании.
kontakty.md:
---
name: "Контакты"
slug: "kontakty"
url: "/kontakty/"
lang: "ru"
frame: "article"
---
Почта: hello@example.com
404.md — ответ «не найдено» для всего сайта:
---
name: "Страница не найдена"
slug: "404"
url: "/404/"
lang: "ru"
frame: "article"
---
Такой страницы нет. Начните с [главной](/).
Опубликуйте:
for p in home o-kompanii kontakty 404; do
curl -s -X POST "$API/site/$SITE/pages/markdown" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d "$(jq -n --rawfile md "$p.md" '{markdown: $md}')" \
| jq -c '{id, url, link, how: .printed.how, warnings}'
done
У каждой страницы в ответе how: "on_request" и пустые warnings. Страница со слагом 404 собирает ответ сайта на любой несуществующий адрес.
4. Меню
Шапка — одним запросом: создать, поставить в область, наполнить.
curl -s -X POST "$API/site/$SITE/menus" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "Шапка", "location": "header", "lang": "ru", "items": [
{"page": "/o-kompanii/"},
{"page": "/kontakty/"}
]}' | jq -c '{menu, invalid, rebaked: .rebaked.status}'
Подвал — две колонки:
curl -s -X POST "$API/site/$SITE/menus" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "Компания", "location": "footer_1", "lang": "ru", "items": [{"page": "/o-kompanii/"}, {"page": "/kontakty/"}]}' | jq -c .menu
curl -s -X POST "$API/site/$SITE/menus" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "Мы в сети", "location": "footer_2", "lang": "ru", "items": [{"url": "https://t.me/acme", "title": "Telegram", "target": "_blank"}]}' | jq -c .menu
Имя меню подвала становится заголовком колонки onpress/footer-columns.
5. Главная
curl -s -X PUT "$API/site/$SITE/front-page" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"page": "/home/"}' | jq '{changed, page_on_front, front_pages}'
Теперь / отдаёт страницу home, а её собственный адрес /home/ уводит на корень.
6. Название и видимость
curl -s -X PATCH "$API/site/$SITE/settings" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"blogname": "Acme", "blogdescription": "Сайты через API"}' | jq '{changed}'
blog_public: 1 откроет сайт поисковикам — сделайте это в самом конце, когда всё проверено.
7. Оформление
Цвет бренда — токеном, раскладка фреймов — своим CSS:
curl -s -X PATCH "$API/site/$SITE/design" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"tokens": {"color.primary": "#16a34a", "radius.default": 8}}' | jq -c '[.changed[].token]'
site.css:
.site-header{display:flex;align-items:center;gap:24px;padding:16px 24px;border-bottom:1px solid var(--line-color)}
.site-header__logo{font-weight:700;color:var(--primary-color);text-decoration:none}
.site-header__menu{display:flex;gap:16px;list-style:none;margin:0;padding:0}
.article{max-width:760px;margin:0 auto;padding:40px 24px}
.article__lead{color:var(--font-second-color)}
.article__lead:empty{display:none}
.site-footer{display:flex;justify-content:space-between;padding:32px 24px;border-top:1px solid var(--line-color)}
curl -s -X PUT "$API/site/$SITE/css" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d "$(jq -n --rawfile css site.css '{css: $css}')" | jq -c '{applied, bytes, stripped, cache: .cache.status}'
Если на сайте уже есть свой CSS, не затирайте его: прочитайте GET /css, добавьте свой кусок и залейте лист целиком (стили).
8. Проверка
DOMAIN=$(curl -s -H "Authorization: Bearer $OP_TOKEN" "$API/site/$SITE/settings" | jq -r .settings.domain)
for u in / /o-kompanii/ /kontakty/ /net-takoj-stranicy/; do
printf '%s %s\n' "$(curl -s -o /dev/null -w '%{http_code}' "https://$DOMAIN$u")" "$u"
done
200 /
200 /o-kompanii/
200 /kontakty/
404 /net-takoj-stranicy/
Несуществующий адрес отвечает 404, но с вашей страницей «не найдено» внутри шапки и подвала. Проверьте SEO-обход: GET $API/site/$SITE/seo/pages — на страницах не должно быть many_h1 (заголовок выводит фрейм, в теле # не нужен) и пропущенных описаний.
9. Открыть сайт
curl -s -X PATCH "$API/site/$SITE/settings" \
-H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-d '{"blog_public": 1}' | jq '{changed}'
Свой домен вместо acme.onpress.pro подключается в разделе «Домен» дашборда.
Что дальше
- Раздел документации или лендинг рядом с основными страницами.
- FAQ на страницах.
- Второй язык.