Skip to content

fix: prevent the site media picker from dropping gallery media on cancel - #25866

Open
dcalhoun wants to merge 3 commits into
trunkfrom
fix/site-media-picker-cancel-drops-selection
Open

fix: prevent the site media picker from dropping gallery media on cancel#25866
dcalhoun wants to merge 3 commits into
trunkfrom
fix/site-media-picker-cancel-drops-selection

Conversation

@dcalhoun

@dcalhoun dcalhoun commented Aug 4, 2026

Copy link
Copy Markdown
Member

Description

Follow-up to #25857, which fixed GutenbergKit site media selection.

Cancelling the media picker dropped media from a gallery (experimental block editor only). buttonCancelTapped reported initialSelection back through the same delegate method as buttonDoneTapped, so a cancel was indistinguishable from a confirmed selection. initialSelection can be a subset of the media a gallery actually references — the picker resolves it up front from the local Core Data store, and the media library syncs asynchronously after presentation, so anything not yet cached resolves to nothing. Cancelling wrote that subset back to the block, silently deleting the rest.

Cancel now reports an empty selection, restoring the behaviour already documented on SiteMediaPickerViewControllerDelegate ("If the user cancels the flow, the selection is empty") and matching ExternalMediaPickerViewController. All four conformers already treat an empty selection as a cancel.

Known follow-up

Confirming with Add has the same root cause and still drops unsynced media: late-arriving cells are inserted unchecked because the selection is seeded once and never reconciled, so buttonDoneTapped reports a set that omits them. Fixing it means having the picker reconcile pending selections as media arrives, which touches SiteMediaCollectionViewController (shared with the Media tab) and MediaPickerMenu (shared with Aztec, site icon, avatar, and stock photos), and needs a decision on preserving gallery ordering for late arrivals. Left out to keep this PR scoped.

Testing instructions

This bug only affects the experimental block editor (GutenbergKit). The gallery media path runs through PostGBKEditorViewController, which is only instantiated when the newGutenberg remote feature flag is on. The shipping block editor (Gutenberg Mobile) and Aztec are not affected.

Enable it first: Me → App Settings → Experimental Features → Experimental Block Editor.

A regression test is included, verified to fail against the pre-fix code.

To reproduce the bug manually, the gallery needs media that is not yet cached locally:

  1. On a test site, upload 4+ images via wp-admin and publish a post with a Gallery block containing all of them.
  2. In the app, sign in to that site and do not open the Media tab — that syncs the library and caches every row, which defeats the repro.
  3. Open the post in the experimental editor and tap the Gallery block → Edit / Add media. The picker opens with fewer images checked than the gallery contains.
  4. Tap Cancel.
  5. Before: the gallery is rewritten to only the images that were checked. After: the gallery is unchanged.

Check the block's ids attribute before and after via Switch to code editor.

Note the picker must be multi-select (a Gallery block, not a single Image block) — initialSelection is only applied when allowsMultipleSelection is true.

Regression areas

GutenbergMediaPickerHelper is shared with the legacy Gutenberg Mobile editor (GutenbergViewController), so that path is worth a smoke test. It calls presentSiteMediaPicker without initialSelection, so this change is a no-op there — cancel already reported an empty selection — but this was verified by code tracing rather than by running the legacy editor.

Other SiteMediaPickerViewController consumers (site icon, Aztec) also pass an empty initialSelection and are unaffected.

`buttonCancelTapped` reported `initialSelection` back to the delegate
using the same method as `buttonDoneTapped`, making a cancel
indistinguishable from a confirmed selection.

That matters because `initialSelection` can be a subset of the media a
gallery block actually references. The picker computes it up front from
the local Core Data store, and the media library syncs asynchronously
after the picker is presented, so any media not yet cached resolves to
nothing. Cancelling then wrote that subset back to the block, dropping
the unresolved items from the user's gallery.

Report an empty selection on cancel instead. This restores the behaviour
already documented on `SiteMediaPickerViewControllerDelegate` ("If the
user cancels the flow, the selection is empty") and matches
`ExternalMediaPickerViewController`, which cancels the same way.

All three conformers already handle an empty selection as a cancel:
`SiteIconPickerPresenter` calls `onCompletion?(nil, nil)`,
`AztecPostViewController` inserts nothing, and `GutenbergMediaPickerHelper`
forwards to a callback guarded on `!media.isEmpty`.

This fixes the cancel case only. Confirming with "Add" has the same root
cause and still drops unsynced media: the late-arriving cells are
inserted unchecked because the selection is seeded once and never
reconciled, so `buttonDoneTapped` reports a set that omits them. That
needs the picker to reconcile pending selections as media arrives, and is
left to a follow-up.

Only the GutenbergKit editor passes a non-empty `initialSelection`, so
this is a no-op for the other pickers, including the legacy Gutenberg
Mobile editor, which already cancelled with an empty selection.
@dangermattic

Copy link
Copy Markdown
Collaborator
1 Message
📖 This PR is still a Draft: some checks will be skipped.

Generated by 🚫 Danger

@dcalhoun dcalhoun added this to the 27.2 milestone Aug 4, 2026
@dcalhoun dcalhoun added Gutenberg Editing and display of Gutenberg blocks. [Type] Bug labels Aug 4, 2026
@dcalhoun
dcalhoun force-pushed the fix/site-media-picker-cancel-drops-selection branch from a00d600 to cc58ec6 Compare August 4, 2026 15:40
@wpmobilebot

wpmobilebot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in WordPress by scanning the QR code below to install the corresponding build.
App NameWordPress
ConfigurationRelease-Alpha
Build Number33598
VersionPR #25866
Bundle IDorg.wordpress.alpha
Commit4541fd3
Installation URL099nv1boqdvu8
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot

wpmobilebot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in Jetpack by scanning the QR code below to install the corresponding build.
App NameJetpack
ConfigurationRelease-Alpha
Build Number33598
VersionPR #25866
Bundle IDcom.jetpack.alpha
Commit4541fd3
Installation URL4nul0p0agj5ko
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@dcalhoun
dcalhoun force-pushed the fix/site-media-picker-cancel-drops-selection branch from cc58ec6 to 9bb338d Compare August 4, 2026 16:54
@wpmobilebot

Copy link
Copy Markdown
Contributor

🤖 Build Failure Analysis

This build has failures. Claude has analyzed them - check the build annotations for details.

`cancellingReportsEmptySelection` fires the Cancel bar button's own
`UIAction` rather than calling the delegate method directly, so the
assertion exercises what `buttonCancelTapped` actually reports instead of
restating the expected value. It reads the preselected media from the
embedded `SiteMediaCollectionViewController`, which the picker adds as a
child view controller, so no production declaration had to be widened.

The test overrides `ContextManager.shared` for its duration.
`mapMediaIdsToMedia` fetches from `ContextManager.shared.mainContext`, so
the blog has to live there for the picker to preselect anything. Without
the override the lookup returns nothing and the test degenerates into
asserting that an empty selection stays empty, which passes against the
pre-fix code too.

The existing `useAsSharedInstance(untilTestFinished:)` helper takes an
`XCTestCase` to hang its teardown on, which Swift Testing does not
provide, so the override is scoped with `defer` here instead. The suite
is `.serialized` because `ContextManager.overrideInstance` is global
state.

Verified to fail against the pre-fix code: restoring
`didFinishWithSelection: initialSelection` in `buttonCancelTapped` fails
the assertion with a non-empty selection.
@dcalhoun
dcalhoun force-pushed the fix/site-media-picker-cancel-drops-selection branch from 9bb338d to 4541fd3 Compare August 4, 2026 17:21
@dcalhoun
dcalhoun marked this pull request as ready for review August 4, 2026 17:35
@dcalhoun
dcalhoun requested a review from crazytonyli August 4, 2026 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Gutenberg Editing and display of Gutenberg blocks. [Type] Bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants