Skip to main content
The gallery management system provides comprehensive tools for organizing photos into albums with media library integration using Spatie Media Library.

Permission Requirements

Gallery management requires the access.admin.panel permission. All routes are protected by authentication, email verification, and permission checks.
All gallery routes are nested under /admin/gallery:
// routes/web.php:103-110
Route::prefix('gallery')->name('gallery.')->group(function () {
    // Photo routes
    Route::resource('photos', PhotoController::class);
    
    // Album routes
    Route::resource('albums', AlbumController::class);
});

Photo Management

Manage individual photos at /admin/gallery/photos.

Viewing Photos

The photo index displays all photos with media attachments:
// app/Http/Controllers/Admin/PhotoController.php:15-19
public function index()
{
    $photos = Photo::with('media')->get();
    return view('admin.gallery.photos', compact('photos'));
}

Uploading Photos

Upload photos using the Livewire upload component.
1

Navigate to Upload

Go to /admin/gallery/photos/create
2

Select Image File

Choose an image file (max 20MB)
3

Upload and Process

The system creates a photo record and stores the media
4

View Uploaded Photo

Redirected to photo list with success message

Upload Photo Livewire Component

The UploadPhoto component handles file uploads:
// app/Livewire/Admin/UploadPhoto.php:11-42
class UploadPhoto extends Component
{
    use WithFileUploads;

    #[Validate('image|max:20480')]
    public $image;

    public function save()
    {
        $this->validate();

        // Create a new photo record
        $photo = Photo::create();

        // Add media to 'photos' collection
        $photo
            ->addMedia($this->image->getRealPath())
            ->usingFileName($this->image->getClientOriginalName())
            ->toMediaCollection('images', 'public');

        // Clear input and show success message
        $this->reset('image');
        return redirect()->route('admin.gallery.photos.index')
            ->with('success', 'Photo created successfully.');
    }
}

Photo Validation

Upload Limits
  • File type: Images only
  • Max size: 20MB (20,480 KB)
  • Accepted formats: JPEG, PNG, GIF, WebP

Editing Photos

Update photo details at /admin/gallery/photos/{photo}/edit.
// app/Http/Controllers/Admin/PhotoController.php:50-53
public function edit(Photo $photo)
{
    return view('admin.gallery.photo.edit', compact('photo'));
}
1

Access Photo Editor

Click “Edit” on any photo in the gallery
2

Update Metadata

Modify title, description, or other attributes
3

Save Changes

Photo updates with validation
// app/Http/Controllers/Admin/PhotoController.php:58-63
public function update(UpdatePhotoRequest $request, Photo $photo)
{
    $photo->update($request->validated());
    return redirect()->route('admin.gallery.photos.index')
        ->with('success', 'Photo updated successfully.');
}

Deleting Photos

Delete photos with automatic cleanup of media files and album relationships.
// app/Http/Controllers/Admin/PhotoController.php:68-73
public function destroy(Photo $photo)
{
    $photo->delete();
    return redirect()->route('admin.gallery.photos.index')
        ->with('success', 'Photo deleted successfully.');
}
Photo Deletion: When you delete a photo, it will be removed from all albums and its media files will be deleted from storage.

Managing Unassigned Photos

The Managephoto Livewire component shows photos not in any album:
// app/Livewire/Admin/Gallery/Managephoto.php:9-36
class Managephoto extends Component
{
    use WithFileUploads;

    public function deletePhoto($photoId)
    {
        $photo = Photo::find($photoId);

        if ($photo) {
            $photo->albums()->detach();
            $photo->clearMediaCollection('images');
            $photo->delete();
        }
    }

    public function render()
    {
        $unassignedPhotos = Photo::whereDoesntHave('albums')
            ->with('media')
            ->latest()
            ->paginate(12, ['*'], 'photosPage');

        return view('livewire.admin.gallery.managephoto', [
            'photos' => $unassignedPhotos
        ]);
    }
}

Album Management

Organize photos into albums at /admin/gallery/albums.

Viewing Albums

Albums are displayed with photo counts and cover images:
// app/Http/Controllers/Admin/AlbumController.php:14-22
public function index()
{
    $albums = Album::with('cover_photo')
        ->withCount('photos')
        ->latest()
        ->get();

    return view('admin.gallery.albums', compact('albums'));
}

Creating Albums

Create albums using the Livewire album manager.
1

Open Album Modal

Click “Create New Album” button
2

Enter Album Details

Provide album name, description, and category
3

Upload Cover Image

Optional: Upload a cover image (max 1MB)
4

Save Album

System generates slug and creates album

Manage Album Livewire Component

// app/Livewire/Admin/Gallery/Managealbum.php:10-48
class Managealbum extends Component
{
    use WithPagination;

    public $showAlbumModal = false;
    public $showDeleteModal = false;
    public $albumToDelete = null;

    // Album form properties
    public $album_name;
    public $description;
    public $category;
    public $album_cover;

    protected $rules = [
        'album_name' => 'required|min:3|max:255',
        'description' => 'nullable|max:1000',
        'category' => 'nullable|max:255',
        'album_cover' => 'nullable|image|max:1024'
    ];

    public function createAlbum()
    {
        $this->validate();

        $album = Album::create([
            'album_name' => $this->album_name,
            'description' => $this->description,
            'category' => $this->category,
        ]);

        if ($this->album_cover) {
            $album->addMedia($this->album_cover)
                ->toMediaCollection('album_cover');
        }

        $this->reset(['album_name', 'description', 'category', 'album_cover', 'showAlbumModal']);
        $this->dispatch('album-created');
    }
}

Album Validation Rules

Album Requirements
  • Name: Required, 3-255 characters
  • Description: Optional, max 1000 characters
  • Category: Optional, max 255 characters
  • Cover image: Optional, max 1MB

Album Slug Generation

Albums automatically generate URL-friendly slugs:
// app/Models/Album.php:25-34
protected static function boot()
{
    parent::boot();
    static::creating(function ($album) {
        // Only generate slug if album_name is set
        if ($album->album_name) {
            $album->slug = Str::slug($album->album_name);
        }
    });
}

Deleting Albums

Album deletion removes all associations and media:
// app/Livewire/Admin/Gallery/Managealbum.php:56-69
public function deleteAlbum()
{
    if ($this->albumToDelete) {
        $album = Album::find($this->albumToDelete);

        if ($album) {
            $album->photos()->detach();
            $album->clearMediaCollection('album_cover');
            $album->delete();
        }
    }

    $this->reset(['albumToDelete', 'showDeleteModal']);
}
Album Deletion: Deleting an album removes the album and its cover image, but does not delete the photos. Photos can be reassigned to other albums or remain unassigned.

Photo Model

The Photo model uses Spatie Media Library:
// app/Models/Photo.php:11-39
class Photo extends Model implements HasMedia
{
    use InteractsWithMedia;

    protected $table = 'photos';

    protected $fillable = [
        'title',
        'description'
    ];

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('images');
    }

    public function registerMediaConversions(?Media $media = null): void
    {
        $this
            ->addMediaConversion('preview')
            ->fit(Fit::Contain, 300, 300)
            ->nonQueued();
    }

    public function albums()
    {
        return $this->belongsToMany(Album::class, 'album_photo', 'photo_id', 'album_id');
    }
}

Photo Features

  • Media Collection: Photos stored in images collection
  • Preview Generation: Automatic 300x300 preview thumbnails
  • Album Association: Many-to-many relationship with albums

Album Model

The Album model with media support:
// app/Models/Album.php:12-54
class Album extends Model implements HasMedia
{
    use InteractsWithMedia;

    protected $table = 'album';

    protected $fillable = [
        'album_name',
        'slug',
        'category',
        'description'
    ];

    // Find album by slug instead of ID
    public function getRouteKeyName()
    {
        return 'slug';
    }

    public function registerMediaConversions(?Media $media = null): void
    {
        $this
            ->addMediaConversion('preview')
            ->fit(Fit::Contain, 300, 300)
            ->nonQueued();
    }

    public function photos()
    {
        return $this->belongsToMany(Photo::class, 'album_photo');
    }
}

Album Features

  • Slug-based URLs: Albums use slugs for clean URLs
  • Cover Image: Optional album cover in album_cover collection
  • Photo Count: Eager load photo counts for performance
  • Preview Generation: 300x300 previews for cover images

Media Library Integration

Spatie Media Library

LaraCMS uses Spatie Media Library for file management:
  • Collections: Organize media by type (images, album_cover)
  • Conversions: Automatic thumbnail generation
  • Storage: Files stored in public disk
  • Database: Media metadata in media table

Media Collections

CollectionUsed ByPurpose
imagesPhotosFull-size photo storage
album_coverAlbumsAlbum cover images

Image Conversions

Both photos and albums generate preview conversions:
// 300x300 preview with aspect ratio maintained
->addMediaConversion('preview')
    ->fit(Fit::Contain, 300, 300)
    ->nonQueued();

Photo-Album Relationships

Photos and albums use a many-to-many relationship:

Database Structure

  • Pivot Table: album_photo
  • Foreign Keys: photo_id, album_id
  • Association: One photo can belong to multiple albums

Managing Associations

// Attach photo to album
$album->photos()->attach($photoId);

// Detach photo from album
$album->photos()->detach($photoId);

// Detach photo from all albums
$photo->albums()->detach();

// Check if photo has albums
$unassigned = Photo::whereDoesntHave('albums')->get();

Best Practices

Optimize images before upload:
  • Resize large images (recommended max: 3000px)
  • Compress for web (80-90% quality)
  • Use appropriate formats (JPEG for photos, PNG for graphics)
  • Remove EXIF data if privacy is a concern
Organize albums effectively:
  • Use descriptive album names
  • Group related photos together
  • Add descriptions for context
  • Use categories for better organization
  • Set meaningful cover images
Keep storage clean:
  • Delete unused photos regularly
  • Monitor disk space usage
  • Run php artisan media-library:clean to remove orphaned files
  • Configure automatic cleanup if needed
Optimize gallery performance:
  • Use pagination for large galleries
  • Eager load relationships (with('media'))
  • Generate thumbnails for grid views
  • Consider CDN for public galleries

Troubleshooting

Common upload issues:
  • File too large: Increase PHP upload_max_filesize and post_max_size
  • Permission denied: Check storage directory permissions (775/755)
  • Invalid file type: Only images are accepted
  • Timeout: Large files may need increased max_execution_time
If images don’t display:
  • Verify storage link: php artisan storage:link
  • Check file permissions
  • Verify public disk configuration in config/filesystems.php
  • Clear cache: php artisan cache:clear
If thumbnails aren’t generating:
  • Check GD or Imagick extension is installed
  • Verify sufficient memory: memory_limit in php.ini
  • Check queue is running if using queued conversions
  • Run conversions manually: php artisan media-library:regenerate
Photos and albums are displayed on the frontend:
// routes/web.php:61-65
Route::prefix('gallery')->group(function () {
    Route::get('/', [GalleryController::class, 'index'])->name('gallery.index');
    Route::get('/album/{album:slug}', [GalleryController::class, 'album'])->name('gallery.album');
    Route::get('/album/{album:slug}/{image}', [GalleryController::class, 'image'])->name('gallery.image');
});

Next Steps

Blog Management

Learn about managing blog content

User Management

Control who can manage the gallery

Build docs developers (and LLMs) love