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

Sortable Gallery Laravel Package

tjmpromos/sortable-gallery

A Laravel package for adding sortable image galleries to your app. Attach images to Eloquent models, reorder them with drag-and-drop sorting, and render galleries in your views. Streamlines gallery image management and custom ordering.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require tjmpromos/sortable-gallery
php artisan vendor:publish --provider="Tjmpromos\SortableGallery\SortableGalleryServiceProvider"
php artisan migrate

Look at three things first in the repo: the config/sortable-gallery.php (storage disk, image conversions, upload rules), the migration that ships with the package (what table/columns it adds and whether it's a polymorphic gallery table or a column on your model), and the src/ directory to confirm the Filament plugin class name before you register it.

Register the plugin on your panel (typically in app/Providers/Filament/AdminPanelProvider.php):

use Tjmpromos\SortableGallery\SortableGalleryPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(SortableGalleryPlugin::make());
}

Your first real use case is almost always a "Product images" or "Project photos" field inside a Filament resource form. Add the gallery component to the resource's form() schema, attach the package trait to the model, and you have upload + drag-to-reorder in the admin without writing a relation manager yourself. From there, render it on the frontend with the package's Blade component (or a small loop over the sorted relation) before you start customizing.

Implementation Patterns

Attach the gallery to an existing model. Add the package's trait/interface to the model (e.g. Product) and, if the package uses a dedicated table, make sure the migration is published and run. Keep a separate gallery relation or column rather than overloading a generic images mutator — the sort order is the whole point, and you want it scoped to one logical gallery.

Use it inside a Filament resource form. Drop the component into form() alongside your normal fields so editors configure the product and its images on the same screen:

public static function form(Form $form): Form
{
    return $form->schema([
        TextInput::make('name')->required(),
        SortableGallery::make('images')
            ->label('Product photos')
            ->maxFiles(12),
    ]);
}

Multiple galleries per model. Use the package's gallery/collection name argument (e.g. ->collection('hero') vs ->collection('gallery')) rather than duplicating models. This keeps sorting independent per gallery and lets the frontend request only the set it needs.

Render ordered on the frontend. Always query through the package's ordered scope / relation instead of relying on $model->images returning sorted rows by accident. A typical Blade usage:

@foreach ($product->gallery()->ordered()->get() as $image)
    <img src="{{ $image->url('thumb') }}" alt="{{ $image->alt }}">
@endforeach

If the package ships a Blade component, prefer <x-sortable-gallery :model="$product" collection="gallery" /> — it usually handles responsive srcset, lazy loading, and the sort_order join for you.

Reorder persistence. Reordering in the Filament UI writes the new sort_order via a Livewire reorder call. If you expose sorting anywhere else (custom page, API), reuse the package's reorder method rather than writing sort_order directly, so any cache-busting or model events it fires stay consistent.

API / Inertia integration. When images are consumed by an SPA, return id, url, thumb_url, alt, and sort_order from a resource or transformer. Don't send the raw media/attachment records — they leak paths and internal fields you don't want clients depending on.

Tenancy and per-tenant galleries. If you use Filament tenancy, make sure the gallery records are scoped to the tenant (either through the package's owner morph or by adding a tenant_id to the published migration). The default migration is usually global, so check before you deploy.

Gotchas and Tips

  • Don't paginate a sortable listing. Drag-to-reorder only works within one page of results. If you must paginate, disable dragging on non-first pages or the saved order silently interleaves across pages.
  • Storage disk and visibility. The published config defaults to public in most gallery packages. On S3 you usually need visibility: 'public' or signed URLs; confirm the URL method the Blade component uses before shipping.
  • Cache invalidation. If you cache the frontend gallery (fragment or model cache), clear it on the package's reorder/upload/delete events. Adding an observer on the gallery model for saved/deleted is the safest hook if the package doesn't already clear your cache.
  • Livewire upload limits. Large photos fail before the package sees them. Raise upload_max_filesize, post_max_size, and Livewire's temporary_file_upload.rules/max_upload_time in config/livewire.php.
  • Delete cascade. Verify the migration's foreign keys use cascadeOnDelete for the owning model. If not, add a deleting model observer to detach and delete gallery rows/files, otherwise orphaned files pile up on S3.
  • Conversions are lazy by default. The first frontend render can be slow while thumbnails generate. Either generate conversions on upload (a model event / queued job) or run php artisan media-library:regenerate if you're on Spatie underneath.
  • Config publishing collisions. The package likely publishes a migration and config with generic names. Publish with --tag if supported, and move the migration timestamp if it must run after your own *_create_* migrations.
  • Filament authorization. If editors shouldn't manage images, gate the component with ->visible() or a policy check on the owning model. Without it, any panel user with form access can upload and reorder.
  • Extension points. The clean places to customize are: the published config (disk, conversions, mime/size rules), a subclass of the gallery component (if it's a Filament field, you can extend and override getUploadedFileUsing/saveUploadedFileUsing), a custom Blade view for rendering, and model observers for cache/cleanup. Avoid editing package files in vendor/ — copy the view/config out on the first fork-worthy change.
  • Low-maturity caveat. At ~12 stars and a single recent release, treat the package as a thin wrapper you'll likely extend. Pin the version in composer.json, read the source for the reorder and delete paths, and add a feature test that uploads two images, reorders them, and asserts the frontend order — that one test will catch most regressions when you upgrade.
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
shitoudev/permissionmanager