Skip to content

#[Publishable] on AbstractPage / AbstractPageData — page-level draft/live toggle #186

Description

@silverbackdan

Problem

#[Publishable] (with publishedAt) exists for components: a component can be in draft state even inside a published page. There is no equivalent for pages themselves.

Currently, the only "draft" signal for a page is the absence of a Route. This works before publication, but once a page is live (route exists), there is no way to take it offline without deleting the route — losing URL history and any redirects pointed at it.

Desired behaviour

  • AbstractPage (base of Page and AbstractPageData) gets a publishedAt: ?\DateTimeInterface column via #[Publishable] (or a new #[PublishablePage] attribute if there are conflicts with the existing component-level implementation)
  • Unpublished pages (publishedAt: null) are invisible to unauthenticated users via the existing voter infrastructure (AbstractRoutableVoter, RouteVoter)
  • Admins can still access and edit unpublished pages via the entity IRI (same as draft components today)
  • RouteVoter gates public route resolution by the target page's publishedAt state
  • The resource_manifest endpoint respects the same gate

Things to consider

  • #[Publishable] today lives on components; its voter logic (PublishableVoter?) would need to be checked / extended for page-level entities
  • Page.isTemplate pages should probably always be accessible to admins regardless of publishedAt (template pages are never public-facing)
  • Draft page data entities with an existing Route — the route should resolve to 404/403 for public traffic, not 500
  • Interaction with cascadeChildPaths and the children endpoint: should unpublished children be hidden from the public children list?
  • Migration: existing pages have no publishedAt — default to null (draft) or to now() (treat existing pages as already published)? Likely now() for backwards compatibility

Acceptance criteria

  • AbstractPage and/or AbstractPageData gain a publishedAt column
  • Unauthenticated GET /_/routes/{path} to a page with publishedAt: null returns 403/404
  • Admin GET /_/resource_manifest/{uuid} for an unpublished page works for ROLE_ADMIN
  • Behat scenarios cover: public access denied, admin access allowed, publish via PATCH
  • Backwards-compatible migration (existing pages treated as published)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions