Guide

Synchronization and REST API

DocsPress builds a desired Page model from Markdown, lists existing WordPress Pages, and reconciles only the Pages carrying a valid management sentinel.

WordPress endpoints

For WordPress.com, the Pages collection is:

https://public-api.wordpress.com/wp/v2/sites/{site}/pages

For self-hosted WordPress, it is:

{wordpress-url}/wp-json/wp/v2/pages

Listing requests use context=edit, status=any, and pages of 100 records until x-wp-totalpages is exhausted.

Request POST /wp-json/wp/v2/pages
HeadersKey: value
Accept application/jsonContent-Type application/jsonAuthorization Bearer $WP_ACCESS_TOKEN
Request bodyJSON
{
  "title": "Getting started",
  "slug": "getting-started",
  "status": "draft",
  "parent": 42,
  "content": "<!-- docspress:{...} -->\n<!-- wp:paragraph -->..."
}
Response 201 Created
BodyJSON
{
  "id": 43,
  "slug": "getting-started",
  "status": "draft",
  "parent": 42
}

Updates use POST /pages/{id}. Deletions use DELETE /pages/{id} and add force=true only for delete-mode: force.

Management sentinel

Every generated Page starts with a hidden comment containing version, Page key, source path, and content hash:

<!-- docspress:{"version":1,"key":"docs/getting-started","source":"docs/getting-started.md","hash":"…"} -->

The hash covers the Page key, source, title, slug, parent key, status, and converted body. A content, route, hierarchy, source, or status change therefore schedules an update.

In propose and reconcile modes, the same hash acts as a common ancestor. DocsPress computes the current GitHub and live WordPress states against that ancestor before it performs any write.

Reconciliation order

Desired Pages are sorted by depth and key so parents are available before children. Existing Pages are indexed by their full parent path and by sentinel key.

ConditionOperation
No Page at the desired pathCreate
Managed Page with changed hash or parentUpdate
Managed Page with matching hash and parentUnchanged
Unmanaged Page already using the pathConflict; do not write
Managed Page below root-slug absent from desired docsTrash or permanently delete
Desired child whose parent is unavailableConflict

For bidirectional runs, a GitHub-only change is published, a WordPress-only title or content change becomes a pull request, and matching current states refresh the sentinel after that pull request merges. If both current states differ from the sentinel and from each other, the run fails before writes. WordPress-created or deleted Pages and WordPress slug, parent, or status changes are intentionally outside reverse-sync scope.

Dry-run behavior

Dry-run performs discovery, conversion, Page listing, comparison, conflict detection, deletion planning, and reverse Markdown generation. It assigns synthetic parent IDs for planned creates but does not call WordPress or GitHub write endpoints.

API errors

DocsPress surfaces the WordPress error message. When WordPress.com reports that global scope is required, the error adds a hint to regenerate WP_ACCESS_TOKEN with the token helper.