wp/wp-includes/blocks/gallery.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    10  * whose images feature a `data-id` attribute.
    10  * whose images feature a `data-id` attribute.
    11  *
    11  *
    12  * Now that the Gallery Block contains inner Image Blocks,
    12  * Now that the Gallery Block contains inner Image Blocks,
    13  * we add a custom `data-id` attribute before rendering the gallery
    13  * we add a custom `data-id` attribute before rendering the gallery
    14  * so that the Image Block can pick it up in its render_callback.
    14  * so that the Image Block can pick it up in its render_callback.
       
    15  *
       
    16  * @since 5.9.0
    15  *
    17  *
    16  * @param array $parsed_block The block being rendered.
    18  * @param array $parsed_block The block being rendered.
    17  * @return array The migrated block object.
    19  * @return array The migrated block object.
    18  */
    20  */
    19 function block_core_gallery_data_id_backcompatibility( $parsed_block ) {
    21 function block_core_gallery_data_id_backcompatibility( $parsed_block ) {
    31 }
    33 }
    32 
    34 
    33 add_filter( 'render_block_data', 'block_core_gallery_data_id_backcompatibility' );
    35 add_filter( 'render_block_data', 'block_core_gallery_data_id_backcompatibility' );
    34 
    36 
    35 /**
    37 /**
    36  * Adds a style tag for the --wp--style--unstable-gallery-gap var.
    38  * Renders the `core/gallery` block on the server.
    37  *
    39  *
    38  * The Gallery block needs to recalculate Image block width based on
    40  * @since 6.0.0
    39  * the current gap setting in order to maintain the number of flex columns
       
    40  * so a css var is added to allow this.
       
    41  *
    41  *
    42  * @param array  $attributes Attributes of the block being rendered.
    42  * @param array  $attributes Attributes of the block being rendered.
    43  * @param string $content Content of the block being rendered.
    43  * @param string $content Content of the block being rendered.
    44  * @return string The content of the block being rendered.
    44  * @return string The content of the block being rendered.
    45  */
    45  */
    46 function block_core_gallery_render( $attributes, $content ) {
    46 function block_core_gallery_render( $attributes, $content ) {
    47 	$gap = _wp_array_get( $attributes, array( 'style', 'spacing', 'blockGap' ) );
    47 	// Adds a style tag for the --wp--style--unstable-gallery-gap var.
       
    48 	// The Gallery block needs to recalculate Image block width based on
       
    49 	// the current gap setting in order to maintain the number of flex columns
       
    50 	// so a css var is added to allow this.
       
    51 
       
    52 	$gap = $attributes['style']['spacing']['blockGap'] ?? null;
    48 	// Skip if gap value contains unsupported characters.
    53 	// Skip if gap value contains unsupported characters.
    49 	// Regex for CSS value borrowed from `safecss_filter_attr`, and used here
    54 	// Regex for CSS value borrowed from `safecss_filter_attr`, and used here
    50 	// because we only want to match against the value, not the CSS attribute.
    55 	// because we only want to match against the value, not the CSS attribute.
    51 	if ( is_array( $gap ) ) {
    56 	if ( is_array( $gap ) ) {
    52 		foreach ( $gap as $key => $value ) {
    57 		foreach ( $gap as $key => $value ) {
    53 			$gap[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value;
    58 			// Make sure $value is a string to avoid PHP 8.1 deprecation error in preg_match() when the value is null.
       
    59 			$value = is_string( $value ) ? $value : '';
       
    60 			$value = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value;
       
    61 
       
    62 			// Get spacing CSS variable from preset value if provided.
       
    63 			if ( is_string( $value ) && str_contains( $value, 'var:preset|spacing|' ) ) {
       
    64 				$index_to_splice = strrpos( $value, '|' ) + 1;
       
    65 				$slug            = _wp_to_kebab_case( substr( $value, $index_to_splice ) );
       
    66 				$value           = "var(--wp--preset--spacing--$slug)";
       
    67 			}
       
    68 
       
    69 			$gap[ $key ] = $value;
    54 		}
    70 		}
    55 	} else {
    71 	} else {
       
    72 		// Make sure $gap is a string to avoid PHP 8.1 deprecation error in preg_match() when the value is null.
       
    73 		$gap = is_string( $gap ) ? $gap : '';
    56 		$gap = $gap && preg_match( '%[\\\(&=}]|/\*%', $gap ) ? null : $gap;
    74 		$gap = $gap && preg_match( '%[\\\(&=}]|/\*%', $gap ) ? null : $gap;
       
    75 
       
    76 		// Get spacing CSS variable from preset value if provided.
       
    77 		if ( is_string( $gap ) && str_contains( $gap, 'var:preset|spacing|' ) ) {
       
    78 			$index_to_splice = strrpos( $gap, '|' ) + 1;
       
    79 			$slug            = _wp_to_kebab_case( substr( $gap, $index_to_splice ) );
       
    80 			$gap             = "var(--wp--preset--spacing--$slug)";
       
    81 		}
    57 	}
    82 	}
    58 
    83 
    59 	$class   = wp_unique_id( 'wp-block-gallery-' );
    84 	$unique_gallery_classname = wp_unique_id( 'wp-block-gallery-' );
    60 	$content = preg_replace(
    85 	$processed_content        = new WP_HTML_Tag_Processor( $content );
    61 		'/' . preg_quote( 'class="', '/' ) . '/',
    86 	$processed_content->next_tag();
    62 		'class="' . $class . ' ',
    87 	$processed_content->add_class( $unique_gallery_classname );
    63 		$content,
       
    64 		1
       
    65 	);
       
    66 
    88 
    67 	// --gallery-block--gutter-size is deprecated. --wp--style--gallery-gap-default should be used by themes that want to set a default
    89 	// --gallery-block--gutter-size is deprecated. --wp--style--gallery-gap-default should be used by themes that want to set a default
    68 	// gap on the gallery.
    90 	// gap on the gallery.
    69 	$fallback_gap = 'var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )';
    91 	$fallback_gap = 'var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )';
    70 	$gap_value    = $gap ? $gap : $fallback_gap;
    92 	$gap_value    = $gap ? $gap : $fallback_gap;
    74 		$gap_row    = isset( $gap_value['top'] ) ? $gap_value['top'] : $fallback_gap;
    96 		$gap_row    = isset( $gap_value['top'] ) ? $gap_value['top'] : $fallback_gap;
    75 		$gap_column = isset( $gap_value['left'] ) ? $gap_value['left'] : $fallback_gap;
    97 		$gap_column = isset( $gap_value['left'] ) ? $gap_value['left'] : $fallback_gap;
    76 		$gap_value  = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column;
    98 		$gap_value  = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column;
    77 	}
    99 	}
    78 
   100 
       
   101 	// The unstable gallery gap calculation requires a real value (such as `0px`) and not `0`.
       
   102 	if ( '0' === $gap_column ) {
       
   103 		$gap_column = '0px';
       
   104 	}
       
   105 
    79 	// Set the CSS variable to the column value, and the `gap` property to the combined gap value.
   106 	// Set the CSS variable to the column value, and the `gap` property to the combined gap value.
    80 	$style = '.' . $class . '{ --wp--style--unstable-gallery-gap: ' . $gap_column . '; gap: ' . $gap_value . '}';
   107 	$gallery_styles = array(
       
   108 		array(
       
   109 			'selector'     => ".wp-block-gallery.{$unique_gallery_classname}",
       
   110 			'declarations' => array(
       
   111 				'--wp--style--unstable-gallery-gap' => $gap_column,
       
   112 				'gap'                               => $gap_value,
       
   113 			),
       
   114 		),
       
   115 	);
    81 
   116 
    82 	// Ideally styles should be loaded in the head, but blocks may be parsed
   117 	wp_style_engine_get_stylesheet_from_css_rules(
    83 	// after that, so loading in the footer for now.
   118 		$gallery_styles,
    84 	// See https://core.trac.wordpress.org/ticket/53494.
   119 		array(
    85 	add_action(
   120 			'context' => 'block-supports',
    86 		'wp_footer',
   121 		)
    87 		function () use ( $style ) {
   122 	);
    88 			echo '<style> ' . $style . '</style>';
   123 
       
   124 	// The WP_HTML_Tag_Processor class calls get_updated_html() internally
       
   125 	// when the instance is treated as a string, but here we explicitly
       
   126 	// convert it to a string.
       
   127 	$updated_content = $processed_content->get_updated_html();
       
   128 
       
   129 	/*
       
   130 	 * Randomize the order of image blocks. Ideally we should shuffle
       
   131 	 * the `$parsed_block['innerBlocks']` via the `render_block_data` hook.
       
   132 	 * However, this hook doesn't apply inner block updates when blocks are
       
   133 	 * nested.
       
   134 	 * @todo In the future, if this hook supports updating innerBlocks in
       
   135 	 * nested blocks, it should be refactored.
       
   136 	 *
       
   137 	 * @see: https://github.com/WordPress/gutenberg/pull/58733
       
   138 	 */
       
   139 	if ( empty( $attributes['randomOrder'] ) ) {
       
   140 		return $updated_content;
       
   141 	}
       
   142 
       
   143 	// This pattern matches figure elements with the `wp-block-image` class to
       
   144 	// avoid the gallery's wrapping `figure` element and extract images only.
       
   145 	$pattern = '/<figure[^>]*\bwp-block-image\b[^>]*>.*?<\/figure>/';
       
   146 
       
   147 	// Find all Image blocks.
       
   148 	preg_match_all( $pattern, $updated_content, $matches );
       
   149 	if ( ! $matches ) {
       
   150 		return $updated_content;
       
   151 	}
       
   152 	$image_blocks = $matches[0];
       
   153 
       
   154 	// Randomize the order of Image blocks.
       
   155 	shuffle( $image_blocks );
       
   156 	$i       = 0;
       
   157 	$content = preg_replace_callback(
       
   158 		$pattern,
       
   159 		static function () use ( $image_blocks, &$i ) {
       
   160 			$new_image_block = $image_blocks[ $i ];
       
   161 			++$i;
       
   162 			return $new_image_block;
    89 		},
   163 		},
    90 		11
   164 		$updated_content
    91 	);
   165 	);
       
   166 
    92 	return $content;
   167 	return $content;
    93 }
   168 }
    94 /**
   169 /**
    95  * Registers the `core/gallery` block on server.
   170  * Registers the `core/gallery` block on server.
       
   171  *
       
   172  * @since 5.9.0
    96  */
   173  */
    97 function register_block_core_gallery() {
   174 function register_block_core_gallery() {
    98 	register_block_type_from_metadata(
   175 	register_block_type_from_metadata(
    99 		__DIR__ . '/gallery',
   176 		__DIR__ . '/gallery',
   100 		array(
   177 		array(