Create a page
Publish a markdown document as a page in the right section, check that it really serves, update it in place and put it where it belongs in the docs tree.
One endpoint does all of it: POST /pages/markdown creates the page when there is none and updates it when there is. The responses below are the real ones this very page got when it was published on the test site.
1. Write the document
A page is a markdown document with YAML frontmatter. name is the only required field; url places the page in the tree (every segment before the last must already exist), lang sets its language and scopes the lookup. How the page looks is frame: — the shell it is printed in, for example frame: article. There is nothing else to set for the look: template is ignored in v2 and answers with the warning template_ignored.
---
name: "Create a page"
excerpt: "Publish a markdown document as a page in the right section."
slug: "sozdat-stranicu"
status: "draft"
url: "/docs/recepty/sozdat-stranicu/"
lang: "en"
frame: "obolochka-dokumentaciya"
---
## 1. Write the document
A page is a markdown document with YAML frontmatter.
Do not write an H1 in the body: the shell prints the title from name. Start with ##. Everything the converter understands is on Markdown syntax; every frontmatter field is on Pages and markdown.
2. Publish it as a draft
The body of the request is just {"markdown": "…"}; the site goes in blog_id or the X-OnPress-Blog-Id header. jq --rawfile keeps the file’s line breaks intact.
curl -s -X POST -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
-H "X-OnPress-Blog-Id: 233" "$BASE/pages/markdown" \
-d "$(jq -n --rawfile md page.md '{markdown: $md}')"
{
"success": true,
"updated": false,
"id": 6351,
"status": "draft",
"lang": "en",
"parent": 6349,
"url": "/docs/recepty/sozdat-stranicu/",
"link": null,
"visible": false,
"translations": { "en": 6351 },
"frame": { "id": "af33214f168f8efd", "slug": "obolochka-dokumentaciya", "meta_key": "_onpress_frame" },
"lang_changed": { "changed": true, "from": null, "to": "en" },
"warnings": [
"page is not published (status \"draft\"), the address does not serve it"
],
"preview_url": "https://test.onpress.pro/?page_id=6351",
"…": "…"
}
3. Read the response
The response is the state of the page after saving, not an echo of the request. Four fields answer “did it work”:
| Field | What it tells you |
|---|---|
updated | false — a new page was created, true — an existing one was overwritten |
link | the public address; null while the page has none (draft, pending) |
visible | true only when the status is publish, no ancestor is unpublished and the page really shows up in its language |
warnings | every reason something is off without failing the request, including why visible is false |
Keep id: write it into the frontmatter as id: 6351, and every later publish goes straight to this page. A template_ignored warning, if you sent a template, means the field was not applied at all — the look is the frame, and the docs sidebar is step 5.
4. Publish and update in place
Change status to publish, edit the text and send the same document again. With id in the frontmatter the page is updated directly; without it the page is found by slug + lang (and url, when given, narrows the search to one branch). Either way you get the same page, now with updated: true.
{
"success": true,
"updated": true,
"id": 6351,
"status": "publish",
"lang": "en",
"parent": 6349,
"url": "/docs/recepty/sozdat-stranicu/",
"link": "https://test.onpress.pro/docs/recepty/sozdat-stranicu/",
"visible": true,
"translations": { "en": 6351 },
"frame": { "id": "af33214f168f8efd", "slug": "obolochka-dokumentaciya", "meta_key": "_onpress_frame" },
"warnings": [],
"preview_url": null,
"…": "…"
}
On a multilingual site always send lang. Without it a page with the same slug in another language is still a match and gets overwritten; several matches without id are 409 ambiguous_page with the candidates, and nothing is written. A segment of url that does not exist is 422 parent_not_found — create the parent first.
5. Put it in place in the docs tree
An item of the docs sidebar is a page with the meta _wp_page_template = templates/docs.php — that is how the theme selects them. v2 does not write that meta any more, so a freshly published page is put into the sidebar by the sidebar itself:
curl -s -X POST -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
"$BASE/docs/sidebar/items/6351/show" -d '{"blog_id": 233}'
A page that is already in the sidebar needs none of this: republishing it leaves the meta alone.
A new page lands among its siblings by menu_order. The order inside one branch is set with POST /docs/sidebar/reorder. The full form names the order of the branch; siblings you leave out follow the named ones and come back in appended.
curl -s -X POST -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
"$BASE/docs/sidebar/reorder" -d '{"blog_id": 233, "parent": 101, "order": [103, 102, 104]}'
{
"success": true,
"blog_id": 233,
"parent": 101,
"order": [103, 102, 104, 106],
"appended": [106],
"updated": 4,
"notified": 4
}
To move one page, send {"id": 6351, "after": <sibling>}, or before, or a zero-based position; the answer then carries id, its new menu_order and the resulting order. Reorder never moves a page into another branch: a page from another parent in order is 409 not_a_sibling. Changing the parent changes the page’s address, and the old one is not redirected — see Docs sidebar.
Check
Open link from the last response: it answers 200 and shows the text. visible is true and warnings is empty. GET /docs/sidebar?blog_id=233&lang=en lists the page under its parent. A second publish of the same file returns updated: true and the same id — no -2 copies.
See also
- Pages and markdown — every frontmatter field, lookup rules and publish errors.
- Markdown syntax — what the converter turns into blocks.
- Docs sidebar — the tree, reorder, hiding and moving items.
- Frames — the shell named in
frame:.