• Как устроено
  • Быстрый старт
  • Доступ и токен
    • Страницы
      • Frontmatter
      • Синтаксис markdown
      • Переводы страниц
    • Фреймы
      • Вставки onpress/
      • Бинды data-op-bind
      • Сборка и копии
    • Готовые фреймы
      • assistant
      • outline
      • faq
      • article
      • docs
      • site__header
      • site__footer
      • article__faq
      • landing
      • assistant__chat
      • site__404
      • news
      • news__category
      • news__post
      • news__more
      • news__share
      • author__page
      • author__byline
      • author__card
      • author__avatar
      • author__socials
      • author__head
      • home
      • pricing
    • Данные
      • Повторитель onpress/repeat
  • Стили
  • Меню
  • Сайдбар документации
  • Языки сайта
  • Настройки и кэш
  • SEO
  • Медиа
  • Сайты и домены
  • Пользователи и профиль
  • Дашборд и вход
    • Рецепты
      • Сайт с нуля
      • Раздел документации
      • Лендинг
      • FAQ
      • Свой фрейм из готового
      • Многоязычный сайт
      • Поменять меню
      • Перенести страницу
      • Картинки в статье
      • Список из данных
      • Сменить оформление
    • Справочник API
      • Страницы
      • Переводы
      • Фреймы
      • Данные
      • Меню
      • Сайдбар документации
      • Стили
      • Настройки, главная, кэш
      • Языки
      • SEO
      • Медиа
      • Сайты
      • Пользователи и профиль
      • Вход и служебное
    • Ошибки и проблемы
      • Коды ошибок
OnPress OnPress
  • Документация
  • Контакты
Войти
  • Как устроено
  • Быстрый старт
  • Доступ и токен
    • Страницы
      • Frontmatter
      • Синтаксис markdown
      • Переводы страниц
    • Фреймы
      • Вставки onpress/
      • Бинды data-op-bind
      • Сборка и копии
    • Готовые фреймы
      • assistant
      • outline
      • faq
      • article
      • docs
      • site__header
      • site__footer
      • article__faq
      • landing
      • assistant__chat
      • site__404
      • news
      • news__category
      • news__post
      • news__more
      • news__share
      • author__page
      • author__byline
      • author__card
      • author__avatar
      • author__socials
      • author__head
      • home
      • pricing
    • Данные
      • Повторитель onpress/repeat
  • Стили
  • Меню
  • Сайдбар документации
  • Языки сайта
  • Настройки и кэш
  • SEO
  • Медиа
  • Сайты и домены
  • Пользователи и профиль
  • Дашборд и вход
    • Рецепты
      • Сайт с нуля
      • Раздел документации
      • Лендинг
      • FAQ
      • Свой фрейм из готового
      • Многоязычный сайт
      • Поменять меню
      • Перенести страницу
      • Картинки в статье
      • Список из данных
      • Сменить оформление
    • Справочник API
      • Страницы
      • Переводы
      • Фреймы
      • Данные
      • Меню
      • Сайдбар документации
      • Стили
      • Настройки, главная, кэш
      • Языки
      • SEO
      • Медиа
      • Сайты
      • Пользователи и профиль
      • Вход и служебное
    • Ошибки и проблемы
      • Коды ошибок
Рецепты
Markdown
Открыть в ИИ
  • Открыть в ChatGPT
  • Открыть в Claude
  • Открыть в Gemini
  • Открыть в Perplexity
  • Открыть в Grok
  • Открыть в DeepSeek

Сайт с нуля

Результат: сайт с шапкой и подвалом, меню, главной, страницами «О компании» и «Контакты», оформленной страницей 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 на страницах.
  • Второй язык.
arrow_backНазад
Рецепты
Далееarrow_forward
Раздел документации
На этой странице
  • 0. Сайт
    • 1. Язык
      • 2. Фреймы
        • 3. Страницы
          • 4. Меню
            • 5. Главная
              • 6. Название и видимость
                • 7. Оформление
                  • 8. Проверка
                    • 9. Открыть сайт
                      • Что дальше
                      OnPress
                      OnPress
                      ИП Зуев И.В. ИНН: 360408359441
                      © 2026
                      политика конфиденциальности публичная оферта
                      • visa
                      • mastercard
                      • sber
                      • tpay