Media lifecycle hooks
Action hooks fired when files are uploaded or deleted from the media library.
These action hooks fire during upload and deletion in the media library. Each hook receives a Media model (or just the ID after deletion) so your plugin can react to file changes without polling the database.
contensio/media/uploaded
Type: Action
Since: 1.4.0
Source: MediaController::upload()
Fired after a file has been stored on disk and the Media database record has been created. Fires once per file — if a user uploads three files in a single batch, this hook fires three times.
For image files, the ProcessMediaVariants job is dispatched just before this hook fires, so variant generation (thumbnail, medium) may still be in progress when your callback runs.
Arguments
| # | Name | Type | Description |
|---|---|---|---|
| 1 | $media |
Media |
The newly created media record. |
Media properties
| Property | Type | Description |
|---|---|---|
$media->id |
int |
Database ID |
$media->file_name |
string |
Original filename as uploaded by the user |
$media->file_path |
string |
Storage-relative path (uploads/2026/04/uuid.jpg) |
$media->mime_type |
string |
MIME type (image/jpeg, application/pdf, etc.) |
$media->file_size |
int |
Size in bytes |
$media->width |
int|null |
Pixel width — images only |
$media->height |
int|null |
Pixel height — images only |
$media->disk |
string |
Laravel storage disk name (default: public) |
$media->isImage() |
bool |
Helper method — true if MIME starts with image/ |
Example — sync to a CDN after upload
use Contensio\Models\Media;
add_action('contensio/media/uploaded', function (Media $media) {
if (! $media->isImage()) return;
CdnSync::push(
storage_path('app/public/' . $media->file_path),
$media->file_name
);
});
Example — reject file types outside an allowlist
add_action('contensio/media/uploaded', function (Media $media) {
$allowed = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
if (! in_array($media->mime_type, $allowed)) {
Storage::disk($media->disk)->delete($media->file_path);
$media->delete();
}
});
Notes
- Variant images (thumbnail, medium) are queued before this hook fires and may not yet exist on disk when your callback runs. If your callback needs variants, listen for a later point (e.g. a custom event dispatched from your own
ProcessMediaVariantsreplacement). - This hook fires for every file type — images, PDFs, videos, etc. Use
$media->isImage()or check$media->mime_typeif your callback is image-specific.
contensio/media/deleting
Type: Action
Since: 1.4.0
Source: MediaController::destroy()
Fired just before the file is removed from disk and the database record is deleted. All variant records are still in the database and all files are still on disk when this hook runs.
Arguments
| # | Name | Type | Description |
|---|---|---|---|
| 1 | $media |
Media |
The media entry about to be deleted, with variants eager-loaded. |
Example
use Contensio\Models\Media;
add_action('contensio/media/deleting', function (Media $media) {
// Remove from CDN before we lose the path
CdnSync::delete($media->file_name);
foreach ($media->variants as $variant) {
CdnSync::delete($variant->path);
}
});
Notes
- Use this hook (not
contensio/media/deleted) when you need access to the file path, filename, or variant records. - Both the original file and all variant files are deleted after this hook returns.
contensio/media/deleted
Type: Action
Since: 1.4.0
Source: MediaController::destroy()
Fired after the file has been removed from disk and the Media database record has been deleted. Only the original ID is available.
Arguments
| # | Name | Type | Description |
|---|---|---|---|
| 1 | $id |
int |
The ID of the deleted media record. |
Example
add_action('contensio/media/deleted', function (int $id) {
AuditLog::record('media.deleted', $id);
Cache::forget("media:{$id}");
});
Notes
- The database record and all variant records are already gone. Do not attempt
Media::find($id). - If you need file path or filename, use
contensio/media/deletinginstead.