feat: process New Block Editor media uploads with app Media settings - #25824
Open
dcalhoun wants to merge 14 commits into
Open
feat: process New Block Editor media uploads with app Media settings#25824dcalhoun wants to merge 14 commits into
dcalhoun wants to merge 14 commits into
Conversation
dcalhoun
force-pushed
the
feat/process-gutenberg-kit-media-uploads
branch
from
July 22, 2026 20:12
5eb00ce to
f373395
Compare
dcalhoun
commented
Jul 22, 2026
dcalhoun
marked this pull request as ready for review
July 22, 2026 20:37
Contributor
|
| App Name | WordPress | |
| Configuration | Release-Alpha | |
| Build Number | 33787 | |
| Version | PR #25824 | |
| Bundle ID | org.wordpress.alpha | |
| Commit | 435046a | |
| Installation URL | 2jckuumdr1530 |
Contributor
|
| App Name | Jetpack | |
| Configuration | Release-Alpha | |
| Build Number | 33787 | |
| Version | PR #25824 | |
| Bundle ID | com.jetpack.alpha | |
| Commit | 435046a | |
| Installation URL | 64jea119125b0 |
7 tasks
dcalhoun
force-pushed
the
feat/process-gutenberg-kit-media-uploads
branch
from
August 16, 2026 12:54
c908b31 to
e65c714
Compare
Collaborator
Gates the upcoming native media upload processing for the experimental block editor, with a Debug-menu override for quick disabling.
Points GutenbergKit at the XCFramework snapshot for wordpress-mobile/GutenbergKit#357, which adds the native media upload server and MediaUploadDelegate. Swap to a tagged release before merge.
Implements GutenbergKit's MediaUploadDelegate so device media picked in the experimental block editor is processed natively before upload, honoring the app's Media settings: Optimize Images, Max Image Upload Size, Image Quality, Max Video Upload Size, and Remove Location From Media. Previously these uploads went directly from the WebView to the REST API with no processing. GBKMediaUploadProcessor mirrors the exporter option mapping used by MediaImportService and reuses MediaURLExporter, so the editor now matches the behavior of the legacy editor and My Site > Media. GIFs and non-media files pass through untouched, and non-web-safe image formats (e.g. HEIC) are converted to JPEG. Uploads still use GutenbergKit's default uploader, which relays the raw WordPress response to the editor.
Verifies resizing, GPS stripping, HEIC-to-JPEG conversion, GIF and no-op passthrough, disallowed file extensions, and the video duration limit using the existing media fixtures.
Adds the gbkMediaUploadOptimization flag to the Experimental Features list and aligns display names with the "New Block Editor (NBE)" naming.
Removes the gbkMediaUploadOptimization gate ahead of reverting the flag. GutenbergKit degrades gracefully if the upload server cannot start, so a dedicated kill switch isn't needed.
…res" This reverts commit f373395.
This reverts commit ea1ad1f.
Moves the pin off the pr-build/357 snapshot now that wordpress-mobile/GutenbergKit#357 has merged. Trunk also carries the follow-up hardening in #561, which adds a defaulted handlesFile(ofType: named:) to MediaUploadDelegate, so GBKMediaUploadProcessor conforms unchanged. No tagged release includes #357 yet — v0.19.0 predates it. Swap to a tagged release before merge.
dcalhoun
force-pushed
the
feat/process-gutenberg-kit-media-uploads
branch
from
August 17, 2026 12:36
e65c714 to
435046a
Compare
Contributor
🤖 Build Failure AnalysisThis build has failures. Claude has analyzed them - check the build annotations for details. |
SVG conforms to `UTType.image`, so `MediaURLExporter.expectedExport` classifies it as `.image` and it reaches the exporter. ImageIO cannot decode or encode SVG: `CGImageSourceCreateWithURL` returns a source with zero images, and both `CGImageSourceCreateThumbnailAtIndex` and `CGImageDestinationCreateWithURL` return nil. The export therefore fails instead of producing a file. Return the original file for SVG, as we already do for GIF, and drop `.svg` from `webSafeImageTypes`. That set decides whether an image needs converting to JPEG, so it should only hold raster formats ImageIO can actually read and write; SVG's membership there implied it could reach the exporter safely. Only sites whose plan allows SVG can upload one, so this is not reachable on plans where the picker greys the file out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`MediaDirectory.temporary` is a computed property returning `.temporary(id: UUID())`, so each export was written to a fresh `tmp/<uuid>/Media/`. GutenbergKit's cleanup removes only the file at `uploadURL`, never the two enclosing directories, so every processed image or video left an empty directory pair behind for the lifetime of the process. Write every export to one directory identified by a fixed UUID. `MediaFileManager.makeLocalMediaURL` increments filenames, so uploads sharing a source name do not collide. The ID is stable across launches so a directory orphaned by a crash is reused rather than accumulating. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The comment claimed the guard skips processing "when it would be a no-op", which is broader than what the condition tests. With image optimization off, `imageSizeForUpload` returns `Int.max` (no downscale) but `imageQualityForUpload` returns `.high`, so an image that falls through is still re-encoded at 0.9 quality. Describe what the guard actually checks and note that the quality mapping matches `MediaImportService`. No behavior change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`makeExporter` is shared by the image and video paths, and it derived `exportImageType` from the source URL's type alone. A video's UTI is not in `webSafeImageTypes`, so every video export was configured to write JPEG. `MediaURLExporter.exportVideo` ignores `imageOptions`, so this had no effect, but it stated something untrue about the export. Pass the classification `processFile` already computed and set `exportImageType` only for an image. No behavior change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`exportsShareOneTemporaryDirectory` cleaned up each export inside the loop body, so `defer` fired at the end of every iteration and deleted the file before the next export ran. `incrementalFilename` only increments while a file exists, so all three exports resolved to the same path and the directory set was trivially of size one. The test passed whether or not exports shared a directory. Collect the output URLs and clean them up after the loop so all three files coexist, and assert they are three distinct paths in one directory. Verified by reverting dd8c5bb locally: the test now fails with three directories instead of one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Description
Ref CMM-1249. Ref CMM-2155.
Integrates GutenbergKit's native media upload pipeline (wordpress-mobile/GutenbergKit#357) so device media picked in the New Block Editor (NBE) is processed natively before upload, honoring the app's Media settings: Optimize Images, Max Image Upload Size, Image Quality, Max Video Upload Size, and Remove Location From Media. Previously these uploads went directly from the WebView to the REST API with no processing, bypassing the settings the legacy editor and My Site > Media already honor.
How it works
GBKMediaUploadProcessorimplements GutenbergKit's newMediaUploadDelegate. When the editor uploads a device file, GutenbergKit's localhost upload server hands the staged file toprocessFile, which reusesMediaURLExporterwith the same option mapping asMediaImportService:ItemProviderMediaExporter.videoLimitExceededsurfaces WordPress's "requires a paid plan" message in the editor).PostGBKEditorViewController(covers posts, pages, and custom post types). If GutenbergKit's upload server cannot start, it degrades gracefully to the standard WebView upload path.Notes
Mediastore, so My Site > Media shows them after the next sync. This matches the NBE's pre-existing behavior; syncing after upload is a possible follow-up.Testing instructions