Changeset 57578 for trunk/src/wp-includes/blocks/image.php
- Timestamp:
- 02/09/2024 06:20:12 PM (9 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/blocks/image.php
r57377 r57578 21 21 } 22 22 23 $p rocessor= new WP_HTML_Tag_Processor( $content );24 25 if ( ! $p rocessor->next_tag( 'img' ) || null === $processor->get_attribute( 'src' ) ) {23 $p = new WP_HTML_Tag_Processor( $content ); 24 25 if ( ! $p->next_tag( 'img' ) || null === $p->get_attribute( 'src' ) ) { 26 26 return ''; 27 27 } 28 28 29 29 if ( isset( $attributes['data-id'] ) ) { 30 // Add the data-id="$id" attribute to the img element31 // to provide backwards compatibility for the Gallery Block,32 // which now wraps Image Blocks within innerBlocks.33 // The data-id attribute is added in a core/gallery`render_block_data` hook.34 $p rocessor->set_attribute( 'data-id', $attributes['data-id'] );30 // Adds the data-id="$id" attribute to the img element to provide backwards 31 // compatibility for the Gallery Block, which now wraps Image Blocks within 32 // innerBlocks. The data-id attribute is added in a core/gallery 33 // `render_block_data` hook. 34 $p->set_attribute( 'data-id', $attributes['data-id'] ); 35 35 } 36 36 … … 39 39 40 40 /* 41 * If the lightbox is enabled and the image is not linked, add the filter42 * andthe JavaScript view file.41 * If the lightbox is enabled and the image is not linked, adds the filter and 42 * the JavaScript view file. 43 43 */ 44 44 if ( … … 48 48 true === $lightbox_settings['enabled'] 49 49 ) { 50 $suffix = wp_scripts_get_suffix(); 51 if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { 52 $module_url = gutenberg_url( '/build/interactivity/image.min.js' ); 53 } 54 55 wp_register_script_module( 56 '@wordpress/block-library/image', 57 isset( $module_url ) ? $module_url : includes_url( "blocks/image/view{$suffix}.js" ), 58 array( '@wordpress/interactivity' ), 59 defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' ) 60 ); 61 50 62 wp_enqueue_script_module( '@wordpress/block-library/image' ); 51 63 … … 54 66 * it runs after the duotone filter and that duotone styles are applied to 55 67 * the image in the lightbox. Lightbox has to work with any plugins that 56 * might use filters as well. Removing this can be considered in the 57 * future if the way the blocks are rendered changes, or if a58 * new kind of filter isintroduced.68 * might use filters as well. Removing this can be considered in the future 69 * if the way the blocks are rendered changes, or if a new kind of filter is 70 * introduced. 59 71 */ 60 72 add_filter( 'render_block_core/image', 'block_core_image_render_lightbox', 15, 2 ); … … 66 78 } 67 79 68 return $p rocessor->get_updated_html();80 return $p->get_updated_html(); 69 81 } 70 82 … … 79 91 */ 80 92 function block_core_image_get_lightbox_settings( $block ) { 81 // Get the lightbox setting from the block attributes.93 // Gets the lightbox setting from the block attributes. 82 94 if ( isset( $block['attrs']['lightbox'] ) ) { 83 95 $lightbox_settings = $block['attrs']['lightbox']; … … 90 102 // 91 103 // NOTE: If no block-level settings are found, the previous call to 92 // `wp_get_global_settings` will return the whole `theme.json` 93 // structure in which case we can check if the "lightbox" key is present at94 // the top-levelof the global settings and use its value.104 // `wp_get_global_settings` will return the whole `theme.json` structure in 105 // which case we can check if the "lightbox" key is present at the top-level 106 // of the global settings and use its value. 95 107 if ( isset( $lightbox_settings['lightbox'] ) ) { 96 108 $lightbox_settings = wp_get_global_settings( array( 'lightbox' ) ); … … 111 123 function block_core_image_render_lightbox( $block_content, $block ) { 112 124 /* 113 * If it's not possible that an IMG element exists then return the given114 * block content as-is. It may be that there's no actual image in the block115 * or it could be that another plugin already modified this HTML.125 * If there's no IMG tag in the block then return the given block content 126 * as-is. There's nothing that this code can knowingly modify to add the 127 * lightbox behavior. 116 128 */ 117 if ( false === stripos( $block_content, '<img' ) ) { 129 $p = new WP_HTML_Tag_Processor( $block_content ); 130 if ( $p->next_tag( 'figure' ) ) { 131 $p->set_bookmark( 'figure' ); 132 } 133 if ( ! $p->next_tag( 'img' ) ) { 118 134 return $block_content; 119 135 } 120 136 121 $processor = new WP_HTML_Tag_Processor( $block_content ); 122 123 $aria_label = __( 'Enlarge image' ); 124 125 /* 126 * If there's definitely no IMG element in the block then return the given 127 * block content as-is. There's nothing that this code can knowingly modify 128 * to add the lightbox behavior. 129 */ 130 if ( ! $processor->next_tag( 'img' ) ) { 131 return $block_content; 132 } 133 134 $alt_attribute = $processor->get_attribute( 'alt' ); 135 136 // An empty alt attribute `alt=""` is valid for decorative images. 137 if ( is_string( $alt_attribute ) ) { 138 $alt_attribute = trim( $alt_attribute ); 139 } 140 141 // It only makes sense to append the alt text to the button aria-label when the alt text is non-empty. 142 if ( $alt_attribute ) { 137 $alt = $p->get_attribute( 'alt' ); 138 $img_uploaded_src = $p->get_attribute( 'src' ); 139 $img_class_names = $p->get_attribute( 'class' ); 140 $img_styles = $p->get_attribute( 'style' ); 141 $img_width = 'none'; 142 $img_height = 'none'; 143 $aria_label = __( 'Enlarge image' ); 144 145 if ( $alt ) { 143 146 /* translators: %s: Image alt text. */ 144 $aria_label = sprintf( __( 'Enlarge image: %s' ), $alt_attribute ); 145 } 146 147 // Currently, we are only enabling the zoom animation. 148 $lightbox_animation = 'zoom'; 149 150 // Note: We want to store the `src` in the context so we 151 // can set it dynamically when the lightbox is opened. 147 $aria_label = sprintf( __( 'Enlarge image: %s' ), $alt ); 148 } 149 152 150 if ( isset( $block['attrs']['id'] ) ) { 153 151 $img_uploaded_src = wp_get_attachment_url( $block['attrs']['id'] ); … … 155 153 $img_width = $img_metadata['width'] ?? 'none'; 156 154 $img_height = $img_metadata['height'] ?? 'none'; 157 } else { 158 $img_uploaded_src = $processor->get_attribute( 'src' ); 159 $img_width = 'none'; 160 $img_height = 'none'; 161 } 162 163 if ( isset( $block['attrs']['scale'] ) ) { 164 $scale_attr = $block['attrs']['scale']; 165 } else { 166 $scale_attr = false; 167 } 168 169 $w = new WP_HTML_Tag_Processor( $block_content ); 170 $w->next_tag( 'figure' ); 171 $w->add_class( 'wp-lightbox-container' ); 172 $w->set_attribute( 'data-wp-interactive', '{"namespace":"core/image"}' ); 173 174 $w->set_attribute( 155 } 156 157 // Figure. 158 $p->seek( 'figure' ); 159 $figure_class_names = $p->get_attribute( 'class' ); 160 $figure_styles = $p->get_attribute( 'style' ); 161 $p->add_class( 'wp-lightbox-container' ); 162 $p->set_attribute( 'data-wp-interactive', '{"namespace":"core/image"}' ); 163 $p->set_attribute( 175 164 'data-wp-context', 176 sprintf( 177 '{ "imageLoaded": false, 178 "initialized": false, 179 "lightboxEnabled": false, 180 "hideAnimationEnabled": false, 181 "preloadInitialized": false, 182 "lightboxAnimation": "%s", 183 "imageUploadedSrc": "%s", 184 "imageCurrentSrc": "", 185 "targetWidth": "%s", 186 "targetHeight": "%s", 187 "scaleAttr": "%s", 188 "dialogLabel": "%s" 189 }', 190 $lightbox_animation, 191 $img_uploaded_src, 192 $img_width, 193 $img_height, 194 $scale_attr, 195 __( 'Enlarged image' ) 165 wp_json_encode( 166 array( 167 'uploadedSrc' => $img_uploaded_src, 168 'figureClassNames' => $figure_class_names, 169 'figureStyles' => $figure_styles, 170 'imgClassNames' => $img_class_names, 171 'imgStyles' => $img_styles, 172 'targetWidth' => $img_width, 173 'targetHeight' => $img_height, 174 'scaleAttr' => $block['attrs']['scale'] ?? false, 175 'ariaLabel' => $aria_label, 176 'alt' => $alt, 177 ), 178 JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP 196 179 ) 197 180 ); 198 $w->next_tag( 'img' ); 199 $w->set_attribute( 'data-wp-init', 'callbacks.initOriginImage' ); 200 $w->set_attribute( 'data-wp-on--load', 'actions.handleLoad' ); 201 $w->set_attribute( 'data-wp-watch', 'callbacks.setButtonStyles' ); 202 // We need to set an event callback on the `img` specifically 203 // because the `figure` element can also contain a caption, and 204 // we don't want to trigger the lightbox when the caption is clicked. 205 $w->set_attribute( 'data-wp-on--click', 'actions.showLightbox' ); 206 $w->set_attribute( 'data-wp-watch--setStylesOnResize', 'callbacks.setStylesOnResize' ); 207 $body_content = $w->get_updated_html(); 208 209 // Add a button alongside image in the body content. 181 182 // Image. 183 $p->next_tag( 'img' ); 184 $p->set_attribute( 'data-wp-init', 'callbacks.setButtonStyles' ); 185 $p->set_attribute( 'data-wp-on--load', 'callbacks.setButtonStyles' ); 186 $p->set_attribute( 'data-wp-on-window--resize', 'callbacks.setButtonStyles' ); 187 // Sets an event callback on the `img` because the `figure` element can also 188 // contain a caption, and we don't want to trigger the lightbox when the 189 // caption is clicked. 190 $p->set_attribute( 'data-wp-on--click', 'actions.showLightbox' ); 191 192 $body_content = $p->get_updated_html(); 193 194 // Adds a button alongside image in the body content. 210 195 $img = null; 211 196 preg_match( '/<img[^>]+>/', $body_content, $img ); … … 230 215 $body_content = preg_replace( '/<img[^>]+>/', $button, $body_content ); 231 216 232 // We need both a responsive image and an enlarged image to animate 233 // the zoom seamlessly on slow internet connections; the responsive 234 // image is a copy of the one in the body, which animates immediately 235 // as the lightbox is opened, while the enlarged one is a full-sized 236 // version that will likely still be loading as the animation begins. 237 $m = new WP_HTML_Tag_Processor( $block_content ); 238 $m->next_tag( 'figure' ); 239 $m->add_class( 'responsive-image' ); 240 $m->next_tag( 'img' ); 241 // We want to set the 'src' attribute to an empty string in the responsive image 242 // because otherwise, as of this writing, the wp_filter_content_tags() function in 243 // WordPress will automatically add a 'srcset' attribute to the image, which will at 244 // times cause the incorrectly sized image to be loaded in the lightbox on Firefox. 245 // Because of this, we bind the 'src' attribute explicitly the current src to reliably 246 // use the exact same image as in the content when the lightbox is first opened while 247 // we wait for the larger image to load. 248 $m->set_attribute( 'src', '' ); 249 $m->set_attribute( 'data-wp-bind--src', 'context.imageCurrentSrc' ); 250 $m->set_attribute( 'data-wp-style--object-fit', 'state.lightboxObjectFit' ); 251 $initial_image_content = $m->get_updated_html(); 252 253 $q = new WP_HTML_Tag_Processor( $block_content ); 254 $q->next_tag( 'figure' ); 255 $q->add_class( 'enlarged-image' ); 256 $q->next_tag( 'img' ); 257 258 // We set the 'src' attribute to an empty string to prevent the browser from loading the image 259 // on initial page load, then bind the attribute to a selector that returns the full-sized image src when 260 // the lightbox is opened. We could use 'loading=lazy' in combination with the 'hidden' attribute to 261 // accomplish the same behavior, but that approach breaks progressive loading of the image in Safari 262 // and Chrome (see https://github.com/WordPress/gutenberg/pull/52765#issuecomment-1674008151). Until that 263 // is resolved, manually setting the 'src' seems to be the best solution to load the large image on demand. 264 $q->set_attribute( 'src', '' ); 265 $q->set_attribute( 'data-wp-bind--src', 'state.enlargedImgSrc' ); 266 $q->set_attribute( 'data-wp-style--object-fit', 'state.lightboxObjectFit' ); 267 $enlarged_image_content = $q->get_updated_html(); 268 269 // If the current theme does NOT have a `theme.json`, or the colors are not defined, 270 // we need to set the background color & close button color to some default values 271 // because we can't get them from the Global Styles. 217 add_action( 'wp_footer', 'block_core_image_print_lightbox_overlay' ); 218 219 return $body_content; 220 } 221 222 function block_core_image_print_lightbox_overlay() { 223 $close_button_label = esc_attr__( 'Close' ); 224 225 // If the current theme does NOT have a `theme.json`, or the colors are not 226 // defined, it needs to set the background color & close button color to some 227 // default values because it can't get them from the Global Styles. 272 228 $background_color = '#fff'; 273 229 $close_button_color = '#000'; … … 282 238 } 283 239 284 $close_button_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z"></path></svg>'; 285 $close_button_label = esc_attr__( 'Close' ); 286 287 $lightbox_html = <<<HTML 288 <div data-wp-body="" class="wp-lightbox-overlay $lightbox_animation" 289 data-wp-bind--role="state.roleAttribute" 290 data-wp-bind--aria-label="state.dialogLabel" 291 data-wp-class--initialized="context.initialized" 292 data-wp-class--active="context.lightboxEnabled" 293 data-wp-class--hideAnimationEnabled="context.hideAnimationEnabled" 294 data-wp-bind--aria-modal="state.ariaModal" 295 data-wp-watch="callbacks.initLightbox" 296 data-wp-on--keydown="actions.handleKeydown" 297 data-wp-on--touchstart="actions.handleTouchStart" 298 data-wp-on--touchmove="actions.handleTouchMove" 299 data-wp-on--touchend="actions.handleTouchEnd" 300 data-wp-on--click="actions.hideLightbox" 301 tabindex="-1" 302 > 303 <button type="button" aria-label="$close_button_label" style="fill: $close_button_color" class="close-button" data-wp-on--click="actions.hideLightbox"> 304 $close_button_icon 305 </button> 306 <div class="lightbox-image-container">$initial_image_content</div> 307 <div class="lightbox-image-container">$enlarged_image_content</div> 308 <div class="scrim" style="background-color: $background_color" aria-hidden="true"></div> 309 </div> 240 echo <<<HTML 241 <div 242 class="wp-lightbox-overlay zoom" 243 data-wp-interactive='{"namespace":"core/image"}' 244 data-wp-context='{}' 245 data-wp-bind--role="state.roleAttribute" 246 data-wp-bind--aria-label="state.currentImage.ariaLabel" 247 data-wp-bind--aria-modal="state.ariaModal" 248 data-wp-class--active="state.overlayEnabled" 249 data-wp-class--show-closing-animation="state.showClosingAnimation" 250 data-wp-watch="callbacks.setOverlayFocus" 251 data-wp-on--keydown="actions.handleKeydown" 252 data-wp-on--touchstart="actions.handleTouchStart" 253 data-wp-on--touchmove="actions.handleTouchMove" 254 data-wp-on--touchend="actions.handleTouchEnd" 255 data-wp-on--click="actions.hideLightbox" 256 data-wp-on-window--resize="callbacks.setOverlayStyles" 257 data-wp-on-window--scroll="actions.handleScroll" 258 tabindex="-1" 259 > 260 <button type="button" aria-label="$close_button_label" style="fill: $close_button_color" class="close-button"> 261 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z"></path></svg> 262 </button> 263 <div class="lightbox-image-container"> 264 <figure data-wp-bind--class="state.currentImage.figureClassNames" data-wp-bind--style="state.currentImage.figureStyles"> 265 <img data-wp-bind--alt="state.currentImage.alt" data-wp-bind--class="state.currentImage.imgClassNames" data-wp-bind--style="state.imgStyles" data-wp-bind--src="state.currentImage.currentSrc"> 266 </figure> 267 </div> 268 <div class="lightbox-image-container"> 269 <figure data-wp-bind--class="state.currentImage.figureClassNames" data-wp-bind--style="state.currentImage.figureStyles"> 270 <img data-wp-bind--alt="state.currentImage.alt" data-wp-bind--class="state.currentImage.imgClassNames" data-wp-bind--style="state.imgStyles" data-wp-bind--src="state.enlargedSrc"> 271 </figure> 272 </div> 273 <div class="scrim" style="background-color: $background_color" aria-hidden="true"></div> 274 <style data-wp-text="state.overlayStyles"></style> 275 </div> 310 276 HTML; 311 312 return str_replace( '</figure>', $lightbox_html . '</figure>', $body_content );313 277 } 314 278 … … 323 287 ) 324 288 ); 325 326 wp_register_script_module(327 '@wordpress/block-library/image',328 defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ? gutenberg_url( '/build/interactivity/image.min.js' ) : includes_url( 'blocks/image/view.min.js' ),329 array( '@wordpress/interactivity' ),330 defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )331 );332 289 } 333 290 add_action( 'init', 'register_block_core_image' );
Note: See TracChangeset
for help on using the changeset viewer.