Pages form a nested tree. A PagibleAI installation can have several root pages for different domains or languages, and each page stores immutable versions so editors can work on drafts without changing the public site.
GraphQL Pages
Query root pages and children
The pages query is paginated. Filter by parent_id: null for roots or pass a parent UUID for its direct children.
query PageTreeLevel($parent: ID, $first: Int!, $page: Int!) {
pages(
filter: { parent_id: $parent, lang: "" }
publish: DRAFT
trashed: WITHOUT
sort: [{column: _LFT, order: ASC}]
first: $first
page: $page
) {
data {
id
parent_id
name
title
path
status
has
latest { id published publish_at }
}
paginatorInfo {
currentPage
lastPage
count
total
}
}
}
{
"parent": null,
"first": 25,
"page": 1
}
{
"data": {
"pages": {
"data": [
{
"id": "018f0f9d-83b3-7d69-a1b2-6f2db5e40c35",
"parent_id": null,
"name": "Home",
"title": "Home",
"path": "",
"status": 1,
"has": 12,
"latest": {
"id": "0198d2c8-b887-7a31-9e96-1082195f6bb0",
"published": false,
"publish_at": null
}
}
],
"paginatorInfo": {
"currentPage": 1,
"lastPage": 1,
"count": 1,
"total": 1
}
}
}
}
has is the number of descendants below the page, not a Boolean. Use publish: DRAFT for the latest editor versions and publish: PUBLISHED for currently published versions.
Retrieve one page
query PageDetail($id: ID!) {
page(id: $id) {
id
parent_id
related_id
lang
path
domain
name
title
to
tag
theme
type
meta
config
content
status
cache
restricted
access
editor
changed
parent { id title }
children(first: 25) {
data { id title path }
paginatorInfo { total }
}
ancestors { id title path }
latest { id published publish_at editor created_at }
}
}
The access field requires access:view; restricted only tells you whether immediate rules exist. Relations to shared elements and files require their corresponding view permissions.
Page fields
Frequently used Page fields
Filter and sort pages
Effective PageFilter fields
The current resolver applies the fields listed above. Use any for page-name, title, metadata, configuration or content text. Sort with sort: [{column: TITLE, order: ASC}]; supported columns are ID, NAME, TITLE, EDITOR and _LFT.
Create a page draft
Omit both parent and ref to append a root page. Pass parent to append a child, or ref to insert before a sibling. The new page receives an unpublished version.
mutation AddPage($input: PageInput!, $parent: ID) {
addPage(input: $input, parent: $parent) {
id
parent_id
title
latest { id published }
}
}
{
"parent": "018f0f9d-83b3-7d69-a1b2-6f2db5e40c35",
"input": {
"lang": "en",
"path": "about-us",
"name": "About",
"title": "About our company",
"status": 1,
"cache": 5,
"meta": "{\"meta-tags\":{\"type\":\"meta-tags\",\"data\":{\"description\":\"Meet the people behind our company.\"},\"files\":[]}}",
"config": "{}",
"content": "[{\"id\":\"intro\",\"type\":\"text\",\"group\":\"main\",\"data\":{\"text\":\"This is our story.\"}}]"
}
}
The MLL JSON scalar accepts JSON-encoded strings. Stringify meta, config and content once when sending variables, and parse those fields when reading them. References inside the decoded documents are resolved automatically, so addPage has no separate files or elements arguments.
Create a translation
Create a separate page for each language and set related_id to the source page’s UUID. Place the translation below the appropriate language root.
mutation AddTranslation($input: PageInput!, $parent: ID!) {
addPage(input: $input, parent: $parent) {
id
related_id
lang
path
latest { id published }
}
}
{
"parent": "018f3112-b0a3-7201-9040-1ed12f57fc20",
"input": {
"related_id": "018f0f9d-83b3-7d69-a1b2-6f2db5e40c35",
"lang": "de",
"path": "ueber-uns",
"name": "Über uns",
"title": "Über unser Unternehmen",
"status": 1,
"content": "[]",
"meta": "{}",
"config": "{}"
}
}
Save redirects and canonical URLs
Set to to a site-relative path or validated absolute URL when the page should redirect. Store canonical metadata as a keyed, canonical entry and encode the complete metadata document once:
{
"id": "018f0f9d-83b3-7d69-a1b2-6f2db5e40c35",
"latestId": "0198d2c8-b887-7a31-9e96-1082195f6bb0",
"input": {
"to": "",
"meta": "{\"canonical\":{\"type\":\"canonical\",\"data\":{\"url\":\"https://www.example.com/about-us\"},\"files\":[]}}"
}
}
Pass these variables to the existing SavePage operation. Use a non-empty to only for a redirect; clear it with an empty string when the page should render normally.
Move a page
mutation MovePage($id: ID!, $parent: ID, $before: ID) {
movePage(id: $id, parent: $parent, ref: $before) {
id
parent_id
}
}
Position arguments
Save with conflict detection
PageInput is partial when saving. Send only changed fields, and pass the latest.id you originally read as latestId. If another editor saved first, PagibleAI merges non-overlapping changes and returns details in changed for conflicting fields.
mutation SavePage($id: ID!, $latestId: ID!, $input: PageInput!) {
savePage(id: $id, latestId: $latestId, input: $input) {
id
title
changed
latest { id published }
}
}
{
"id": "018f0f9d-83b3-7d69-a1b2-6f2db5e40c35",
"latestId": "0198d2c8-b887-7a31-9e96-1082195f6bb0",
"input": {
"title": "A clearer page title",
"cache": 10
}
}
{
"data": {
"savePage": {
"id": "018f0f9d-83b3-7d69-a1b2-6f2db5e40c35",
"title": "A clearer page title",
"changed": null,
"latest": {
"id": "0198d3ad-5c8f-7be7-a09e-5ae6d4eac542",
"published": false
}
}
}
}
Update several pages
bulkPage applies one partial input to up to 1,000 pages. Set descendants: true to include each selected page’s subtree. Bulk saves create drafts; they do not alter published output.
mutation HideSubtree($ids: [ID!]!) {
bulkPage(id: $ids, input: {status: 2}, descendants: true) {
ids
latest
data
failed
}
}
Set frontend access
Access changes take effect immediately and are separate from page versions. Pass null for public access, an empty list to require any authenticated user, or one or more access values when a matching grant is required.
mutation ProtectPages($ids: [ID!]!) {
setPageAccess(
id: $ids
access: ["customer", "subscriber"]
descendants: true
)
}
{
"data": {
"setPageAccess": 3
}
}
Publish now or schedule
Publish the latest version of one or more pages with pubPage. Omit at to publish now or pass a DateTime to schedule publication.
mutation PublishPages($ids: [ID!]!, $at: DateTime) {
pubPage(id: $ids, at: $at) {
id
title
latest { id published publish_at }
}
}
Clear cached page output
clearCache(id: ID!) invalidates the selected page and its descendants and returns the number of affected pages.
mutation ClearPageCache($id: ID!) {
clearCache(id: $id)
}
Trash, restore and purge
mutation PageLifecycle($trash: [ID!]!, $restore: [ID!]!, $purge: [ID!]!) {
dropped: dropPage(id: $trash) { id deleted_at }
restored: keepPage(id: $restore) { id deleted_at }
purged: purgePage(id: $purge) { id }
}
dropPage soft-deletes pages so they can be restored with keepPage. purgePage permanently removes them and cannot be undone. Keep destructive operations separate in production workflows so the intended IDs are easy to review.
Troubleshoot page operations
Common page problems
any for indexed text