{"id":124446,"date":"2026-07-22T17:24:03","date_gmt":"2026-07-22T17:24:03","guid":{"rendered":"https:\/\/make.wordpress.org\/core\/?p=124446"},"modified":"2026-08-20T00:12:44","modified_gmt":"2026-08-20T00:12:44","slug":"client-side-media-processing-in-wordpress-7-1","status":"publish","type":"post","link":"https:\/\/make.wordpress.org\/core\/2026\/07\/22\/client-side-media-processing-in-wordpress-7-1\/","title":{"rendered":"Client-Side Media Processing in WordPress 7.1"},"content":{"rendered":"<p class=\"wp-block-paragraph\">WordPress 7.1 ships client-side media processing \u2013 a <span tabindex='0' class='glossary-item-container'>capability<span class='glossary-item-hidden-content'><span class='glossary-item-header'>capability<\/span> <span class='glossary-item-description'>A\u00a0<strong>capability<\/strong>\u00a0is permission to perform one or more types of task. Checking if a user has a capability is performed by the <code>current_user_can<\/code> function. Each user of a WordPress site might have some permissions but not others, depending on their\u00a0role. For example, users who have the Author role usually have permission to edit their own posts (the \u201cedit_posts\u201d capability), but not permission to edit other users\u2019 posts (the \u201cedit_others_posts\u201d capability).<\/span><\/span><\/span> that handles image compression, resizing, format conversion, rotation, and thumbnail generation directly in the user\u2019s browser using WebAssembly, rather than on the server. The feature is enabled by default in supporting browsers.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This post outlines what\u2019s changing, how it works, and what <span tabindex='0' class='glossary-item-container'>plugin<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Plugin<\/span> <span class='glossary-item-description'>A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory <a href=\"https:\/\/wordpress.org\/plugins\/\">https:\/\/wordpress.org\/plugins\/<\/a> or can be cost-based plugin from a third-party.<\/span><\/span><\/span> and theme developers need to know.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is client-side media processing?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Traditionally, when a user uploads an image in the <span tabindex='0' class='glossary-item-container'>block<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Block<\/span> <span class='glossary-item-description'>Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience.<\/span><\/span><\/span> editor, the file is sent to the server where <span tabindex='0' class='glossary-item-container'>PHP<span class='glossary-item-hidden-content'><span class='glossary-item-header'>PHP<\/span> <span class='glossary-item-description'>The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher<\/span><\/span><\/span> (using GD or Imagick) generates thumbnails (various image sizes for the front end), applies format conversions, handles EXIF rotation, and scales large images. This approach is limited by PHP memory constraints, server CPU availability, and the <span tabindex='0' class='glossary-item-container'>capabilities<span class='glossary-item-hidden-content'><span class='glossary-item-header'>capability<\/span> <span class='glossary-item-description'>A\u00a0<strong>capability<\/strong>\u00a0is permission to perform one or more types of task. Checking if a user has a capability is performed by the <code>current_user_can<\/code> function. Each user of a WordPress site might have some permissions but not others, depending on their\u00a0role. For example, users who have the Author role usually have permission to edit their own posts (the \u201cedit_posts\u201d capability), but not permission to edit other users\u2019 posts (the \u201cedit_others_posts\u201d capability).<\/span><\/span><\/span> of the server\u2019s installed image library.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Client-side media processing moves this work to the browser. Images are processed using\u00a0<a href=\"https:\/\/github.com\/kleisauke\/wasm-vips\">wasm-vips<\/a>, a WebAssembly compilation of the high-performance <a href=\"https:\/\/github.com\/libvips\/libvips\">libvips image processing library<\/a>. The processed images \u2013 including all thumbnails \u2013 are then uploaded to the server, which stores them. After all client-side operations complete, a finalize step applies the\u00a0<code>wp_generate_attachment_metadata<\/code>\u00a0<span tabindex='0' class='glossary-item-container'>filter<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Filter<\/span> <span class='glossary-item-description'>Filters are one of the two types of Hooks <a href=\"https:\/\/codex.wordpress.org\/Plugin_API\/Hooks\">https:\/\/codex.wordpress.org\/Plugin_API\/Hooks<\/a>. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output.<\/span><\/span><\/span> with context\u00a0<code>'update'<\/code>\u00a0so plugins see the full sub-sizes metadata. This mirrors how the server already handlesimage uploads, where sub-sizes trigger the same\u00a0<code>'update'<\/code>\u00a0pass.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/upload-flow.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"730\" data-attachment-id=\"124451\" data-permalink=\"https:\/\/make.wordpress.org\/core\/2026\/07\/22\/client-side-media-processing-in-wordpress-7-1\/upload-flow\/#main\" data-orig-file=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/upload-flow.png\" data-orig-size=\"2480,1768\" data-comments-opened=\"1\" data-image-meta='{\"aperture\":\"0\",\"credit\":\"\",\"camera\":\"\",\"caption\":\"\",\"created_timestamp\":\"0\",\"copyright\":\"\",\"focal_length\":\"0\",\"iso\":\"0\",\"shutter_speed\":\"0\",\"title\":\"\",\"orientation\":\"0\",\"alt\":\"\"}' data-image-title=\"upload-flow\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/upload-flow-1024x730.png\" src=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/upload-flow-1024x730.png\" alt=\"\" class=\"wp-image-124451\" srcset=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/upload-flow-1024x730.png 1024w, https:\/\/make.wordpress.org\/core\/files\/2026\/07\/upload-flow-300x214.png 300w, https:\/\/make.wordpress.org\/core\/files\/2026\/07\/upload-flow-767x547.png 767w, https:\/\/make.wordpress.org\/core\/files\/2026\/07\/upload-flow-1536x1095.png 1536w, https:\/\/make.wordpress.org\/core\/files\/2026\/07\/upload-flow-2048x1460.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\"><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Key benefits<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Consistent, high-quality output with modern image support.<\/strong>\u00a0All users get the same libvips powered processing regardless of whether the server has GD or Imagick, and regardless of which version is installed.<\/li>\n\n\n\n<li><strong>Faster downloads for visitors.<\/strong>\u00a0libvips produces better-compressed output  than GD or Imagick (JPEGs are reduced ~15% with MozJPEG like encoding), so the generated images served to site visitors are smaller and load faster.<\/li>\n\n\n\n<li><strong>No more PHP memory limit failures.<\/strong>\u00a0Large image processing that would exceed PHP\u2019s memory limit now succeeds because it runs in the browser\u2019s memory space.<\/li>\n\n\n\n<li><strong>Reduced server load.<\/strong>\u00a0Image processing is offloaded to the user\u2019s device, freeing server CPU and memory for other tasks.<\/li>\n\n\n\n<li><strong>iPhone photos just work.<\/strong>\u00a0HEIC images can be decoded in the browser and converted to JPEG before upload, even on hosts without server-side HEIC support.\u00a0<strong>Note<\/strong>: HEIC decode relies on platform codecs and is supported in Chromium browsers (Chrome, Edge, Brave) on macOS and on Windows with HEVC support, and in Safari on macOS. The full WASM pipeline (everything beyond HEIC) is Chromium-only \u2013 see\u00a0Browser compatibility and fallback\u00a0below.<\/li>\n\n\n\n<li><strong>AVIF without server-side AVIF support.<\/strong>\u00a0Hosts whose PHP image editor doesn\u2019t support AVIF can still accept AVIF uploads when client-side processing is active. The MIME-type check is bypassed for client-decoded uploads \u2013 see the security FAQ below for details.<\/li>\n\n\n\n<li><strong>Animated GIFs become efficient video.<\/strong>\u00a0Opaque animated GIFs can be converted in the browser to a companion MP4\/WebM video that plays exactly like the original GIF, dramatically cutting the bytes visitors download, with no loss of the autoplay-<span tabindex='0' class='glossary-item-container'>loop<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Loop<\/span> <span class='glossary-item-description'>The Loop is PHP code used by WordPress to display posts. Using The Loop, WordPress processes each post to be displayed on the current page, and formats it according to how it matches specified criteria within The Loop tags. Any HTML or PHP code in the Loop will be processed on each post. <a href=\"https:\/\/codex.wordpress.org\/The_Loop\">https:\/\/codex.wordpress.org\/The_Loop<\/a><\/span><\/span><\/span> GIF feel.<\/li>\n\n\n\n<li><strong>More resilient uploads.<\/strong>\u00a0Sub-size uploads are independent requests, so a <span tabindex='0' class='glossary-item-container'>network<span class='glossary-item-hidden-content'><span class='glossary-item-header'>network<\/span> <span class='glossary-item-description'>(versus site, blog)<\/span><\/span><\/span> hiccup mid-upload doesn\u2019t lose the entire batch. Failed requests are retried automatically with exponential backoff, so transient network errors recover without user intervention. Uploads are paused if you go offline and resume when you come back online.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">What\u2019s included<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Browser-based image processing<\/strong>\u00a0\u2013 Compression, resizing, cropping, format conversion (JPEG, PNG, WebP, AVIF, GIF), EXIF rotation, and progressive\/interlaced encoding via WebAssembly in a Web Worker.<\/li>\n\n\n\n<li><strong>Thumbnail generation in the browser<\/strong>\u00a0\u2013 All registered image sub-sizes are generated client-side and uploaded individually via a new sideload <span tabindex='0' class='glossary-item-container'>REST API<span class='glossary-item-hidden-content'><span class='glossary-item-header'>REST API<\/span> <span class='glossary-item-description'>The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think \u201cphone app\u201d or \u201cwebsite\u201d) can communicate with the data store (think \u201cdatabase\u201d or \u201cfile system\u201d)\r<a href=\"https:\/\/developer.wordpress.org\/rest-api\/\">https:\/\/developer.wordpress.org\/rest-api\/<\/a><\/span><\/span><\/span> endpoint. Sizes that share dimensions with built-in sizes (e.g. Twenty Eleven\u2019s\u00a0<code>large<\/code>\u00a0matches\u00a0<code>medium_large<\/code>) are deduplicated to a single physical file registered under all matching size names.<\/li>\n\n\n\n<li><strong>HEIC\/HEIF support<\/strong>\u00a0\u2013 iPhone photos (<code>image\/heic<\/code>,\u00a0<code>image\/heif<\/code>) are decoded in the browser and uploaded as web-ready JPEG. The original HEIC is kept as a companion file (<code>source_image<\/code>) and removed when the attachment is deleted.<\/li>\n\n\n\n<li><strong>AVIF end-to-end uploads<\/strong>\u00a0\u2013\u00a0AVIF can be decoded client-side, no longer requiring server-side AVIF support. High-bit-depth AVIF sources (10- or 12-bit, common for HDR photos) keep their bit depth in generated sub-sizes.<\/li>\n\n\n\n<li><strong>Gain Map HDR support<\/strong>\u00a0\u2013 UltraHDR JPEGs embed a gain map alongside a standard SDR base image: a new, backwards-compatible way of adding HDR data to SDR images that is supported by Google (UltraHDR), Apple (Adaptive HDR), and Adobe (Camera Raw, Lightroom, and Photoshop). These files are detected on upload and preserved end-to-end: the original uploads unmodified, and every generated sub-size keeps its gain map, so thumbnails stay HDR. Format conversion via\u00a0<code>image_editor_output_format<\/code>\u00a0is intentionally skipped for these files, since converting to a different codec would strip the gain map.<\/li>\n\n\n\n<li><strong>Automatic format conversion<\/strong>\u00a0\u2013 The existing\u00a0<code>image_editor_output_format<\/code>\u00a0filter is respected client-side, enabling automatic conversion (e.g., JPEG to WebP) during processing.<\/li>\n\n\n\n<li><strong>Animated GIF to video conversion<\/strong>\u00a0\u2013 Opaque animated GIFs are converted in the browser to an MP4 (or WebM) using the native WebCodecs APIs and the\u00a0<a href=\"https:\/\/www.npmjs.com\/package\/mediabunny\">mediabunny<\/a>\u00a0library. The GIF stays a single\u00a0<code>image\/gif<\/code>\u00a0attachment; the converted video and a first-frame poster are sideloaded as companion files (<code>media_details.animated_video<\/code>\u00a0\/\u00a0<code>animated_video_poster<\/code>). In the editor the block is optionally switched to a \u201cGIF\u201d variation of the Video block that autoplays, loops, and is muted \u2013 playing just like the original GIF \u2013 and the front end renders a native\u00a0<code>&lt;video&gt;<\/code>. The swap is fully reversible via the block transform menu, transparent GIFs are left as images, and browsers without WebCodecs video encoding (e.g. Firefox) upload the original GIF unchanged.<\/li>\n\n\n\n<li><strong>A cross-origin-isolated editor<\/strong>\u00a0\u2013 To run the WASM pipeline, the editor needs\u00a0<code>SharedArrayBuffer<\/code>, which browsers only expose to cross-origin-isolated documents. WordPress enables this with\u00a0<code>Document-Isolation-Policy: isolate-and-credentialless<\/code>\u00a0on block editor screens for Chromium 137+. Beyond media processing, this means\u00a0<code>SharedArrayBuffer<\/code>\u00a0and high-resolution timers are now available to any code running in the editor, so plugins can build their own multithreaded or WASM-backed features there. Because DIP is per-document, it provides this isolation without imposing the page-wide constraints of COOP\/COEP. See\u00a0Cross-origin isolation impact\u00a0below for what extenders should watch for.<\/li>\n\n\n\n<li><strong>Server-side hook compatibility<\/strong>\u00a0\u2013\u00a0<code>wp_generate_attachment_metadata<\/code>\u00a0fires the same way as for a server-side upload: once with context\u00a0<code>'create'<\/code>\u00a0during the initial upload and again with\u00a0<code>'update'<\/code>\u00a0after\u00a0<code>POST \/wp\/v2\/media\/{id}\/finalize<\/code>\u00a0runs. Plugins that hook into it (watermarking, CDN sync, etc.) continue to work, the same way they already handle the deferred-subsize pass on big-image uploads.<\/li>\n\n\n\n<li><strong>Upload progress feedback<\/strong>\u00a0\u2013 A snackbar in the editor tracks batch upload progress, with a spinner while uploads run and a brief checkmark on completion. It works on both the client-side and server-side upload paths, and announces start and completion via\u00a0<code>wp.a11y.speak()<\/code>\u00a0for screen reader users.<\/li>\n\n\n\n<li><strong>Smart fallback<\/strong>\u00a0\u2013 Browsers that don\u2019t support the required features automatically fall back to server-side processing with no user-facing change.<\/li>\n\n\n\n<li><strong>Image quality filters honored<\/strong>\u00a0\u2013 The standard\u00a0<code>wp_editor_set_quality<\/code>\u00a0and\u00a0<code>jpeg_quality<\/code>\u00a0filters flow through to client-side sub-size generation via a size-aware\u00a0<code>image_quality<\/code>\u00a0field in the upload response, so existing quality-tuning code works unchanged.<\/li>\n\n\n\n<li><strong>Server-side import of external images<\/strong>\u00a0\u2013 The Image block\u2019s \u201cUpload to Media Library\u201d action and the pre-publish \u201cExternal media\u201d panel now send the image <span tabindex='0' class='glossary-item-container'>URL<span class='glossary-item-hidden-content'><span class='glossary-item-header'>URL<\/span> <span class='glossary-item-description'>A specific web address of a website or web page on the Internet, such as a website\u2019s URL www.wordpress.org<\/span><\/span><\/span> to the server, which downloads and sideloads it \u2013 avoiding browser CORS failures entirely (the old client-side fetch also could not work in the cross-origin-isolated editor).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Technical overview<\/h2>\n\n\n\n<div class=\"wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-0e47273b wp-block-group-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/architecture-overview.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"572\" data-attachment-id=\"124453\" data-permalink=\"https:\/\/make.wordpress.org\/core\/2026\/07\/22\/client-side-media-processing-in-wordpress-7-1\/architecture-overview\/#main\" data-orig-file=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/architecture-overview.png\" data-orig-size=\"2480,1386\" data-comments-opened=\"1\" data-image-meta='{\"aperture\":\"0\",\"credit\":\"\",\"camera\":\"\",\"caption\":\"\",\"created_timestamp\":\"0\",\"copyright\":\"\",\"focal_length\":\"0\",\"iso\":\"0\",\"shutter_speed\":\"0\",\"title\":\"\",\"orientation\":\"0\",\"alt\":\"\"}' data-image-title=\"architecture-overview\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/architecture-overview-1024x572.png\" src=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/architecture-overview-1024x572.png\" alt=\"\" class=\"wp-image-124453\" srcset=\"https:\/\/make.wordpress.org\/core\/files\/2026\/07\/architecture-overview-1024x572.png 1024w, https:\/\/make.wordpress.org\/core\/files\/2026\/07\/architecture-overview-300x168.png 300w, https:\/\/make.wordpress.org\/core\/files\/2026\/07\/architecture-overview-768x429.png 768w, https:\/\/make.wordpress.org\/core\/files\/2026\/07\/architecture-overview-1536x858.png 1536w, https:\/\/make.wordpress.org\/core\/files\/2026\/07\/architecture-overview-2048x1145.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\"><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n<\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>@wordpress\/upload-media<\/code><\/strong>\u00a0\u2013 Manages the upload queue, concurrency (max 5 uploads, max 2 image processing operations), and orchestrates the pipeline.<\/li>\n\n\n\n<li><strong><code>@wordpress\/vips<\/code><\/strong>\u00a0\u2013 Wraps wasm-vips in a Web Worker for non-blocking image processing. The WASM bundle is loaded lazily on first use and bundles\u00a0<code>vips.wasm<\/code>\u00a0and\u00a0<code>vips-heif.wasm<\/code>\u00a0(the latter is needed for AVIF decoding).<\/li>\n\n\n\n<li><strong><code>@wordpress\/media-utils<\/code><\/strong>\u00a0\u2013 Handles <span tabindex='0' class='glossary-item-container'>HTTP<span class='glossary-item-hidden-content'><span class='glossary-item-header'>HTTP<\/span> <span class='glossary-item-description'>HTTP is an acronym for Hyper Text Transfer Protocol. HTTP  is the underlying protocol used by the World Wide Web and this protocol defines how messages are formatted and transmitted, and what actions Web servers and browsers should take in response to various commands.<\/span><\/span><\/span> transport to the WordPress REST API.<\/li>\n\n\n\n<li><strong><code>@wordpress\/video-conversion<\/code><\/strong>\u00a0\u2013 Wraps the\u00a0<a href=\"https:\/\/www.npmjs.com\/package\/mediabunny\">mediabunny<\/a>\u00a0library in a Web Worker (mirroring the\u00a0<code>@wordpress\/vips<\/code>\u00a0pattern) to convert animated GIFs to MP4\/WebM off the main thread, gated on WebCodecs\u00a0<code>ImageDecoder<\/code>\/<code>VideoEncoder<\/code>\u00a0availability and run with a concurrency limit of 1.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">On the PHP side:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>wp_is_client_side_media_processing_enabled()<\/code><\/strong>\u00a0\u2013 Feature gate, filterable via\u00a0<code>wp_client_side_media_processing_enabled<\/code>.<\/li>\n\n\n\n<li><strong>Cross-origin isolation<\/strong>\u00a0\u2013\u00a0<code>wp_start_cross_origin_isolation_output_buffer()<\/code>\u00a0sends\u00a0<code>Document-Isolation-Policy<\/code>\u00a0on\u00a0<code>load-post.php<\/code>,\u00a0<code>load-post-new.php<\/code>,\u00a0<code>load-site-editor.php<\/code>, and\u00a0<code>load-widgets.php<\/code>\u00a0for Chromium 137+. Only active when client side media is enabled.<\/li>\n\n\n\n<li><strong>REST API extensions<\/strong>\u00a0\u2013 New\u00a0<code>generate_sub_sizes<\/code>\u00a0and\u00a0<code>convert_format<\/code>\u00a0parameters, sideload endpoint (<code>POST \/wp\/v2\/media\/{id}\/sideload<\/code>), finalize endpoint (<code>POST \/wp\/v2\/media\/{id}\/finalize<\/code>),\u00a0<code>replace_file<\/code>\u00a0flag for HEIC companion uploads, and new response fields (<code>exif_orientation<\/code>,\u00a0<code>missing_image_sizes<\/code>,\u00a0<code>filename<\/code>,\u00a0<code>filesize<\/code>).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For the full architecture deep-dive, see the\u00a0<a href=\"https:\/\/developer.wordpress.org\/block-editor\/explanations\/architecture\/client-side-media-architecture\/\">client-side media processing architecture documentation<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What plugin developers need to know<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Disabling client-side processing<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If your plugin needs to disable client-side media processing, use the\u00a0<code>wp_client_side_media_processing_enabled<\/code>\u00a0filter:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">add_filter( 'wp_client_side_media_processing_enabled', '__return_false' );<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Server-side <span tabindex='0' class='glossary-item-container'>hooks<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Hooks<\/span> <span class='glossary-item-description'>In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same.<\/span><\/span><\/span> still fire<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A common concern: if client-side processing bypasses server-side image generation, do plugins that hook into\u00a0<code>wp_generate_attachment_metadata<\/code>\u00a0stop working? No \u2013 the filter fires the same way it does during a server-side upload, just with the work shifted around. WordPress fires it once with context\u00a0<code>'create'<\/code>\u00a0during the initial upload (before the sub-sizes are created), and again with\u00a0<code>'update'<\/code>\u00a0after the finalize endpoint runs (once all client-side sub-size sideloads are complete). Plugins for watermarking, CDN sync, custom metadata processing, and similar use cases continue to work without modification \u2013 write them idempotently so they handle both passes correctly. This double-fire pattern matches how WordPress already handles big-image uploads on the server, where sub-size generation is deferred and triggers a second\u00a0<code>'update'<\/code>\u00a0pass.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If finalize fails, the error is logged but the upload still succeeds \u2013 the call is best-effort so a plugin failure can\u2019t block the user\u2019s upload.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Existing filters still work<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Client-side processing reads settings from the server and respects:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>big_image_size_threshold<\/code>\u00a0\u2013 Maximum image dimension before scaling.<\/li>\n\n\n\n<li><code>image_editor_output_format<\/code>\u00a0\u2013 Automatic format conversion.<\/li>\n\n\n\n<li><code>image_save_progressive<\/code>\u00a0\u2013 Progressive\/interlaced encoding.<\/li>\n\n\n\n<li><code>wp_image_maybe_exif_rotate<\/code>\u00a0\u2013 EXIF rotation.<\/li>\n\n\n\n<li><code>wp_editor_set_quality<\/code>\u00a0(and\u00a0<code>jpeg_quality<\/code>\u00a0for JPEG output) \u2013 Encode quality, resolved per registered size.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">There is\u00a0<strong>no<\/strong>\u00a0<code>client_side_supported_mime_types<\/code>\u00a0filter; the supported set (<code>image\/jpeg<\/code>,\u00a0<code>image\/png<\/code>,\u00a0<code>image\/gif<\/code>,\u00a0<code>image\/webp<\/code>,\u00a0<code>image\/avif<\/code>) is fixed at\u00a0<code>CLIENT_SIDE_SUPPORTED_MIME_TYPES<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Controlling image quality<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Client-side encoding honors the same PHP filters that control server-side quality:\u00a0<code>wp_editor_set_quality<\/code>\u00a0and, for JPEG output,\u00a0<code>jpeg_quality<\/code>. The server resolves the filters per registered size and reports the result in the upload response\u2019s size-aware\u00a0<code>image_quality<\/code>\u00a0field, which the client applies during sub-size resize and transcode. The same code that tunes server-side quality works unchanged:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">\/*\n * Size-aware: drop JPEG thumbnails (300px wide or less) to quality 60,\n * leave larger sizes untouched.\n *\/\nadd_filter(\n\t'wp_editor_set_quality',\n\tfunction ( $quality, $mime_type, $size ) {\n\t\tif ( 'image\/jpeg' === $mime_type &amp;&amp; isset( $size['width'] ) &amp;&amp; $size['width'] &lt;= 300 ) {\n\t\t\treturn 60;\n\t\t}\n\t\treturn $quality;\n\t},\n\t10,\n\t3\n);\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When the server doesn\u2019t report the field, the client falls back to a default of\u00a0<code>0.82<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cross-origin isolation impact<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When client-side media is active, WordPress sends\u00a0<code>Document-Isolation-Policy: isolate-and-credentialless<\/code>\u00a0on block editor screens for Chromium 137+. Since DIP is per-document, it doesn\u2019t impose the page-wide constraints of COEP\/COOP. Notable behavior:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>External scripts loaded across origins<\/strong>\u00a0automatically get a\u00a0<code>crossorigin=\"anonymous\"<\/code>\u00a0attribute via the server-side\u00a0<code>wp_add_crossorigin_attributes()<\/code>\u00a0output buffer and a client-side MutationObserver.\u00a0<code>&lt;img&gt;<\/code>\u00a0is excluded so external image previews aren\u2019t affected.<\/li>\n\n\n\n<li><strong>DIP is skipped on <span tabindex='0' class='glossary-item-container'>admin<span class='glossary-item-hidden-content'><span class='glossary-item-header'>admin<\/span> <span class='glossary-item-description'>(and super admin)<\/span><\/span><\/span> pages with an\u00a0<code>action<\/code>\u00a0other than\u00a0<code>edit<\/code><\/strong>, which keeps third-party page builders that rely on same-origin <span tabindex='0' class='glossary-item-container'>iframe<span class='glossary-item-hidden-content'><span class='glossary-item-header'>iframe<\/span> <span class='glossary-item-description'>iFrame is an acronym for an inline frame. An iFrame is used inside a webpage to load another HTML document and render it. This HTML document may also contain JavaScript and\/or CSS which is loaded at the time when iframe tag is parsed by the user\u2019s browser.<\/span><\/span><\/span> access functional.<\/li>\n\n\n\n<li><strong>External images are imported server-side.<\/strong>\u00a0\u201cUpload to Media Library\u201d and the pre-publish \u201cExternal media\u201d panel POST the image URL to the media endpoint (a new\u00a0<code>url<\/code>\u00a0parameter) and the server downloads and sideloads it. Plugins importing remote media should do the same rather than\u00a0<code>fetch()<\/code>ing image bytes in the browser \u2013 a cross-origin fetch is subject to CORS and fails in a\u00a0<code>credentialless<\/code>\u00a0isolated document.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Content Security Policy (CSP)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If your plugin sets a Content Security Policy, ensure the\u00a0<code>worker-src<\/code>\u00a0directive includes\u00a0<code>blob:<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">Content-Security-Policy: worker-src 'self' blob:;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Without this, the WASM processing worker cannot be created and processing falls back to server-side.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Server specific hooks don\u2019t fire<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Because a server side editor is not used, <code>wp_image_editors<\/code>, <code>image_memory_limit<\/code> and <code>image_make_intermediate_size<\/code> never fire. A complete accounting of media hooks before and after this change is <a href=\"https:\/\/developer.wordpress.org\/block-editor\/explanations\/architecture\/client-side-media-architecture\/\">available in the handbook<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What theme developers need to know<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Client-side media processing is transparent to themes. Existing filters (<code>big_image_size_threshold<\/code>,\u00a0<code>image_editor_output_format<\/code>, etc.) continue to work without modification. Image sizes registered via\u00a0<code>add_image_size()<\/code>\u00a0are automatically generated client-side, and sizes that share dimensions with built-in sizes are deduplicated to a single physical file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Browser compatibility and fallback<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Client-side processing depends on\u00a0<code>Document-Isolation-Policy<\/code>\u00a0to enable\u00a0<code>SharedArrayBuffer<\/code>, which is currently only available in Chromium-based browsers.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Browser<\/th><th class=\"has-text-align-left\" data-align=\"left\">Minimum Version<\/th><th class=\"has-text-align-left\" data-align=\"left\">Status<\/th><\/tr><\/thead><tbody><tr><td>Chrome<\/td><td>137+<\/td><td>Full support via Document-Isolation-Policy<\/td><\/tr><tr><td>Edge<\/td><td>137+<\/td><td>Full support via Document-Isolation-Policy<\/td><\/tr><tr><td>Firefox<\/td><td>\u2013<\/td><td>*Not supported (no Document-Isolation-Policy) \u2013 falls back to server-side<\/td><\/tr><tr><td>Safari<\/td><td>\u2013<\/td><td>*Not supported (no Document-Isolation-Policy) \u2013 falls back to server-side. In-browser HEIC decode still works, since it does not require Document-Isolation-Policy.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Chrome and Edge have supported\u00a0<code>Document-Isolation-Policy<\/code>\u00a0since version 137 (released in mid-2025).  As of this post\u2019s publication, current stable Chrome and Edge are well past that, so the overwhelming majority of Chromium users already meet the requirement. Chrome on Android supports the feature from version 146.\u00a0<code>Document-Isolation-Policy<\/code>\u00a0is not yet tracked on caniuse; the most reliable place to check current and future browser support is the\u00a0<a href=\"https:\/\/chromestatus.com\/feature\/5141940204208128\">Chrome Platform Status entry<\/a>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>On unsupported browsers WordPress falls back to server-side processing automatically. Users see no difference in behavior. A <a href=\"https:\/\/wordpress.org\/plugins\/client-side-media-everywhere\/\">plugin is available<\/a> to enable the client-side media feature in Firefox\/Safari using COEP\/COOP headers. These are not used by default because they create compatibility issues with embeds and other third party resources.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Feature detection and limitations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Beyond browser support, the client checks several runtime conditions before activating the WASM pipeline. Failing any check causes a transparent fallback to server-side processing \u2013 there is no user-facing change.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Check<\/th><th class=\"has-text-align-left\" data-align=\"left\">Threshold<\/th><th class=\"has-text-align-left\" data-align=\"left\">Why<\/th><\/tr><\/thead><tbody><tr><td>Device memory<\/td><td>&gt; 2 GB<\/td><td>WASM image processing can OOM on very low-memory devices.<\/td><\/tr><tr><td>CPU cores<\/td><td>\u2265 2<\/td><td>WASM image processing benefits from at least one <span tabindex='0' class='glossary-item-container'>core<span class='glossary-item-hidden-content'><span class='glossary-item-header'>Core<\/span> <span class='glossary-item-description'>Core is the set of software required to run WordPress. The Core Development Team builds WordPress.<\/span><\/span><\/span> for the worker plus one for the <span tabindex='0' class='glossary-item-container'>UI<span class='glossary-item-hidden-content'><span class='glossary-item-header'>UI<\/span> <span class='glossary-item-description'>User interface<\/span><\/span><\/span> thread.<\/td><\/tr><tr><td>Network<\/td><td>not\u00a0<code>2g<\/code>\/<code>slow-2g<\/code>, no\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Reference\/Headers\/Save-Data\"><code>Save-Data<\/code>\u00a0header<\/a><\/td><td>The ~13 MB worker download is gated to faster connections;\u00a0<code>3g<\/code>\u00a0is allowed.<\/td><\/tr><tr><td>CSP\u00a0<code>blob:<\/code>\u00a0workers<\/td><td>must succeed<\/td><td>The worker is created from a blob URL; strict\u00a0<code>worker-src<\/code>\u00a0policies block it.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Frequently asked questions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Isn\u2019t this just a bandwidth optimization?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Not exactly. The client uploads the original plus every sub-size, so total bytes over the wire actually go\u00a0<em>up<\/em>\u00a0during uploads compared to the server-side path (which receives only the original). Bandwidth <em>is saved<\/em> when serving the images since encoding is better and modern images are always supported. For uploads the real win is\u00a0<strong>server CPU and memory relief<\/strong>: hosts no longer pay the GD\/Imagick cost of generating sub-sizes on upload, which is one of the most common causes of PHP timeouts and memory-limit failures on shared hosting. See \u201cKey benefits\u201d above.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Doesn\u2019t the \u201cnever trust the client\u201d rule apply here?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Client-side processing is a\u00a0<strong>performance optimization, not a trust boundary<\/strong>. The server still validates every uploaded file \u2013 MIME type, dimensions, capability checks, sanitization \u2013 and runs the same\u00a0<code>wp_generate_attachment_metadata<\/code>\u00a0filter chain. If the browser can\u2019t or won\u2019t process the file, WordPress falls back to server-side processing transparently.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What happens if the browser can\u2019t process the image?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Server-side processing runs as before. The fallback is automatic and transparent to the user \u2013 no UI change, no error. The exact gating (browser features, device memory, CPU cores, network class, CSP) is described in \u201cFeature detection and limitations\u201d above.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Will my plugin\u2019s\u00a0<code>wp_generate_attachment_metadata<\/code>\u00a0hooks still run?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes. The filter fires the same way as during a server-side upload: once with context\u00a0<code>'create'<\/code>\u00a0during the initial upload, and again with\u00a0<code>'update'<\/code>\u00a0after the finalize endpoint runs (once all client-side sub-size sideloads complete). Watermarking, CDN sync, custom metadata processing, and similar plugins should keep working without modification, but should be checked to make sure they handle both passes. See \u201cServer-side hooks still fire\u201d above.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Does this change the format my users upload?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Only if\u00a0<code>image_editor_output_format<\/code>\u00a0says so \u2013 the existing filter is honored client-side. There are two new behaviors. HEIC inputs are converted to JPEG before upload and the original is kept as a companion file. And opaque animated GIFs are converted to a companion video (see below). AVIF inputs upload as AVIF, even on hosts whose server-side image editor lacks AVIF support. HDR images using gain maps upload unmodified, so their HDR gain maps survive \u2013 including in every generated sub-size.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What happens to animated GIFs?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Opaque animated GIFs are converted in the browser to a companion MP4\/WebM video, and the editor offers a transform to convert the block to a \u201cGIF\u201d variation of the Video block that autoplays, loops, and is muted \u2013 so it behaves exactly like the original GIF while downloading far less data. Important details for extenders:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>The attachment is still a GIF.<\/strong>\u00a0It stays a single\u00a0<code>image\/gif<\/code>\u00a0attachment in the media library; the video and a first-frame poster are companion files recorded in\u00a0<code>media_details.animated_video<\/code>\u00a0\/\u00a0<code>animated_video_poster<\/code>, removed automatically when the GIF is deleted.<\/li>\n\n\n\n<li><strong>The front end is a real video block.<\/strong>\u00a0The swap is a block switch in the editor, not a render-time filter, so the published markup is a native\u00a0<code>&lt;video autoplay loop muted playsinline poster&gt;<\/code>\u00a0\u2013 nothing GIF-specific to filter.<\/li>\n\n\n\n<li><strong>It\u2019s reversible<\/strong>, transparent GIFs are left as images, and only standalone Image blocks are converted (GIFs inside a Gallery, Media &amp; Text, or Cover are untouched).<\/li>\n\n\n\n<li><strong>Browser support.<\/strong>\u00a0Conversion needs WebCodecs video encoding (<code>ImageDecoder<\/code>\u00a0+\u00a0<code>VideoEncoder<\/code>). Browsers without it \u2013 notably Firefox \u2013 upload the original GIF unchanged, with no error. There is no separate opt-out filter; disabling client-side media processing also disables GIF conversion.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Why aren\u2019t Firefox and Safari supported?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">They don\u2019t ship\u00a0<code>Document-Isolation-Policy<\/code>, which is what enables\u00a0<code>SharedArrayBuffer<\/code>\u00a0(required for the WASM pipeline). Users on those browsers get the existing server-side path \u2013 no <span tabindex='0' class='glossary-item-container'>regression<span class='glossary-item-hidden-content'><span class='glossary-item-header'>regression<\/span> <span class='glossary-item-description'>A software bug that breaks or degrades something that previously worked. Regressions are often treated as critical bugs or <a href=\"#blocker\">blockers<\/a>. Recent regressions may be given higher priorities. A \"3.6 regression\" would be a bug in 3.6 that worked as intended in 3.5.<\/span><\/span><\/span>. The HEIC canvas fallback still works in Safari for HEIC inputs.  A <a href=\"https:\/\/wordpress.org\/plugins\/client-side-media-everywhere\/\">plugin is available<\/a> (<span tabindex='0' class='glossary-item-container'>wordpress.org<span class='glossary-item-hidden-content'><span class='glossary-item-header'>WordPress.org<\/span> <span class='glossary-item-description'>The community site where WordPress code is created and shared by the users. This is where you can download the source code for WordPress core, plugins and themes as well as the central location for community conversations and organization.  <a href=\"https:\/\/wordpress.org\/\">https:\/\/wordpress.org\/<\/a><\/span><\/span><\/span> version coming soon, available now on <a href=\"https:\/\/github.com\/adamsilverstein\/client-side-media-everywhere\">GitHub<\/a>) to enable the client-side media feature in Firefox\/Safari using COEP\/COOP headers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Testing and feedback<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We encourage plugin and theme developers to test client-side media processing with their products. In particular:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verify that uploads work with your plugin\u2019s custom image sizes and format settings \u2013 including sizes that share dimensions with built-in sizes.<\/li>\n\n\n\n<li>Test HEIC uploads if you target sites with iPhone-using authors.<\/li>\n\n\n\n<li>Test AVIF uploads on hosts whose image editor lacks AVIF support.<\/li>\n\n\n\n<li>Test gain-mapped HDR photos (UltraHDR JPEGs) if your plugin transforms images \u2013 sub-sizes remain UltraHDR JPEGs with their gain maps, and format conversion is intentionally skipped for them.<\/li>\n\n\n\n<li>Test animated GIF uploads \u2013 confirm the block converts to a looping muted video, the round-trip back to a GIF works, and any plugin that post-processes attachments handles the companion video\/poster correctly.<\/li>\n\n\n\n<li>Check that cross-origin isolation doesn\u2019t break any external resources or embeds your plugin loads in the editor.<\/li>\n\n\n\n<li>Test with\u00a0<code>wp_client_side_media_processing_enabled<\/code>\u00a0returning\u00a0<code>false<\/code>\u00a0to ensure your fallback path works.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Please report any issues on the\u00a0<a href=\"https:\/\/github.com\/WordPress\/gutenberg\/issues\">Gutenberg GitHub repository<\/a>. Related tracking issues:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/WordPress\/gutenberg\/issues\/76756\">Client-side media processing iteration for WordPress 7.1 (#76756)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/WordPress\/gutenberg\/issues\/75111\">Documentation tracking issue (#75111)<\/a><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For detailed developer documentation, see:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.wordpress.org\/block-editor\/explanations\/architecture\/client-side-media-architecture\/\">Architecture explanation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.wordpress.org\/block-editor\/how-to-guides\/client-side-media\/\">Developer how-to guide<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.wordpress.org\/block-editor\/reference-guides\/filters\/editor-filters\/#client-side-media-processing\">Editor filters reference<\/a><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Props to <a href=\"https:\/\/profiles.wordpress.org\/swissspidy\/\" class=\"mention\"><span class=\"mentions-prefix\">@<\/span>swissspidy<\/a>, <a href=\"https:\/\/profiles.wordpress.org\/andrewserong\/\" class=\"mention\"><span class=\"mentions-prefix\">@<\/span>andrewserong<\/a>, and the many other contributors who worked on this feature.  Thanks to <a href=\"https:\/\/profiles.wordpress.org\/wildworks\/\" class=\"mention\"><span class=\"mentions-prefix\">@<\/span>wildworks<\/a> and <a href=\"https:\/\/profiles.wordpress.org\/andrewserong\/\" class=\"mention\"><span class=\"mentions-prefix\">@<\/span>andrewserong<\/a> for reviewing this post.<\/p>\n<p class=\"o2-appended-tags\"><a href=\"https:\/\/make.wordpress.org\/core\/tag\/7-1\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>7-1<\/a>, <a href=\"https:\/\/make.wordpress.org\/core\/tag\/dev-notes\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>dev-notes<\/a>, <a href=\"https:\/\/make.wordpress.org\/core\/tag\/dev-notes-7-1\/\" class=\"tag\"><span class=\"tag-prefix\">#<\/span>dev-notes-7-1<\/a><\/p><nav class='o2-post-footer-actions'><ul class='o2-post-footer-action-row'><li class='o2-post-footer-action'><a href=\"https:\/\/login.wordpress.org\/?redirect_to=https%3A%2F%2Fmake.wordpress.org%2Fcore%2F2026%2F07%2F22%2Fclient-side-media-processing-in-wordpress-7-1%2F%23respond&#038;locale=en_US\" title=\"Login to Reply\"  class=\"genericon  genericon-reply\"  data-action=\"login-to-reply\"  data-actionstate=\"default\" >Login to Reply<\/a><\/li><\/ul><div class='o2-post-footer-action-likes'><\/div><ul class='o2-post-footer-action-row'><\/ul><\/nav>","protected":false},"excerpt":{"rendered":"<p>WordPress 7.1 ships client-side media processing \u2013 a capabilitycapability A\u00a0capability\u00a0is permission to perform one or more types of task. Checking if a user has a capability is performed by the current_user_can function. Each user of a WordPress site might have some permissions but not others, depending on their\u00a0role. For example, users who have the Author [&hellip;]<\/p>\n","protected":false},"author":10464658,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_seo_schema_type":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1175],"tags":[5885,1443,5894],"class_list":["post-124446","post","type-post","status-publish","format-standard","hentry","category-general","tag-7-1","tag-dev-notes","tag-dev-notes-7-1","mentions-aldavigdis","mentions-andrewserong","mentions-clorith","mentions-masoudnkh","mentions-swissspidy","mentions-wildworks","author-adamsilverstein"],"revision_note":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2AvED-wnc","jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts\/124446","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/users\/10464658"}],"replies":[{"embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/comments?post=124446"}],"version-history":[{"count":27,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts\/124446\/revisions"}],"predecessor-version":[{"id":125674,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/posts\/124446\/revisions\/125674"}],"wp:attachment":[{"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/media?parent=124446"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/categories?post=124446"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/make.wordpress.org\/core\/wp-json\/wp\/v2\/tags?post=124446"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}