Skip to content

PageBuilder Module

The PageBuilder module provides a drag-and-drop page editor with a block-based content system. Pages can be published, drafted, or archived and are rendered on the public frontend.

Overview

  • Visual drag-and-drop page editor
  • Block-based content system, extensible by other modules
  • Page status management (draft, published, archived)
  • SEO meta tags (OG balises) per page
  • Soft delete support
  • Public page rendering via slug

Routes

Web

MethodURINameMiddleware
GET/admin/page/listpage.listauth
GET/admin/page/createpage.createauth, can:page_create
POST/admin/page/createpage.create.requestauth, can:page_create
GET/admin/page/edit/{page}page.editauth, can:page_edit
PUT/admin/page/edit/{page}page.edit.requestauth, can:page_edit
DELETE/admin/page/delete/{page}page.deleteauth, can:page_delete
GET/{slug?}page.render

WARNING

The page.render route catches all unmatched URLs. Make sure it is the last route registered in your application.

Permissions

KeyDisplay NameDescription
page_createCreate pageAbility to create new pages
page_editEdit pageAbility to edit existing pages
page_deleteDelete pageAbility to delete pages

Page model

FieldTypeDescription
titlestringPage title
slugstringUnique URL slug
contentarraySerialized block tree
statusenumdraft, published, archived
og_balisesarraySEO meta tags as key/value pairs
created_byforeignIdUser who created the page
updated_byforeignIdUser who last updated the page
published_attimestampSet automatically when status changes to published

Block system

A block is the smallest unit of content in the PageBuilder. Each block has a PHP class that defines its schema and a Vue component that renders it.

Built-in blocks

TypeLabelDescription
pagePage containerRoot container with background color, text color, and padding
rowRowHorizontal container with configurable gap
columnColumnVertical container with configurable gap
textRich textRich text editor with Markdown output
imageImageImage with URL and alt text

Adding blocks from another module

See Creating a Block for a full step-by-step guide.

In short, register your block class in your module's service provider:

php
ModuleHelper::when('PageBuilder', function () {
    $registry = $this->app->make(\App\Modules\PageBuilder\Services\BlockRegistry::class);
    $registry->register(MyBlock::class);
});

And register the Vue component in your module's blocks.ts:

ts
import BlockRegistry from '@modules/PageBuilder/blockRegistry';

BlockRegistry.register('my-block', () => import('./Blocks/MyBlock.vue'));

BlockRegistry (PHP)

The BlockRegistry singleton manages all registered block classes on the PHP side.

MethodDescription
register(string $blockClass)Registers a single block class
registerMany(array $blockClasses)Registers multiple block classes
has(string $type): boolChecks if a block type is registered
definitions(): arrayReturns all block definitions (type, label, icon, schema)
serialize(array $blocks): arrayCleans and serializes a block tree for storage
render(array $blocks): arrayPrepares a block tree for frontend rendering
resolveInstance(array $block): AbstractBlockInstantiates a block from raw data

Frontend stores

The PageBuilder frontend uses a Pinia store (usePageBuilderStore) to manage the editor state.

Key state

PropertyTypeDescription
blocksPageBlock[]The current block tree
settingsPageBuilderSettingsPage title, slug, status, og_balises
selectedBlockPageBlock | nullCurrently selected block in the editor
hoveredBlockPageBlock | nullCurrently hovered block

Key actions

ActionDescription
addBlock(definition)Adds a block to the tree or to the selected container
removeById(id)Removes a block by ID anywhere in the tree
findBlockById(id)Finds a block by ID recursively
duplicateBlock(block)Deep-clones a block with new IDs
selectBlock(block)Sets the selected block
selectParentBlock(block)Selects the parent of the given block
hydrate(page, definitions?)Loads a page into the editor
serialize()Returns the current state ready for form submission
reset()Resets the store to its initial state
Page builder
├── List   →  page.list
└── Create →  page.create