Make WordPress Core

Opened 5 months ago

Last modified 8 weeks ago

#65086 new enhancement

Add action hooks to media modal attachment details templates for field extensibility

Reported by: kaavyaiyer Owned by:
Priority: normal Milestone: 7.2
Component: Media Version:
Severity: normal Keywords: has-patch
Cc: Focuses:

Description

Since WP 7.0 ships with a built-in AI client, there is a need for AI-powered features like alt text generation to be able to place controls (e.g., a "Generate" button) directly next to the fields they act on within the media modal.

Currently, wp-includes/media-template.php does not provide any hooks inside the attachment details templates where fields like Alternative Text are rendered. This leaves JavaScript DOM manipulation as a workaround to place controls directly next to existing fields.

The first concrete use case is the https://github.com/WordPress/ai alt text generation experiment, which needs a "Generate" button next to the Alternative Text textarea. See: WordPress/ai#425 for the original discussion.

Proposed Solution

Add action hooks inside the two attachment details Backbone templates in media-template.php

Extending to other fields

Beyond the media modal, similar hooks would benefit other areas of the admin where AI features need to place controls next to existing fields for title, image, caption generation, etc. This ticket focuses on the media modal as the starting point.

Attachments (2)

before-11748.png (1.8 MB ) - added by ozgursar 3 months ago.
Before applying patch 11748
after-11748.png (1.8 MB ) - added by ozgursar 3 months ago.
After applying patch 11748

Change History (9)

#1 @darshitrajyaguru97
4 months ago

This is a great initiative and clearly needed, especially with AI-powered features like alt text generation.

One important consideration: since the attachment details UI is rendered via Backbone templates (media-template.php), traditional PHP action hooks (do_action) won’t be effective inside <script type="text/html"> blocks.

A more robust approach could be introducing JavaScript-based extensibility points using wp.hooks, for example:

wp.hooks.doAction(
  'media_attachment_field_after',
  'alt',
  view,
  model
);

Additionally, field-specific hooks (e.g., media_attachment_field_after_alt, media_attachment_field_before_caption) would provide more granular control and avoid reliance on DOM querying.

As an alternative or fallback, Core could introduce dedicated placeholder containers within templates (e.g., .media-field-hook-alt) to allow safe UI injection without fragile DOM manipulation.

This approach would:

  • Avoid performance overhead from runtime DOM mutations
  • Provide a stable API for plugins
  • Align well with AI-driven enhancements like alt text, caption, and title generation

Starting with the media modal makes sense, and this pattern could later extend to other admin UI areas where contextual field-level extensibility is needed.

This ticket was mentioned in PR #11666 on WordPress/wordpress-develop by @shreyasikhar26.


4 months ago
#2

  • Keywords has-patch added

#### Trac ticket: https://core.trac.wordpress.org/ticket/65086
---

## Summary

Adds new action hooks in the media modal attachment details templates so plugins can render controls directly next to core fields such as Alternative Text, Title, Caption, and Description, without relying on DOM manipulation.

## What changed

  • Added hooks in the two-column attachment details template after:
    1. Alternative Text
    2. Title
    3. Caption
    4. Description
  • Added hooks in the single-column attachment details template after:
    1. Alternative Text
    2. Title
    3. Caption
    4. Description

## Why

This enables feature plugins and integrations, including AI-powered workflows, to place contextual controls (for example, a Generate button for alt text) exactly where users expect them in the media modal UI.

This ticket was mentioned in PR #11748 on WordPress/wordpress-develop by @dhruvang21.


4 months ago
#3

Trac ticket: https://core.trac.wordpress.org/ticket/65086

## Use of AI Tools
AI assistance: Yes
Tool(s): Claude code
Model(s): opus 4.6
Used for: used for documentation and code review.

## Example plugin integration

// my-ai-plugin/js/generate-alt-text.js
wp.hooks.addAction(
	'media.view.attachment.renderFieldAfter',
	'my-ai-plugin/generate-alt-text',
	function( $setting, context ) {
		// Only inject beside the alt text field.
		if ( 'alt' !== context.field ) {
			return;
		}

		// Avoid double-injection on repeated renders.
		if ( $setting.find( '.my-ai-generate-alt' ).length ) {
			return;
		}

		var $button = $( '<button>', {
			type:  'button',
			class: 'button button-small my-ai-generate-alt',
			text:  wp.i18n.__( 'Generate', 'my-ai-plugin' ),
		} );

		$button.on( 'click', function() {
			var attachment = context.attachment;
			var $textarea  = $setting.find( 'textarea' );

			$button.prop( 'disabled', true ).text( wp.i18n.__( 'Generating…', 'my-ai-plugin' ) );

			wp.apiFetch( {
				path: '/my-ai-plugin/v1/generate-alt',
				method: 'POST',
				data: { attachment_id: attachment.get( 'id' ) },
			} ).then( function( response ) {
				// Update the Backbone model — triggers save via existing event binding.
				attachment.set( 'alt', response.alt_text );
				$textarea.val( response.alt_text ).trigger( 'change' );
			} ).catch( function() {
				// Surface error accessibly.
				wp.a11y.speak( wp.i18n.__( 'Could not generate alt text.', 'my-ai-plugin' ) );
			} ).finally( function() {
				$button.prop( 'disabled', false ).text( wp.i18n.__( 'Generate', 'my-ai-plugin' ) );
			} );
		} );

		$setting.append( $button );
	}
);

#4 @JeffPaul
4 months ago

  • Keywords needs-testing added
  • Milestone Awaiting Review7.1

@ozgursar
3 months ago

Before applying patch 11748

@ozgursar
3 months ago

After applying patch 11748

#5 @ozgursar
3 months ago

  • Keywords needs-testing removed

## Test Report
Patch tested: https://github.com/WordPress/wordpress-develop/pull/11748

### Environment

  • WordPress: 7.1-alpha-62161-src
  • Subdirectory: No
  • PHP: 8.2.29
  • Server: nginx/1.29.4
  • Database: mysqli (Server: 8.4.7 / Client: mysqlnd 8.2.29)
  • Browser: Chrome 148.0.0.0
  • OS: macOS
  • Theme: Twenty Twenty-Five 1.5
  • MU Plugins: None activated
  • Plugins:
    • Code Snippets 3.9.6
    • Test Reports 1.3.0

### Steps taken

  1. Add the following snippet to your active plugin's functions.php or using Code Snippets plugin
add_action(
	'admin_enqueue_scripts',
	function () {
		wp_enqueue_media();

		wp_add_inline_script(
			'media-views',
			"wp.hooks.addAction(
	'media.view.attachment.renderFieldAfter',
	'test-renderfield-hook',
	function( \$setting, context ) {
		console.log(
			'[renderFieldAfter]',
			'field:', context.field,
			'| attachment id:', context.attachment.get( 'id' ),
			'| \$setting el:', \$setting[ 0 ]
		);

		if ( \$setting.find( '.hook-fired-badge' ).length ) {
			return;
		}

		\$setting.append(
			jQuery( '<span>', {
				class: 'hook-fired-badge',
				text:  'hook fired: ' + context.field,
				css: {
					display:      'inline-block',
					marginTop:    '4px',
					padding:      '1px 6px',
					fontSize:     '11px',
					background:   '#d63638',
					color:        '#fff',
					borderRadius: '3px',
					fontFamily:   'monospace',
				},
			} )
		);
	}
);"
		);
	}
);
  1. Add an image to Media, click and observe Attachment Details modal
  2. Apply the patch
  3. Click the same image in media and observe again
  4. Sidebar should show red hook fired: alt, hook fired: title, hook fired: caption, hook fired: description, hook fired: url badges on each field.
  5. Open a non-image (PDF, video), alt badge should be absent, others present
  6. Open an audio file, artist and album badges should appear too
  7. Switch to a different attachment and back and observe badges appear once per field, not duplicated
  8. ✅ Patch is solving the problem

### Expected result

  • After the patch, wp.hooks.doAction( 'media.view.attachment.renderFieldAfter' ) fires once for each visible field in the Attachment Details sidebar of the media modal, passing the field's .setting container element and a context object with field, attachment, and view. Plugins can use this hook to inject controls (e.g. buttons) directly adjacent to specific fields without resorting to brittle DOM manipulation.

### Additional Notes

  • The hook only fires in the single-column Attachment Details sidebar of the media modal (tmpl-attachment-details). It does not fire on the full Edit Media screen (tmpl-attachment-details-two-column), as that view's JS file (details-two-column.js) is not modified by this patch. Plugins that need to inject controls on the Edit Media screen still need to use the attachment_fields_to_edit PHP filter for that context.

### Screenshots/Screencast with results
Before
https://core.trac.wordpress.org/raw-attachment/ticket/65086/before-11748.png

After
https://core.trac.wordpress.org/raw-attachment/ticket/65086/after-11748.png

This ticket was mentioned in Slack in #core by adrianduffell. View the logs.


2 months ago

#7 @wildworks
8 weeks ago

  • Milestone 7.17.2

PR 11666 adds a filter to the server-side, and PR 11748 adds a filter to the client-side. We first need to decide whether to adopt only one of these filters or both, based on actual use cases.

As 7.1 Beta1 is imminent, I would like to postpone this to 7.2. However, I would appreciate feedback from the AI team, who would likely be the primary users of these hooks. @dkotter

Note: See TracTickets for help on using tickets.