diff --git a/.github/workflows/php-test-plugins.yml b/.github/workflows/php-test-plugins.yml index 3594515140..97e862abfd 100644 --- a/.github/workflows/php-test-plugins.yml +++ b/.github/workflows/php-test-plugins.yml @@ -46,7 +46,7 @@ jobs: coverage: [false] include: - php: '7.4' - wp: '6.5' + wp: '6.6' - php: '8.3' wp: 'trunk' - php: '8.2' diff --git a/plugins/auto-sizes/hooks.php b/plugins/auto-sizes/hooks.php index 45612d9af2..21899cd332 100644 --- a/plugins/auto-sizes/hooks.php +++ b/plugins/auto-sizes/hooks.php @@ -38,3 +38,5 @@ function auto_sizes_render_generator(): void { add_filter( 'the_content', 'auto_sizes_prime_attachment_caches', 9 ); // This must run before 'do_blocks', which runs at priority 9. add_filter( 'render_block_core/image', 'auto_sizes_filter_image_tag', 10, 3 ); add_filter( 'render_block_core/cover', 'auto_sizes_filter_image_tag', 10, 3 ); +add_filter( 'get_block_type_uses_context', 'auto_sizes_allowed_uses_context_for_image_blocks', 10, 2 ); +add_filter( 'render_block_context', 'auto_sizes_modify_render_block_context', 10, 2 ); diff --git a/plugins/auto-sizes/includes/improve-calculate-sizes.php b/plugins/auto-sizes/includes/improve-calculate-sizes.php index 61df526a23..12bc6e83e8 100644 --- a/plugins/auto-sizes/includes/improve-calculate-sizes.php +++ b/plugins/auto-sizes/includes/improve-calculate-sizes.php @@ -84,6 +84,7 @@ function auto_sizes_filter_image_tag( $content, array $parsed_block, WP_Block $b if ( ! is_string( $content ) ) { return ''; } + $processor = new WP_HTML_Tag_Processor( $content ); $has_image = $processor->next_tag( array( 'tag_name' => 'IMG' ) ); @@ -98,12 +99,14 @@ function auto_sizes_filter_image_tag( $content, array $parsed_block, WP_Block $b * @param string $sizes The image sizes attribute value. * @param string $size The image size data. */ - $filter = static function ( $sizes, $size ) use ( $block ) { - $id = $block->attributes['id'] ?? 0; - $alignment = $block->attributes['align'] ?? ''; - $width = $block->attributes['width'] ?? ''; + $filter = static function ( $sizes, $size ) use ( $block, $parsed_block ) { + $id = $block->attributes['id'] ?? 0; + $alignment = $block->attributes['align'] ?? ''; + $width = $block->attributes['width'] ?? ''; + $has_parent_block = isset( $parsed_block['parentLayout'] ); + $ancestor_block_align = $block->context['ancestor_block_align'] ?? ''; - return auto_sizes_calculate_better_sizes( (int) $id, (string) $size, (string) $alignment, (string) $width ); + return auto_sizes_calculate_better_sizes( (int) $id, (string) $size, (string) $alignment, (string) $width, $has_parent_block, (string) $ancestor_block_align ); }; // Hook this filter early, before default filters are run. @@ -135,50 +138,121 @@ function auto_sizes_filter_image_tag( $content, array $parsed_block, WP_Block $b /** * Modifies the sizes attribute of an image based on layout context. * - * @param int $id The image id. - * @param string $size The image size data. - * @param string $align The image alignment. - * @param string $resize_width Resize image width. + * @since n.e.x.t + * + * @param int $id The image id. + * @param string $size The image size data. + * @param string $align The image alignment. + * @param string $resize_width Resize image width. + * @param bool $has_parent_block Check if image block has parent block. + * @param string $ancestor_block_align The ancestor block alignment. * @return string The sizes attribute value. */ -function auto_sizes_calculate_better_sizes( int $id, string $size, string $align, string $resize_width ): string { - $sizes = ''; +function auto_sizes_calculate_better_sizes( int $id, string $size, string $align, string $resize_width, bool $has_parent_block, string $ancestor_block_align ): string { $image = wp_get_attachment_image_src( $id, $size ); if ( false === $image ) { - return $sizes; + return ''; } // Retrieve width from the image tag itself. $image_width = '' !== $resize_width ? (int) $resize_width : $image[1]; + if ( $has_parent_block ) { + if ( 'full' === $ancestor_block_align && 'full' === $align ) { + return auto_sizes_get_sizes_by_block_alignments( $align, $image_width, true ); + } elseif ( 'full' !== $ancestor_block_align && 'full' === $align ) { + return auto_sizes_get_sizes_by_block_alignments( $ancestor_block_align, $image_width, true ); + } elseif ( 'full' !== $ancestor_block_align ) { + $parent_block_alignment_width = auto_sizes_get_sizes_by_block_alignments( $ancestor_block_align, $image_width ); + $block_alignment_width = auto_sizes_get_sizes_by_block_alignments( $align, $image_width ); + if ( (int) $parent_block_alignment_width < (int) $block_alignment_width ) { + return sprintf( '(max-width: %1$s) 100vw, %1$s', $parent_block_alignment_width ); + } else { + return sprintf( '(max-width: %1$s) 100vw, %1$s', $block_alignment_width ); + } + } + } + + return auto_sizes_get_sizes_by_block_alignments( $align, $image_width, true ); +} + +/** + * Generates the `sizes` attribute value based on block information. + * + * @since n.e.x.t + * + * @param string $alignment The alignment. + * @param int $image_width The image width. + * @param bool $print_sizes Print the sizes attribute. Default is false. + * @return string The sizes attribute value. + */ +function auto_sizes_get_sizes_by_block_alignments( string $alignment, int $image_width, bool $print_sizes = false ): string { + $sizes = ''; + $layout = wp_get_global_settings( array( 'layout' ) ); // Handle different alignment use cases. - switch ( $align ) { + switch ( $alignment ) { case 'full': $sizes = '100vw'; break; case 'wide': if ( array_key_exists( 'wideSize', $layout ) ) { - $sizes = sprintf( '(max-width: %1$s) 100vw, %1$s', $layout['wideSize'] ); + $sizes = $layout['wideSize']; } break; case 'left': case 'right': case 'center': - $sizes = sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $image_width ); + $sizes = auto_sizes_get_width( '', $image_width ); break; default: if ( array_key_exists( 'contentSize', $layout ) ) { - $width = auto_sizes_get_width( $layout['contentSize'], $image_width ); - $sizes = sprintf( '(max-width: %1$s) 100vw, %1$s', $width ); + $sizes = auto_sizes_get_width( $layout['contentSize'], $image_width ); } break; } + if ( $print_sizes ) { + $sizes = 'full' === $alignment ? $sizes : sprintf( '(max-width: %1$s) 100vw, %1$s', $sizes ); + } + return $sizes; } + +/** + * Filters the context keys that a block type uses. + * + * @since n.e.x.t + * + * @param array $uses_context Array of registered uses context for a block type. + * @param WP_Block_Type $block_type The full block type object. + * @return array The filtered context keys used by the block type. + */ +function auto_sizes_allowed_uses_context_for_image_blocks( array $uses_context, WP_Block_Type $block_type ): array { + if ( 'core/image' === $block_type->name ) { + // Use array_values to reset the array keys after merging. + return array_values( array_unique( array_merge( $uses_context, array( 'ancestor_block_align' ) ) ) ); + } + return $uses_context; +} + +/** + * Modifies the block context during rendering to blocks. + * + * @since n.e.x.t + * + * @param array $context Current block context. + * @param array $block The block being rendered. + * @return array Modified block context. + */ +function auto_sizes_modify_render_block_context( array $context, array $block ): array { + if ( 'core/group' === $block['blockName'] || 'core/columns' === $block['blockName'] ) { + $context['ancestor_block_align'] = $block['attrs']['align'] ?? ''; + } + return $context; +} diff --git a/plugins/auto-sizes/tests/test-improve-calculate-sizes.php b/plugins/auto-sizes/tests/test-improve-calculate-sizes.php index ca19201626..188d73065d 100644 --- a/plugins/auto-sizes/tests/test-improve-calculate-sizes.php +++ b/plugins/auto-sizes/tests/test-improve-calculate-sizes.php @@ -389,41 +389,146 @@ public function test_no_image(): void { /** * Test that the layout property of a group block is passed by context to the image block. * - * @group test + * @dataProvider data_ancestor_and_image_block_alignment + * + * @param string $ancestor_block_alignment Ancestor block alignment. + * @param string $image_block_alignment Image block alignment. + * @param string $expected Expected output. */ - public function test_ancestor_layout_is_passed_by_context(): void { + public function test_ancestor_layout_is_passed_by_context( string $ancestor_block_alignment, string $image_block_alignment, string $expected ): void { $block_content = $this->get_group_block_markup( - $this->get_image_block_markup( self::$image_id, 'large', 'full' ) + $this->get_image_block_markup( self::$image_id, 'large', $image_block_alignment ), + array( + 'align' => $ancestor_block_alignment, + ) ); $result = apply_filters( 'the_content', $block_content ); - $this->assertStringContainsString( 'sizes="(max-width: 620px) 100vw, 620px" ', $result ); + $this->assertStringContainsString( $expected, $result ); } + /** + * Data provider. + * + * @return array> The ancestor and image alignments. + */ + public function data_ancestor_and_image_block_alignment(): array { + return array( + // Parent default alignment. + 'Return contentSize 620px, parent block default alignment, image block default alignment' => array( + '', + '', + 'sizes="(max-width: 620px) 100vw, 620px" ', + ), + 'Return contentSize 620px, parent block default alignment, image block wide alignment' => array( + '', + 'wide', + 'sizes="(max-width: 620px) 100vw, 620px" ', + ), + 'Return contentSize 620px, parent block default alignment, image block full alignment' => array( + '', + 'full', + 'sizes="(max-width: 620px) 100vw, 620px" ', + ), + 'Return contentSize 620px, parent block default alignment, image block left alignment' => array( + '', + 'left', + 'sizes="(max-width: 620px) 100vw, 620px" ', + ), + 'Return contentSize 620px, parent block default alignment, image block center alignment' => array( + '', + 'center', + 'sizes="(max-width: 620px) 100vw, 620px" ', + ), + 'Return contentSize 620px, parent block default alignment, image block right alignment' => array( + '', + 'right', + 'sizes="(max-width: 620px) 100vw, 620px" ', + ), + + // Parent wide alignment. + 'Return contentSize 620px, parent block wide alignment, image block default alignment' => array( + 'wide', + '', + 'sizes="(max-width: 620px) 100vw, 620px" ', + ), + 'Return wideSize 1280px, parent block wide alignment, image block wide alignment' => array( + 'wide', + 'wide', + 'sizes="(max-width: 1280px) 100vw, 1280px" ', + ), + 'Return wideSize 1280px, parent block wide alignment, image block full alignment' => array( + 'wide', + 'full', + 'sizes="(max-width: 1280px) 100vw, 1280px" ', + ), + 'Return image size 1024px, parent block wide alignment, image block left alignment' => array( + 'wide', + 'left', + 'sizes="(max-width: 1024px) 100vw, 1024px" ', + ), + 'Return image size 1024px, parent block wide alignment, image block center alignment' => array( + 'wide', + 'center', + 'sizes="(max-width: 1024px) 100vw, 1024px" ', + ), + 'Return image size 1024px, parent block wide alignment, image block right alignment' => array( + 'wide', + 'right', + 'sizes="(max-width: 1024px) 100vw, 1024px" ', + ), + + // Parent full alignment. + 'Return contentSize 620px, parent block full alignment, image block default alignment' => array( + 'full', + '', + 'sizes="(max-width: 620px) 100vw, 620px" ', + ), + 'Return wideSize 1280px, parent block full alignment, image block wide alignment' => array( + 'full', + 'wide', + 'sizes="(max-width: 1280px) 100vw, 1280px" ', + ), + 'Return full size, parent block full alignment, image block full alignment' => array( + 'full', + 'full', + 'sizes="100vw" ', + ), + 'Return image size 1024px, parent block full alignment, image block left alignment' => array( + 'full', + 'left', + 'sizes="(max-width: 1024px) 100vw, 1024px" ', + ), + 'Return image size 1024px, parent block full alignment, image block center alignment' => array( + 'full', + 'center', + 'sizes="(max-width: 1024px) 100vw, 1024px" ', + ), + 'Return image size 1024px, parent block full alignment, image block right alignment' => array( + 'full', + 'right', + 'sizes="(max-width: 1024px) 100vw, 1024px" ', + ), + ); + } /** * Helper to generate image block markup. * * @param int $attachment_id Attachment ID. * @param string $size Optional. Image size. Default 'full'. - * @param string $align Optional. Image alignment. Default null. + * @param string $align Optional. Image alignment. Default null. * @return string Image block markup. */ public function get_image_block_markup( int $attachment_id, string $size = 'full', string $align = null ): string { $image_url = wp_get_attachment_image_url( $attachment_id, $size ); - $atts = wp_parse_args( - array( - 'id' => $attachment_id, - 'sizeSlug' => $size, - 'align' => $align, - ), - array( - 'id' => $attachment_id, - 'sizeSlug' => 'large', - 'linkDestination' => 'none', - ) + $atts = array( + 'id' => $attachment_id, + 'sizeSlug' => $size, + 'align' => $align, + 'linkDestination' => 'none', ); return '
';