Skip to content

[6.x] Forms 2: Expose form sections, pages and access restrictions in the REST & GraphQL APIs - #15349

Merged
jasonvarga merged 9 commits into
forms-2from
api-form-sections-pages
Oct 21, 2026
Merged

jasonvarga merged 9 commits into
forms-2from
api-form-sections-pages

Conversation

@duncanmcclean

@duncanmcclean duncanmcclean commented Sep 2, 2026 •

Copy link
Copy Markdown
Member

This pull request implements support for form sections in the REST API, and pages in both the REST and GraphQL APIs. The GraphQL API has had sections since #11466 but the REST API never got them, and neither API exposed pages.

sections returns every section across all pages, so it's the easy way to render a single-page form with the same structure as the Control Panel. pages returns each page's id, display, instructions and its sections, for rendering multi-page forms. Single-page forms return a single page with an id of main.

A page's display is the title configured in the form builder, or null when it doesn't have one. The Control Panel's "Page 1 of 2" placeholder isn't returned, so frontends can decide whether to render a heading.

Sectioned fieldset imports keep their sections (using Tab::expandedSections() from #15694), rather than being merged into the section they were imported into.

This PR also fixes the GraphQL sections field only returning the first page's sections on multi-page forms.

Access restrictions

This PR also exposes require_login, closed_message and require_login_message alongside the existing status, so headless frontends can tell whether a form is currently accepting submissions and what to show when it isn't.

The messages are the ones configured on the form (or the default messages when they're left blank), and they're always returned. It's up to the frontend to decide which one applies: closed_message when status isn't open, and require_login_message when require_login is true and its visitor isn't logged in. The API can't know who is visiting a headless frontend, which is why the template-only restriction_message isn't exposed.

REST API

GET /api/forms/contact

{
  "data": {
    "handle": "contact",
    "title": "Contact",
    "fields": { "name": {...}, "email": {...} },
    "sections": [
      { "display": "Your Details", "instructions": null, "fields": { "name": {...}, "email": {...} } }
    ],
    "pages": [
      { "id": "main", "display": null, "instructions": null, "sections": [...] }
    ],
    "status": "open",
    "require_login": false,
    "require_login_message": "You must be logged in to submit this form.",
    "closed_message": "This form is no longer accepting submissions.",
    "api_url": "http://example.com/api/forms/contact"
  }
}

GraphQL

{
    form(handle: "contact") {
        status
        require_login
        require_login_message
        closed_message
        pages {
            id
            display
            instructions
            sections {
                display
                instructions
                fields { handle display }
            }
        }
    }
}

Closes statamic/ideas#1320

duncanmcclean and others added 9 commits September 2, 2026 14:46
… graphql apis

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qe1g6yd25kh7oTxtWfzB95
…pages

# Conflicts:
#	src/Forms/Form.php
#	tests/Feature/GraphQL/FormTest.php
…on message

The restriction message depends on who is logged in, which an API request can't know. Expose the configured closed_message and require_login_message so headless frontends can decide what to show from status and require_login.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Untitled pages were returned with the control panel's "Page X of Y" placeholder. Return null instead, and cover the single-page shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jasonvarga
jasonvarga merged commit b9dc5e4 into forms-2 Oct 21, 2026
62 checks passed
@jasonvarga
jasonvarga deleted the api-form-sections-pages branch October 21, 2026 22:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants