Layout Builder
Package docs status
Section titled “Package docs status”This page is generated from public package documentation in capell-4/packages and the package manifest checked into the source repository.
| Field | Value |
|---|---|
| Composer package | capell-app/layout-builder |
| Package slug | layout-builder |
| Product group | Capell Foundation |
| Tier | free |
| Bundle | foundation |
| Runtime contexts | admin, frontend, console |
| Capell version | ^4.0 |
| Source repository | capell-app/packages |
| Source path | packages/layout-builder |
| Docs source | packages/layout-builder/docs |
| Manifest | capell.json |
capell-app/layout-builder owns Capell’s visual layout composition layer: layout containers, blocks, block assets, public layout graphs, content-first editing, and the Filament layout editor.
Core still owns sites, pages, languages, URLs, themes, and base content models. Admin still owns the Filament panel shell. Layout Builder plugs into both through package registrars and exposes its public API from the Capell\LayoutBuilder namespace.
Why It Helps Your Capell Workflow
Section titled “Why It Helps Your Capell Workflow”- Provides the visual composition layer for Capell: layouts, containers, blocks, assets, public render graphs, and editor mutations.
- Helps editors assemble pages without storing theme-specific presentation markup in database content fields.
- Gives developers Actions and registries for public-safe layout payloads, reusable presets, layout areas, and content-first editing.
Best Used With
Section titled “Best Used With”Install
Section titled “Install”composer require capell-app/layout-builderphp artisan capell:layout-builder-installThe install command publishes and runs the package migrations listed by Capell\LayoutBuilder\Support\CapellLayoutBuilderManager.
Configuration
Section titled “Configuration”Configuration lives in config/capell-layout-builder.php.
| Key | Purpose |
|---|---|
editor_mode.default | Default editor mode. Defaults to content_first. |
editor_mode.allowed | Allowed modes. Current values are content_first and layout_first. |
preview.match_frontend_container_layout | Match admin preview container layout to frontend columns. |
block.skip_render_empty | Skip empty blocks in public rendering. |
default_block | Default renderable key for new blocks. |
Main Surfaces
Section titled “Main Surfaces”| Surface | Package path |
|---|---|
| Public graph building | src/Actions/BuildPublicLayoutGraphAction.php |
| Public block payloads | src/Contracts/PublicBlockPayloadContributor.php, src/Support/DefaultPublicBlockPayloadResolver.php |
| Layout areas | src/Support/LayoutAreas/LayoutAreaRegistry.php, src/Actions/ResolveLayoutAreaContainersAction.php |
| Block presentation projection | src/Actions/ResolveBlockPresentationDataAction.php |
| Layout health checks | src/Actions/AnalyzeLayoutHealthAction.php |
| Reusable layout presets | src/Models/LayoutPreset.php, src/Actions/SaveLayoutPresetAction.php, src/Actions/ApplyLayoutPresetAction.php |
| Content-first inventory | src/Actions/BuildLayoutContentInventoryAction.php |
| Layout mutations | src/Actions/Mutations/ |
| Filament resources and schemas | src/Filament/ |
| Livewire editor | src/Livewire/Filament/LayoutBuilder.php |
| Admin views and components | resources/views/ |
Public Rendering
Section titled “Public Rendering”Use Capell\LayoutBuilder\Actions\BuildPublicLayoutGraphAction when a public route, API, or package needs layout content without depending on the frontend renderer.
$graph = BuildPublicLayoutGraphAction::run( layout: $layout, page: $page, language: $language, containers: ['main'], includeHtml: false,);Payload contributors are tagged with Capell\LayoutBuilder\Contracts\PublicBlockPayloadContributor::TAG. Contributors should return public-safe data or HTML only; do not expose admin state, editor-only metadata, private IDs, or unpublished content.
Block variants and settings are stored as authoring state in block meta, but public rendering receives only the sanitized presentation payload:
[ 'variant' => 'split-media', 'spacing' => 'normal', 'background' => 'default', 'mediaPosition' => 'top', 'cardsPerRow' => 3, 'showCta' => true, 'headingWidth' => 'normal', 'anchorId' => null,]Public Blade must not query the database, lazy-load relationships, resolve block contracts, expose raw meta, or include authoring selectors, signed URLs, diagnostics, package internals, schema, labels, or preview/admin view names.
Layout Areas
Section titled “Layout Areas”Layout areas let a theme expose named places where normal Layout Builder blocks can render outside the main page-body loop. The storage model stays unchanged: blocks still live inside layout containers, and containers may set meta.area.
- Missing
meta.areais treated asmainfor backwards compatibility. mainis built in and rendered by the normal main-content hook.- Themes and packages can register extra areas through
Capell\LayoutBuilder\Support\LayoutAreas\LayoutAreaRegistry. - The Foundation Theme registers
header, so editors can place normal blocks into the site header without hidden containers or a separate data model.
Register areas from a package service provider after the registry resolves:
use Capell\LayoutBuilder\Support\LayoutAreas\LayoutAreaRegistry;
$this->app->afterResolving( LayoutAreaRegistry::class, function (LayoutAreaRegistry $registry): void { $registry->register( key: 'header', label: __('capell-layout-builder::generic.header_area'), ); },);If an area only applies to one active theme, pass the theme key:
$registry->register( key: 'announcement', label: __('capell-theme-client::layout_areas.announcement'), themeKey: 'client',);Public area rendering should use the package renderer rather than querying from Blade:
<x-capell::layout.area area="header" />The area component reads the already-resolved layout containers and uses the stored CapellLayoutManager block instances. Keep public Blade query-free and authoring-free; area keys are public placement data, but editor state, model IDs, field paths, signed URLs, and package/admin metadata must stay out of the HTML.
Apps and package seeders should use AttachBlockToLayoutAreaAction when placing blocks into a named area. The action creates the area container when needed, normalizes the area key, preserves existing container metadata, and avoids duplicate block/occurrence pairs.
use Capell\LayoutBuilder\Actions\AttachBlockToLayoutAreaAction;
AttachBlockToLayoutAreaAction::run( layout: $layout, area: 'header', blockKey: 'announcement-bar', containerKey: 'site-announcement', containerMeta: ['container' => 'full'],);Reusable Presets
Section titled “Reusable Presets”Saved agency presets are persisted in layout_presets and scoped to a required site_id with optional theme_key. Presets are layout-only by default: they deep-copy structure, selected block variants, and settings without duplicating client content. Applying a preset revalidates site scope and regenerates duplicate anchors.
The older in-session LayoutPresetRepository remains only for temporary editor fragments; package and agency presets should use SaveLayoutPresetAction and ApplyLayoutPresetAction.
Visual Regression Manifests
Section titled “Visual Regression Manifests”Use capell:layout-builder-block-visual-regression capture or assert to emit deterministic block/variant/viewport fixture entries for a screenshot runner. The command supports --block, --theme, --variant, --changed, --concurrency, and --ci-limit.
The command does not authenticate, generate signed routes, query tenant content, or use live media. Browser capture/compare remains the responsibility of the runner.
Editor Modes
Section titled “Editor Modes”content_first is the default mode. It shows editor-facing content groups from the current layout state and lets editors update assigned block assets without navigating the full layout canvas.
layout_first opens the drag/drop layout builder directly. Keep it available for designers and implementers who need placement and structure control.
Both modes write through the same BlockAsset persistence path.
Run the package suite from the packages monorepo:
vendor/bin/pest packages/layout-builder/tests --configuration=phpunit.xmlRun the focused public graph and package-boundary checks after changing public rendering or package ownership:
vendor/bin/pest packages/layout-builder/tests/Integration/PublicLayoutGraphActionTest.php packages/layout-builder/tests/Arch/LayoutBuilderPackageBoundaryTest.php --configuration=phpunit.xml