Image Upload Documentation

Overview

The Image Upload feature provides a complete solution for image uploading with client-side cropping and server-side optimization.

  • Client-side image cropping using Cropper.js
  • Configurable aspect ratios (1:1, 16:9, 4:3, free-form)
  • Server-side image optimization (resize, quality, WebP conversion)
  • File size optimization (targets 50-80KB for optimal loading)
  • Temporary storage workflow (images processed before form submission)
  • Theme-aware UI using CSS variables
  • Livewire/Volt component architecture

Enabling the Feature

The feature is disabled by default. Enable it via the Admin Dashboard:

  1. Log in as an admin
  2. Go to Admin → Settings
  3. Scroll to the "Features" section
  4. Check "Image Upload with Cropping"
  5. Click "Save Settings"

After enabling, you may need to clear the config cache: php artisan optimize:clear

Basic Usage

Use the Blade component in your forms:

<x-forms.image-upload
    name="image"
    label="Product Image"
    :aspect-ratio="1"
    :target-width="600"
    :target-height="600"
    :existing-image="$product->image ?? null"
    hint="Upload a square image for best results"
/>

Component Props

Prop Type Default Description
name string 'image' Form field name
label string 'Image' Field label
directory string 'images/uploads' Storage directory
aspect-ratio float|null 1.0 Aspect ratio (null for free-form)
target-width int 600 Output width in pixels
target-height int 600 Output height in pixels
existing-image string|null null Path to existing image
required bool false Whether field is required
hint string '' Helper text below label
existing-image-url string|null null URL for existing image (when path not in storage)
preview-max-width int|null null Max width in pixels for preview area
auto-cleanup bool false Delete temp image on page leave (demos)
immediate-upload-url string|null null URL to save image when crop & save is clicked
immediate-remove-url string|null null URL to remove image when Remove is clicked
show-remove-button bool true When false, only Add/Change Image button is shown

Controller Example

Use ImageProcessingService to commit the temporary image:

use App\Services\ImageProcessingService;

public function store(Request $request, ImageProcessingService $imageService)
{
    $validated = $request->validate([
        'name' => 'required|string',
        'image_path' => 'nullable|string',
    ]);

    $imagePath = null;
    if ($request->filled('image_path')) {
        $imagePath = $imageService->commitTemporaryImage(
            $request->input('image_path'),
            null, // existing image to delete
            $validated['name'] // optional: rename to match name
        );
    }

    $product = Product::create([
        'name' => $validated['name'],
        'image' => $imagePath,
    ]);

    return redirect()->route('products.show', $product);
}

Livewire Events

The component dispatches these events:

  • image-processed
    Dispatched when an image is successfully cropped. Payload: ['path' => '...']
  • image-removed
    Dispatched when the user removes the selected image.
  • image-error
    Dispatched when an error occurs. Payload: ['message' => '...']

Troubleshooting

Images aren't displaying after upload

Ensure the storage symlink exists: php artisan storage:link

Feature toggle doesn't work after enabling

Clear config cache: php artisan optimize:clear

Upload fails with large files

Check PHP's upload_max_filesize and post_max_size settings.