Skip to content

REST API: Move sideload metadata writing to the finalize endpoint (backport GB #75888)#12002

Open
adamsilverstein wants to merge 3 commits into
WordPress:trunkfrom
adamsilverstein:backport/75888-sideload-finalize
Open

REST API: Move sideload metadata writing to the finalize endpoint (backport GB #75888)#12002
adamsilverstein wants to merge 3 commits into
WordPress:trunkfrom
adamsilverstein:backport/75888-sideload-finalize

Conversation

@adamsilverstein
Copy link
Copy Markdown
Member

What

Core backport of Gutenberg #75888 — Upload Media: Enable concurrent sideload uploads.

Part of the post-restore client-side-media backport stack (see #11324).

Why

Concurrent sideloads for the same attachment each did a read-modify-write of _wp_attachment_metadata, so parallel requests could overwrite each other's changes. The merged Gutenberg PR explored MySQL advisory locks and transient locks, then settled on removing the shared write entirely.

How

  • sideload_item() no longer writes attachment metadata. It returns lightweight sub-size data (image_size, dimensions, file, mime_type, filesize, and original_image for the scaled case). The scaled flow still repoints _wp_attached_file (that is not the contended _wp_attachment_metadata).
  • finalize_item() accepts a new sub_sizes array param (schema-validated) and applies all collected sub-sizes to the metadata in a single wp_update_attachment_metadata() before firing wp_generate_attachment_metadata.

This matches how core generates sub-sizes (one metadata write after all sizes exist).

Notes

  • The JS counterpart (media-utils sideloadToServer returning sub-size data; client-side accumulation passed to finalize) ships via the normal Gutenberg -> Core package sync and is not part of this PHP backport.
  • Tests: updated test_sideload_scaled_image to assert the new response shape + finalize write, and added three finalize tests - test_finalize_writes_regular_sub_sizes, test_finalize_writes_original_metadata (covers the original branch), and test_finalize_preserves_image_meta (EXIF image_meta is preserved when finalize adds sub-sizes). Together with the existing test_finalize_item* tests, all three finalize branches (regular / scaled / original) plus the empty-sub_sizes path are covered. Validated locally with php -l and PHPCS (WordPress-Core).

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

Backport of Gutenberg PR #75888. Eliminate the read-modify-write race
between concurrent sideloads for the same attachment by no longer
writing attachment metadata in the sideload endpoint. Instead, sideload
returns lightweight sub-size data (dimensions, filename, filesize) which
the client accumulates and passes to the finalize endpoint, which writes
all collected sub-sizes in a single metadata update.

This matches how core generates sub-sizes (one metadata write after all
sizes exist) and replaces the earlier per-attachment locking approach
that the merged Gutenberg PR ultimately abandoned.
The three sub-size finalize tests added in this backport used the
placeholder ticket 62243 (the original client-side media feature ticket)
before a dedicated ticket existed. Trac #65329 now tracks this change, so
update those @ticket annotations. Pre-existing finalize tests keep 62243.
This backport changes the scaled-image sideload behavior (sideload now
returns sub-size data and metadata is written at finalize), so add a
65329 ticket reference alongside the existing 64737.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 28, 2026

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.

Core Committers: Use this line as a base for the props when committing in SVN:

Props adamsilverstein, westonruter.

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

@westonruter
Copy link
Copy Markdown
Member

This also seems to have much of the same code as #12003, which I've reviewed in depth, so I guess that should be committed first before proceeding here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants