Media Utils: Add media.slimImageObject filter to preserve custom attachment fields#79539
Media Utils: Add media.slimImageObject filter to preserve custom attachment fields#79539thisismyurl wants to merge 7 commits into
Conversation
…chment fields
`slimImageObject` is called when a user selects media from the WordPress
media library and reduces the full attachment object to a small subset of
fields before passing it to the block's `onSelect` callback. Because the
field list is a closed allowlist, any custom attachment meta added by
plugins (e.g. licensing data, alt-text service flags, focal point coords)
is silently dropped.
This commit adds a `media.slimImageObject` WordPress hook so that blocks
and plugins can opt in to preserving additional fields:
addFilter(
'media.slimImageObject',
'my-plugin/slim-image-object',
( slimmed, img ) => {
if ( img.hasOwnProperty( 'license_id' ) ) {
slimmed.license_id = img.license_id;
}
return slimmed;
}
);
Changes:
- `packages/media-utils/src/components/media-upload/index.js` — import
`applyFilters` from `@wordpress/hooks`; store the base-field reduction
in `baseFields` and return `applyFilters( 'media.slimImageObject', baseFields, img )`;
export the function as a named export so tests and advanced consumers
can import it directly.
- `packages/media-utils/src/components/index.ts` — re-export `slimImageObject`
from the components barrel.
- `packages/media-utils/package.json` — add `@wordpress/hooks` as a
declared dependency (it was already available transitively but must be
declared for the monorepo linter).
- `packages/media-utils/src/components/media-upload/test/index.test.js` —
new unit tests: verifies the standard-fields-only default, then registers
a `media.slimImageObject` filter and asserts the custom field survives.
Closes WordPress#64415
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @thisismyurl! In case you missed it, we'd love to have you join us in our Slack community. If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information. |
Move @wordpress/hooks to correct alphabetical position (between @wordpress/element and @wordpress/i18n). Fixes 'Lint package.json files' CI failure on PR WordPress#79539. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…te API docs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Failing checks: All (Node.js 24 on Linux)
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
There was a problem hiding this comment.
Pull request overview
This PR adds a media.slimImageObject filter hook to @wordpress/media-utils so blocks using MediaUpload can preserve plugin-added attachment fields (custom meta) in the onUpdate() path used by gallery/multi-image flows.
Changes:
- Wraps the existing
slimImageObjectallowlist reduction withapplyFilters( 'media.slimImageObject', baseFields, img )and exportsslimImageObject. - Adds unit tests to verify default allowlist behavior remains unchanged and that filters can preserve custom fields.
- Declares
@wordpress/hooksas an explicit dependency and updates package exports/docs accordingly.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/media-utils/src/components/media-upload/index.js | Adds the media.slimImageObject filter application and exports slimImageObject. |
| packages/media-utils/src/components/media-upload/test/index.test.js | Adds unit tests covering default behavior and the new filter behavior. |
| packages/media-utils/src/components/index.ts | Re-exports slimImageObject alongside MediaUpload. |
| packages/media-utils/package.json | Adds @wordpress/hooks as an explicit dependency. |
| packages/media-utils/tsconfig.json | Adds a project reference to ../hooks to match the new dependency. |
| packages/media-utils/README.md | Updates the generated API surface listing to include slimImageObject. |
| it( 'passes the full attachment to the media.slimImageObject filter', () => { | ||
| const filterName = 'media.slimImageObject'; | ||
| const namespace = 'test/slim-image-object'; | ||
|
|
||
| addFilter( filterName, namespace, ( slimmed, img ) => { | ||
| if ( img?.hasOwnProperty( 'custom_meta' ) ) { | ||
| slimmed.custom_meta = img.custom_meta; | ||
| } | ||
| return slimmed; | ||
| } ); | ||
|
|
||
| const img = { | ||
| id: 2, | ||
| url: 'https://example.com/img.png', | ||
| alt: '', | ||
| custom_meta: 'plugin-data', | ||
| }; | ||
|
|
||
| const result = slimImageObject( img ); | ||
|
|
||
| expect( result.id ).toBe( 2 ); | ||
| expect( result.custom_meta ).toBe( 'plugin-data' ); | ||
|
|
||
| removeFilter( filterName, namespace ); | ||
| } ); |
| // The media library image object contains numerous attributes | ||
| // we only need this set to display the image in the library. | ||
| const slimImageObject = ( img ) => { | ||
| export const slimImageObject = ( img ) => { |
The package-lock.json entry for packages/media-utils was not updated when @wordpress/hooks was added to package.json. Running npm install in CI would regenerate the lock file and cause check-local-changes to fail. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Addresses two review comments on WordPress#79539. The test registered `media.slimImageObject` and removed it after the assertions, so a failing assertion would leave the filter registered and leak it into later tests. Cleanup now runs in `afterEach`, which executes whether or not the test body throws. Removing a filter that was never added is a no-op, so the shared hook is safe for both tests. The comment above `slimImageObject` described only the field reduction and did not mention that the result is filterable. It is now a docblock that names the `media.slimImageObject` hook and its two arguments, so the extension point is discoverable from the function it belongs to. As a side effect the generated API reference now documents `slimImageObject`, which previously read "Undocumented declaration". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for the review. Both points are addressed in Filter cleanup. Agreed, a failing assertion would have left the filter registered. I used Documenting the hook. The inline comment is now a docblock naming On the earlier CI failure, in case anyone else hits it: Verified locally: both tests pass, and removing the |
What?
Fixes #64415
`slimImageObject` in `packages/media-utils` is called inside the `onUpdate` handler — the path that fires for gallery and multi-image selection flows in the classic media library. It reduces the WordPress attachment object to a fixed 9-field allowlist before forwarding to the block's `onSelect` prop callback, silently dropping any custom attachment meta.
Why?
Plugins that extend WordPress attachments with custom meta (via `register_post_meta`, `attachment_fields_to_edit`, or REST API extensions) have no way to surface those fields to blocks using `MediaUpload` in the gallery/multi-image flow. The slimmed object is all the block receives; custom fields are dropped unconditionally regardless of what was registered.
How?
Usage after this change:
Note on scope: `onSelect()` (the `select` event / single-image flow) does not call `slimImageObject` and is unchanged by this PR. The filter applies only to the `onUpdate()` path where `slimImageObject` is currently called.
Testing Instructions
In a plugin, register a meta field for attachments:
Register the `media.slimImageObject` filter in your block's JS:
Open a Gallery block, open the media library, select images.
In the block's `onSelect` callback, confirm `my_custom_field` is present.
Default behavior (unchanged): Open any media library and select images; confirm the attachment object has only the standard allowlist fields when no filter is registered.
Unit tests: `npm run test:unit -- --scope='@wordpress/media-utils'`
Props @thisismyurl.
(full disclosure: AI helped me identify the issue and verify my work)