Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Pagebuilder Laravel Package

flobbos/laravel-pagebuilder

flobbos/laravel-pagebuilder is a flexible, extensible page builder for Laravel apps. Compose pages from reusable content blocks, manage templates and translations, and render dynamic content in Blade views—ideal for maintainable, content-driven sites without custom CMS overhead.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and publish — pull the package in, then publish its config, migrations, and front-end assets:

    composer require flobbos/laravel-pagebuilder
    php artisan vendor:publish --provider="Flobbos\Pagebuilder\PagebuilderServiceProvider"
    php artisan migrate
    

    Check the published config/pagebuilder.php first — that's where model bindings, table names, and element registration usually live.

  2. Look at the migrations and models first. This package is opinionated around a Page → Row → Column → Element hierarchy. Reading the migration files tells you the exact table/column names faster than any docs. Then inspect the shipped Page, Row, Column, and Element models to see the relationships and any HasTranslations/SoftDeletes traits.

  3. Check the routes and editor UI. The service provider typically registers routes for the builder admin UI and asset/public paths for the editor JS/CSS. Run php artisan route:list | grep -i page to confirm what's exposed and whether it's guarded by middleware out of the box (it usually isn't — see Gotchas).

  4. First practical use case: create a Page record, attach a couple of Rows, put Columns inside them, and drop a text Element into a column. Render it in a Blade view with the package's render helper or by iterating relationships:

    @foreach ($page->rows as $row)
        <div class="row">
            @foreach ($row->columns as $column)
                <div class="col-{{ $column->width }}">
                    @foreach ($column->elements as $element)
                        @include("pagebuilder.elements.{$element->type}", ['data' => $element->data])
                    @endforeach
                </div>
            @endforeach
        </div>
    @endforeach
    

    Get that loop working before touching the editor UI — it isolates whether your problem is data shape or front-end.

Implementation Patterns

  • Custom elements as a registry. The core value of this package is "custom tailored elements." Register element types (usually in the config or a service provider) mapping a type string → a Blade partial and possibly a form definition. Keep each element as its own partial under resources/views/pagebuilder/elements/ so designers can edit markup without touching PHP. Treat the type column as a stable contract; renaming it later orphans stored content.

  • Store element payloads as JSON, render defensively. Elements generally persist a data JSON blob. Cast it on the model ('data' => 'array'), validate the shape when saving in your own controllers, and guard the render partial with data_get()/null-coalescing so a partially-filled element never throws a 500 on a public page.

  • Wrap the builder behind your own admin resource. Rather than exposing the package routes directly, mount the editor inside your existing admin (Nova, Filament, Backpack, or plain controllers) and keep the package as the storage/render layer. You get auth, policies, and audit for free, and you're insulated if the package's route names change.

  • Compose pages into layouts, not the reverse. Let Page own rows, and let a "template" be a named Blade layout that includes the row loop. This keeps the builder agnostic: marketing pages, landing pages, and CMS articles can all reuse the same render partial with different wrappers.

  • Render-and-cache. Page builder content changes rarely but is read constantly. Store a rendered HTML snapshot (HTML column or cache key) invalidated on save/deleted model events. This also lets you strip the editor's runtime JS from the public bundle entirely.

  • Reusable element patterns: hero/banner, rich text (store sanitized HTML), image + caption, CTA button group, embed (YouTube/Vimeo with allow-list), and a "columns of cards" grid. Each maps cleanly to one partial and one form schema, and together they cover ~80% of marketing asks.

  • Multi-language pages: if the package ships translation traits, keep translated fields on the element data, not the row/column structure, so layout stays shared across locales. If it doesn't, add a locale scope on Page rather than duplicating rows.

  • Seeding/fixtures: build a small artisan command or seeder that constructs a demo page (2 rows, mixed elements). It doubles as a smoke test in CI to catch broken render partials after upgrades.

  • Blueprints as data: encode default page templates (e.g., "Landing", "About") as JSON in config/pagebuilder.php and have a service hydrate rows/columns/elements from them on page creation. Faster than clicking through the editor for every new page.

Gotchas and Tips

  • No authorization out of the box (typically). The shipped editor routes are frequently unguarded or guarded only by web. Before deploying, verify every route in route:list, and either wrap the package routes in your own middleware group or disable them and build your own editor endpoints. This is the single biggest production risk with small builder packages.

  • Asset publishing is easy to forget. After composer update, editor JS/CSS in public/vendor/... can go stale. Add vendor:publish --tag=pagebuilder-assets --force to your deploy script (or a post-update composer script) and confirm the tag name in the service provider.

  • Sanitize rich-text element content on save, not just render. Store clean HTML (HTMLPurifier / mews/purifier) so downstream consumers (RSS, search index, API) can't accidentally re-emit unsafe markup. Also escape in Blade for non-HTML element types — {!! !!} should only appear in the one partial that expects sanitized HTML.

  • N+1 on render is the default failure mode. The row→column→element loop will issue a query per level. Eager load the whole tree: Page::with('rows.columns.elements')->findOrFail($id). For listing pages, restrict columns (with('rows:id,page_id', ...)) or you'll pull every JSON blob on the index.

  • Schema drift is silent. Because content lives in JSON, altering an element's expected keys won't fail at save time — it fails at render, in production, on one page. Version your element payloads (e.g., data._v) and write a migration command that rewrites old shapes when you change a form.

  • Config cache traps. Custom element registrations done via a closure or config() merge at boot behave differently under php artisan config:cache. Register elements in a service provider binding, not inline in a route or controller, and always test with config:cache enabled before shipping.

  • Editor and app JS conflicts. Page builder editors often bundle an older Vue/jQuery or a global window helper. If the editor page breaks your admin layout, load its scripts via a dedicated layout that excludes your global bundle rather than debugging conflicts in reverse.

  • Small-package maintenance risk. With a low star count and recent-but-sparse releases, pin the version in composer.json ("flobbos/laravel-pagebuilder": "^1.0"), and keep your render partials in your app (not overriding vendor views via a fragile path) so a breaking upstream view change can't take down production pages. Fork readiness: the row/column/element model is simple enough that migration to a homegrown equivalent is a weekend if needed.

  • Debugging "empty page" reports: check in this order — (1) rows relation returns anything, (2) status/published scope, (3) the element type string matches a registered partial, (4) Blade @include path is correct for the namespaced view (pagebuilder::elements.x vs pagebuilder.elements.x). The 90% case is a mismatch between the stored type and the partial name.

  • Extension points worth using: model swapping via config (so you can add HasMedia, search indexing, or a slug unique constraint), the element registry, and the render partial override path. Avoid editing the vendor directory directly — every one of these packages gets a small breaking change eventually.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource