Make WordPress Core

Opened 4 weeks ago

Last modified 4 weeks ago

#65873 new defect (bug)

Media: enable HEIC/HEIF sequence uploads when the server lacks image editor support

Reported by: adamsilverstein Owned by:
Priority: normal Milestone: Awaiting Review
Component: Media Version:
Severity: normal Keywords: has-patch has-unit-tests gutenberg-merge
Cc: Focuses:

Description

Claude went through the code for this one and drafted the ticket:

Follow up to #64915, which stopped WP_REST_Attachments_Controller::create_item_permissions_check() from rejecting HEIC/HEIF uploads on servers whose image editor can't process them. That change was narrowed during commit to the still formats only, so image/heic-sequence and image/heif-sequence are still rejected with rest_upload_image_type_not_supported.

Those two mime types are what an Apple Live Photo or an Android burst is. The comment in core explains the reasoning:

 * The '-sequence' variants (multi-frame Live Photos) are deliberately
 * excluded: neither the server nor the browser fallback can process
 * them yet, so they should fall through to the standard unsupported
 * mime-type error rather than be stored unprocessable.

That was accurate when it was written. The browser half of it has since changed: https://github.com/WordPress/gutenberg/pull/79647 demuxes a sequence and decodes its first frame in the browser, uploading that still in its place, so a capable browser never reaches this check at all.

What does reach it is a browser that can't decode HEVC. Rejecting the upload there is worse than storing it. wp_check_filetype_and_ext() already collapses a sequence to its first frame, so the user still gets a usable photo - just without the motion, which is the same result they'd get uploading the file anywhere else. Today they get an error instead and no photo at all.

Worth noting that core is already set up for these files everywhere else. wp_get_mime_types() registers the heics and heifs extensions, and wp_is_heic_image_mime_type() already returns true for all four mime types. The permissions check is the one place that treats the sequence variants differently.

Proposed change

Replace the hardcoded still-only array with the existing helper, which is what #64915 originally proposed:

if (
    $prevent_unsupported_uploads &&
    ! empty( $files['file']['type'] ) &&
    wp_is_heic_image_mime_type( $files['file']['type'] )
) {
    $prevent_unsupported_uploads = false;
}

Net 7 lines removed.

Testing

  1. Remove image editor support so the check is reachable: add_filter( 'wp_image_editors', '__return_empty_array' );
  2. POST a .heics file (or anything sent as image/heic-sequence) to /wp/v2/media.
  3. Before the change the request fails with rest_upload_image_type_not_supported. After it, the attachment is created and stores the first frame.

The existing unit test asserting the old behavior (test_upload_heic_sequence_is_not_bypassed) is removed, and the sequence mime types are folded into the data provider for test_upload_heic_bypasses_unsupported_image_type_check so one case covers all four.

PR: https://github.com/WordPress/wordpress-develop/pull/13042

Related Gutenberg work: https://github.com/WordPress/gutenberg/pull/79647

Change History (1)

This ticket was mentioned in PR #13042 on WordPress/wordpress-develop by @adamsilverstein.


4 weeks ago
#1

## What

Extends the HEIC/HEIF upload bypass added in #64915 to the multi-frame -sequence variants: image/heic-sequence and image/heif-sequence, which is what Apple Live Photos and Android bursts are.

Today those are rejected with rest_upload_image_type_not_supported when the server's image editor cannot handle them, which is most servers.

## Why

The original exclusion was correct when it was written - the comment says the sequence variants are skipped because "neither the server nor the browser fallback can process them yet". The browser half of that has changed: WordPress/gutenberg#79647 demuxes a sequence and decodes its first frame in the browser, uploading that still in its place, so a capable browser never reaches this check at all.

More to the point, rejecting them is inconsistent with what the rest of the pipeline does with the same bytes. wp_check_filetype_and_ext() renames a .heics upload to .heic and rewrites its type to image/heic, verified against a real 120-frame sequence:

wp_get_image_mime()        => 'image/heif-sequence'
wp_check_filetype_and_ext():
  ext                      => 'heic'
  type                     => 'image/heic'
  proper_filename          => 'live-photo.heic'

So a file this permissions check turns away is one the very next step would have relabelled as an ordinary still HEIC - a mime type the same check already allows. The bytes are stored unchanged either way; only the label differs.

## Approach

Uses the existing wp_is_heic_image_mime_type() helper, which already returns true for all four mime types, in place of the hardcoded still-only array. This is what #64915 originally proposed before it was narrowed. Net 7 lines removed from the source.

## Testing instructions

  1. Ensure the server has no image editor that supports HEIC: add_filter( 'wp_image_editors', '__return_empty_array' );
  2. Upload a .heics file (or any file sent as image/heic-sequence) through POST /wp/v2/media.
  3. Before this change the request fails with rest_upload_image_type_not_supported; after it, the attachment is created.

The existing unit test asserting the old behavior is removed, and the sequence mime types are folded into the data provider for the bypass test so one case covers all four:

phpunit --filter test_upload_heic_bypasses_unsupported_image_type_check

## AI Use

Claude Code wrote this patch and the description. I will review and test.

Note: See TracTickets for help on using tickets.