Overview

The Docs CMS plugin is a first-party panel plugin that stores documentation pages as a tree and gives editors a drag-handle sidebar outline editor. It owns the data model, the admin CRUD, and the outline cache; the public /docs/{path} route is wired by the clone, not by the plugin.

Storage

Pages live in the doc_pages table — an adjacency list with a cached denormalised path.

Column Purpose
id Primary key
parent_id Self-FK, cascade-on-delete (subtree goes with the parent)
slug URL segment for this node
path Full materialised path, unique (e.g. plugins/docs-cms/overview)
position Sibling order, 1-based after applyTree
body Markdown (longText)
published_at null or past = published; future = scheduled
user_id Author FK, restrict-on-delete
seo_meta Polymorphic SEO via filament-seo (HasSeo)

Doc::booted() builds path on save (buildPath()), re-saves children when path/slug/parent_id change, and busts the outline cache on save/delete/restore.

Components

  • FilamentDocsPlugin::make() — the panel plugin; register() mounts DocResource and the ArrangeDocs page.
  • Doc model (Mamenein\FilamentDocs\Models\Doc, table doc_pages) — tree, publish scope, publicPath(), media collection body on the s3 disk.
  • DocResource — Create / Edit / List pages; form has parent select, title, slug, MediaMarkdownEditor body, PublishStatus, SeoFields.
  • ArrangeDocs page (Docs sidebar) — renders the filament-docs::sidebar-editor view; reorder() authorises every moved doc then runs DocOutline::applyTree() inside a transaction.
  • DocOutlinetree(), flatten(), moveUp/Down, nest/unnest, applyTree(), idsInTree().

Outline cache

DocOutline::tree(publishedOnly: true) selects only id, parent_id, title, slug, path, position, published_atbody is excluded — in one query. When DOCS_OUTLINE_CACHE=true the published set is cached as plain attribute arrays (binary-safe for libSQL cache stores) and hydrated back into Doc models. Saving or deleting any doc calls DocOutline::flushCache(). The editor view always fetches live (publishedOnly: false).

Public rendering

The plugin does not register /docs/{path}. The clone wires the route and the Blade view; it calls Doc::publicPath() (/docs/{path}) for links and the resource preview action.

flowchart LR
    A["Arrange Docs (drag)"] --> B["DocOutline::applyTree"]
    B --> C["doc_pages\nparent_id / position / path"]
    C --> D["DocOutline::tree\n(cached, body excluded)"]
    D --> E["clone route\n/docs/{path}"]
    C -. save/delete .-> F["flushCache"]
    F --> D

See also

Built by Qcentic