PluginProbe
Gutenberg / trunk
Gutenberg vtrunk
24.1.0 24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 All 404 releases
← All changes | build/scripts/block-library/gallery.php +179 -65 24.0.0 → trunk View file →
@@ -87,8 +87,85 @@
87 87 return '0' === $gap_column ? '0px' : $gap_column;
88 88 }
89 89
90 90 /**
91 + * Returns whether a value can be used as a Gallery aspect ratio.
92 + *
93 + * Aspect ratios are interpolated into a generated stylesheet instead of being
94 + * set as an inline style, so only the numeric forms produced by aspect ratio
95 + * presets (and `auto`) are accepted. A value from saved content that isn't one
96 + * of those is ignored rather than emitted, so it can't close the rule early and
97 + * inject declarations of its own. The editor applies the same restriction in
98 + * `isValidGalleryAspectRatio()`.
99 + *
100 + * @since 7.1.0
101 + *
102 + * @param mixed $value Value to check.
103 + * @return bool Whether the value is a valid aspect ratio.
104 + */
105 +function gutenberg_block_core_gallery_is_valid_aspect_ratio( $value ) {
106 + return is_string( $value ) && 1 === preg_match( '#^(auto|\d+(\.\d+)?(\s*/\s*\d+(\.\d+)?)?)$#', trim( $value ) );
107 +}
108 +
109 +/**
110 + * Returns Gallery-specific responsive aspect ratio rules for a viewport.
111 + *
112 + * Unlike the column and crop rules, these are not scoped to the Flex layout:
113 + * the aspect ratio applies to the images in every Gallery layout. They also
114 + * cover dynamic galleries, whose images are rendered by the Gallery rather than
115 + * carrying their own block attributes.
116 + *
117 + * @since 7.1.0
118 + *
119 + * @param string $selector Gallery block selector.
120 + * @param mixed $viewport_style Viewport style data.
121 + * @param string $media_query Viewport media query.
122 + * @return array[] Gallery responsive aspect ratio rules.
123 + */
124 +function gutenberg_block_core_gallery_get_responsive_aspect_ratio_style_rules( $selector, $viewport_style, $media_query ) {
125 + if ( ! is_array( $viewport_style ) || ! is_string( $media_query ) ) {
126 + return array();
127 + }
128 +
129 + $aspect_ratio = $viewport_style['aspectRatio'] ?? null;
130 + if ( ! gutenberg_block_core_gallery_is_valid_aspect_ratio( $aspect_ratio ) ) {
131 + return array();
132 + }
133 +
134 + $aspect_ratio = trim( $aspect_ratio );
135 +
136 + /*
137 + * The base aspect ratio is an inline style on each image, so these
138 + * declarations have to be important to win for the viewport.
139 + *
140 + * Original cancels the base ratio, which means rolling the declaration out
141 + * of the cascade rather than giving it a value. `auto` - and `initial`,
142 + * `unset` and `revert`, which all compute to it - would override the
143 + * `width`/`height` presentational hint that gives a lazy-loaded image its
144 + * placeholder ratio, collapsing the image to zero height until it loads:
145 + * the Featured Image bug fixed in #80386. `revert-layer` drops the
146 + * declaration instead, so the image falls back to that hint while loading,
147 + * to its natural ratio once loaded, and to any ratio a theme set in a lower
148 + * cascade layer. `object-fit` is left as the base set it, so a cropped
149 + * Gallery still crops.
150 + */
151 + $declarations = 'auto' === $aspect_ratio
152 + ? array( 'aspect-ratio' => 'revert-layer !important' )
153 + : array(
154 + 'aspect-ratio' => "{$aspect_ratio} !important",
155 + 'object-fit' => 'cover !important',
156 + );
157 +
158 + return array(
159 + array(
160 + 'selector' => "{$selector}.wp-block-gallery.has-nested-images figure.wp-block-image:not(#individual-image) img",
161 + 'declarations' => $declarations,
162 + 'rules_group' => $media_query,
163 + ),
164 + );
165 +}
166 +
167 +/**
91 168 * Returns Gallery-specific responsive Flex rules for a viewport.
92 169 *
93 170 * @since 7.1.0
94 171 *
@@ -473,98 +550,135 @@
473 550
474 551 $processed_content = new WP_HTML_Tag_Processor( $content );
475 552 $processed_content->next_tag();
476 553
477 - if ( $is_flex_layout ) {
478 - // Add a style tag for the --wp--style--unstable-gallery-gap var. The
479 - // Gallery's custom Flex layout recalculates Image block widths based on
480 - // the current gap so it can maintain the selected number of columns.
481 - $style_attr = is_array( $attributes['style'] ?? null )
482 - ? $attributes['style']
483 - : array();
554 + $style_attr = is_array( $attributes['style'] ?? null )
555 + ? $attributes['style']
556 + : array();
557 + if (
558 + defined( 'IS_GUTENBERG_PLUGIN' ) &&
559 + IS_GUTENBERG_PLUGIN &&
560 + function_exists( 'gutenberg_resolve_style_state_aliases' )
561 + ) {
562 + $style_attr = gutenberg_resolve_style_state_aliases( $style_attr, 'core/gallery' );
563 + }
564 +
565 + $global_settings = gutenberg_get_global_settings();
566 + $viewport_settings = $global_settings['viewport'] ?? null;
567 + $responsive_media_queries = array();
568 + foreach ( array( 'WP_Theme_JSON_Gutenberg', 'WP_Theme_JSON' ) as $theme_json_class_name ) {
569 + if ( method_exists( $theme_json_class_name, 'get_viewport_media_queries' ) ) {
570 + $responsive_media_queries = $theme_json_class_name::get_viewport_media_queries( $viewport_settings );
571 + break;
572 + }
573 + }
574 +
575 + // Columns and cropping are Flex-only, but the aspect ratio applies in every
576 + // layout, so a Gallery with a viewport aspect ratio needs the per-instance
577 + // stylesheet (and the class scoping it) even when it isn't a Flex Gallery.
578 + $has_viewport_aspect_ratio = false;
579 + foreach ( $responsive_media_queries as $breakpoint => $media_query ) {
580 + $viewport_style = $style_attr[ $breakpoint ] ?? null;
484 581 if (
485 - defined( 'IS_GUTENBERG_PLUGIN' ) &&
486 - IS_GUTENBERG_PLUGIN &&
487 - function_exists( 'gutenberg_resolve_style_state_aliases' )
582 + is_array( $viewport_style ) &&
583 + gutenberg_block_core_gallery_is_valid_aspect_ratio( $viewport_style['aspectRatio'] ?? null )
488 584 ) {
489 - $style_attr = gutenberg_resolve_style_state_aliases( $style_attr, 'core/gallery' );
585 + $has_viewport_aspect_ratio = true;
586 + break;
490 587 }
588 + }
491 589
590 + /*
591 + * Only generate the gap styles — and, when nothing else needs it, the unique
592 + * classname that exists solely to scope them — if the theme has not opted out
593 + * of layout styles. The responsive aspect ratio rules are not layout styles,
594 + * so they keep rendering either way.
595 + */
596 + $should_generate_gap_styles = $is_flex_layout && ! current_theme_supports( 'disable-layout-styles' );
597 +
598 + if ( $should_generate_gap_styles || $has_viewport_aspect_ratio ) {
492 599 $unique_gallery_classname = wp_unique_id( 'wp-block-gallery-' );
493 600 $processed_content->add_class( $unique_gallery_classname );
601 + $gallery_styles = array();
494 602
495 - // --gallery-block--gutter-size is deprecated. --wp--style--gallery-gap-default should be used by themes that want to set a default
496 - // gap on the gallery.
497 - $fallback_gap = 'var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )';
603 + if ( $should_generate_gap_styles ) {
604 + // Add a style tag for the --wp--style--unstable-gallery-gap var. The
605 + // Gallery's custom Flex layout recalculates Image block widths based on
606 + // the current gap so it can maintain the selected number of columns.
498 607
499 - if ( null === $global_styles ) {
500 - $global_styles = function_exists( 'gutenberg_get_global_styles' ) ? gutenberg_get_global_styles() : array();
501 - }
608 + // --gallery-block--gutter-size is deprecated. --wp--style--gallery-gap-default should be used by themes that want to set a default
609 + // gap on the gallery.
610 + $fallback_gap = 'var( --wp--style--gallery-gap-default, var( --gallery-block--gutter-size, var( --wp--style--block-gap, 0.5em ) ) )';
502 611
503 - $global_gallery_styles = $global_styles['blocks']['core/gallery'] ?? array();
504 - $global_gallery_gap = $global_gallery_styles['spacing']['blockGap'] ?? $fallback_gap;
505 - $has_block_gap = is_array( $style_attr['spacing'] ?? null ) && array_key_exists( 'blockGap', $style_attr['spacing'] );
506 - // Prefer the block's own gap value, then Gallery global styles. Missing
507 - // values fall back to the Gallery blockGap default.
508 - $block_gap = $has_block_gap
509 - ? $style_attr['spacing']['blockGap']
510 - : $global_gallery_gap;
511 - $gap_column = gutenberg_block_core_gallery_get_column_gap_value( $block_gap, $fallback_gap );
612 + if ( null === $global_styles ) {
613 + $global_styles = function_exists( 'gutenberg_get_global_styles' ) ? gutenberg_get_global_styles() : array();
614 + }
512 615
513 - // Set the CSS variable to the column value for Gallery's flex width calculations.
514 - $gallery_styles = array(
515 - array(
616 + $global_gallery_styles = $global_styles['blocks']['core/gallery'] ?? array();
617 + $global_gallery_gap = $global_gallery_styles['spacing']['blockGap'] ?? $fallback_gap;
618 + $has_block_gap = is_array( $style_attr['spacing'] ?? null ) && array_key_exists( 'blockGap', $style_attr['spacing'] );
619 + // Prefer the block's own gap value, then Gallery global styles. Missing
620 + // values fall back to the Gallery blockGap default.
621 + $block_gap = $has_block_gap
622 + ? $style_attr['spacing']['blockGap']
623 + : $global_gallery_gap;
624 + $gap_column = gutenberg_block_core_gallery_get_column_gap_value( $block_gap, $fallback_gap );
625 +
626 + // Set the CSS variable to the column value for Gallery's flex width calculations.
627 + $gallery_styles[] = array(
516 628 'selector' => ".wp-block-gallery.{$unique_gallery_classname}",
517 629 'declarations' => array(
518 630 '--wp--style--unstable-gallery-gap' => $gap_column,
519 631 ),
520 - ),
521 - );
522 -
523 - $global_settings = gutenberg_get_global_settings();
524 - $viewport_settings = $global_settings['viewport'] ?? null;
525 - $responsive_media_queries = array();
526 - foreach ( array( 'WP_Theme_JSON_Gutenberg', 'WP_Theme_JSON' ) as $theme_json_class_name ) {
527 - if ( method_exists( $theme_json_class_name, 'get_viewport_media_queries' ) ) {
528 - $responsive_media_queries = $theme_json_class_name::get_viewport_media_queries( $viewport_settings );
529 - break;
530 - }
632 + );
531 633 }
532 634
533 635 foreach ( $responsive_media_queries as $breakpoint => $media_query ) {
534 - $viewport_style = $style_attr[ $breakpoint ] ?? null;
535 - $has_viewport_block_gap = is_array( $viewport_style ) &&
536 - is_array( $viewport_style['spacing'] ?? null ) &&
537 - array_key_exists( 'blockGap', $viewport_style['spacing'] );
538 - $has_global_viewport_block_gap = is_array( $global_gallery_styles[ $breakpoint ]['spacing'] ?? null ) &&
539 - array_key_exists( 'blockGap', $global_gallery_styles[ $breakpoint ]['spacing'] );
636 + $viewport_style = $style_attr[ $breakpoint ] ?? null;
540 637
541 - // Viewport-specific block values win. Gallery global viewport values
542 - // only apply when the block has no base gap, so they do not override an instance value.
543 - if ( $has_viewport_block_gap ) {
544 - $viewport_gap = $viewport_style['spacing']['blockGap'];
545 - } elseif ( ! $has_block_gap && $has_global_viewport_block_gap ) {
546 - $viewport_gap = $global_gallery_styles[ $breakpoint ]['spacing']['blockGap'];
547 - } else {
548 - $viewport_gap = null;
549 - }
638 + if ( $should_generate_gap_styles ) {
639 + $has_viewport_block_gap = is_array( $viewport_style ) &&
640 + is_array( $viewport_style['spacing'] ?? null ) &&
641 + array_key_exists( 'blockGap', $viewport_style['spacing'] );
642 + $has_global_viewport_block_gap = is_array( $global_gallery_styles[ $breakpoint ]['spacing'] ?? null ) &&
643 + array_key_exists( 'blockGap', $global_gallery_styles[ $breakpoint ]['spacing'] );
550 644
551 - if ( null !== $viewport_gap ) {
552 - $gallery_styles[] = array(
553 - 'selector' => ".wp-block-gallery.{$unique_gallery_classname}",
554 - 'declarations' => array(
555 - '--wp--style--unstable-gallery-gap' => gutenberg_block_core_gallery_get_column_gap_value(
556 - $viewport_gap,
557 - $fallback_gap
645 + // Viewport-specific block values win. Gallery global viewport values
646 + // only apply when the block has no base gap, so they do not override an instance value.
647 + if ( $has_viewport_block_gap ) {
648 + $viewport_gap = $viewport_style['spacing']['blockGap'];
649 + } elseif ( ! $has_block_gap && $has_global_viewport_block_gap ) {
650 + $viewport_gap = $global_gallery_styles[ $breakpoint ]['spacing']['blockGap'];
651 + } else {
652 + $viewport_gap = null;
653 + }
654 +
655 + if ( null !== $viewport_gap ) {
656 + $gallery_styles[] = array(
657 + 'selector' => ".wp-block-gallery.{$unique_gallery_classname}",
658 + 'declarations' => array(
659 + '--wp--style--unstable-gallery-gap' => gutenberg_block_core_gallery_get_column_gap_value(
660 + $viewport_gap,
661 + $fallback_gap
662 + ),
558 663 ),
559 - ),
560 - 'rules_group' => $media_query,
664 + 'rules_group' => $media_query,
665 + );
666 + }
667 +
668 + $gallery_styles = array_merge(
669 + $gallery_styles,
670 + gutenberg_block_core_gallery_get_responsive_flex_style_rules(
671 + ".{$unique_gallery_classname}",
672 + $viewport_style,
673 + $media_query
674 + )
561 675 );
562 676 }
563 677
564 678 $gallery_styles = array_merge(
565 679 $gallery_styles,
566 - gutenberg_block_core_gallery_get_responsive_flex_style_rules(
680 + gutenberg_block_core_gallery_get_responsive_aspect_ratio_style_rules(
567 681 ".{$unique_gallery_classname}",
568 682 $viewport_style,
569 683 $media_query
570 684 )