Reduce maximum image size used as background image based on container width#2258
Conversation
…ml tag attributes
… enhancement/reduce-maximum-image-size-used-as-background-image
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## trunk #2258 +/- ##
==========================================
+ Coverage 69.32% 69.37% +0.04%
==========================================
Files 90 90
Lines 7746 7791 +45
==========================================
+ Hits 5370 5405 +35
- Misses 2376 2386 +10
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
…as-background-image
Updated the PHP docblock for clarity and consistency.
There was a problem hiding this comment.
Pull request overview
This PR implements background image size optimization for core/group and core/cover blocks by exposing attachment IDs as data attributes and using URL Metrics to serve appropriately-sized images based on container dimensions.
Changes:
- Added
auto_sizes_add_background_image_data_attributesfunction to extract and expose background image attachment IDs and URLs as data attributes on rendered HTML elements - Implemented
reduce_background_image_sizemethod in Image Prioritizer to downsize background images based on desktop viewport metrics - Registered new filter hooks for core/group and core/cover blocks at priority 5
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php | Added method to reduce background image sizes using attachment IDs from data attributes and URL Metrics |
| plugins/auto-sizes/includes/improve-calculate-sizes.php | Added function to extract background image data from block attributes and add as data attributes to HTML |
| plugins/auto-sizes/hooks.php | Registered filter hooks for core/group and core/cover blocks to add background image data attributes |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Replace the background image URL in the style attribute. | ||
| $style = $processor->get_attribute( 'style' ); | ||
| if ( is_string( $style ) ) { | ||
| $updated_style = str_replace( $background_image_url, $smaller_image_url, $style ); |
There was a problem hiding this comment.
The str_replace approach could potentially replace unintended occurrences if the same URL appears multiple times in the style attribute. While unlikely in practice, consider using a more targeted replacement that specifically replaces within the background-image or background property. Alternatively, verify that this edge case is acceptable for the intended use cases.
| // Replace the background image URL in the style attribute. | |
| $style = $processor->get_attribute( 'style' ); | |
| if ( is_string( $style ) ) { | |
| $updated_style = str_replace( $background_image_url, $smaller_image_url, $style ); | |
| // Replace the background image URL in the background/background-image declarations in the style attribute. | |
| $style = $processor->get_attribute( 'style' ); | |
| if ( is_string( $style ) ) { | |
| $declarations = explode( ';', $style ); | |
| foreach ( $declarations as &$declaration ) { | |
| $trimmed_declaration = ltrim( $declaration ); | |
| if ( | |
| 0 === stripos( $trimmed_declaration, 'background:' ) || | |
| 0 === stripos( $trimmed_declaration, 'background-image:' ) | |
| ) { | |
| $declaration = str_replace( $background_image_url, $smaller_image_url, $declaration ); | |
| } | |
| } | |
| unset( $declaration ); | |
| $updated_style = implode( ';', $declarations ); |
| private function reduce_background_image_size( string $background_image_url, OD_Tag_Visitor_Context $context ): void { | ||
| $processor = $context->processor; | ||
| $xpath = $processor->get_xpath(); | ||
|
|
||
| /* | ||
| * Obtain maximum width of the element exclusively from the URL Metrics group with the widest viewport width, | ||
| * which would be desktop. This prevents the situation where if URL Metrics have only so far been gathered for | ||
| * mobile viewports that an excessively-small background image would end up getting served to the first desktop visitor. | ||
| */ | ||
| $max_element_width = 0; | ||
| foreach ( $context->url_metric_group_collection->get_last_group() as $url_metric ) { | ||
| foreach ( $url_metric->get_elements() as $element ) { | ||
| if ( $element->get_xpath() === $xpath ) { | ||
| $max_element_width = max( $max_element_width, $element->get_bounding_client_rect()['width'] ); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // If the element wasn't present in any URL Metrics gathered for desktop, then abort downsizing the background image. | ||
| if ( 0 === $max_element_width ) { | ||
| return; | ||
| } | ||
|
|
||
| // Try to get the attachment ID from the data attribute (populated via filter from block attributes). | ||
| $attachment_id = $processor->get_attribute( 'data-bg-attachment-id' ); | ||
|
|
||
| if ( is_numeric( $attachment_id ) && $attachment_id > 0 ) { | ||
| $smaller_image_url = wp_get_attachment_image_url( (int) $attachment_id, array( (int) $max_element_width, 0 ) ); | ||
| if ( is_string( $smaller_image_url ) && $smaller_image_url !== $background_image_url ) { | ||
| // Replace the background image URL in the style attribute. | ||
| $style = $processor->get_attribute( 'style' ); | ||
| if ( is_string( $style ) ) { | ||
| $updated_style = str_replace( $background_image_url, $smaller_image_url, $style ); | ||
| $processor->set_attribute( 'style', $updated_style ); | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
The new reduce_background_image_size method lacks test coverage. Consider adding snapshot tests similar to the existing video poster tests (e.g., video-with-large-poster-and-desktop-url-metrics-collected) to verify the background image size reduction functionality works correctly.
| function auto_sizes_add_background_image_data_attributes( $content, array $parsed_block ): string { | ||
| if ( ! is_string( $content ) || '' === $content ) { | ||
| return ''; | ||
| } | ||
|
|
||
| $block_name = $parsed_block['blockName'] ?? ''; | ||
| $attrs = $parsed_block['attrs'] ?? array(); | ||
|
|
||
| // Extract background image data based on block type. | ||
| $attachment_id = null; | ||
| $image_url = null; | ||
|
|
||
| if ( 'core/cover' === $block_name ) { | ||
| $attachment_id = $attrs['id'] ?? null; | ||
| $image_url = $attrs['url'] ?? null; | ||
| } elseif ( 'core/group' === $block_name ) { | ||
| $attachment_id = $attrs['style']['background']['backgroundImage']['id'] ?? null; | ||
| $image_url = $attrs['style']['background']['backgroundImage']['url'] ?? null; | ||
| } else { | ||
| return $content; | ||
| } | ||
|
|
||
| // Validate extracted data. | ||
| if ( | ||
| ! isset( $attachment_id, $image_url ) || | ||
| $attachment_id <= 0 || | ||
| '' === $image_url || | ||
| ! is_array( wp_get_attachment_metadata( $attachment_id ) ) | ||
| ) { | ||
| return $content; | ||
| } | ||
|
|
||
| // Find and update the element with background image. | ||
| $processor = new WP_HTML_Tag_Processor( $content ); | ||
| while ( $processor->next_tag() ) { | ||
| $style = $processor->get_attribute( 'style' ); | ||
| if ( is_string( $style ) && str_contains( $style, 'background-image:' ) && str_contains( $style, $image_url ) ) { | ||
| $processor->set_attribute( 'data-bg-attachment-id', (string) $attachment_id ); | ||
| $processor->set_attribute( 'data-bg-original-url', $image_url ); | ||
| return $processor->get_updated_html(); | ||
| } | ||
| } | ||
|
|
||
| return $content; | ||
| } |
There was a problem hiding this comment.
The new auto_sizes_add_background_image_data_attributes function lacks test coverage. The auto-sizes plugin has comprehensive tests in test-improve-calculate-sizes.php. Consider adding unit tests to verify that data attributes are correctly added to Group and Cover blocks with background images.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…lify return logic Consolidate multiple return statements into a single return at the end of auto_sizes_add_background_image_data_attributes(), keeping only the initial guard clause. Co-authored-by: gemini-cli <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Consolidate duplicated logic for obtaining maximum element width into a protected method in the parent Image_Prioritizer_Tag_Visitor class. The new method returns null if the element is not found, providing a more robust check in subclasses. Co-authored-by: gemini-cli <176961590+gemini-code-assist[bot]@users.noreply.github.com>
… enhancement/reduce-maximum-image-size-used-as-background-image
westonruter
left a comment
There was a problem hiding this comment.
Sorry for the long delay in following up on this.
| // Try to get the attachment ID from the data attribute (populated via filter from block attributes). | ||
| $attachment_id = $processor->get_attribute( 'data-bg-attachment-id' ); |
There was a problem hiding this comment.
There is a plugin dependency issue here. Currently this requires that the auto-sizes plugin be active in order for this attribute to be added. This dependency shouldn't exist. This attribute should be added in the Image Prioritizer plugin for its own use. If the Image Prioritizer plugin isn't active, then the auto-sizes plugin should be able to scale down the image all on its own because it has access to template layout information on its own. The Image Prioritizer implementation is a parallel one which will benefit sites without auto-sizes active, or sites which are using a classic theme in which case the layout information is not available.
| while ( $processor->next_tag() ) { | ||
| $style = $processor->get_attribute( 'style' ); | ||
| if ( is_string( $style ) && str_contains( $style, 'background-image:' ) && str_contains( $style, $image_url ) ) { | ||
| $processor->set_attribute( 'data-bg-attachment-id', (string) $attachment_id ); |
There was a problem hiding this comment.
As noted below, this attribute is being added here exclusively for the use of another plugin: Image Prioritizer. This dependency needs to be removed. Instead, this needs to be determining the size of the block as informed by the layout it has access to based on the block structure on a block template.
In other words, I believe all of the logic here in auto_sizes_filter_render_block_context() needs to be re-factored into auto_sizes_filter_uses_context(), auto_sizes_filter_render_block_context(), and auto_sizes_filter_image_tag(), for example, to follow the pattern of how other blocks are currently handled.
| add_filter( 'render_block_core/group', 'auto_sizes_add_background_image_data_attributes', 5, 2 ); | ||
| add_filter( 'render_block_core/cover', 'auto_sizes_add_background_image_data_attributes', 5, 2 ); |
There was a problem hiding this comment.
Taking auto_sizes_filter_image_tag() for inspiration, something like:
| add_filter( 'render_block_core/group', 'auto_sizes_add_background_image_data_attributes', 5, 2 ); | |
| add_filter( 'render_block_core/cover', 'auto_sizes_add_background_image_data_attributes', 5, 2 ); | |
| add_filter( 'render_block_core/group', 'auto_sizes_filter_background_image_style', 5, 2 ); | |
| add_filter( 'render_block_core/cover', 'auto_sizes_filter_background_image_style', 5, 2 ); |
A new auto_sizes_filter_background_image_style() function will be needed modeled after auto_sizes_filter_image_tag().
Summary
Fixes #2216
Relevant technical choices
This change exposes background image attachment IDs and original URLs from block attributes (core/group and core/cover) as data attributes on the rendered HTML element, and uses those attributes in Image Prioritizer to pick and serve a more appropriate-sized background image. It enables downsizing background images based on collected URL Metrics (preferring desktop metrics to avoid serving overly small images to desktop visitors).
Use of AI Tools