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:
- Log in as an admin
- Go to Admin → Settings
- Scroll to the "Features" section
- Check "Image Upload with Cropping"
- 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.