[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Server-side rendering of the `core/image` block. 4 * 5 * @package WordPress 6 */ 7 8 /** 9 * Renders the `core/image` block on the server, 10 * adding a data-id attribute to the element if core/gallery has added on pre-render. 11 * 12 * @param array $attributes The block attributes. 13 * @param string $content The block content. 14 * @param WP_Block $block The block object. 15 * 16 * @return string The block content with the data-id attribute added. 17 */ 18 function render_block_core_image( $attributes, $content, $block ) { 19 if ( false === stripos( $content, '<img' ) ) { 20 return ''; 21 } 22 23 $p = new WP_HTML_Tag_Processor( $content ); 24 25 if ( ! $p->next_tag( 'img' ) || null === $p->get_attribute( 'src' ) ) { 26 return ''; 27 } 28 29 if ( isset( $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 } 36 37 $link_destination = isset( $attributes['linkDestination'] ) ? $attributes['linkDestination'] : 'none'; 38 $lightbox_settings = block_core_image_get_lightbox_settings( $block->parsed_block ); 39 40 /* 41 * If the lightbox is enabled and the image is not linked, adds the filter and 42 * the JavaScript view file. 43 */ 44 if ( 45 isset( $lightbox_settings ) && 46 'none' === $link_destination && 47 isset( $lightbox_settings['enabled'] ) && 48 true === $lightbox_settings['enabled'] 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 62 wp_enqueue_script_module( '@wordpress/block-library/image' ); 63 64 /* 65 * This render needs to happen in a filter with priority 15 to ensure that 66 * it runs after the duotone filter and that duotone styles are applied to 67 * the image in the lightbox. Lightbox has to work with any plugins that 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. 71 */ 72 add_filter( 'render_block_core/image', 'block_core_image_render_lightbox', 15, 2 ); 73 } else { 74 /* 75 * Remove the filter if previously added by other Image blocks. 76 */ 77 remove_filter( 'render_block_core/image', 'block_core_image_render_lightbox', 15 ); 78 } 79 80 return $p->get_updated_html(); 81 } 82 83 /** 84 * Adds the lightboxEnabled flag to the block data. 85 * 86 * This is used to determine whether the lightbox should be rendered or not. 87 * 88 * @param array $block Block data. 89 * 90 * @return array Filtered block data. 91 */ 92 function block_core_image_get_lightbox_settings( $block ) { 93 // Gets the lightbox setting from the block attributes. 94 if ( isset( $block['attrs']['lightbox'] ) ) { 95 $lightbox_settings = $block['attrs']['lightbox']; 96 } 97 98 if ( ! isset( $lightbox_settings ) ) { 99 $lightbox_settings = wp_get_global_settings( array( 'lightbox' ), array( 'block_name' => 'core/image' ) ); 100 101 // If not present in global settings, check the top-level global settings. 102 // 103 // NOTE: If no block-level settings are found, the previous call to 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. 107 if ( isset( $lightbox_settings['lightbox'] ) ) { 108 $lightbox_settings = wp_get_global_settings( array( 'lightbox' ) ); 109 } 110 } 111 112 return $lightbox_settings ?? null; 113 } 114 115 /** 116 * Adds the directives and layout needed for the lightbox behavior. 117 * 118 * @param string $block_content Rendered block content. 119 * @param array $block Block object. 120 * 121 * @return string Filtered block content. 122 */ 123 function block_core_image_render_lightbox( $block_content, $block ) { 124 /* 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. 128 */ 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' ) ) { 134 return $block_content; 135 } 136 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 ) { 146 /* translators: %s: Image alt text. */ 147 $aria_label = sprintf( __( 'Enlarge image: %s' ), $alt ); 148 } 149 150 if ( isset( $block['attrs']['id'] ) ) { 151 $img_uploaded_src = wp_get_attachment_url( $block['attrs']['id'] ); 152 $img_metadata = wp_get_attachment_metadata( $block['attrs']['id'] ); 153 $img_width = $img_metadata['width'] ?? 'none'; 154 $img_height = $img_metadata['height'] ?? 'none'; 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', 'core/image' ); 163 $p->set_attribute( 164 'data-wp-context', 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 179 ) 180 ); 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. 195 $img = null; 196 preg_match( '/<img[^>]+>/', $body_content, $img ); 197 198 $button = 199 $img[0] 200 . '<button 201 class="lightbox-trigger" 202 type="button" 203 aria-haspopup="dialog" 204 aria-label="' . esc_attr( $aria_label ) . '" 205 data-wp-init="callbacks.initTriggerButton" 206 data-wp-on--click="actions.showLightbox" 207 data-wp-style--right="context.imageButtonRight" 208 data-wp-style--top="context.imageButtonTop" 209 > 210 <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12"> 211 <path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" /> 212 </svg> 213 </button>'; 214 215 $body_content = preg_replace( '/<img[^>]+>/', $button, $body_content ); 216 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. 228 $background_color = '#fff'; 229 $close_button_color = '#000'; 230 if ( wp_theme_has_theme_json() ) { 231 $global_styles_color = wp_get_global_styles( array( 'color' ) ); 232 if ( ! empty( $global_styles_color['background'] ) ) { 233 $background_color = esc_attr( $global_styles_color['background'] ); 234 } 235 if ( ! empty( $global_styles_color['text'] ) ) { 236 $close_button_color = esc_attr( $global_styles_color['text'] ); 237 } 238 } 239 240 echo <<<HTML 241 <div 242 class="wp-lightbox-overlay zoom" 243 data-wp-interactive="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> 276 HTML; 277 } 278 279 /** 280 * Registers the `core/image` block on server. 281 */ 282 function register_block_core_image() { 283 register_block_type_from_metadata( 284 __DIR__ . '/image', 285 array( 286 'render_callback' => 'render_block_core_image', 287 ) 288 ); 289 } 290 add_action( 'init', 'register_block_core_image' );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Fri Apr 26 08:20:02 2024 | Cross-referenced by PHPXref |