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

Nova Page Builder Field Laravel Package

digitalcloud/nova-page-builder-field

A Laravel Nova field that adds a page builder to your resources, letting users compose and manage page content through a flexible builder UI. Integrates page building directly into Nova so content structures can be created and edited alongside your models.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you install, check the calendar. The last tagged release is January 2019, which puts this package in the Nova 1.x / 2.x era (Laravel 5.7–5.8). If you're on Nova 4 or 5, the field's compiled JS relies on the old FormField / HandlesValidationErrors mixins and Nova::script() asset registration, so it will not mount without a fork and a rebuild. Verify against your composer.json Nova constraint first — that single check saves the most time.

Minimal path on a compatible Nova install:

composer require digitalcloud/nova-page-builder-field
php artisan vendor:publish --provider="DigitalCloud\NovaPageBuilderField\FieldServiceProvider"
php artisan nova:publish

Then add the field to a resource — the class lives under src/ in the package (commonly DigitalCloud\NovaPageBuilderField\PageBuilder; confirm the exact FQCN in the README or src/):

use DigitalCloud\NovaPageBuilderField\PageBuilder;

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Title'),
        PageBuilder::make('Content')->hideFromIndex(),
    ];
}

Where to look first, in order:

  1. README.md — for the exact field class name and any config options.
  2. src/ — the Field subclass; this is where component, resolveUsing, and fillUsing behavior is defined.
  3. resources/js/field.js (or similar) — the Vue component that boots GrapesJS. This is the file you'll almost certainly end up forking.
  4. config/ — if published, editor/plugin settings live here; otherwise options are hard-coded in the Vue component.

First use case: a Page model with a longText or json content column, a single Nova resource, and a Blade view that renders {!! $page->content !!} inside your site layout. Get one page rendering end-to-end before you introduce blocks, plugins, or a media manager. This validates the two things that usually break: the editor not mounting, and the stored HTML not surviving sanitization.

Implementation Patterns

Decide the storage shape on day one. GrapesJS emits HTML and CSS, and its project state is JSON. Storing only HTML means you can never re-open the page in the editor without losing structure; storing only JSON means your front end has to render the project. The durable pattern is both:

  • content_html (LONGTEXT) — what the front end serves.
  • content_project (JSON/LONGTEXT) — what the editor rehydrates.
  • content_css (LONGTEXT, nullable) — GrapesJS's component CSS, if you enable it.

Model events are the natural place to derive one from the other:

protected static function booted()
{
    static::saving(function ($page) {
        $page->content_html = app(HtmlSanitizer::class)->clean(
            $page->content_html ?? ''
        );
    });
}

Render with a wrapper contract. Pair the builder field with a plain Select for layout/template, then dispatch in Blade:

@extends('layouts.' . ($page->template ?? 'default'))

@section('content')
    <div class="pb-scope">
        @if($page->content_css)<style>{!! $page->content_css !!}</style>@endif
        {!! $page->content_html !!}
    </div>
@endsection

The .pb-scope wrapper matters — see gotchas.

Custom blocks without forking. GrapesJS's block manager is the intended extension point. If the package exposes a JS hook (check the Vue component for a block registration pass), register your app's blocks there. If not, publish the field's JS, keep the package's editor init, and append your own editor.BlockManager.add(...) calls. Keep these in a small, versioned JS file so upgrades are a diff, not a rewrite.

Draft vs. published. Don't serve unpublished edits straight from the same column. Keep the editor bound to draft columns, and on an explicit "Publish" action, copy draft → published and bump a published_at. This is cheap and prevents the common failure where an editor saves a half-finished layout and the live page breaks.

Preview inside Nova. A Text field with asHtml() or a small custom detail field that renders the stored HTML in an iframe is worth 20 lines — it lets editors check output without leaving the admin.

Multiple builders on one resource. If a page has hero + body + footer builders, give each a distinct attribute and confirm the package's Vue component keys its GrapesJS container by field attribute. If it hard-codes a container ID, only the first field will mount, and you'll need to patch the component.

Caching. Generated HTML is expensive to re-render but trivial to cache. Put a Cache::remember("page:{$id}:html", ...) around the render, and Cache::forget in the saved observer. This is the single highest-leverage addition for a builder-driven site.

Gotchas and Tips

  • The package is effectively unmaintained. 31 stars and a 2019 release means no Nova 4/5 support and no fixes for GrapesJS CVEs. Budget for a fork — treat the package as a starting reference implementation rather than a dependency you upgrade.
  • GrapesJS asset manager is not wired to Laravel storage by default. Images inserted via the editor frequently end up as base64 blobs inside the HTML, which bloats your column and destroys page weight. Configure an upload endpoint (Storage::disk('public')) and a custom AssetManager before you let anyone near the editor.
  • Sanitize server-side, always. The field stores raw HTML. Nova authorization controls who edits, not what they can inject. Run HTMLPurifier (or equivalent) on save with a conservative allowlist; strip <script>, on* handlers, and javascript: URLs.
  • CSS bleed is real. GrapesJS component CSS is global by default. Namespace it (.pb-scope { ... }) or, better, scope each component's rules at save time. Without this, a page builder style will silently restyle your admin or your marketing site.
  • hideFromIndex() on the builder field — the resource index will try to resolve and render megabytes of JSON otherwise, and Nova's search/sort columns get slow fast.
  • nova:publish after every install or update. The classic "field renders blank" symptom is stale compiled assets in public/vendor/nova. Clear it, re-publish, hard-refresh.
  • Debugging mount failures: open the browser console first (GrapesJS init errors surface there), then the network tab for the field's JS chunk, then storage/logs/laravel.log for PHP-side resolution errors. A blank grey box almost always means the Vue component threw during mounted().
  • Version pin GrapesJS. If you fork the JS and bump GrapesJS independently of the package's plugins, expect silent breakage in block rendering. Pin the exact version in your package.json and upgrade deliberately.
  • Storage limits. Project JSON for a rich page can exceed 64KB. Use LONGTEXT/JSON (not TEXT), and consider excluding the project column from default SELECT * queries via $hidden/$appends discipline.
  • Extension points, ranked by cost: (1) field options in the resource, (2) GrapesJS block/plugin registration in published JS, (3) a custom Nova field wrapping the package's component, (4) fork and rebuild. Stop at the lowest level that solves the problem — every step down increases your upgrade surface.
  • Have an exit plan. If you're on Nova 4+, the realistic options are a fork with rebuilt Vite assets or replacing the field with a bespoke GrapesJS integration. Decide which before you've built content dependent on this field's exact HTML output, because migration later means re-authoring pages.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package