Skip to content

Client-side media: Transform image block to video block after GIF conversion#78369

Closed
adamsilverstein wants to merge 12 commits into
worktree-gif-to-videofrom
gif-to-video-block-transform
Closed

Client-side media: Transform image block to video block after GIF conversion#78369
adamsilverstein wants to merge 12 commits into
worktree-gif-to-videofrom
gif-to-video-block-transform

Conversation

@adamsilverstein
Copy link
Copy Markdown
Member

@adamsilverstein adamsilverstein commented May 15, 2026

Summary

Stacked on #76946 (base branch: worktree-gif-to-video).

#76946 adds client-side animated GIF → MP4/WebM conversion during upload, but per its scope the originating core/image block stays an image block.

This PR completes the feature without changing the block and without adding a second media library item. An uploaded animated GIF stays a single, normal image attachment (the editor is unchanged). The GIF is also transcoded to a video which is sideloaded as a companion file of that same attachment — exactly like the existing HEIC original — and recorded in the attachment metadata under animated_video. On the front end the GIF <img> is swapped for a GIF-behaving <video> while the HTML is generated.

This avoids the surprising block-type change (raised by @andrewserong) and the lost clientId/poster reference (raised by @swissspidy), and keeps the media library clean (one item per GIF).

How it works

Producer (@wordpress/upload-media)

  • An animated GIF uploads through the normal image pipeline (Upload → ThumbnailGeneration → Finalize); the original is stashed on the queue item (animatedGifFile).
  • In generateThumbnails, a child sideload item of the GIF transcodes it (TranscodeGif, preserving the existing FFmpeg-WASM concurrency limit) and sideloads the result with image_size: 'animated-video'. No separate attachment, no second top-level upload item.

Server (CSM attachments controller)

  • sideload/finalize learn the animated-video role: the video filename is written to wp_get_attachment_metadata()['animated_video'] (mirrors original-heic).

Render swap + cleanup (lib/media/animated-gif-to-video.php)

  • wp_content_img_tag (inside wp_filter_content_tags() → post content, widgets, excerpts): if the attachment has an animated_video, reads the <img> attributes with WP_HTML_Tag_Processor and returns <video autoplay loop muted playsinline poster=…>. Covers Image, Gallery, Media & Text, Cover, etc.
  • gutenberg_swap_animated_gif_for_video filter lets developers keep specific GIFs as GIFs per-image.
  • delete_attachment: deletes the companion video. The path is rebuilt from the attachment's own directory + the recorded basename only, then confirmed via realpath() to be a regular file strictly inside the uploads directory before deletion — it can only ever remove the sideloaded companion.

Removed: the editor BlockEdit block-transform hook and the earlier separate-attachment + pair-token linking mechanism.

Test plan

With client-side media processing enabled in a cross-origin-isolated browser:

  • Upload an animated GIF via the Image block → editor shows a normal Image block; Media Library shows one item (the GIF), no separate video
  • wp_get_attachment_metadata() for the GIF has an animated_video entry; the file exists next to the GIF
  • Front end renders the GIF as an autoplaying, looping, muted, inline <video> (no controls)
  • Same swap for a GIF in Gallery / Media & Text / Cover
  • Static (non-animated) GIF and non-GIF images are unaffected (no companion, render as <img>)
  • Deleting the GIF attachment removes the companion video file from disk

A block-level "convert GIF ↔ video" affordance for existing uploads, and a generated poster image, are intentionally out of scope (separate follow-ups).

Adds an editor.BlockEdit filter that watches a core/image block's
attachment record. When client-side animated GIF to video conversion
(@wordpress/upload-media) replaces the uploaded GIF with an MP4/WebM,
the attachment mime_type becomes video/*. This swaps the core/image
block for a core/video block configured to mirror the original GIF
behavior (muted, looping, autoplaying, inline, no controls).

Stacked on the GIF-to-video conversion PR so the end-to-end feature
(upload animated GIF, get an autoplaying looping video block) can be
tested as a whole.
@github-actions github-actions Bot added the [Package] Editor /packages/editor label May 15, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 15, 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.

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: adamsilverstein <adamsilverstein@git.wordpress.org>
Co-authored-by: swissspidy <swissspidy@git.wordpress.org>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>

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

The transcodeGifItem error path intentionally logs the failure cause
via console.error for debuggability. jest-console treats any
unexpected console.error as a test failure, so assert the expected
error explicitly.
Remove the maxDimensions parameter (and the now-unused padToEven helper)
from convertGifToVideo and its wrappers. Nothing in the upload pipeline
ever supplied a value, so the scaling branch was unreachable dead code.

Copy FFmpeg output via new Uint8Array(output).slice().buffer instead of
casting output.buffer.slice() to ArrayBuffer. Under crossOriginIsolated
FFmpeg builds the MEMFS view can be backed by a SharedArrayBuffer, so
slicing .buffer would yield a SharedArrayBuffer the cast misrepresented.
Slicing the typed array always allocates a standalone ArrayBuffer.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 16, 2026

Size Change: +80 B (0%)

Total Size: 22.1 MB

📦 View Changed
Filename Size Change
build/modules/ffmpeg/worker.min.js 14.1 MB -150 B (0%)
build/scripts/block-library/index.min.js 323 kB +133 B (+0.04%)
build/scripts/upload-media/index.min.js 11.8 kB +97 B (+0.83%)
ℹ️ View Unchanged
Filename Size
build/modules/a11y/index.min.js 355 B
build/modules/abilities/index.min.js 42.3 kB
build/modules/block-editor/utils/fit-text-frontend.min.js 617 B
build/modules/block-library/accordion/view.min.js 595 B
build/modules/block-library/file/view.min.js 346 B
build/modules/block-library/form/view.min.js 528 B
build/modules/block-library/image/view.min.js 2.64 kB
build/modules/block-library/navigation/view.min.js 1.14 kB
build/modules/block-library/playlist/view.min.js 10.9 kB
build/modules/block-library/query/view.min.js 518 B
build/modules/block-library/search/view.min.js 498 B
build/modules/block-library/tabs/view.min.js 946 B
build/modules/boot/index.min.js 19.3 kB
build/modules/connectors/index.min.js 2.05 kB
build/modules/content-types/index.min.js 156 kB
build/modules/core-abilities/index.min.js 926 B
build/modules/edit-site-init/index.min.js 1.4 kB
build/modules/ffmpeg/loader.min.js 128 B
build/modules/interactivity-router/full-page.min.js 451 B
build/modules/interactivity-router/index.min.js 11.6 kB
build/modules/interactivity/index.min.js 15.3 kB
build/modules/latex-to-mathml/index.min.js 56.5 kB
build/modules/latex-to-mathml/loader.min.js 131 B
build/modules/lazy-editor/index.min.js 14.1 kB
build/modules/route/index.min.js 25.2 kB
build/modules/vips/loader.min.js 127 B
build/modules/vips/worker.min.js 4.56 MB
build/modules/workflow/index.min.js 19.9 kB
build/scripts/a11y/index.min.js 1.1 kB
build/scripts/annotations/index.min.js 2.53 kB
build/scripts/api-fetch/index.min.js 2.86 kB
build/scripts/autop/index.min.js 2.21 kB
build/scripts/base-styles/index.min.js 146 B
build/scripts/blob/index.min.js 665 B
build/scripts/block-directory/index.min.js 10.3 kB
build/scripts/block-editor/index.min.js 346 kB
build/scripts/block-serialization-default-parser/index.min.js 1.2 kB
build/scripts/block-serialization-spec-parser/index.min.js 3.12 kB
build/scripts/blocks/index.min.js 57.1 kB
build/scripts/commands/index.min.js 21 kB
build/scripts/components/index.min.js 267 kB
build/scripts/compose/index.min.js 11.1 kB
build/scripts/core-commands/index.min.js 4.37 kB
build/scripts/core-data/index.min.js 31.3 kB
build/scripts/customize-widgets/index.min.js 14.6 kB
build/scripts/data-controls/index.min.js 832 B
build/scripts/data/index.min.js 9.72 kB
build/scripts/date/index.min.js 23.7 kB
build/scripts/deprecated/index.min.js 784 B
build/scripts/dom-ready/index.min.js 502 B
build/scripts/dom/index.min.js 5.04 kB
build/scripts/edit-post/index.min.js 18.8 kB
build/scripts/edit-site/index.min.js 265 kB
build/scripts/edit-widgets/index.min.js 22.2 kB
build/scripts/editor/index.min.js 430 kB
build/scripts/element/index.min.js 5.2 kB
build/scripts/escape-html/index.min.js 622 B
build/scripts/format-library/index.min.js 13.1 kB
build/scripts/hooks/index.min.js 1.86 kB
build/scripts/html-entities/index.min.js 529 B
build/scripts/i18n/index.min.js 2.5 kB
build/scripts/is-shallow-equal/index.min.js 607 B
build/scripts/keyboard-shortcuts/index.min.js 1.65 kB
build/scripts/keycodes/index.min.js 1.6 kB
build/scripts/list-reusable-blocks/index.min.js 2.53 kB
build/scripts/media-utils/index.min.js 79.9 kB
build/scripts/notices/index.min.js 1.89 kB
build/scripts/nux/index.min.js 1.92 kB
build/scripts/patterns/index.min.js 8 kB
build/scripts/plugins/index.min.js 2.18 kB
build/scripts/preferences-persistence/index.min.js 2.19 kB
build/scripts/preferences/index.min.js 3.33 kB
build/scripts/primitives/index.min.js 1.05 kB
build/scripts/priority-queue/index.min.js 1.65 kB
build/scripts/private-apis/index.min.js 1.14 kB
build/scripts/react-i18n/index.min.js 868 B
build/scripts/redux-routine/index.min.js 3.4 kB
build/scripts/reusable-blocks/index.min.js 3.14 kB
build/scripts/rich-text/index.min.js 14 kB
build/scripts/router/index.min.js 5.99 kB
build/scripts/server-side-render/index.min.js 1.94 kB
build/scripts/shortcode/index.min.js 1.62 kB
build/scripts/style-engine/index.min.js 2.45 kB
build/scripts/sync/index.min.js 39.3 kB
build/scripts/theme/index.min.js 22.3 kB
build/scripts/token-list/index.min.js 767 B
build/scripts/undo-manager/index.min.js 954 B
build/scripts/url/index.min.js 4.02 kB
build/scripts/vendors/react-dom.min.js 43.3 kB
build/scripts/vendors/react-jsx-runtime.min.js 667 B
build/scripts/vendors/react.min.js 2.77 kB
build/scripts/viewport/index.min.js 1.25 kB
build/scripts/warning/index.min.js 482 B
build/scripts/widgets/index.min.js 7.84 kB
build/scripts/wordcount/index.min.js 1.07 kB
build/styles/base-styles/admin-schemes-rtl.css 1.71 kB
build/styles/base-styles/admin-schemes-rtl.min.css 775 B
build/styles/base-styles/admin-schemes.css 1.71 kB
build/styles/base-styles/admin-schemes.min.css 775 B
build/styles/block-directory/style-rtl.css 1.97 kB
build/styles/block-directory/style-rtl.min.css 1.06 kB
build/styles/block-directory/style.css 1.98 kB
build/styles/block-directory/style.min.css 1.06 kB
build/styles/block-editor/content-rtl.css 5.44 kB
build/styles/block-editor/content-rtl.min.css 4.01 kB
build/styles/block-editor/content.css 5.44 kB
build/styles/block-editor/content.min.css 4.01 kB
build/styles/block-editor/default-editor-styles-rtl.css 697 B
build/styles/block-editor/default-editor-styles-rtl.min.css 224 B
build/styles/block-editor/default-editor-styles.css 697 B
build/styles/block-editor/default-editor-styles.min.css 224 B
build/styles/block-editor/style-rtl.css 18.7 kB
build/styles/block-editor/style-rtl.min.css 15.9 kB
build/styles/block-editor/style.css 18.7 kB
build/styles/block-editor/style.min.css 15.9 kB
build/styles/block-library/accordion-heading/style-rtl.css 346 B
build/styles/block-library/accordion-heading/style-rtl.min.css 325 B
build/styles/block-library/accordion-heading/style.css 346 B
build/styles/block-library/accordion-heading/style.min.css 325 B
build/styles/block-library/accordion-item/style-rtl.css 239 B
build/styles/block-library/accordion-item/style-rtl.min.css 180 B
build/styles/block-library/accordion-item/style.css 238 B
build/styles/block-library/accordion-item/style.min.css 180 B
build/styles/block-library/accordion-panel/style-rtl.css 110 B
build/styles/block-library/accordion-panel/style-rtl.min.css 99 B
build/styles/block-library/accordion-panel/style.css 110 B
build/styles/block-library/accordion-panel/style.min.css 99 B
build/styles/block-library/accordion/style-rtl.css 69 B
build/styles/block-library/accordion/style-rtl.min.css 62 B
build/styles/block-library/accordion/style.css 69 B
build/styles/block-library/accordion/style.min.css 62 B
build/styles/block-library/archives/style-rtl.css 101 B
build/styles/block-library/archives/style-rtl.min.css 90 B
build/styles/block-library/archives/style.css 101 B
build/styles/block-library/archives/style.min.css 90 B
build/styles/block-library/audio/editor-rtl.css 166 B
build/styles/block-library/audio/editor-rtl.min.css 149 B
build/styles/block-library/audio/editor.css 166 B
build/styles/block-library/audio/editor.min.css 151 B
build/styles/block-library/audio/style-rtl.css 945 B
build/styles/block-library/audio/style-rtl.min.css 132 B
build/styles/block-library/audio/style.css 945 B
build/styles/block-library/audio/style.min.css 132 B
build/styles/block-library/audio/theme-rtl.css 967 B
build/styles/block-library/audio/theme-rtl.min.css 134 B
build/styles/block-library/audio/theme.css 967 B
build/styles/block-library/audio/theme.min.css 134 B
build/styles/block-library/avatar/editor-rtl.css 127 B
build/styles/block-library/avatar/editor-rtl.min.css 115 B
build/styles/block-library/avatar/editor.css 127 B
build/styles/block-library/avatar/editor.min.css 115 B
build/styles/block-library/avatar/style-rtl.css 117 B
build/styles/block-library/avatar/style-rtl.min.css 104 B
build/styles/block-library/avatar/style.css 117 B
build/styles/block-library/avatar/style.min.css 104 B
build/styles/block-library/breadcrumbs/style-rtl.css 233 B
build/styles/block-library/breadcrumbs/style-rtl.min.css 203 B
build/styles/block-library/breadcrumbs/style.css 233 B
build/styles/block-library/breadcrumbs/style.min.css 203 B
build/styles/block-library/button/editor-rtl.css 306 B
build/styles/block-library/button/editor-rtl.min.css 265 B
build/styles/block-library/button/editor.css 317 B
build/styles/block-library/button/editor.min.css 265 B
build/styles/block-library/button/style-rtl.css 651 B
build/styles/block-library/button/style-rtl.min.css 596 B
build/styles/block-library/button/style.css 662 B
build/styles/block-library/button/style.min.css 596 B
build/styles/block-library/buttons/editor-rtl.css 391 B
build/styles/block-library/buttons/editor-rtl.min.css 291 B
build/styles/block-library/buttons/editor.css 391 B
build/styles/block-library/buttons/editor.min.css 291 B
build/styles/block-library/buttons/style-rtl.css 452 B
build/styles/block-library/buttons/style-rtl.min.css 349 B
build/styles/block-library/buttons/style.css 453 B
build/styles/block-library/buttons/style.min.css 349 B
build/styles/block-library/calendar/style-rtl.css 271 B
build/styles/block-library/calendar/style-rtl.min.css 239 B
build/styles/block-library/calendar/style.css 271 B
build/styles/block-library/calendar/style.min.css 239 B
build/styles/block-library/categories/editor-rtl.css 171 B
build/styles/block-library/categories/editor-rtl.min.css 132 B
build/styles/block-library/categories/editor.css 170 B
build/styles/block-library/categories/editor.min.css 131 B
build/styles/block-library/categories/style-rtl.css 226 B
build/styles/block-library/categories/style-rtl.min.css 169 B
build/styles/block-library/categories/style.css 235 B
build/styles/block-library/categories/style.min.css 169 B
build/styles/block-library/classic-rtl.css 402 B
build/styles/block-library/classic-rtl.min.css 358 B
build/styles/block-library/classic.css 402 B
build/styles/block-library/classic.min.css 358 B
build/styles/block-library/code/editor-rtl.css 59 B
build/styles/block-library/code/editor-rtl.min.css 53 B
build/styles/block-library/code/editor.css 59 B
build/styles/block-library/code/editor.min.css 53 B
build/styles/block-library/code/style-rtl.css 158 B
build/styles/block-library/code/style-rtl.min.css 140 B
build/styles/block-library/code/style.css 178 B
build/styles/block-library/code/style.min.css 140 B
build/styles/block-library/code/theme-rtl.css 135 B
build/styles/block-library/code/theme-rtl.min.css 122 B
build/styles/block-library/code/theme.css 135 B
build/styles/block-library/code/theme.min.css 122 B
build/styles/block-library/columns/editor-rtl.css 119 B
build/styles/block-library/columns/editor-rtl.min.css 108 B
build/styles/block-library/columns/editor.css 119 B
build/styles/block-library/columns/editor.min.css 108 B
build/styles/block-library/columns/style-rtl.css 1.3 kB
build/styles/block-library/columns/style-rtl.min.css 421 B
build/styles/block-library/columns/style.css 1.3 kB
build/styles/block-library/columns/style.min.css 421 B
build/styles/block-library/comment-author-avatar/editor-rtl.css 136 B
build/styles/block-library/comment-author-avatar/editor-rtl.min.css 124 B
build/styles/block-library/comment-author-avatar/editor.css 136 B
build/styles/block-library/comment-author-avatar/editor.min.css 124 B
build/styles/block-library/comment-author-name/style-rtl.css 79 B
build/styles/block-library/comment-author-name/style-rtl.min.css 72 B
build/styles/block-library/comment-author-name/style.css 79 B
build/styles/block-library/comment-author-name/style.min.css 72 B
build/styles/block-library/comment-content/style-rtl.css 137 B
build/styles/block-library/comment-content/style-rtl.min.css 120 B
build/styles/block-library/comment-content/style.css 137 B
build/styles/block-library/comment-content/style.min.css 120 B
build/styles/block-library/comment-date/style-rtl.css 72 B
build/styles/block-library/comment-date/style-rtl.min.css 65 B
build/styles/block-library/comment-date/style.css 72 B
build/styles/block-library/comment-date/style.min.css 65 B
build/styles/block-library/comment-edit-link/style-rtl.css 77 B
build/styles/block-library/comment-edit-link/style-rtl.min.css 70 B
build/styles/block-library/comment-edit-link/style.css 77 B
build/styles/block-library/comment-edit-link/style.min.css 70 B
build/styles/block-library/comment-reply-link/style-rtl.css 78 B
build/styles/block-library/comment-reply-link/style-rtl.min.css 71 B
build/styles/block-library/comment-reply-link/style.css 78 B
build/styles/block-library/comment-reply-link/style.min.css 71 B
build/styles/block-library/comment-template/style-rtl.css 213 B
build/styles/block-library/comment-template/style-rtl.min.css 191 B
build/styles/block-library/comment-template/style.css 213 B
build/styles/block-library/comment-template/style.min.css 191 B
build/styles/block-library/comments-pagination-numbers/editor-rtl.css 135 B
build/styles/block-library/comments-pagination-numbers/editor-rtl.min.css 122 B
build/styles/block-library/comments-pagination-numbers/editor.css 144 B
build/styles/block-library/comments-pagination-numbers/editor.min.css 121 B
build/styles/block-library/comments-pagination/editor-rtl.css 184 B
build/styles/block-library/comments-pagination/editor-rtl.min.css 168 B
build/styles/block-library/comments-pagination/editor.css 184 B
build/styles/block-library/comments-pagination/editor.min.css 168 B
build/styles/block-library/comments-pagination/style-rtl.css 224 B
build/styles/block-library/comments-pagination/style-rtl.min.css 201 B
build/styles/block-library/comments-pagination/style.css 236 B
build/styles/block-library/comments-pagination/style.min.css 201 B
build/styles/block-library/comments-title/editor-rtl.css 83 B
build/styles/block-library/comments-title/editor-rtl.min.css 75 B
build/styles/block-library/comments-title/editor.css 83 B
build/styles/block-library/comments-title/editor.min.css 75 B
build/styles/block-library/comments/editor-rtl.css 968 B
build/styles/block-library/comments/editor-rtl.min.css 842 B
build/styles/block-library/comments/editor.css 968 B
build/styles/block-library/comments/editor.min.css 842 B
build/styles/block-library/comments/style-rtl.css 754 B
build/styles/block-library/comments/style-rtl.min.css 637 B
build/styles/block-library/comments/style.css 752 B
build/styles/block-library/comments/style.min.css 637 B
build/styles/block-library/common-rtl.css 2.48 kB
build/styles/block-library/common-rtl.min.css 1.12 kB
build/styles/block-library/common.css 2.5 kB
build/styles/block-library/common.min.css 1.12 kB
build/styles/block-library/cover/editor-rtl.css 1.05 kB
build/styles/block-library/cover/editor-rtl.min.css 631 B
build/styles/block-library/cover/editor.css 1.05 kB
build/styles/block-library/cover/editor.min.css 631 B
build/styles/block-library/cover/style-rtl.css 2.5 kB
build/styles/block-library/cover/style-rtl.min.css 1.82 kB
build/styles/block-library/cover/style.css 2.51 kB
build/styles/block-library/cover/style.min.css 1.81 kB
build/styles/block-library/details/editor-rtl.css 72 B
build/styles/block-library/details/editor-rtl.min.css 65 B
build/styles/block-library/details/editor.css 72 B
build/styles/block-library/details/editor.min.css 65 B
build/styles/block-library/details/style-rtl.css 97 B
build/styles/block-library/details/style-rtl.min.css 86 B
build/styles/block-library/details/style.css 97 B
build/styles/block-library/details/style.min.css 86 B
build/styles/block-library/editor-elements-rtl.css 117 B
build/styles/block-library/editor-elements-rtl.min.css 75 B
build/styles/block-library/editor-elements.css 117 B
build/styles/block-library/editor-elements.min.css 75 B
build/styles/block-library/editor-rtl.css 12.5 kB
build/styles/block-library/editor-rtl.min.css 10.3 kB
build/styles/block-library/editor.css 12.5 kB
build/styles/block-library/editor.min.css 10.3 kB
build/styles/block-library/elements-rtl.css 84 B
build/styles/block-library/elements-rtl.min.css 54 B
build/styles/block-library/elements.css 84 B
build/styles/block-library/elements.min.css 54 B
build/styles/block-library/embed/editor-rtl.css 391 B
build/styles/block-library/embed/editor-rtl.min.css 331 B
build/styles/block-library/embed/editor.css 390 B
build/styles/block-library/embed/editor.min.css 331 B
build/styles/block-library/embed/style-rtl.css 1.29 kB
build/styles/block-library/embed/style-rtl.min.css 448 B
build/styles/block-library/embed/style.css 1.29 kB
build/styles/block-library/embed/style.min.css 448 B
build/styles/block-library/embed/theme-rtl.css 967 B
build/styles/block-library/embed/theme-rtl.min.css 133 B
build/styles/block-library/embed/theme.css 967 B
build/styles/block-library/embed/theme.min.css 133 B
build/styles/block-library/file/editor-rtl.css 352 B
build/styles/block-library/file/editor-rtl.min.css 324 B
build/styles/block-library/file/editor.css 353 B
build/styles/block-library/file/editor.min.css 324 B
build/styles/block-library/file/style-rtl.css 318 B
build/styles/block-library/file/style-rtl.min.css 278 B
build/styles/block-library/file/style.css 331 B
build/styles/block-library/file/style.min.css 278 B
build/styles/block-library/footnotes/style-rtl.css 220 B
build/styles/block-library/footnotes/style-rtl.min.css 198 B
build/styles/block-library/footnotes/style.css 219 B
build/styles/block-library/footnotes/style.min.css 197 B
build/styles/block-library/form-input/editor-rtl.css 286 B
build/styles/block-library/form-input/editor-rtl.min.css 265 B
build/styles/block-library/form-input/editor.css 285 B
build/styles/block-library/form-input/editor.min.css 264 B
build/styles/block-library/form-input/style-rtl.css 467 B
build/styles/block-library/form-input/style-rtl.min.css 366 B
build/styles/block-library/form-input/style.css 467 B
build/styles/block-library/form-input/style.min.css 366 B
build/styles/block-library/form-submission-notification/editor-rtl.css 368 B
build/styles/block-library/form-submission-notification/editor-rtl.min.css 344 B
build/styles/block-library/form-submission-notification/editor.css 368 B
build/styles/block-library/form-submission-notification/editor.min.css 341 B
build/styles/block-library/form-submit-button/style-rtl.css 77 B
build/styles/block-library/form-submit-button/style-rtl.min.css 69 B
build/styles/block-library/form-submit-button/style.css 77 B
build/styles/block-library/form-submit-button/style.min.css 69 B
build/styles/block-library/freeform/editor-rtl.css 1.12 kB
build/styles/block-library/freeform/editor-rtl.min.css 288 B
build/styles/block-library/freeform/editor.css 1.12 kB
build/styles/block-library/freeform/editor.min.css 288 B
build/styles/block-library/gallery/editor-rtl.css 1.52 kB
build/styles/block-library/gallery/editor-rtl.min.css 615 B
build/styles/block-library/gallery/editor.css 1.52 kB
build/styles/block-library/gallery/editor.min.css 616 B
build/styles/block-library/gallery/style-rtl.css 2.84 kB
build/styles/block-library/gallery/style-rtl.min.css 1.84 kB
build/styles/block-library/gallery/style.css 2.84 kB
build/styles/block-library/gallery/style.min.css 1.84 kB
build/styles/block-library/gallery/theme-rtl.css 941 B
build/styles/block-library/gallery/theme-rtl.min.css 108 B
build/styles/block-library/gallery/theme.css 941 B
build/styles/block-library/gallery/theme.min.css 108 B
build/styles/block-library/group/editor-rtl.css 772 B
build/styles/block-library/group/editor-rtl.min.css 335 B
build/styles/block-library/group/editor.css 772 B
build/styles/block-library/group/editor.min.css 335 B
build/styles/block-library/group/style-rtl.css 120 B
build/styles/block-library/group/style-rtl.min.css 103 B
build/styles/block-library/group/style.css 120 B
build/styles/block-library/group/style.min.css 103 B
build/styles/block-library/group/theme-rtl.css 468 B
build/styles/block-library/group/theme-rtl.min.css 79 B
build/styles/block-library/group/theme.css 468 B
build/styles/block-library/group/theme.min.css 79 B
build/styles/block-library/heading/style-rtl.css 604 B
build/styles/block-library/heading/style-rtl.min.css 205 B
build/styles/block-library/heading/style.css 604 B
build/styles/block-library/heading/style.min.css 205 B
build/styles/block-library/html/editor-rtl.css 1.29 kB
build/styles/block-library/html/editor-rtl.min.css 464 B
build/styles/block-library/html/editor.css 1.3 kB
build/styles/block-library/html/editor.min.css 464 B
build/styles/block-library/icon/editor-rtl.css 776 B
build/styles/block-library/icon/editor-rtl.min.css 377 B
build/styles/block-library/icon/editor.css 776 B
build/styles/block-library/icon/editor.min.css 377 B
build/styles/block-library/icon/style-rtl.css 218 B
build/styles/block-library/icon/style-rtl.min.css 154 B
build/styles/block-library/icon/style.css 218 B
build/styles/block-library/icon/style.min.css 154 B
build/styles/block-library/image/editor-rtl.css 1.64 kB
build/styles/block-library/image/editor-rtl.min.css 782 B
build/styles/block-library/image/editor.css 1.64 kB
build/styles/block-library/image/editor.min.css 780 B
build/styles/block-library/image/style-rtl.css 2.92 kB
build/styles/block-library/image/style-rtl.min.css 1.86 kB
build/styles/block-library/image/style.css 2.92 kB
build/styles/block-library/image/style.min.css 1.85 kB
build/styles/block-library/image/theme-rtl.css 971 B
build/styles/block-library/image/theme-rtl.min.css 137 B
build/styles/block-library/image/theme.css 971 B
build/styles/block-library/image/theme.min.css 137 B
build/styles/block-library/latest-comments/style-rtl.css 392 B
build/styles/block-library/latest-comments/style-rtl.min.css 352 B
build/styles/block-library/latest-comments/style.css 390 B
build/styles/block-library/latest-comments/style.min.css 352 B
build/styles/block-library/latest-posts/editor-rtl.css 154 B
build/styles/block-library/latest-posts/editor-rtl.min.css 139 B
build/styles/block-library/latest-posts/editor.css 153 B
build/styles/block-library/latest-posts/editor.min.css 138 B
build/styles/block-library/latest-posts/style-rtl.css 1.36 kB
build/styles/block-library/latest-posts/style-rtl.min.css 520 B
build/styles/block-library/latest-posts/style.css 1.37 kB
build/styles/block-library/latest-posts/style.min.css 520 B
build/styles/block-library/list/style-rtl.css 498 B
build/styles/block-library/list/style-rtl.min.css 107 B
build/styles/block-library/list/style.css 498 B
build/styles/block-library/list/style.min.css 107 B
build/styles/block-library/loginout/style-rtl.css 68 B
build/styles/block-library/loginout/style-rtl.min.css 61 B
build/styles/block-library/loginout/style.css 68 B
build/styles/block-library/loginout/style.min.css 61 B
build/styles/block-library/math/editor-rtl.css 491 B
build/styles/block-library/math/editor-rtl.min.css 105 B
build/styles/block-library/math/editor.css 502 B
build/styles/block-library/math/editor.min.css 105 B
build/styles/block-library/math/style-rtl.css 70 B
build/styles/block-library/math/style-rtl.min.css 61 B
build/styles/block-library/math/style.css 70 B
build/styles/block-library/math/style.min.css 61 B
build/styles/block-library/media-text/editor-rtl.css 389 B
build/styles/block-library/media-text/editor-rtl.min.css 321 B
build/styles/block-library/media-text/editor.css 389 B
build/styles/block-library/media-text/editor.min.css 320 B
build/styles/block-library/media-text/style-rtl.css 873 B
build/styles/block-library/media-text/style-rtl.min.css 552 B
build/styles/block-library/media-text/style.css 901 B
build/styles/block-library/media-text/style.min.css 550 B
build/styles/block-library/more/editor-rtl.css 796 B
build/styles/block-library/more/editor-rtl.min.css 393 B
build/styles/block-library/more/editor.css 798 B
build/styles/block-library/more/editor.min.css 393 B
build/styles/block-library/navigation-link/editor-rtl.css 1.28 kB
build/styles/block-library/navigation-link/editor-rtl.min.css 710 B
build/styles/block-library/navigation-link/editor.css 1.27 kB
build/styles/block-library/navigation-link/editor.min.css 713 B
build/styles/block-library/navigation-link/style-rtl.css 579 B
build/styles/block-library/navigation-link/style-rtl.min.css 190 B
build/styles/block-library/navigation-link/style.css 579 B
build/styles/block-library/navigation-link/style.min.css 188 B
build/styles/block-library/navigation-overlay-close/style-rtl.css 260 B
build/styles/block-library/navigation-overlay-close/style-rtl.min.css 237 B
build/styles/block-library/navigation-overlay-close/style.css 260 B
build/styles/block-library/navigation-overlay-close/style.min.css 237 B
build/styles/block-library/navigation-submenu/editor-rtl.css 1.12 kB
build/styles/block-library/navigation-submenu/editor-rtl.min.css 295 B
build/styles/block-library/navigation-submenu/editor.css 1.12 kB
build/styles/block-library/navigation-submenu/editor.min.css 294 B
build/styles/block-library/navigation/editor-rtl.css 3.28 kB
build/styles/block-library/navigation/editor-rtl.min.css 2.28 kB
build/styles/block-library/navigation/editor.css 3.29 kB
build/styles/block-library/navigation/editor.min.css 2.28 kB
build/styles/block-library/navigation/style-rtl.css 3.59 kB
build/styles/block-library/navigation/style-rtl.min.css 2.52 kB
build/styles/block-library/navigation/style.css 3.59 kB
build/styles/block-library/navigation/style.min.css 2.5 kB
build/styles/block-library/nextpage/editor-rtl.css 799 B
build/styles/block-library/nextpage/editor-rtl.min.css 392 B
build/styles/block-library/nextpage/editor.css 800 B
build/styles/block-library/nextpage/editor.min.css 392 B
build/styles/block-library/page-list/editor-rtl.css 1.18 kB
build/styles/block-library/page-list/editor-rtl.min.css 356 B
build/styles/block-library/page-list/editor.css 1.18 kB
build/styles/block-library/page-list/editor.min.css 356 B
build/styles/block-library/page-list/style-rtl.css 207 B
build/styles/block-library/page-list/style-rtl.min.css 192 B
build/styles/block-library/page-list/style.css 207 B
build/styles/block-library/page-list/style.min.css 192 B
build/styles/block-library/paragraph/editor-rtl.css 315 B
build/styles/block-library/paragraph/editor-rtl.min.css 292 B
build/styles/block-library/paragraph/editor.css 314 B
build/styles/block-library/paragraph/editor.min.css 292 B
build/styles/block-library/paragraph/style-rtl.css 746 B
build/styles/block-library/paragraph/style-rtl.min.css 341 B
build/styles/block-library/paragraph/style.css 752 B
build/styles/block-library/paragraph/style.min.css 340 B
build/styles/block-library/playlist-track/style-rtl.css 453 B
build/styles/block-library/playlist-track/style-rtl.min.css 420 B
build/styles/block-library/playlist-track/style.css 453 B
build/styles/block-library/playlist-track/style.min.css 420 B
build/styles/block-library/playlist/editor-rtl.css 120 B
build/styles/block-library/playlist/editor-rtl.min.css 112 B
build/styles/block-library/playlist/editor.css 120 B
build/styles/block-library/playlist/editor.min.css 112 B
build/styles/block-library/playlist/style-rtl.css 1.52 kB
build/styles/block-library/playlist/style-rtl.min.css 1.42 kB
build/styles/block-library/playlist/style.css 1.52 kB
build/styles/block-library/playlist/style.min.css 1.42 kB
build/styles/block-library/post-author-biography/style-rtl.css 96 B
build/styles/block-library/post-author-biography/style-rtl.min.css 86 B
build/styles/block-library/post-author-biography/style.css 96 B
build/styles/block-library/post-author-biography/style.min.css 86 B
build/styles/block-library/post-author-name/style-rtl.css 76 B
build/styles/block-library/post-author-name/style-rtl.min.css 69 B
build/styles/block-library/post-author-name/style.css 76 B
build/styles/block-library/post-author-name/style.min.css 69 B
build/styles/block-library/post-author/editor-rtl.css 490 B
build/styles/block-library/post-author/editor-rtl.min.css 104 B
build/styles/block-library/post-author/editor.css 490 B
build/styles/block-library/post-author/editor.min.css 104 B
build/styles/block-library/post-author/style-rtl.css 213 B
build/styles/block-library/post-author/style-rtl.min.css 188 B
build/styles/block-library/post-author/style.css 214 B
build/styles/block-library/post-author/style.min.css 189 B
build/styles/block-library/post-comments-count/style-rtl.css 79 B
build/styles/block-library/post-comments-count/style-rtl.min.css 72 B
build/styles/block-library/post-comments-count/style.css 79 B
build/styles/block-library/post-comments-count/style.min.css 72 B
build/styles/block-library/post-comments-form/editor-rtl.css 104 B
build/styles/block-library/post-comments-form/editor-rtl.min.css 96 B
build/styles/block-library/post-comments-form/editor.css 104 B
build/styles/block-library/post-comments-form/editor.min.css 96 B
build/styles/block-library/post-comments-form/style-rtl.css 585 B
build/styles/block-library/post-comments-form/style-rtl.min.css 525 B
build/styles/block-library/post-comments-form/style.css 584 B
build/styles/block-library/post-comments-form/style.min.css 525 B
build/styles/block-library/post-comments-link/style-rtl.css 78 B
build/styles/block-library/post-comments-link/style-rtl.min.css 71 B
build/styles/block-library/post-comments-link/style.css 78 B
build/styles/block-library/post-comments-link/style.min.css 71 B
build/styles/block-library/post-content/style-rtl.css 68 B
build/styles/block-library/post-content/style-rtl.min.css 61 B
build/styles/block-library/post-content/style.css 68 B
build/styles/block-library/post-content/style.min.css 61 B
build/styles/block-library/post-date/style-rtl.css 69 B
build/styles/block-library/post-date/style-rtl.min.css 62 B
build/styles/block-library/post-date/style.css 69 B
build/styles/block-library/post-date/style.min.css 62 B
build/styles/block-library/post-excerpt/editor-rtl.css 78 B
build/styles/block-library/post-excerpt/editor-rtl.min.css 71 B
build/styles/block-library/post-excerpt/editor.css 78 B
build/styles/block-library/post-excerpt/editor.min.css 71 B
build/styles/block-library/post-excerpt/style-rtl.css 171 B
build/styles/block-library/post-excerpt/style-rtl.min.css 155 B
build/styles/block-library/post-excerpt/style.css 171 B
build/styles/block-library/post-excerpt/style.min.css 155 B
build/styles/block-library/post-featured-image/editor-rtl.css 1.14 kB
build/styles/block-library/post-featured-image/editor-rtl.min.css 719 B
build/styles/block-library/post-featured-image/editor.css 1.14 kB
build/styles/block-library/post-featured-image/editor.min.css 717 B
build/styles/block-library/post-featured-image/style-rtl.css 392 B
build/styles/block-library/post-featured-image/style-rtl.min.css 347 B
build/styles/block-library/post-featured-image/style.css 392 B
build/styles/block-library/post-featured-image/style.min.css 347 B
build/styles/block-library/post-navigation-link/style-rtl.css 234 B
build/styles/block-library/post-navigation-link/style-rtl.min.css 215 B
build/styles/block-library/post-navigation-link/style.css 245 B
build/styles/block-library/post-navigation-link/style.min.css 214 B
build/styles/block-library/post-template/style-rtl.css 1.27 kB
build/styles/block-library/post-template/style-rtl.min.css 441 B
build/styles/block-library/post-template/style.css 1.27 kB
build/styles/block-library/post-template/style.min.css 441 B
build/styles/block-library/post-terms/style-rtl.css 108 B
build/styles/block-library/post-terms/style-rtl.min.css 96 B
build/styles/block-library/post-terms/style.css 108 B
build/styles/block-library/post-terms/style.min.css 96 B
build/styles/block-library/post-time-to-read/style-rtl.css 77 B
build/styles/block-library/post-time-to-read/style-rtl.min.css 70 B
build/styles/block-library/post-time-to-read/style.css 77 B
build/styles/block-library/post-time-to-read/style.min.css 70 B
build/styles/block-library/post-title/style-rtl.css 175 B
build/styles/block-library/post-title/style-rtl.min.css 162 B
build/styles/block-library/post-title/style.css 175 B
build/styles/block-library/post-title/style.min.css 162 B
build/styles/block-library/preformatted/style-rtl.css 511 B
build/styles/block-library/preformatted/style-rtl.min.css 125 B
build/styles/block-library/preformatted/style.css 511 B
build/styles/block-library/preformatted/style.min.css 125 B
build/styles/block-library/pullquote/editor-rtl.css 146 B
build/styles/block-library/pullquote/editor-rtl.min.css 133 B
build/styles/block-library/pullquote/editor.css 146 B
build/styles/block-library/pullquote/editor.min.css 133 B
build/styles/block-library/pullquote/style-rtl.css 765 B
build/styles/block-library/pullquote/style-rtl.min.css 365 B
build/styles/block-library/pullquote/style.css 764 B
build/styles/block-library/pullquote/style.min.css 365 B
build/styles/block-library/pullquote/theme-rtl.css 195 B
build/styles/block-library/pullquote/theme-rtl.min.css 176 B
build/styles/block-library/pullquote/theme.css 195 B
build/styles/block-library/pullquote/theme.min.css 176 B
build/styles/block-library/query-pagination-numbers/editor-rtl.css 134 B
build/styles/block-library/query-pagination-numbers/editor-rtl.min.css 121 B
build/styles/block-library/query-pagination-numbers/editor.css 144 B
build/styles/block-library/query-pagination-numbers/editor.min.css 118 B
build/styles/block-library/query-pagination/editor-rtl.css 168 B
build/styles/block-library/query-pagination/editor-rtl.min.css 154 B
build/styles/block-library/query-pagination/editor.css 168 B
build/styles/block-library/query-pagination/editor.min.css 154 B
build/styles/block-library/query-pagination/style-rtl.css 254 B
build/styles/block-library/query-pagination/style-rtl.min.css 237 B
build/styles/block-library/query-pagination/style.css 265 B
build/styles/block-library/query-pagination/style.min.css 237 B
build/styles/block-library/query-title/style-rtl.css 71 B
build/styles/block-library/query-title/style-rtl.min.css 64 B
build/styles/block-library/query-title/style.css 71 B
build/styles/block-library/query-title/style.min.css 64 B
build/styles/block-library/query-total/style-rtl.css 71 B
build/styles/block-library/query-total/style-rtl.min.css 64 B
build/styles/block-library/query-total/style.css 71 B
build/styles/block-library/query-total/style.min.css 64 B
build/styles/block-library/query/editor-rtl.css 1.28 kB
build/styles/block-library/query/editor-rtl.min.css 438 B
build/styles/block-library/query/editor.css 1.28 kB
build/styles/block-library/query/editor.min.css 438 B
build/styles/block-library/quote/style-rtl.css 255 B
build/styles/block-library/quote/style-rtl.min.css 238 B
build/styles/block-library/quote/style.css 256 B
build/styles/block-library/quote/style.min.css 238 B
build/styles/block-library/quote/theme-rtl.css 253 B
build/styles/block-library/quote/theme-rtl.min.css 233 B
build/styles/block-library/quote/theme.css 254 B
build/styles/block-library/quote/theme.min.css 236 B
build/styles/block-library/read-more/style-rtl.css 146 B
build/styles/block-library/read-more/style-rtl.min.css 131 B
build/styles/block-library/read-more/style.css 146 B
build/styles/block-library/read-more/style.min.css 131 B
build/styles/block-library/reset-rtl.css 936 B
build/styles/block-library/reset-rtl.min.css 467 B
build/styles/block-library/reset.css 936 B
build/styles/block-library/reset.min.css 467 B
build/styles/block-library/rss/editor-rtl.css 144 B
build/styles/block-library/rss/editor-rtl.min.css 126 B
build/styles/block-library/rss/editor.css 144 B
build/styles/block-library/rss/editor.min.css 126 B
build/styles/block-library/rss/style-rtl.css 1.11 kB
build/styles/block-library/rss/style-rtl.min.css 284 B
build/styles/block-library/rss/style.css 1.12 kB
build/styles/block-library/rss/style.min.css 283 B
build/styles/block-library/search/editor-rtl.css 217 B
build/styles/block-library/search/editor-rtl.min.css 199 B
build/styles/block-library/search/editor.css 217 B
build/styles/block-library/search/editor.min.css 199 B
build/styles/block-library/search/style-rtl.css 1.1 kB
build/styles/block-library/search/style-rtl.min.css 665 B
build/styles/block-library/search/style.css 1.1 kB
build/styles/block-library/search/style.min.css 666 B
build/styles/block-library/search/theme-rtl.css 130 B
build/styles/block-library/search/theme-rtl.min.css 113 B
build/styles/block-library/search/theme.css 130 B
build/styles/block-library/search/theme.min.css 113 B
build/styles/block-library/separator/editor-rtl.css 106 B
build/styles/block-library/separator/editor-rtl.min.css 100 B
build/styles/block-library/separator/editor.css 106 B
build/styles/block-library/separator/editor.min.css 100 B
build/styles/block-library/separator/style-rtl.css 284 B
build/styles/block-library/separator/style-rtl.min.css 248 B
build/styles/block-library/separator/style.css 297 B
build/styles/block-library/separator/style.min.css 248 B
build/styles/block-library/separator/theme-rtl.css 226 B
build/styles/block-library/separator/theme-rtl.min.css 195 B
build/styles/block-library/separator/theme.css 226 B
build/styles/block-library/separator/theme.min.css 195 B
build/styles/block-library/shortcode/editor-rtl.css 1.1 kB
build/styles/block-library/shortcode/editor-rtl.min.css 286 B
build/styles/block-library/shortcode/editor.css 1.1 kB
build/styles/block-library/shortcode/editor.min.css 286 B
build/styles/block-library/site-logo/editor-rtl.css 1.12 kB
build/styles/block-library/site-logo/editor-rtl.min.css 696 B
build/styles/block-library/site-logo/editor.css 1.12 kB
build/styles/block-library/site-logo/editor.min.css 692 B
build/styles/block-library/site-logo/style-rtl.css 239 B
build/styles/block-library/site-logo/style-rtl.min.css 218 B
build/styles/block-library/site-logo/style.css 238 B
build/styles/block-library/site-logo/style.min.css 218 B
build/styles/block-library/site-tagline/editor-rtl.css 94 B
build/styles/block-library/site-tagline/editor-rtl.min.css 87 B
build/styles/block-library/site-tagline/editor.css 94 B
build/styles/block-library/site-tagline/editor.min.css 87 B
build/styles/block-library/site-tagline/style-rtl.css 72 B
build/styles/block-library/site-tagline/style-rtl.min.css 65 B
build/styles/block-library/site-tagline/style.css 72 B
build/styles/block-library/site-tagline/style.min.css 65 B
build/styles/block-library/site-title/editor-rtl.css 93 B
build/styles/block-library/site-title/editor-rtl.min.css 85 B
build/styles/block-library/site-title/editor.css 93 B
build/styles/block-library/site-title/editor.min.css 85 B
build/styles/block-library/site-title/style-rtl.css 153 B
build/styles/block-library/site-title/style-rtl.min.css 143 B
build/styles/block-library/site-title/style.css 153 B
build/styles/block-library/site-title/style.min.css 143 B
build/styles/block-library/social-link/editor-rtl.css 346 B
build/styles/block-library/social-link/editor-rtl.min.css 314 B
build/styles/block-library/social-link/editor.css 348 B
build/styles/block-library/social-link/editor.min.css 314 B
build/styles/block-library/social-links/editor-rtl.css 737 B
build/styles/block-library/social-links/editor-rtl.min.css 339 B
build/styles/block-library/social-links/editor.css 738 B
build/styles/block-library/social-links/editor.min.css 338 B
build/styles/block-library/social-links/style-rtl.css 1.57 kB
build/styles/block-library/social-links/style-rtl.min.css 1.51 kB
build/styles/block-library/social-links/style.css 1.57 kB
build/styles/block-library/social-links/style.min.css 1.51 kB
build/styles/block-library/spacer/editor-rtl.css 774 B
build/styles/block-library/spacer/editor-rtl.min.css 346 B
build/styles/block-library/spacer/editor.css 774 B
build/styles/block-library/spacer/editor.min.css 346 B
build/styles/block-library/spacer/style-rtl.css 55 B
build/styles/block-library/spacer/style-rtl.min.css 48 B
build/styles/block-library/spacer/style.css 55 B
build/styles/block-library/spacer/style.min.css 48 B
build/styles/block-library/style-rtl.css 21.5 kB
build/styles/block-library/style-rtl.min.css 18 kB
build/styles/block-library/style.css 21.6 kB
build/styles/block-library/style.min.css 18 kB
build/styles/block-library/tab-list/editor-rtl.css 107 B
build/styles/block-library/tab-list/editor-rtl.min.css 97 B
build/styles/block-library/tab-list/editor.css 107 B
build/styles/block-library/tab-list/editor.min.css 97 B
build/styles/block-library/tab-panel/style-rtl.css 238 B
build/styles/block-library/tab-panel/style-rtl.min.css 215 B
build/styles/block-library/tab-panel/style.css 238 B
build/styles/block-library/tab-panel/style.min.css 215 B
build/styles/block-library/tab-panels/style-rtl.css 76 B
build/styles/block-library/tab-panels/style-rtl.min.css 65 B
build/styles/block-library/tab-panels/style.css 76 B
build/styles/block-library/tab-panels/style.min.css 65 B
build/styles/block-library/tab/editor-rtl.css 160 B
build/styles/block-library/tab/editor-rtl.min.css 148 B
build/styles/block-library/tab/editor.css 160 B
build/styles/block-library/tab/editor.min.css 148 B
build/styles/block-library/tab/style-rtl.css 397 B
build/styles/block-library/tab/style-rtl.min.css 352 B
build/styles/block-library/tab/style.css 398 B
build/styles/block-library/tab/style.min.css 356 B
build/styles/block-library/table-of-contents/style-rtl.css 89 B
build/styles/block-library/table-of-contents/style-rtl.min.css 83 B
build/styles/block-library/table-of-contents/style.css 89 B
build/styles/block-library/table-of-contents/style.min.css 83 B
build/styles/block-library/table/editor-rtl.css 1.25 kB
build/styles/block-library/table/editor-rtl.min.css 394 B
build/styles/block-library/table/editor.css 1.25 kB
build/styles/block-library/table/editor.min.css 394 B
build/styles/block-library/table/style-rtl.css 1.06 kB
build/styles/block-library/table/style-rtl.min.css 641 B
build/styles/block-library/table/style.css 1.06 kB
build/styles/block-library/table/style.min.css 640 B
build/styles/block-library/table/theme-rtl.css 985 B
build/styles/block-library/table/theme-rtl.min.css 152 B
build/styles/block-library/table/theme.css 985 B
build/styles/block-library/table/theme.min.css 152 B
build/styles/block-library/tabs/style-rtl.css 64 B
build/styles/block-library/tabs/style-rtl.min.css 57 B
build/styles/block-library/tabs/style.css 64 B
build/styles/block-library/tabs/style.min.css 57 B
build/styles/block-library/tag-cloud/style-rtl.css 283 B
build/styles/block-library/tag-cloud/style-rtl.min.css 248 B
build/styles/block-library/tag-cloud/style.css 283 B
build/styles/block-library/tag-cloud/style.min.css 248 B
build/styles/block-library/template-part/editor-rtl.css 1.2 kB
build/styles/block-library/template-part/editor-rtl.min.css 368 B
build/styles/block-library/template-part/editor.css 1.2 kB
build/styles/block-library/template-part/editor.min.css 368 B
build/styles/block-library/template-part/theme-rtl.css 492 B
build/styles/block-library/template-part/theme-rtl.min.css 113 B
build/styles/block-library/template-part/theme.css 492 B
build/styles/block-library/template-part/theme.min.css 113 B
build/styles/block-library/term-count/style-rtl.css 70 B
build/styles/block-library/term-count/style-rtl.min.css 63 B
build/styles/block-library/term-count/style.css 70 B
build/styles/block-library/term-count/style.min.css 63 B
build/styles/block-library/term-description/style-rtl.css 138 B
build/styles/block-library/term-description/style-rtl.min.css 126 B
build/styles/block-library/term-description/style.css 138 B
build/styles/block-library/term-description/style.min.css 126 B
build/styles/block-library/term-name/style-rtl.css 69 B
build/styles/block-library/term-name/style-rtl.min.css 62 B
build/styles/block-library/term-name/style.css 69 B
build/styles/block-library/term-name/style.min.css 62 B
build/styles/block-library/term-template/editor-rtl.css 267 B
build/styles/block-library/term-template/editor-rtl.min.css 225 B
build/styles/block-library/term-template/editor.css 267 B
build/styles/block-library/term-template/editor.min.css 225 B
build/styles/block-library/term-template/style-rtl.css 124 B
build/styles/block-library/term-template/style-rtl.min.css 114 B
build/styles/block-library/term-template/style.css 124 B
build/styles/block-library/term-template/style.min.css 114 B
build/styles/block-library/text-columns/editor-rtl.css 481 B
build/styles/block-library/text-columns/editor-rtl.min.css 95 B
build/styles/block-library/text-columns/editor.css 481 B
build/styles/block-library/text-columns/editor.min.css 95 B
build/styles/block-library/text-columns/style-rtl.css 177 B
build/styles/block-library/text-columns/style-rtl.min.css 165 B
build/styles/block-library/text-columns/style.css 177 B
build/styles/block-library/text-columns/style.min.css 165 B
build/styles/block-library/theme-rtl.css 1.59 kB
build/styles/block-library/theme-rtl.min.css 715 B
build/styles/block-library/theme.css 1.6 kB
build/styles/block-library/theme.min.css 719 B
build/styles/block-library/verse/style-rtl.css 155 B
build/styles/block-library/verse/style-rtl.min.css 137 B
build/styles/block-library/verse/style.css 155 B
build/styles/block-library/verse/style.min.css 137 B
build/styles/block-library/video/editor-rtl.css 839 B
build/styles/block-library/video/editor-rtl.min.css 428 B
build/styles/block-library/video/editor.css 840 B
build/styles/block-library/video/editor.min.css 428 B
build/styles/block-library/video/style-rtl.css 1.02 kB
build/styles/block-library/video/style-rtl.min.css 202 B
build/styles/block-library/video/style.css 1.02 kB
build/styles/block-library/video/style.min.css 202 B
build/styles/block-library/video/theme-rtl.css 967 B
build/styles/block-library/video/theme-rtl.min.css 134 B
build/styles/block-library/video/theme.css 967 B
build/styles/block-library/video/theme.min.css 134 B
build/styles/commands/style-rtl.css 2.07 kB
build/styles/commands/style-rtl.min.css 1.17 kB
build/styles/commands/style.css 2.06 kB
build/styles/commands/style.min.css 1.17 kB
build/styles/components/style-rtl.css 17.5 kB
build/styles/components/style-rtl.min.css 14.3 kB
build/styles/components/style.css 17.6 kB
build/styles/components/style.min.css 14.3 kB
build/styles/customize-widgets/style-rtl.css 2.35 kB
build/styles/customize-widgets/style-rtl.min.css 1.44 kB
build/styles/customize-widgets/style.css 2.35 kB
build/styles/customize-widgets/style.min.css 1.44 kB
build/styles/edit-post/classic-rtl.css 1.29 kB
build/styles/edit-post/classic-rtl.min.css 425 B
build/styles/edit-post/classic.css 1.31 kB
build/styles/edit-post/classic.min.css 428 B
build/styles/edit-post/style-rtl.css 3.51 kB
build/styles/edit-post/style-rtl.min.css 2.21 kB
build/styles/edit-post/style.css 3.52 kB
build/styles/edit-post/style.min.css 2.21 kB
build/styles/edit-site/style-rtl.css 21.1 kB
build/styles/edit-site/style-rtl.min.css 17.2 kB
build/styles/edit-site/style.css 21.1 kB
build/styles/edit-site/style.min.css 17.2 kB
build/styles/edit-widgets/style-rtl.css 4.85 kB
build/styles/edit-widgets/style-rtl.min.css 3.52 kB
build/styles/edit-widgets/style.css 4.85 kB
build/styles/edit-widgets/style.min.css 3.52 kB
build/styles/editor/style-rtl.css 29.4 kB
build/styles/editor/style-rtl.min.css 24.8 kB
build/styles/editor/style.css 29.4 kB
build/styles/editor/style.min.css 24.8 kB
build/styles/format-library/style-rtl.css 735 B
build/styles/format-library/style-rtl.min.css 326 B
build/styles/format-library/style.css 746 B
build/styles/format-library/style.min.css 326 B
build/styles/list-reusable-blocks/style-rtl.css 1.07 kB
build/styles/list-reusable-blocks/style-rtl.min.css 250 B
build/styles/list-reusable-blocks/style.css 1.07 kB
build/styles/list-reusable-blocks/style.min.css 249 B
build/styles/media-utils/style-rtl.css 2.08 kB
build/styles/media-utils/style-rtl.min.css 1.17 kB
build/styles/media-utils/style.css 2.08 kB
build/styles/media-utils/style.min.css 1.17 kB
build/styles/nux/style-rtl.css 1.48 kB
build/styles/nux/style-rtl.min.css 622 B
build/styles/nux/style.css 1.5 kB
build/styles/nux/style.min.css 618 B
build/styles/patterns/style-rtl.css 1.46 kB
build/styles/patterns/style-rtl.min.css 611 B
build/styles/patterns/style.css 1.46 kB
build/styles/patterns/style.min.css 611 B
build/styles/preferences/style-rtl.css 1.26 kB
build/styles/preferences/style-rtl.min.css 415 B
build/styles/preferences/style.css 1.26 kB
build/styles/preferences/style.min.css 415 B
build/styles/reusable-blocks/style-rtl.css 1.11 kB
build/styles/reusable-blocks/style-rtl.min.css 275 B
build/styles/reusable-blocks/style.css 1.11 kB
build/styles/reusable-blocks/style.min.css 275 B
build/styles/widgets/style-rtl.css 2.05 kB
build/styles/widgets/style-rtl.min.css 1.16 kB
build/styles/widgets/style.css 2.06 kB
build/styles/widgets/style.min.css 1.16 kB

compressed-size-action

@adamsilverstein adamsilverstein added [Type] Feature New feature to highlight in changelogs. [Feature] Client Side Media Media processing in the browser with WASM labels May 16, 2026
@adamsilverstein adamsilverstein self-assigned this May 16, 2026
@swissspidy
Copy link
Copy Markdown
Member

Nice! 👍

Looks similar to what I've built in media-experiments before:

swissspidy/media-experiments#242
https://github.com/swissspidy/media-experiments/blob/cf28384fc2b6d59ca89626f6fceb9d10ddf04474/packages/editor/src/block-media-panel/animated-gif-converter.tsx

One thing I struggled to build when doing this is to attach the generated video poster image to the newly converted video block. See swissspidy/media-experiments#163

The original upload references the old image block clientId, but this reference is lost upon conversion.

Solving this might affect how the transformation is done in the first place, so I'd love your thoughts on it.

@andrewserong
Copy link
Copy Markdown
Contributor

andrewserong commented May 18, 2026

This is an interesting one in terms of UX. A couple of thoughts while testing this out:

  • If I explicitly add an Image block and am intending to upload a GIF and for it to be dealt with as a GIF (e.g. small decorative images, part of a site's header or footer, or emoji-reaction-like small GIFs), then the conversion to a Video block is unexpected (and quite possibly not what the user wanted to do)
  • If I'm thinking "oh, I'd like to upload this video" but I don't know anything about file formats, I might think to add the Video block and then go looking for a GIF that I've saved, not realising that to WP a GIF is an image

It's a fairly subtle issue to deal with, but I'm wondering what the common user expectation is here? And how can we preserve GIFs as GIFs when that's what the user intended 🤔

Just a couple of ideas, but what if:

  • When a user drags from their desktop onto any empty area of the document (e.g. onto an empty paragraph block) then we convert GIF to video as a best effort to match what the user intends, and inject a Video block
  • But, if a user explicitly added an Image block, then we treat the GIF as a GIF? I.e. we don't convert the file format and we don't switch to MP4.
    • If we want to support folks converting after the fact, I'm wondering if a button somewhere in the block UI (i.e. similar to how folks can convert to a Cover block, or in the block settings dropdown) would work? Or is this too complex?
image
  • We also (somehow) allow the Video block to accept gifs as well as video source (when client-side media processing of GIF -> MP4) is allowed

What do you think? Am I overthinking this, or could we use some design or UX input?

@adamsilverstein
Copy link
Copy Markdown
Member Author

This is an interesting one in terms of UX. A couple of thoughts while testing this out:

  • If I explicitly add an Image block and am intending to upload a GIF and for it to be dealt with as a GIF (e.g. small decorative images, part of a site's header or footer, or emoji-reaction-like small GIFs), then the conversion to a Video block is unexpected (and quite possibly not what the user wanted to do)
  • If I'm thinking "oh, I'd like to upload this video" but I don't know anything about file formats, I might think to add the Video block and then go looking for a GIF that I've saved, not realising that to WP a GIF is an image

It's a fairly subtle issue to deal with, but I'm wondering what the common user expectation is here? And how can we preserve GIFs as GIFs when that's what the user intended 🤔

For the vast majority of users, they are thinking "I want this (video|meme|animated gif|animation) on my web page" - they don't really know what the format it or what the different formats are. If they upload a gif, they likely want a looping animation or video, because thats what gifs do. If they upload a video, they probably want a video player with some controls to play and pause the video. WordPress should endeavor to deliver that experience the user wants, without making them worry about the technical implementation details.

Just a couple of ideas, but what if:

  • When a user drags from their desktop onto any empty area of the document (e.g. onto an empty paragraph block) then we convert GIF to video as a best effort to match what the user intends, and inject a Video block

I generally think this makes sense. The video is set to autoplay and has no controls, to it behaves exactly like the gif would on the page, so the user gets what they (most likely want). I do agree that fact that it is a video block is slightly surprising, and might confuse some users. A notification might help, but it still feels odd.

  • But, if a user explicitly added an Image block, then we treat the GIF as a GIF? I.e. we don't convert the file format and we don't switch to MP4.

That also makes sense, although arguably the video would give them the same experience, it would be even more confusing to have an image block you just inserted converted to a video block.

  • If we want to support folks converting after the fact, I'm wondering if a button somewhere in the block UI (i.e. similar to how folks can convert to a Cover block, or in the block settings dropdown) would work? Or is this too complex?
  • We also (somehow) allow the Video block to accept gifs as well as video source (when client-side media processing of GIF -> MP4) is allowed

What do you think? Am I overthinking this, or could we use some design or UX input?

Design input would be good especially if want to add some sort of UI to convert a GIF to a video, or to switch back to the GIF (which we should preserve).

I have a new idea I'm going to try - what about if we leave the GIF as an image block in the editor, and swap it our for a video at run-time. That is, the user uploads a GIF, which stays a GIF and is also converted to a video. Then, while generating the HTML for the front end, if we find we have GIF images with matching videos, we swap in the video instead of the GIF. This results in the user getting the exact behavior they expect, without any unexpected block conversions.

I still think your idea of a UI for converting GIF to video is useful for existing GIF uploads, something to explore in a separate issue.

The editor-side block transform replaced a just-inserted core/image
with a core/video, which is surprising to users and loses the
upload's clientId reference needed to attach a poster.

Instead, keep the uploaded GIF as a normal image attachment (the
block stays a valid core/image) and upload a companion video
attachment generated from the same GIF. Both uploads carry a shared
animated_gif_pair_token so the two are linked server-side via
_animated_video_id post meta. On the front end, wp_content_img_tag
(inside wp_filter_content_tags()) swaps any GIF <img> that has a
linked video for a GIF-behaving <video>, covering every block that
emits a wp-image-{id} image (Image, Gallery, Media & Text, Cover).

Remove the editor BlockEdit transform hook in favor of this
render-time approach.
@github-actions github-actions Bot removed the [Package] Editor /packages/editor label May 18, 2026
@adamsilverstein
Copy link
Copy Markdown
Member Author

I've reworked this to not change the block. Pushed in 47044fc.

Instead of converting core/imagecore/video in the editor, the uploaded GIF now stays a normal image attachment (the block is unchanged), a companion video attachment is generated from it during upload, the two are linked via _animated_video_id post meta, and the swap happens at HTML generation time on the front end via wp_content_img_tag (inside wp_filter_content_tags(), using WP_HTML_Tag_Processor).

This directly addresses both pieces of feedback:

  • @andrewserong — no surprising block conversion. If you insert an Image block and upload a GIF, it stays an Image block in the editor; the visitor still gets the looping/autoplaying behavior because it's swapped to a <video> only in the rendered output. Because it's a content-tag filter, it also covers Gallery / Media & Text / Cover / etc., not just the Image block. I agree a block-level "convert to/from video" affordance for existing uploads is useful — proposing that as a separate issue rather than blocking this.
  • @swissspidy — the poster problem goes away: the original block keeps its clientId and its image attachment, so there's no lost reference. The <video> uses the GIF still as its poster for now; attaching a generated poster image can hang off the same _animated_* meta link as a follow-up.

PR description and test plan updated to match. Feedback welcome on the linking mechanism (shared animated_gif_pair_token → server-side link in lib/media/animated-gif-to-video.php).

Lets developers keep specific GIFs as GIFs based on the attachment,
the linked video, or the rendering context.
@adamsilverstein adamsilverstein marked this pull request as draft May 18, 2026 16:11
@adamsilverstein
Copy link
Copy Markdown
Member Author

Reworking this a bit then will re-open for review.

Uploading a GIF created two media library items: the GIF and the
converted video as its own attachment. The video also drove a stray
top-level upload (the off-center spinner was that, not the image
block).

Treat the video like the HEIC original: transcode it in a child
sideload of the GIF item and record only its filename in the GIF
attachment metadata (animated_video). No second attachment, no
second top-level queue item. The render-time swap reads the
metadata; a delete_attachment hook removes the file, rebuilding the
path from the attachment's own directory + recorded basename and
confirming it resolves inside the uploads dir before deleting.

Removes the pair-token attachment-linking mechanism.
@adamsilverstein adamsilverstein marked this pull request as ready for review May 18, 2026 17:40
@andrewserong
Copy link
Copy Markdown
Contributor

andrewserong commented May 20, 2026

Thanks for the updates, this sure is a tricky one to settle on a good experience!

and the swap happens at HTML generation time on the front end via wp_content_img_tag (inside wp_filter_content_tags(), using WP_HTML_Tag_Processor).

While clever, I'm not sold on this approach for several reasons:

  • It's common for themes to target the image block with styling that uses .wp-block-image img rules
  • The image block's block.json does this internally to support global styles rules for things like borders
  • There is still a use case for folks uploading animated GIFs as images to the image block and expecting them to be preserved without being converted to MP4s (I'll expand on this one more below)
  • It adds to the complexity of the image block (i.e. when features are added or adjusted for the block, it'd be easy for folks to miss that the output of the block will sometimes be a video tag)
image

Here's a screenshot of the site frontend on a site where a user might have downloaded some small transparent animated GIFs e.g. from https://slackmojis.com/ and have placed them within block content (or even in a template) where background colors and global styles rules are present.

Note that in the top block (where the GIF was uploaded on trunk) the animated gif's transparency is preserved, and the global styles rules for border are applied. Whereas in the converted MP4 there is no transparency and the video element means that global styles rules aren't being applied as expected.

In my mind this means that implicitly converting and swapping out images is unfortunately going to be a risky flow as it's making too many assumptions about user intent. My preference would be:

  • If a user uploads an image via the image block, it stays as it does on trunk and no conversion occurs. If we want to allow the flow of converting to MP4 I think this needs to be by an explicit user action (e.g. a button somewhere in the UI) because we cannot know if the user intended to upload a GIF as a GIF (either something they've carefully designed, or a transparent emoji-like GIF)
  • However, I think there's still merit in the idea of (somehow) adding GIF support to the Video block so that folks can select GIFs when intentionally adding a video there

Overall, I still think the conversion from GIF -> MP4 is a really cool feature, I'm just not sure it's a feature that the majority of users will want as a default, and I think it's easy for us to accidentally break things if we try to convert or swap things out implicitly.

But, again, this is just my take! It could be worth getting some more opinions, too 🙂

@swissspidy
Copy link
Copy Markdown
Member

Note that in the top block (where the GIF was uploaded on trunk) the animated gif's transparency is preserved,

We could add some transparency detection and not convert the GIF in that case.

Transparent videos are kinda possible on the web, but hacky, see https://jakearchibald.com/2024/video-with-transparency/.

I think this needs to be by an explicit user action (e.g. a button somewhere in the UI)
Overall, I still think the conversion from GIF -> MP4 is a really cool feature, I'm just not sure it's a feature that the majority of users will want as a default, and I think it's easy for us to accidentally break things if we try to convert or swap things out implicitly.

I would want to avoid adding any sort of UI for this wherever possible. I don't see GIF -> MP4 as a user-facing feature, but as an implementation detail. Adam has already nicely put it: "WordPress should endeavor to deliver that experience the user wants, without making them worry about the technical implementation details."

The frontend-only swapping sounds intriguing, but I agree that this might be worse for theme compatibility.

By the way, in the media-experiments plugin I originally added "GIF" as a video block variant, so that when you upload a GIF, it creates a video block but it says "GIF" in the sidebar:

Screen.Recording.2023-10-11.at.20.31.20.mov

I think from a UX that's quite neat :) Especially since you could then choose GIF from the inserter, drop your GIF file, and under the hood it will be a video.

because we cannot know if the user intended to upload a GIF as a GIF (either something they've carefully designed, or a transparent emoji-like GIF)

Transparency aside, what would be a reason for a user to really want the GIF image format? 🤔 Again, if we do it right, the user shouldn't see a difference, except that the video will load much faster.

@andrewserong
Copy link
Copy Markdown
Contributor

We could add some transparency detection and not convert the GIF in that case.

While the presence of transparency is a useful heuristic, I'm not sure the complexity of doing that would be worth it. It's tricky, but I'm generally cautious of us adding too many conditions that could be hard to reason about or untangle further down the track.

Transparency aside, what would be a reason for a user to really want the GIF image format? 🤔 Again, if we do it right, the user shouldn't see a difference, except that the video will load much faster.

I think for me it's that WordPress is so widely used, I don't feel confident making an assumption on why a user might want to use a GIF. It's that up until now folks can upload and use a GIF that they've designed, and we shouldn't prevent them from being able to do that if that's what they want to do. For me it comes down to the experience that whenever we go to change things about how the Image block works, inevitably we'll discover a use case after the fact that we haven't thought of.

The use case I'm thinking of is: a designer has carefully crafted a GIF that they want to use just as they've created it. WordPress should allow them to do that, as it does currently.

"WordPress should endeavor to deliver that experience the user wants, without making them worry about the technical implementation details."

A counterpoint to this is that if WordPress unexpectedly converts a file into an unexpected format or changes the output on the site frontend in a way they didn't intend, then we expose the technical implementation details to them.

All that said, I also really like this feature! And I appreciate what you say about making things transparent to the user so we don't end up with complexity in the UI. It's a tough balance for sure.

My main concern is that this feature is quite clever but it's also opinionated in a way that I'm used to seeing more in plugins than in core.

For me, I'm wondering if there's a sweet spot somewhere where if a user drags to the desktop (like in your video) but hasn't explicitly added an Image block, then we do the convert to video and add a video block thing. But as for making the Image block automatically convert to a video, I think it's overall risky.

As a user, if WordPress is doing conversions, I'd expect to be able to control the output, like how we allow users to select the image size. Whether that's converting or switching between Video and Image blocks (or a gif video block variation like in your cool example), I think a blocker overall to me is that a user must be able to output a raw GIF if they really want to, or we'll create a regression for someone in a flow they're used to.

@ramonjd
Copy link
Copy Markdown
Member

ramonjd commented May 21, 2026

Coming in late. This is a very cool feature. I know a lot of platforms perform the conversion for performance reasons. I think that's a big win, especially for the single Image block with opaque GIF case.

create a regression for someone in a flow they're used to

On this note, how will we handle galleries for example?

I found the conversion to MP4 breaks a few things here:

  • gallery layouts, inc crop to fit
  • lightbox viewing
  • caption alignment
  • transparency (already spoken about above)
Editor Frontend
Screenshot 2026-05-21 at 12 58 42 pm Screenshot 2026-05-21 at 12 58 47 pm

Similar issues with the Media and Text block. Cover block looks okay so far but I didn't do much testing. Maybe layout could be improved with more specific selectors (e.g., figure.wp-block-image > img doesn't match anymore)

All this makes me guess that any 3rd party blocks with Image as an InnerBlock could be affected. Would some themes have style rules that we'd break too? It looks like we're raising not one, but entire classes of regressions.

On the broader "users don't care about the format, just the experience", I'd agree with this, but if the consequences of the swap are user-facing, even when the format isn't, then that falls over.

From what I've read, could there be a stack of mitigations?

  1. transparency-detect skip... knocks out the worst case1
  2. context-aware swap that bails out if an image is an InnerBlock 🤷🏻
  3. an explicit "convert this GIF to video" affordance for users who want the bandwidth win on an opaque decorative GIF.

Apologies if they sound naive, I'm just catching up on the comments.

Footnotes

  1. TIL that GIF format carries a transparent-color flag in the Graphics Control Extension

@swissspidy
Copy link
Copy Markdown
Member

As a user, if WordPress is doing conversions, I'd expect to be able to control the output, like how we allow users to select the image size. Whether that's converting or switching between Video and Image blocks (or a gif video block variation like in your cool example), I think a blocker overall to me is that a user must be able to output a raw GIF if they really want to, or we'll create a regression for someone in a flow they're used to.

How about offering an opt-out?

Instead of just simply converting the images or asking the user "do you want to use the

"We have automatically optimized this GIF for optimal user experience. If you're seeing issues, you can restore the original. [Restore]"

Where "Restore" would mean turning the GIF video block back into an image.

While the presence of transparency is a useful heuristic, I'm not sure the complexity of doing that would be worth it. It's tricky, but I'm generally cautious of us adding too many conditions that could be hard to reason about or untangle further down the track.

FWIW it's not complex at all. We already do this to prevent transparent PNG -> JPEG conversion:

/**
* Determines whether an image has an alpha channel.
*
* @param buffer Original file object.
* @return Whether the image has an alpha channel.
*/
export async function hasTransparency(
buffer: ArrayBuffer
): Promise< boolean > {
const vips = await getVips();
const image = vips.Image.newFromBuffer( buffer );
const hasAlpha = image.hasAlpha();
cleanup?.();
return hasAlpha;
}

// For PNG -> JPEG conversion, check if the image has transparency.
// If it does, skip transcoding to preserve the alpha channel.
if ( file.type === 'image/png' && outputMimeType === 'image/jpeg' ) {
const blobUrl = createBlobURL( file );
try {
const hasAlpha = await vipsHasTransparency( blobUrl );
if ( hasAlpha ) {
// Image has transparency, skip conversion to JPEG.
return null;
}
} catch {
// If transparency check fails, err on the side of caution.
return null;
} finally {
revokeBlobURL( blobUrl );
}
}

@adamsilverstein
Copy link
Copy Markdown
Member Author

adamsilverstein commented May 21, 2026

Thanks for the feedback @ramonjd, @andrewserong and @swissspidy!

By the way, in the media-experiments plugin I originally added "GIF" as a video block variant, so that when you upload a GIF, it creates a video block but it says "GIF" in the sidebar:

Oh neat, I like the way they changes to video when you turned on the controls in your screencast.

A counterpoint to this is that if WordPress unexpectedly converts a file into an unexpected format or changes the output on the site frontend in a way they didn't intend, then we expose the technical implementation details to them.

FWIW we do a similar thing when you upload a HEIC. We convert it to a JPEG so it will work for most site visitors (unlike an heic). Our assumption is "the user wants an image on their website" not "the user wants an HEIC on their website". GIFs are similar, most users don't know they want a GIF, they know they want an animated image.

The use case I'm thinking of is: a designer has carefully crafted a GIF that they want to use just as they've created it. WordPress should allow them to do that, as it does currently.

For the rare GIF aficionado, I'm sure the community will provide a "no gif to video" plugin.

As a user, if WordPress is doing conversions, I'd expect to be able to control the output, like how we allow users to select the image size.

The interface for adjusting image sizes is terrible, users shouldn't be able to control that at all. My opinion anyway :)

As a user, if WordPress is doing conversions, I'd expect to be able to control the output, like how we allow users to select the image size. Whether that's converting or switching between Video and Image blocks (or a gif video block variation like in your cool example), I think a blocker overall to me is that a user must be able to output a raw GIF if they really want to, or we'll create a regression for someone in a flow they're used to.

I'm open to the idea of adding UI for the conversion, curious to hear some design feedback (ping @jasmussen @karmatosed). I prefer auto-conversion, but we might still need UI and I'm really not sure how that should work.

I think a blocker overall to me is that a user must be able to output a raw GIF if they really want to, or we'll create a regression for someone in a flow they're used to.

This feels like an edge case we could account for with a filter and 'co-video-to-gif' plugin.

On the broader "users don't care about the format, just the experience", I'd agree with this, but if the consequences of the swap are user-facing, even when the format isn't, then that falls over.

Fair point. As we see in the examples, changing from an image tag to a video tag has surprising cascading effects. Dang CSS!

From what I've read, could there be a stack of mitigations?

transparency-detect skip... knocks out the worst case1
right, should be detectable.

context-aware swap that bails out if an image is an InnerBlock 🤷🏻
should be doable, we are using the HTML API after all :) 🎉

an explicit "convert this GIF to video" affordance for users who want the bandwidth win on an opaque decorative GIF.

Need more feedback on how the UI for this would work. I'm guessing we would need the ability to toggle display between video and gif.

"We have automatically optimized this GIF for optimal user experience. If you're seeing issues, you can restore the original. [Restore]"

I like this suggestion, especially coupled with skipping auto conversion for transparent gifs and gifs in inner blocks.

@swissspidy do you still favor transforming the block to a video block immediately on upload? I overall prefer the approach of runtime conversion of the tag, but am open to persuasion. The video block likely provides a better editor wysiwyg preview and by changing its name to "GIF" as in your screencast the transformation become less unexpected.

@adamsilverstein adamsilverstein requested review from ramonjd and removed request for spacedmonkey May 21, 2026 15:57
A <video> cannot reproduce GIF transparency, so converting a transparent
animated GIF would visibly change the image (e.g. small decorative or
emoji-like GIFs over a colored background). Detect transparency at upload
time with vipsHasTransparency() - reusing the PNG to JPEG check pattern -
and keep transparent GIFs as a normal image instead of generating a
companion video. Errs toward keeping the GIF if the check fails.
Swapping every <img> with a companion video at render time broke layouts
when the image was nested: galleries (crop-to-fit, lightbox, captions),
Media & Text and Cover. Gate the swap by block context. A new
render_block_core/image filter marks only eligible images - standalone
Image blocks whose author has not opted out (preserveAnimatedGif) and that
are not inside a Gallery (galleryId context). Media & Text and Cover render
their media as the block's own <img>, not a core/image block, so they never
reach the filter. wp_content_img_tag then swaps only marked images.
Using the GIF itself as the <video> poster makes the browser download the
full animated GIF just to paint the poster, undercutting the conversion's
performance win. Sideload a lightweight static first-frame poster as a
second companion of the GIF attachment: a vips image transcode (vips decodes
only the first GIF frame) under image_size 'animated-video-poster', recorded
in metadata as 'animated_video_poster'. The render swap prefers it for the
<video poster> and the delete_attachment hook removes it with the video.
Some authors deliberately want the original GIF (a carefully crafted
animation, or one a theme styles as an image). Add a 'Display as original
GIF' toggle to the Image block's Media settings, shown only when the
attachment has a converted video companion (media_details.animated_video).
It sets a new preserveAnimatedGif attribute that the render-time swap
honors, leaving that image as a GIF on the front end.
Covers the render-time gating and swap: top-level Image blocks with a
companion video are marked and swapped to <video> (carrying the accessible
name and using the static poster); gallery inner images (galleryId context),
author opt-outs (preserveAnimatedGif) and images without a companion are
left as <img>; and the delete_attachment hook removes both companion files.

Note: pending a wp-env run.
@adamsilverstein
Copy link
Copy Markdown
Member Author

Closing as superseded by #78410.

#78410 switches the conversion engine from FFmpeg WASM to mediabunny + WebCodecs and already includes this PR's render-time swap / companion-file architecture. It also folds in the review feedback from this thread:

  • Transparent GIFs are left as GIFs (a <video> can't reproduce GIF transparency).
  • Only top-level Image blocks are swapped — images nested in a Gallery (via galleryId context) stay GIFs, and Media & Text / Cover are unaffected (their media isn't a core/image block). This resolves the gallery/Media&Text layout, lightbox and caption regressions raised here.
  • A lightweight static poster is generated instead of using the full GIF as the <video> poster.
  • Per-image opt-out via a "Display as original GIF" toggle in the Image block.

Thanks @swissspidy, @andrewserong and @ramonjd for the feedback — it's carried over to #78410.

@andrewserong
Copy link
Copy Markdown
Contributor

andrewserong commented May 21, 2026

Thanks for engaging will all these ideas, folks! IMO so long as there's an opt-out and we don't introduce any bugs (i.e. the top-level Image block idea you mention rather than applying to nested Image blocks), that services the "why did you break this?" customer feedback I'm concerned about. For context, I worked for a few years on WordPress.com where a lot of users don't have access to install plugins, and customer feedback often goes wildly against how we think things should work technically.

Also, glad to hear that the transparency check is easy to do! With the above mitigations I reckon we'll have covered the vast majority of cases/concerns 👍

@jasmussen
Copy link
Copy Markdown
Contributor

I'm open to the idea of adding UI for the conversion, curious to hear some design feedback

Thanks for the ping. I'll extend it a bit to @WordPress/gutenberg-design though also specifically to @fcoveram. He has worked on Openverse, and media in general, and has had a lot of thoughts around the media library and those bits.

In general that's here my instinct goes, that instead of thinking in atomic flows attached to blocks or editors, we think in terms of tooling and how to access it. I.e. if there's an "edit" button on an image that we build for the media library, an edit button from inside the editor could invoke the same interface. Reasonably there could be a similar parallel if we engage with video compression/converesion tooling.

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

Labels

[Feature] Client Side Media Media processing in the browser with WASM [Package] Block library /packages/block-library [Type] Feature New feature to highlight in changelogs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants