feat: #3631526 Generate into the site's own Image and SVG Image media types, keeping the AI tabs
Issue: #3631526
AI Media no longer needs AI media types of its own. Each generator saves into one of the site's media types, and the Media Library keeps its AI tabs: Image, Generate image with AI, SVG Image, Generate SVG with AI.
What changed
- One media type each. Generated images are saved as the site's Image media, generated SVGs as its SVG Image media (core Image source, svg field), generated videos as its Video media (core Video file source). The
ai_generated_imageandai_generated_videomedia sources,AiGeneratedSourceInterface,AiGeneratedSourceTraitand their schema are removed. Generators declare core sources in#[AiMediaGenerator(media_source: ...)]. - Mapping on the settings page. New setting
generators.<id>.media_type(defaults:image,svg_image,video). The Generators table has a Media type column listing only compatible types (by source, and by the field's extensions overlapping the generator's); None means no generator. A missing, non-existent or incompatible mapping simply means no tab and no generator. One media type holds one generator (validated). Older settings read the defaults through the existing settings-defaults override; no update hooks.AiMediaGeneration::generatorOf(MediaTypeInterface)returns the offered generator mapped to a type, or NULL. - Media Library. Core's
imageandvideo_filesources (any source a generator names, while it is on core's form) useAiMediaGenerateForm, which now extends core'sFileUploadForm: withoutai_media=1it is core's upload form; with it, and a mapped generator, the input is the generator exactly as before (description, examples, options, disclosure, cost line, Generate with core HTMX, review with name and alt, Generate again, Remove, Save). The mode is kept in form state across AJAX and HTMX rebuilds.ai_mediais an extra query parameter, outsideMediaLibraryState's hash, whichfromRequest()keeps. Because a module may own the upload form instead (DropzoneJS replaces it forimageandvideo_fileon Varbase), the Media Library UI builder is swapped (service provider, core's arguments kept) to build AI Media's form in AI mode for a type with a generator, and the type's own form otherwise. BothFileUploadFormandMediaLibraryUiBuilderare@internal; the phpstan notices are ignored inline. - AI tabs. In
preprocess_links__media_library_menu, each AI tab is inserted right after its media type's tab, linking to that tab's URL plusai_media=1, and is the active tab (with "(selected)") in AI mode. Same rules as before: tabs setting, generator offered and its tab setting, permission, configured (admins see the setup message), New badge;tab_position: endputs them last in the generators' order. - Core's Add media page (
/media/add/image,/media/add/svg_image,/media/add/video) keeps core's file widget and adds the generator below it, "✦ Or generate with AI". Generating fills the source field, name and alt; core's Save keeps it, and a plain upload still saves without a description. Types without a generator are untouched. - Generate media with AI and
/media/add?ai=1list only types with a mapped, offered generator the user can create. - SVG rules (selectable SVG thumbnails, image style fallback) apply to the SVG generator's mapped type: the thumbnail rule is now a per-bundle definition, not a change to every media type.
- Config actions and recipe. New
setAiMediaTypesaction (image: image,svg: svg_image); unknown or incompatible types fail.recipes/ai_media_svg_examplenow creates (or keeps)svg_imagewithfield_media_svg_image, maps SVG to it, and its page field isfield_animated_svg. - Docs updated, including a new Add media screenshot.
Upgrading from 1.0.0-alpha1
There is no migration while the module is pre-release. Sites on alpha1 must delete their two AI media types (those using "Image generated with AI" and "Video generated with AI"), and their media, before updating, then check the Media type of each generator on the settings page.
Tested
- New Kernel tests:
MediaTypeMappingTest(defaults, older settings, None/missing/incompatible/off, lighter generator wins, compatible types, config action) andMediaLibraryAiTabsTest(tab insertion and order, active state in AI mode,endposition and hiding rules, upload vs AI mode and mode kept on rebuild, Add media stacked form and permission, and the AI tab opening the generator when another module owns the upload form).SvgMediaTestcovers SVG thumbnails on the mapped type only.MediaTypeOrderTestremoved. 80 Kernel tests pass locally on Drupal 11.4.11. - phpcs (Drupal, DrupalPractice) clean on PHP; phpstan level 0 clean apart from the
new static()notices the template ignores; cspell adds no new words; eslint on the step definitions clean. - varbase-e2e free lane (Echo provider) on a fresh Drupal 11.4 standard site with the updated fixtures recipe: 42 scenarios, 784 steps pass.
- Browser at 1440 px: the four tabs in order; an image and an SVG generated from the AI tabs and saved as Image and SVG Image, with the AI tab still selected after Save; the Image tab still uploads;
/media/add/imageshows the upload with "Or generate with AI" below, generates, and saves; the settings page lists only compatible types.
Follow-up for drupal/varbase_ai_media_base
Drop its image_ai_gen / svg_ai_gen media types, set the mapping (setAiMediaTypes: { image: image, svg: svg_image }), keep svg_image allowed in Full HTML Insert Media, and grant create image media / create svg_image media with generate media with ai.
AI-Generated: Yes. Drafted and tested with Claude Code.
Checkpoints:
- File an issue
- Addition/Change/Update/Fix
- Testing to ensure no regression
- Automated unit testing coverage
- Automated functional testing coverage
- UX/UI designer responsibilities
- Readability
- Accessibility
- Performance
- Security
- Documentation
- Reviewed by a human
- Code review by maintainers
- Full testing and approval
- Credit contributors
- Review with the product owner
- Release notes snippet
- Release