media24si/nova-youtube-field
A Laravel Nova field for attaching YouTube videos to your resources. It offers a searchable picker for YouTube URLs or video IDs, displays a thumbnail preview in the form, and saves the selected video so you can easily embed it in your application's frontend.
Install the field into an existing Nova application:
composer require media24si/nova-youtube-field
Before writing any code, confirm two things, because the package was last released in September 2018 and is archived:
Laravel\Nova\Fields\Field). Nova 4/5 moved to Laravel\Nova\Fields\Field with different component/meta conventions; the Vue component shipped here will likely fail to compile or render on modern Nova without patching.--ignore-platform-reqs or a fork.Once installed, the first use case is the obvious one: a model has a youtube_url (or video ID) column, and you want editors to paste a YouTube link in Nova and see a thumbnail/preview instead of a raw string input. The minimal resource wiring looks like:
use Media24si\NovaYoutubeField\NovaYoutubeField;
public function fields(Request $request)
{
return [
NovaYoutubeField::make('Video', 'youtube_url'),
];
}
Where to look first: open src/ and read the field class to see exactly which methods it exposes (->thumbnail(), ->width(), resolution helpers, etc.) and then read the Vue component under resources/js/ to understand what is actually rendered. Because the README is thin and the package is unmaintained, the source is the documentation.
Store the URL, not the embed HTML. Treat the field as a URL/ID input with a preview. Persist youtube_url as a normal string column and resolve the embed at render time on the front end. This keeps the data portable if you later drop Nova or swap the field.
Normalize on save. YouTube links arrive in many shapes (youtu.be/ID, watch?v=ID, embed/ID, with &t= params). Add a mutator or ->fillUsing() / ->storeAs() callback to extract and persist just the 11-character video ID, and keep the field as a thin viewer over that ID. This is the single most useful pattern with this package, because it stops you depending on the package's own parsing.
Pair with index and detail separately. Typical Nova pattern:
NovaYoutubeField::make('Video', 'youtube_id')
->onlyOnDetail(), // full embed/preview on the detail page
Text::make('Video', 'youtube_id')
->onlyOnIndex(), // cheap text on the index to avoid many iframes
Rendering many thumbnails/iframes on the index is a common performance and layout complaint; keep the rich preview on the detail view.
Wrap it in your own field class. Since the package is archived, the durable integration is to subclass or copy its field into app/Nova/Fields/YoutubeField.php and depend on that. You get the same editor experience, you own the upgrade path, and you can add validation (->rules('regex:/.../')) and a fallback placeholder thumbnail.
Validation belongs in your FormRequest, not the field. Use a regex rule for YouTube URLs and a ->help() string telling editors the accepted formats. The field itself does not enforce much.
npm run dev, check nova.mix/asset compilation and the field's component name. Nova silently renders a blank cell when the registered component name does not match the compiled bundle.dist/ and register via a service provider. If thumbnails are broken, run php artisan vendor:publish and confirm the provider is auto-discovered; a stale dist build against a newer Vue is a frequent culprit.img.youtube.com/vi/{id}/... or an youtube.com/embed iframe. Both still work today, but privacy-enhanced youtube-nocookie.com is not handled — swap it in the Vue component if you need GDPR-friendly embeds.Text::make('debug', 'youtube_url') next to the field to confirm whether the problem is input parsing or rendering. If the preview is empty but the URL looks right, the ID extraction in the Vue component (not PHP) is usually at fault.make(). Anything you need — thumbnail size, fallback image, aspect ratio, click-to-play — requires editing the copied Vue component. That is fine for a one-off internal tool, but plan the copy-and-own step up front rather than expecting configuration.How can I help you explore Laravel packages today?