Skip to content

Media Utils: fix TypeError when editing an image in an existing gallery - #81285

Open
jigneshbhavani wants to merge 1 commit into
WordPress:trunkfrom
jigneshbhavani:fix/gallery-frame-edit-image-wrong-state
Open

Media Utils: fix TypeError when editing an image in an existing gallery#81285
jigneshbhavani wants to merge 1 commit into
WordPress:trunkfrom
jigneshbhavani:fix/gallery-frame-edit-image-wrong-state

Conversation

@jigneshbhavani

Copy link
Copy Markdown

What?

Fixes Uncaught TypeError: Cannot read properties of undefined (reading 'toJSON') when opening the image editor for an image that is already in a gallery.

Reported on WordPress Trac as #65816 by @afercia.

Why?

getGalleryDetailsMediaFrame() bound its own handler for content:render:edit-image:

editState() {
	const selection = this.state( 'gallery' ).get( 'selection' );
	const view = new wp.media.view.EditImage( {
		model: selection.single(),
		controller: this,
	} ).render();
	...
}

The gallery state is the "Create gallery" library. It only holds a selection when a gallery is being built from scratch. When the frame is entered through "Edit gallery" on an existing gallery, that state is never used, so selection.single() is undefined and EditImage.prepare() throws on this.model.toJSON().

Measured on WordPress trunk at the moment of the crash:

State selection length single() image
gallery 0 undefined
gallery-edit 1 15
edit-image 15

The image the user clicked was available in two places. The handler read the one place it was not.

The frame ends up in a broken intermediate state: the title changes to "Edit image" but the gallery grid is still displayed and no editor appears.

How?

The override is removed rather than corrected.

getGalleryDetailsMediaFrame() extends wp.media.view.MediaFrame.Post, which already binds content:render:edit-image to core's editImageContent(). That reads this.state().get( 'image' ), which is the value core's own wp.media.view.Attachment.Details.editAttachment() sets immediately before switching state. It is correct on both entry paths.

Listing the handlers bound to the event on an unmodified trunk build gives three, in this order:

  1. editState from this package, reads state( 'gallery' ), throws
  2. editImageContent from core
  3. editImageContent from core

Because the first throws, Backbone's dispatch loop aborts and core's working handlers never run. That is why the content region is left showing the gallery.

Correcting the state lookup instead of removing the handler would leave three handlers all succeeding, which means three EditImage views and three image-editor Ajax requests per click. That already happens on the create path today: with unmodified code, one click on "Edit Image" produces 3 action=image-editor&do=open requests. Removing the override brings that down to 2.

The remaining 2 come from core binding editImageContent twice, in MediaFrame.Select.bindHandlers() and again through the MediaFrame.Post handlers map. That is a separate core issue and is not addressed here.

The getFeaturedImageMediaFrame() handler is deliberately left alone. It reads state( 'featured-image' ), which is the state the user selects in on that path, and I could not reproduce a failure there.

Testing Instructions

  1. Create a post, add a Gallery block with a few images, and save.
  2. Select the Gallery block, not one of its images.
  3. In the block toolbar click "Add", then "Open Media Library".
  4. In the left panel click "Edit gallery".
  5. Click one of the images so the "Attachment details" panel appears.
  6. Click "Edit Image".

Expected: the image editor opens with the image that was clicked.

Before this change: the modal shows the title "Edit image" but still lists the gallery images, no editor appears, and the console logs Uncaught TypeError: Cannot read properties of undefined (reading 'toJSON').

Also check the path that already worked, to confirm it is unaffected:

  1. Add an empty Gallery block and click "Media Library".
  2. Select images and click "Create a new gallery".
  3. Click an image, then "Edit Image".

Expected: the image editor opens, as before.

Testing Instructions for Keyboard

Both flows above are reachable with Tab and Enter only. Tab to the Gallery block toolbar, activate "Add", then "Open Media Library" with Enter. Inside the modal, Tab to the "Edit gallery" tab and activate it, Tab to an image and activate it, then Tab to "Edit Image" and activate it. The image editor should open and receive focus.

Use of AI Tools

I used Claude Code while investigating this. It drove the browser to reproduce the reported steps, captured the stack trace and the media frame state at the point of the crash, and helped draft this description. The root cause, the decision to remove the handler rather than correct it, and the testing were verified by me against a local WordPress trunk build. I take responsibility for the contents of this PR.

The gallery details frame bound its own `content:render:edit-image` handler
that read the selection from the `gallery` state, which is only populated when
a gallery is created from scratch. Entering through "Edit gallery" left it
empty, so `EditImage` was constructed with an undefined model and threw.

`MediaFrame.Post` already binds `editImageContent` for this event and reads the
model core actually sets, so the override is removed rather than corrected.
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

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 props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: jigneshbhavani <bejignesh@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions github-actions Bot added [Package] Media Utils /packages/media-utils First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository labels Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @jigneshbhavani! 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.

oandregal added a commit that referenced this pull request Aug 7, 2026
Point the entries at the current PR (#81294 instead of the stale
#81285) and move the components entry back into the Unreleased
section; the rebase had merged it into the released 38.0.0 section.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Package] Media Utils /packages/media-utils

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant