Installation:
composer require redberry/page-builder-plugin
Publish the plugin assets and config:
php artisan vendor:publish --provider="Redberry\PageBuilderPlugin\PageBuilderPluginServiceProvider"
Register the Plugin:
Add to app/Providers/Filament/AdminPanelProvider.php:
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
\Redberry\PageBuilderPlugin\PageBuilderPlugin::make(),
]);
}
First Use Case:
Create a basic block (e.g., TextBlock) by generating a stub:
php artisan make:page-builder-block TextBlock
This creates a TextBlock class in app/Filament/Resources/Blocks/TextBlock.php.
Register the Block:
In your PageBuilderPlugin registration, add:
->blocks([
\App\Filament\Resources\Blocks\TextBlock::class,
])
Use in a Resource:
Attach the page builder to a Filament resource (e.g., PageResource):
use Redberry\PageBuilderPlugin\Fields\PageBuilder;
public static function form(Form $form): Form
{
return $form->schema([
PageBuilder::make('content')->blocks([
\App\Filament\Resources\Blocks\TextBlock::class,
]),
]);
}
Structure:
Each block is a class extending Redberry\PageBuilderPlugin\Contracts\Block. Key methods:
fields(): Define form fields for block configuration.render(): Return a Blade view or string for frontend rendering.preview() (optional): Customize preview in the builder.Example:
class TextBlock extends Block
{
public static function fields(): array
{
return [
TextInput::make('title')->required(),
RichEditor::make('content'),
];
}
public function render(): string
{
return view('blocks.text', [
'title' => $this->title,
'content' => $this->content,
])->render();
}
}
Reusability:
Extend existing blocks or compose blocks (e.g., a ColumnBlock containing other blocks).
CRUD Integration:
Use PageBuilder field in a Filament resource to manage pages. Example:
PageBuilder::make('layout')
->blocks([TextBlock::class, ImageBlock::class])
->enableReorders()
->previewInIframe()
Data Handling:
content).$record->content to get raw data or $record->content->blocks for parsed blocks.@foreach($page->content->blocks as $block)
{!! $block->render() !!}
@endforeach
style="background: {{ $block->bgColor }}").Iframe Preview: Enable real-time preview with:
PageBuilder::make('content')->previewInIframe()
Configure the iframe URL in config/page-builder.php:
'preview_url' => env('APP_URL'),
Custom Preview Views:
Override preview() in blocks:
public function preview(): string
{
return view('blocks.previews.text', ['block' => $this])->render();
}
class PageResource extends Resource
{
public static function form(Form $form): Form
{
return $form->schema([
PageBuilder::make('builder_content')
->blocks([TextBlock::class, HeroBlock::class])
->columnSpanFull(),
]);
}
}
JsonSerializable or custom accessors to format API responses:
public function jsonSerialize(): array
{
return [
'title' => $this->title,
'content' => $this->content,
// Add other fields
];
}
config/page-builder.php:
'blocks' => [
'text' => [
'label' => 'Text Block',
'plural' => 'Text Blocks',
],
],
mix or Vite to compile block-specific CSS/JS. Reference assets in render():
@vite(['resources/css/blocks/text.css'])
PageBuilder field and the plugin config:
// In PageBuilderPlugin registration
->blocks([TextBlock::class]);
// In resource form
PageBuilder::make('content')->blocks([TextBlock::class]);
Undefined index errors when accessing block data.
@foreach($page->content->blocks ?? [] as $block)
{!! optional($block)->render() !!}
@endforeach
php artisan filament:cache:clear
config/page-builder.php during development:
'cache_previews' => false,
enableReorders() only on top-level blocks. For nested blocks, implement custom logic in fields():
PageBuilder::make('nested_content')->enableReorders(false);
render() for debugging:
\Log::debug('Block data:', $this->toArray());
$blocks = json_decode($record->content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
\Log::error('Invalid JSON in page builder:', $record->content);
}
BlockSaved):
use Redberry\PageBuilderPlugin\Events\BlockSaved;
BlockSaved::listen(function (BlockSaved $event) {
\Log::info('Block saved:', $event->block->toArray());
});
PageBuilder::make('content')
->blocks([
TextBlock::class->category('Content'),
ImageBlock::class->category('Media'),
]);
PageBuilder::make('content')
->blocks(fn () => BlockRepository::getAvailableBlocks())
class TextBlock extends Block
{
public static function thumbnail(): string
{
return view('blocks.thumbnails.text')->render();
}
}
use Redberry\PageBuilderPlugin\Contracts\StorageEngine;
class RedisStorage implements StorageEngine
{
public function store($data): string
{
// Custom logic
}
}
// Register in config
'storage_engine' => \App\Services\RedisStorage::class,
PageBuilder::make('content')
->blocks([
TextBlock::class->visible(fn (User $user) => $user->can('edit-text')),
]);
APP_URL. Override in `config/page-builderHow can I help you explore Laravel packages today?