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 Repeater Blocks Laravel Package

dewsign/nova-repeater-blocks

A Laravel Nova package that adds repeater block fields, letting you build flexible, repeatable content sections in your admin panel with a simple drag-and-drop style interface for managing structured data.

Deep Wiki
Context7

Getting Started

1. Install and publish

composer require dewsign/nova-repeater-blocks
php artisan vendor:publish --provider="Dewsign\NovaRepeaterBlocks\NovaRepeaterBlocksServiceProvider"
php artisan migrate

Check composer.json constraints before you run this — the last tagged release is May 2022, so confirm the laravel/nova and illuminate/* version ranges actually admit your app. On Nova 4/5 expect to fork the package (see Gotchas).

2. Create your first block type

A block is two things: an Eloquent model (its own table, plus the polymorphic blockable_id / blockable_type columns) and a Nova resource describing how it's edited. Do this once with a trivial TextBlock and render it before you build the other ten.

3. Attach the field to the parent resource

use Dewsign\NovaRepeaterBlocks\Fields\RepeaterBlocks;

RepeaterBlocks::make('Blocks')
    ->types([
        TextBlock::class,
        ImageBlock::class,
    ]);

The field name (Blocks) must match the relation you expose on the parent model, and the parent needs the package's trait / morphMany relation wired up so $page->blocks returns the ordered collection.

4. First use case

A CMS Page with a mixed, reorderable stack: hero → rich text → image gallery → CTA. That's the whole point of the package — you get drag-and-drop ordering and per-block edit forms without hand-rolling a JSON schema field.

Where to look first: the package's source for RepeaterBlocks::make() and the base block model/contract, then the published migration (table names and column shapes). Everything else follows from those two files.

Implementation Patterns

One Nova resource per block type, hidden from navigation. Blocks are edited inside the parent form, not as standalone resources. Register them, then suppress them:

public static $displayInNavigation = false;

Also confirm the block resource is actually registered in NovaServiceProvider::resources() — the repeater resolves block forms through Nova's resource registry, and a missing registration fails at render time, not at boot.

Render with a per-type partial, resolved off the morph type. Keep the switch out of your Blade templates:

@foreach ($page->blocks as $block)
    @includeIf("blocks.{$block->blockType()}", ['block' => $block])
@endforeach

Give every block model a blockType() (or reuse $block->type) so the front end never touches class names.

Enforce a morph map early. If you let Nova write fully-qualified class names into blockable_type, you can never rename or namespace-move a block model. Register Relation::enforceMorphMap([...]) in a service provider on day one, not after 500 rows exist.

Ordering is yours to maintain. Store an order (or sort_order) column, sort in the relation definition (->orderBy('order')), and re-index on save if the package's drag-and-drop only writes positions. Verify what actually lands in the DB after a reorder — this is the single most common source of "why is the block order wrong in production but right in Nova".

Reuse across parents. Because the relation is polymorphic, the same block models work on Page, Post, and Product. If you need shared blocks (one instance referenced by many parents), that's a different schema — a pivot or a belongs-to-many — and this package won't give it to you.

Nested repeaters. A block can itself expose a RepeaterBlocks field. It works, but eager-load explicitly (blocks.blocks) or you'll pay for it on every list page.

API output. Don't leak raw models. Add a toArray()/toJson() on a base block class or a dedicated API resource per block type so the front end gets a stable { type, data } shape regardless of schema churn.

Seed and test with factories. Define a factory per block type and a helper that attaches Block::factory()->count(3)->create(['blockable_id' => $page->id, 'blockable_type' => $page->getMorphClass()]). It's the difference between 3-line tests and 30-line ones.

Gotchas and Tips

Version compatibility is the headline risk. Last release 2022-05-05, 34 stars, repo URL unknown. That predates Nova 4's field API rewrite. Before committing, read the package's composer.json and check whether the field extends Laravel\Nova\Fields\Field in a Nova-4-compatible way. If it doesn't, budget for a fork — the views and the resolve/fill logic are the parts that break, and they're usually small enough to patch in a day.

Orphaned blocks. Deleting a parent won't necessarily delete its blocks. Add a deleting model event or a DB-level cascade on the polymorphic relation — a real cascade needs application logic, since FKs can't express it across a morph.

Field name ≠ relation name is a silent failure: the field renders, the form submits, nothing saves. Double-check the string passed to make().

blockable_type stored as FQCN. If you adopt a morph map later, write a migration to rewrite existing rows. Mismatched values between the morph map and stored data produce empty repeater collections with no error message.

Authorization surprises. Every block type is a Nova resource, so policies and canSee/canRun apply to the embedded form too. Editors who can edit a Page but not an ImageBlock will see a broken or empty block form rather than a permission error. Audit policies when you scope roles.

N+1 on index views. Nova's index doesn't know your blocks exist. Any custom card, metric, or resource that displays block content must ->with('blocks') explicitly.

Stale vendor assets. After publishing or updating, clear compiled views and re-publish Nova assets (nova:publish). A half-rendered block form is almost always a cached view, not a bug.

i18n and multi-column blocks. Packages like spatie/laravel-translatable usually need to be applied field-by-field inside your block resource; don't assume the repeater propagates translatable configuration.

Debugging checklist for a block that won't render: (1) is the block resource registered in Nova? (2) does blockable_type match the morph map? (3) does the order column have a value? (4) does the relation on the parent exist and return a collection? Four checks, ninety percent of issues.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect