PHPackages                             bambamboole/filament-pages - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. bambamboole/filament-pages

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

bambamboole/filament-pages
==========================

A Filament plugin for managing hierarchical, block-based content pages with a drag-and-drop page tree, SEO integration, and live preview

0.4.2(1mo ago)0150↑66.7%[1 issues](https://github.com/bambamboole/filament-pages/issues)[2 PRs](https://github.com/bambamboole/filament-pages/pulls)1MITPHPPHP ^8.4CI passing

Since Mar 3Pushed 1mo agoCompare

[ Source](https://github.com/bambamboole/filament-pages)[ Packagist](https://packagist.org/packages/bambamboole/filament-pages)[ Docs](https://github.com/bambamboole/filament-pages)[ GitHub Sponsors](https://github.com/:vendor_name)[ RSS](/packages/bambamboole-filament-pages/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (8)Dependencies (63)Versions (11)Used By (1)

Filament Pages
==============

[](#filament-pages)

[![Latest Version on Packagist](https://camo.githubusercontent.com/9bc168a6e6b453d7f55701c5bdc2a8ec407ec2687535a51024c591156bc66a36/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f62616d62616d626f6f6c652f66696c616d656e742d70616765732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/bambamboole/filament-pages)[![GitHub Tests Action Status](https://camo.githubusercontent.com/7a395c7e536bd6836ef06cad84a359255dbb89f7562af11b683b05efacfa0874/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f62616d62616d626f6f6c652f66696c616d656e742d70616765732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/bambamboole/filament-pages/actions?query=workflow%3Arun-tests+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/a90db92471b08c869157736e43494eddef656a959032b377a6f0076ca04f4a28/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f62616d62616d626f6f6c652f66696c616d656e742d70616765732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/bambamboole/filament-pages)

A Filament plugin for managing hierarchical, block-based content pages. Features a drag-and-drop page tree, extensible block system (Markdown, Image out of the box), nested pages with automatic slug path computation, multi-locale support, SEO integration, and live preview.

Features
--------

[](#features)

- **Page Tree** — Interactive drag-and-drop tree for reordering and nesting pages
- **Block Builder** — Flexible content composition with an extensible block system
- **Markdown Block** — Rich editor with table of contents, heading permalinks, GFM support, and optional Torchlight syntax highlighting
- **Image Block** — Spatie Media Library integration with responsive images and an image editor
- **Custom Blocks &amp; Layouts** — Artisan generators for scaffolding your own blocks and layouts
- **Multi-Locale** — Locale-scoped page trees with automatic route prefixing and browser language detection
- **SEO** — Built-in SEO metadata tab with extensible fields and optional OG image generation via Browsershot
- **Live Preview** — Instant page preview powered by Filament Peek
- **Publishing Workflow** — Draft, published, and scheduled states with `published_at` datetime
- **Authorization** — Laravel policy support for `create`, `update`, `delete`, and `reorder` abilities
- **Frontend Routing** — Catch-all route registration that resolves pages by slug path and locale
- **Hierarchical Slugs** — Automatic slug path computation based on the page tree hierarchy

Screenshots
-----------

[](#screenshots)

Page EditorSEO Tab[![Page Editor](art/page-tree.png)](art/page-tree.png)[![SEO Tab](art/page-seo.png)](art/page-seo.png)Installation
------------

[](#installation)

```
composer require bambamboole/filament-pages
```

Publish and run the migrations:

```
php artisan vendor:publish --tag="filament-pages-migrations"
php artisan migrate
```

Optionally publish the config:

```
php artisan vendor:publish --tag="filament-pages-config"
```

Register the plugin in your Filament panel provider:

```
use Bambamboole\FilamentPages\FilamentPagesPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            FilamentPagesPlugin::make(),
        ]);
}
```

Add the plugin views to your Tailwind CSS content paths:

```
@source '../../../../vendor/bambamboole/filament-pages/resources/**/*.blade.php';
```

Configuration
-------------

[](#configuration)

The plugin is configured through the fluent API on `FilamentPagesPlugin` and the published config file.

```
FilamentPagesPlugin::make()
    ->seoForm(fn () => [
        TextInput::make('canonical_url'),
    ])
    ->treeItemActions(fn (ManagePages $page) => [
        Action::make('duplicate')->action(fn (array $arguments) => /* ... */),
    ])
    ->previewView('my-custom-preview-view')
```

Blocks and layouts are auto-discovered using PHP attributes. Add your application's directories to the discovery paths in `config/filament-pages.php`:

```
// config/filament-pages.php
'block_discovery_paths' => [
    app_path('Blocks'),
],

'layout_discovery_paths' => [
    app_path('Layouts'),
],
```

### Blocks

[](#blocks)

Blocks are classes annotated with `#[IsBlock]` that extend `AbstractBlock`. They are auto-discovered from the package's built-in `Blocks/` directory and any directories listed in `block_discovery_paths`.

Two blocks ship out of the box:

- **MarkdownBlock** — Rich markdown editor with optional table of contents (top/left/right positioning), front matter parsing, and Torchlight syntax highlighting.
- **ImageBlock** — Spatie Media Library file upload with responsive images and an image editor.

### Layouts

[](#layouts)

Layouts control how pages render on the frontend. They are classes annotated with `#[IsLayout]` that extend `AbstractLayout`. They are auto-discovered from the package's built-in `Layouts/` directory and any directories listed in `layout_discovery_paths`.

### Multi-Locale

[](#multi-locale)

Enable multi-language content by configuring locales in the config file:

```
// config/filament-pages.php
'routing' => [
    'prefix' => '',
    'locales' => ['en' => 'English', 'de' => 'Deutsch'],
],
```

When locales are enabled, the page tree filters by locale and frontend routes include a `{locale}` prefix.

### SEO

[](#seo)

SEO is always enabled. Every page form includes an SEO tab (powered by `ralphjsmit/laravel-filament-seo`).

Extend the SEO form with custom fields:

```
->seoForm(fn () => [
    TextInput::make('canonical_url'),
])
```

### Response Caching

[](#response-caching)

Enable HTTP response caching for frontend pages using `spatie/laravel-responsecache`:

```
// config/filament-pages.php
'cache' => [
    'enabled' => env('FILAMENT_PAGES_CACHE_ENABLED', false),
    'lifetime' => 60 * 60,   // 1 hour fresh
    'grace' => 60 * 15,      // 15 min stale-while-revalidate
],
```

When enabled, cached responses are served instantly and refreshed in the background after expiry. The cache is automatically invalidated when a page is saved or deleted.

### Preview

[](#preview)

Live preview is always enabled (powered by `pboivin/filament-peek`). To use a custom preview view:

```
->previewView('my-custom-preview-view')
```

Creating Custom Blocks
----------------------

[](#creating-custom-blocks)

Generate a block stub with the Artisan command:

```
php artisan filament-pages:make-block MyCustomBlock
```

A custom block uses the `#[IsBlock]` attribute for metadata, extends `AbstractBlock`, and defines a `build()` method to configure the Filament form schema:

```
use Bambamboole\FilamentPages\Blocks\AbstractBlock;
use Bambamboole\FilamentPages\Blocks\IsBlock;
use Filament\Forms\Components\Builder\Block;
use Filament\Forms\Components\TextInput;

#[IsBlock(type: 'call-to-action', label: 'Call to Action')]
class CallToActionBlock extends AbstractBlock
{
    protected string $view = 'blocks.call-to-action';

    public function build(Block $block): Block
    {
        return $block->schema([
            TextInput::make('heading')->required(),
            TextInput::make('button_text')->required(),
            TextInput::make('button_url')->url()->required(),
        ]);
    }
}
```

The `#[IsBlock]` attribute accepts `type` (unique identifier matching the block type stored in the database), `label` (display name), and an optional `translateLabel` flag. If `label` is omitted, it is derived from the type automatically.

### Block Schema (Structured Data)

[](#block-schema-structured-data)

Blocks can contribute JSON-LD structured data by overriding the `registerSchema()` method. The page model collects schema entries from all blocks and passes them to the SEO layer automatically.

```
use Bambamboole\FilamentPages\Blocks\AbstractBlock;
use Bambamboole\FilamentPages\Blocks\IsBlock;
use Bambamboole\FilamentPages\Models\Page;
use Filament\Forms\Components\Builder\Block;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\TextInput;
use RalphJSmit\Laravel\SEO\SchemaCollection;

#[IsBlock(type: 'faq', label: 'FAQ')]
class FaqBlock extends AbstractBlock
{
    protected string $view = 'blocks.faq';

    public function build(Block $block): Block
    {
        return $block->schema([
            Repeater::make('questions')->schema([
                TextInput::make('question')->required(),
                TextInput::make('answer')->required(),
            ]),
        ]);
    }

    public function registerSchema(SchemaCollection $schema, array $data, Page $page): SchemaCollection
    {
        return $schema->addFaqPage(function ($faqSchema) use ($data) {
            foreach ($data['questions'] ?? [] as $item) {
                $faqSchema->addQuestion($item['question'], $item['answer']);
            }

            return $faqSchema;
        });
    }
}
```

The `SchemaCollection` supports `addFaqPage()`, `addArticle()`, and `addBreadcrumbs()` out of the box. Blocks that don't override `registerSchema()` contribute nothing — no empty `` tags are generated.

### Block Assets

[](#block-assets)

Blocks can declare CSS and JavaScript assets by overriding the `assets()` method. Assets are deduplicated per request and rendered via Blade directives in your layout.

```
use Bambamboole\FilamentPages\Blocks\BlockAsset;

public function assets(): array
{
    return [
        'css' => [
            BlockAsset::url(asset('css/cta.css')),
            BlockAsset::inline('.cta { background: var(--primary); }'),
        ],
        'js' => [
            BlockAsset::url('https://cdn.example.com/lib.js'),
            BlockAsset::inline('console.log("CTA loaded");'),
        ],
    ];
}
```

`BlockAsset::url()` creates a ``/`` tag while `BlockAsset::inline()` creates an inline ``/`` tag. CSP nonces are applied automatically when `Vite::cspNonce()` is set.

Include the Blade directives in your layout to render block assets:

```

    @filamentPagesStyles
    @filamentPagesBlockStyles

    {!! $page->renderBlocks() !!}

    @filamentPagesBlockScripts

```

Blocks that don't override `assets()` contribute nothing.

Creating Custom Layouts
-----------------------

[](#creating-custom-layouts)

Generate a layout stub:

```
php artisan filament-pages:make-layout LandingPage
```

A layout uses the `#[IsLayout]` attribute for metadata, extends `AbstractLayout`, and provides a `render()` method:

```
use Bambamboole\FilamentPages\Layouts\AbstractLayout;
use Bambamboole\FilamentPages\Layouts\IsLayout;
use Bambamboole\FilamentPages\Models\Page;
use Illuminate\Http\Request;
use Illuminate\View\View;

#[IsLayout(key: 'landing-page', label: 'Landing Page')]
class LandingPageLayout extends AbstractLayout
{
    protected string $view = 'layouts.landing-page';

    public function render(Request $request, Page $page): View
    {
        return view($this->view, ['page' => $page]);
    }
}
```

The `#[IsLayout]` attribute accepts `key` (unique identifier used in the database), `label` (display name), and an optional `translateLabel` flag. If `label` is omitted, it is derived from the key automatically.

Include the asset directives in your layout to load the frontend CSS and any block-specific assets:

```

    @filamentPagesStyles
    @filamentPagesBlockStyles

    {!! $page->renderBlocks() !!}

    @filamentPagesBlockScripts

```

Route Registration
------------------

[](#route-registration)

Register the frontend page routes in your `routes/web.php`:

```
use Bambamboole\FilamentPages\Facades\FilamentPages;

FilamentPages::routes();
```

When locales are configured, routes are automatically prefixed with `{locale}`.

Frontend Rendering
------------------

[](#frontend-rendering)

Pages are rendered through their assigned layout using `{!! $page->renderBlocks() !!}`.

You can also render blocks programmatically:

```
$page = Page::where('slug_path', '/about')->first();
echo $page->renderBlocks();
```

Import &amp; Export
-------------------

[](#import--export)

Pages can be exported to and imported from YAML files. Both commands are idempotent — running them multiple times produces the same result.

### Export

[](#export)

```
php artisan filament-pages:export --path=resources/pages --locale=en --type=page
```

Exports pages as YAML files in a hierarchical directory structure. Media files are exported alongside their page. Parent pages with children use `_index.yaml`, and filenames are prefixed with their sort order (e.g. `01-about/`).

### Import

[](#import)

```
php artisan filament-pages:import --path=resources/pages --locale=en --type=page --prune --dry-run
```

OptionDescription`--path`Source directory (default: `resources/pages`)`--locale`Locale for imported pages`--type`Page type (default: `page`)`--prune`Soft-delete database pages not found in source`--dry-run`Preview changes without modifying the databaseThe importer creates, updates, or skips pages based on whether changes are detected. Soft-deleted pages are restored if they reappear in the source files. Media referenced in YAML blocks are imported automatically.

Page Tree
---------

[](#page-tree)

The plugin provides an interactive page tree at `/pages` in your Filament panel. You can:

- Drag and drop to reorder and nest pages
- Create, edit, and delete pages via slide-over modals
- Publish/unpublish with datetime scheduling
- Switch between locales
- Preview pages before publishing

Custom actions can be added to tree items:

```
FilamentPagesPlugin::make()
    ->treeItemActions(fn (ManagePages $page) => [
        Action::make('duplicate')->action(fn (array $arguments) => /* ... */),
    ])
```

Authorization
-------------

[](#authorization)

The package supports Laravel policies for access control. Create a policy for your page model to restrict actions:

```
php artisan make:policy PagePolicy --model=Page
```

Supported abilities: `create`, `update`, `delete`, `reorder`.

The package is **permissive by default** — when no policy is registered, all actions are allowed. Once a policy exists, only explicitly allowed abilities are permitted.

Laravel Boost Skill
-------------------

[](#laravel-boost-skill)

This package ships with a [Laravel Boost](https://laravel.com/docs/12.x/boost) skill that teaches AI agents how to create custom blocks and layouts. The skill is auto-installed when users run `php artisan boost:install` and provides detailed guidance on the block/layout architecture, asset system, and testing patterns.

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Credits
-------

[](#credits)

- [Manuel Christlieb](https://github.com/bambamboole)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance91

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

8

Last Release

53d ago

PHP version history (2 changes)0.1.0PHP ^8.3

0.2.0PHP ^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/547137a6d80cad01ed1dd065b1c6af329d9a23a4134a895cff01e078cc155500?d=identicon)[bambamboole](/maintainers/bambamboole)

---

Top Contributors

[![bambamboole](https://avatars.githubusercontent.com/u/8823695?v=4)](https://github.com/bambamboole "bambamboole (64 commits)")

---

Tags

laravelfilamentfilament-pluginfilamentphpbambamboolefilament-pages

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/bambamboole-filament-pages/health.svg)

```
[![Health](https://phpackages.com/badges/bambamboole-filament-pages/health.svg)](https://phpackages.com/packages/bambamboole-filament-pages)
```

###  Alternatives

[dotswan/filament-map-picker

Easily pick and retrieve geo-coordinates using a map-based interface in your Filament applications.

124139.3k2](/packages/dotswan-filament-map-picker)[jibaymcs/filament-tour

Bring the power of DriverJs to your Filament panels and start a tour !

12247.8k](/packages/jibaymcs-filament-tour)[schmeits/filament-character-counter

This is a Filament character counter TextField and Textarea form field for Filament v4 and v5

33184.7k6](/packages/schmeits-filament-character-counter)[defstudio/filament-searchable-input

A searchable autocomplete input for Filament forms

3212.4k](/packages/defstudio-filament-searchable-input)[agencetwogether/hookshelper

Simple plugin to toggle display hooks available in current page.

2312.7k](/packages/agencetwogether-hookshelper)[jiten14/jitone-ai

jitone-ai is a powerful FilamentPHP plugin that integrates AI-powered features directly into your Filament forms.

213.1k](/packages/jiten14-jitone-ai)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
