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

Filament Sort Order Laravel Package

ibrahimbougaoua/filament-sort-order

filament-sort-order is a Laravel/Filament package that adds drag-and-drop sorting to Filament tables. Configure an order column, enable reordering in your resource, and persist row positions automatically.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package via Composer and let Filament's plugin auto-discovery do its work:

    composer require ibrahimbougaoua/filament-sort-order
    

    Check config/filament-sort-order.php after install (publish it with php artisan vendor:publish --tag="filament-sort-order-config" if the package ships one) — this is where the sort column name and any global toggles typically live.

  2. Add an order column to the model's table if you don't already have one. The description says “no extra migrations required,” but that means no package-specific migrations — you still need a column to persist to:

    $table->unsignedInteger('sort_order')->default(0)->index();
    

    A nullable or defaulted integer is fine; the package writes the new values on drop.

  3. Enable reordering on the table in your Filament resource. The first thing to check is the resource's table() method — that's where every configuration example in the package's README will live:

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                TextColumn::make('name'),
            ])
            ->defaultSort('sort_order')
            ->reorderable('sort_order'); // column name matches your migration
    }
    
  4. Your first use case: a Category resource where editors control navigation order. Seed a few rows with sequential sort_order values, drag one row above another in the admin panel, refresh, and confirm the persisted order changed. That single end-to-end loop is the whole value proposition — verify it before wiring it into anything complex.

  5. Where to look first if something is off: the resource's table() signature (does it expect ->reorderable() or a plugin registration like ->plugin(SortOrderPlugin::make())?), then the published config for the column name, then the browser network tab for the PATCH/POST request fired on drop. With a 22-star package, the README is the source of truth and may lag behind the code — read the actual src/ classes if the documented method names don't exist on your Filament version.

Implementation Patterns

Default-sort everything. The single most important pattern: any table using reordering should also have ->defaultSort('sort_order'). Without it, the rows render in whatever order the database returns, so the drag-and-drop UI appears to “lose” the order after a reload even though the write succeeded.

Scope ordering to a parent. For menus, FAQ sections, or anything nested, the sort is almost always relative to a parent. Use Filament's scoped reordering so positions are (parent_id, sort_order) rather than global:

->reorderable('sort_order', condition: fn (Builder $query) => $query->where('menu_id', $this->menuId))

If the package doesn't expose a condition parameter, handle scoping in getEloquentQuery() on the resource and confirm the package reads the filtered query when computing positions.

Combine with the standard Filament reordering trait for new records. Dragging only fixes existing rows. New rows still need a position assigned on create. In the model (or an observer):

protected static function booted(): void
{
    static::creating(function ($model) {
        $model->sort_order ??= (static::max('sort_order') ?? 0) + 1;
    });
}

This keeps appends at the end rather than all collapsing to 0.

Use it inside Relation Managers too. Relation manager tables are just tables, so the same ->reorderable() call applies — this is the natural fit for “FAQ items within an FAQ category” where you don't want a separate resource per child.

Respect policies. The description notes it “works with existing policies,” which means you should verify it actually checks update before persisting. If it doesn't, wrap the table visibility yourself (->reorderable(fn () => auth()->user()->can('update', $record))) so read-only roles can't reorder.

Pair with ->paginated(false) for small lists. Drag-and-drop across paginated pages is a known limitation in every Filament reorder implementation — the UI only reorders the visible page. For short lists (categories, statuses, nav items), disabling pagination gives editors the full picture and avoids surprise “positions reset on page 2” bugs.

Seeding and imports should always set sort_order deterministically ($index + 1 in the seeder loop), because the drag handler assumes the column is populated and unique-ish. Gaps are fine; duplicates cause ambiguity on the next drag.

Gotchas and Tips

  • Duplicated positions. If two rows share the same sort_order (common after manual DB edits or bulk inserts with defaults), a drag may only update one and leave rows visually “stuck.” Run a one-off php artisan tinker cleanup to renumber sequentially before handing the feature to editors.
  • No unique index on sort_order. Don't add one — reordering rewrites several rows in sequence, and a unique constraint will throw mid-transaction. Use a plain index instead.
  • Multi-tenant / global scopes are invisible to the package. If your model has a global scope (tenant, published, soft-deleted), confirm the reorder query includes it. Soft-deleted rows with positions will otherwise cause gaps or collisions when restoring.
  • Reordering + active filters = surprise renumbers. If an editor filters to “published only” and drags, most implementations renumber the filtered subset from 1, which silently re-orders unpublished rows into unexpected spots. Test this explicitly; if it misbehaves, disable reorder while any filter is active.
  • Check the Filament version. The package's last release is 2024-09-24 — that predates Filament 4. If you're on Filament 4, note that ->reorderable() is built into the table builder natively, so you may not need the package at all. Verify compatibility before committing to it in a new project.
  • Debug the drop with the network tab, not the UI. When a drag appears to work but doesn't persist, it's usually a 403 (policy), a 422 (validation on the sort column), or the wrong column name in config. Inspect the request payload and the returned JSON — that tells you which of the three it is in seconds.
  • Cache invalidation. If you cache the ordered list (navigation, sitemap, API response), hook the model's updated event or the package's persistence point to bust the cache. Otherwise editors reorder, see it in the admin, and report “the frontend is broken.”
  • Testing. Livewire drag events are awkward to simulate. The pragmatic approach: unit-test the underlying reorder logic/observer directly (call the model method with an array of IDs and assert the resulting sort_order values), and leave the actual drag UX to manual QA.
  • Extension points to know: the config file (column name), the table's ->reorderable() call (per-resource opt-in), and the model itself (new-record positioning). Those three cover 95% of customization — if you find yourself patching vendor code, you're probably fighting a missing default sort or a missing scope rather than a package limitation.
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