Skip to content

Accurate Sizes: Incorporate layout constraints in image sizes calculations #1738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
3d61681
Update existing code with new approach
mukeshpanchal27 Oct 22, 2024
614b1a5
Merge pull request #1623 from WordPress/trunk
mukeshpanchal27 Oct 23, 2024
4396c78
Fix spell
mukeshpanchal27 Oct 23, 2024
8edeb67
Merge branch 'feature/1511-incorporate-layout-constraints-from-ancest…
mukeshpanchal27 Oct 23, 2024
af890e2
Disable lazy loading attribute for unit tests
mukeshpanchal27 Oct 23, 2024
d9af569
Fix comment indention
mukeshpanchal27 Oct 24, 2024
b87adcf
Use HTML API for attachment cache
mukeshpanchal27 Oct 24, 2024
bfdab10
Address review feedback
mukeshpanchal27 Oct 25, 2024
97dcb8f
Apply suggestions from code review
mukeshpanchal27 Oct 28, 2024
2cbf39d
Add types for function variables
mukeshpanchal27 Oct 28, 2024
4c7faa0
Fix lint PHP
mukeshpanchal27 Oct 28, 2024
dd0e12b
Apply suggestions from code review
mukeshpanchal27 Nov 6, 2024
fad4e87
Remove unused parameter from auto_sizes_prime_attachment_caches()
mukeshpanchal27 Nov 6, 2024
198f2cd
Fix PHPStan error
mukeshpanchal27 Nov 6, 2024
de20e12
Added inline comment for filter priority
mukeshpanchal27 Nov 15, 2024
9e276f1
Merge pull request #1663 from WordPress/trunk
felixarntz Nov 18, 2024
69ac2e1
Merge branch 'feature/1511-incorporate-layout-constraints-from-ancest…
mukeshpanchal27 Nov 18, 2024
ad51973
Update priority for prime attachement cache
mukeshpanchal27 Nov 22, 2024
6b8747c
Remove message
mukeshpanchal27 Nov 22, 2024
c06b4e7
Update function doc
mukeshpanchal27 Nov 22, 2024
6e9f892
Merge pull request #1625 from WordPress/update/use-filter-approach
joemcgill Nov 22, 2024
7f3e44d
Merge branch 'trunk' into feature/1511-incorporate-layout-constraints…
joemcgill Nov 22, 2024
63b2544
Separate file structure by feature
joemcgill Nov 25, 2024
7cd300a
Rename /inc to /includes
joemcgill Nov 25, 2024
11a63e2
Rename test class
joemcgill Nov 25, 2024
042232f
Add tests for passing parent alignment context to images
joemcgill Nov 25, 2024
9ffe60c
Merge pull request #1699 from WordPress/update/separate-file-structure
mukeshpanchal27 Nov 26, 2024
47c6779
POC - Pass group block alignment context to image block
mukeshpanchal27 Nov 26, 2024
894ed57
Fix spell
mukeshpanchal27 Nov 26, 2024
cf8691a
Clean up
mukeshpanchal27 Nov 26, 2024
ee5f028
Merge branch 'feature/1511-incorporate-layout-constraints-from-ancest…
joemcgill Nov 26, 2024
93d3f08
Remove test group from unit test
mukeshpanchal27 Nov 28, 2024
f1ec64d
Move add_filter() calls in hooks.php
mukeshpanchal27 Nov 28, 2024
2735713
Remove unused wp_parse_args from unit test
mukeshpanchal27 Nov 28, 2024
b84d33e
Remove parent block context instead use existing key for check
mukeshpanchal27 Nov 28, 2024
5a9ce37
Bump unit test WP version to 6.6
mukeshpanchal27 Nov 28, 2024
2085845
Merge pull request #1704 from WordPress/update/poc-pass-alignment-by-…
mukeshpanchal27 Nov 28, 2024
de77338
implement static cache
mukeshpanchal27 Dec 2, 2024
ae82ccd
Separate function for width calculation and format sizes attribute
mukeshpanchal27 Dec 3, 2024
8189d71
Remove unused old function
mukeshpanchal27 Dec 3, 2024
d209703
Merge branch 'trunk' into feature/1511-incorporate-layout-constraints…
joemcgill Dec 3, 2024
2f03e55
Merge branch 'feature/1511-incorporate-layout-constraints-from-ancest…
joemcgill Dec 3, 2024
25d95ea
Rename filter callbacks for consistency
joemcgill Dec 3, 2024
9677bca
Simplify passing of context for sizes calculation
joemcgill Dec 5, 2024
5c6f7fd
Simplify context logic further
joemcgill Dec 5, 2024
df8741f
Remove unused auto_sizes_get_width function
joemcgill Dec 5, 2024
0790b92
Minor docbock update
mukeshpanchal27 Dec 6, 2024
8ca8b27
WIP: fix center alignments and cover blocks
joemcgill Dec 10, 2024
83be032
Return accurate sizes for center alignment
mukeshpanchal27 Dec 11, 2024
d3a60d0
Improve cover block left/right alignment
joemcgill Dec 12, 2024
266e457
Initial review feedback improvements
joemcgill Dec 12, 2024
aecb3de
Force resize width to be an int
joemcgill Dec 12, 2024
7fb1962
Additional type casting fixes
joemcgill Dec 12, 2024
59e86f8
Merge pull request #1701 from WordPress/update/pass-alignment-by-context
joemcgill Dec 12, 2024
501c65e
Initial concept for supporting relative alingment widths
joemcgill Dec 12, 2024
e69b2af
Revert unwanted doc indention changes
mukeshpanchal27 Dec 13, 2024
7dd60d5
Chance typing for `sprintf()` placeholder
joemcgill Dec 13, 2024
35988a4
Add tests for relative alignment
joemcgill Dec 13, 2024
aa340dc
Merge pull request #1737 from WordPress/update/1511-support-relative-…
joemcgill Dec 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions plugins/auto-sizes/auto-sizes.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@

define( 'IMAGE_AUTO_SIZES_VERSION', '1.3.0' );

require_once __DIR__ . '/includes/auto-sizes.php';
require_once __DIR__ . '/includes/improve-calculate-sizes.php';
require_once __DIR__ . '/hooks.php';
234 changes: 11 additions & 223 deletions plugins/auto-sizes/hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,102 +10,6 @@
exit; // Exit if accessed directly.
}

/**
* Adds auto to the sizes attribute to the image, if applicable.
*
* @since 1.0.0
*
* @param array<string, string>|mixed $attr Attributes for the image markup.
* @return array<string, string> The filtered attributes for the image markup.
*/
function auto_sizes_update_image_attributes( $attr ): array {
if ( ! is_array( $attr ) ) {
$attr = array();
}

// Bail early if the image is not lazy-loaded.
if ( ! isset( $attr['loading'] ) || 'lazy' !== $attr['loading'] ) {
return $attr;
}

// Bail early if the image is not responsive.
if ( ! isset( $attr['sizes'] ) ) {
return $attr;
}

// Don't add 'auto' to the sizes attribute if it already exists.
if ( auto_sizes_attribute_includes_valid_auto( $attr['sizes'] ) ) {
return $attr;
}

$attr['sizes'] = 'auto, ' . $attr['sizes'];

return $attr;
}

/**
* Adds auto to the sizes attribute to the image, if applicable.
*
* @since 1.0.0
*
* @param string|mixed $html The HTML image tag markup being filtered.
* @return string The filtered HTML image tag markup.
*/
function auto_sizes_update_content_img_tag( $html ): string {
if ( ! is_string( $html ) ) {
$html = '';
}

$processor = new WP_HTML_Tag_Processor( $html );

// Bail if there is no IMG tag.
if ( ! $processor->next_tag( array( 'tag_name' => 'IMG' ) ) ) {
return $html;
}

// Bail early if the image is not lazy-loaded.
$value = $processor->get_attribute( 'loading' );
if ( ! is_string( $value ) || 'lazy' !== strtolower( trim( $value, " \t\f\r\n" ) ) ) {
return $html;
}

$sizes = $processor->get_attribute( 'sizes' );

// Bail early if the image is not responsive.
if ( ! is_string( $sizes ) ) {
return $html;
}

// Don't add 'auto' to the sizes attribute if it already exists.
if ( auto_sizes_attribute_includes_valid_auto( $sizes ) ) {
return $html;
}

$processor->set_attribute( 'sizes', "auto, $sizes" );
return $processor->get_updated_html();
}

// Skip loading plugin filters if WordPress Core already loaded the functionality.
if ( ! function_exists( 'wp_sizes_attribute_includes_valid_auto' ) ) {
add_filter( 'wp_get_attachment_image_attributes', 'auto_sizes_update_image_attributes' );
add_filter( 'wp_content_img_tag', 'auto_sizes_update_content_img_tag' );
}

/**
* Checks whether the given 'sizes' attribute includes the 'auto' keyword as the first item in the list.
*
* Per the HTML spec, if present it must be the first entry.
*
* @since 1.2.0
*
* @param string $sizes_attr The 'sizes' attribute value.
* @return bool True if the 'auto' keyword is present, false otherwise.
*/
function auto_sizes_attribute_includes_valid_auto( string $sizes_attr ): bool {
list( $first_size ) = explode( ',', $sizes_attr, 2 );
return 'auto' === strtolower( trim( $first_size, " \t\f\r\n" ) );
}

/**
* Displays the HTML generator tag for the plugin.
*
Expand All @@ -120,135 +24,19 @@ function auto_sizes_render_generator(): void {
add_action( 'wp_head', 'auto_sizes_render_generator' );

/**
* Gets the smaller image size if the layout width is bigger.
*
* It will return the smaller image size and return "px" if the layout width
* is something else, e.g. min(640px, 90vw) or 90vw.
*
* @since 1.1.0
*
* @param string $layout_width The layout width.
* @param int $image_width The image width.
* @return string The proper width after some calculations.
* Filters related to the auto-sizes functionality.
*/
function auto_sizes_get_width( string $layout_width, int $image_width ): string {
if ( str_ends_with( $layout_width, 'px' ) ) {
return $image_width > (int) $layout_width ? $layout_width : $image_width . 'px';
}
return $image_width . 'px';
}

/**
* Filter the sizes attribute for images to improve the default calculation.
*
* @since 1.1.0
*
* @param string $content The block content about to be rendered.
* @param array{ attrs?: array{ align?: string, width?: string } } $parsed_block The parsed block.
* @return string The updated block content.
*/
function auto_sizes_filter_image_tag( string $content, array $parsed_block ): string {
$processor = new WP_HTML_Tag_Processor( $content );
$has_image = $processor->next_tag( array( 'tag_name' => 'img' ) );

// Only update the markup if an image is found.
if ( $has_image ) {
$processor->set_attribute( 'data-needs-sizes-update', true );
if ( isset( $parsed_block['attrs']['align'] ) ) {
$processor->set_attribute( 'data-align', $parsed_block['attrs']['align'] );
}

// Resize image width.
if ( isset( $parsed_block['attrs']['width'] ) ) {
$processor->set_attribute( 'data-resize-width', $parsed_block['attrs']['width'] );
}

$content = $processor->get_updated_html();
}
return $content;
// Skip loading plugin filters if WordPress Core already loaded the functionality.
if ( ! function_exists( 'wp_img_tag_add_auto_sizes' ) ) {
add_filter( 'wp_get_attachment_image_attributes', 'auto_sizes_update_image_attributes' );
add_filter( 'wp_content_img_tag', 'auto_sizes_update_content_img_tag' );
}
add_filter( 'render_block_core/image', 'auto_sizes_filter_image_tag', 10, 2 );
add_filter( 'render_block_core/cover', 'auto_sizes_filter_image_tag', 10, 2 );

/**
* Filter the sizes attribute for images to improve the default calculation.
*
* @since 1.1.0
*
* @param string $content The block content about to be rendered.
* @return string The updated block content.
* Filters related to the improved image sizes functionality.
*/
function auto_sizes_improve_image_sizes_attributes( string $content ): string {
$processor = new WP_HTML_Tag_Processor( $content );
if ( ! $processor->next_tag( array( 'tag_name' => 'img' ) ) ) {
return $content;
}

$remove_data_attributes = static function () use ( $processor ): void {
$processor->remove_attribute( 'data-needs-sizes-update' );
$processor->remove_attribute( 'data-align' );
$processor->remove_attribute( 'data-resize-width' );
};

// Bail early if the responsive images are disabled.
if ( null === $processor->get_attribute( 'sizes' ) ) {
$remove_data_attributes();
return $processor->get_updated_html();
}

// Skips second time parsing if already processed.
if ( null === $processor->get_attribute( 'data-needs-sizes-update' ) ) {
return $content;
}

$align = $processor->get_attribute( 'data-align' );

// Retrieve width from the image tag itself.
$image_width = $processor->get_attribute( 'width' );
if ( ! is_string( $image_width ) && ! in_array( $align, array( 'full', 'wide' ), true ) ) {
return $content;
}

$layout = wp_get_global_settings( array( 'layout' ) );

$sizes = null;
// Handle different alignment use cases.
switch ( $align ) {
case 'full':
$sizes = '100vw';
break;

case 'wide':
if ( array_key_exists( 'wideSize', $layout ) ) {
$sizes = sprintf( '(max-width: %1$s) 100vw, %1$s', $layout['wideSize'] );
}
break;

case 'left':
case 'right':
case 'center':
// Resize image width.
$image_width = $processor->get_attribute( 'data-resize-width' ) ?? $image_width;
$sizes = sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $image_width );
break;

default:
if ( array_key_exists( 'contentSize', $layout ) ) {
// Resize image width.
$image_width = $processor->get_attribute( 'data-resize-width' ) ?? $image_width;
$width = auto_sizes_get_width( $layout['contentSize'], (int) $image_width );
$sizes = sprintf( '(max-width: %1$s) 100vw, %1$s', $width );
}
break;
}

if ( is_string( $sizes ) ) {
$processor->set_attribute( 'sizes', $sizes );
}

$remove_data_attributes();

return $processor->get_updated_html();
}
// Run filter prior to auto sizes "auto_sizes_update_content_img_tag" filter.
add_filter( 'wp_content_img_tag', 'auto_sizes_improve_image_sizes_attributes', 9 );
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_filter_uses_context', 10, 2 );
add_filter( 'render_block_context', 'auto_sizes_filter_render_block_context', 10, 2 );
97 changes: 97 additions & 0 deletions plugins/auto-sizes/includes/auto-sizes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php
/**
* Functionality to implement auto-sizes for lazy loaded images.
*
* @package auto-sizes
* @since n.e.x.t
*/

/**
* Adds auto to the sizes attribute to the image, if applicable.
*
* @since 1.0.0
*
* @param array<string, string>|mixed $attr Attributes for the image markup.
* @return array<string, string> The filtered attributes for the image markup.
*/
function auto_sizes_update_image_attributes( $attr ): array {
if ( ! is_array( $attr ) ) {
$attr = array();
}

// Bail early if the image is not lazy-loaded.
if ( ! isset( $attr['loading'] ) || 'lazy' !== $attr['loading'] ) {
return $attr;
}

// Bail early if the image is not responsive.
if ( ! isset( $attr['sizes'] ) ) {
return $attr;
}

// Don't add 'auto' to the sizes attribute if it already exists.
if ( auto_sizes_attribute_includes_valid_auto( $attr['sizes'] ) ) {
return $attr;
}

$attr['sizes'] = 'auto, ' . $attr['sizes'];

return $attr;
}

/**
* Adds auto to the sizes attribute to the image, if applicable.
*
* @since 1.0.0
*
* @param string|mixed $html The HTML image tag markup being filtered.
* @return string The filtered HTML image tag markup.
*/
function auto_sizes_update_content_img_tag( $html ): string {
if ( ! is_string( $html ) ) {
$html = '';
}

$processor = new WP_HTML_Tag_Processor( $html );

// Bail if there is no IMG tag.
if ( ! $processor->next_tag( array( 'tag_name' => 'IMG' ) ) ) {
return $html;
}

// Bail early if the image is not lazy-loaded.
$value = $processor->get_attribute( 'loading' );
if ( ! is_string( $value ) || 'lazy' !== strtolower( trim( $value, " \t\f\r\n" ) ) ) {
return $html;
}

$sizes = $processor->get_attribute( 'sizes' );

// Bail early if the image is not responsive.
if ( ! is_string( $sizes ) ) {
return $html;
}

// Don't add 'auto' to the sizes attribute if it already exists.
if ( auto_sizes_attribute_includes_valid_auto( $sizes ) ) {
return $html;
}

$processor->set_attribute( 'sizes', "auto, $sizes" );
return $processor->get_updated_html();
}

/**
* Checks whether the given 'sizes' attribute includes the 'auto' keyword as the first item in the list.
*
* Per the HTML spec, if present it must be the first entry.
*
* @since 1.2.0
*
* @param string $sizes_attr The 'sizes' attribute value.
* @return bool True if the 'auto' keyword is present, false otherwise.
*/
function auto_sizes_attribute_includes_valid_auto( string $sizes_attr ): bool {
list( $first_size ) = explode( ',', $sizes_attr, 2 );
return 'auto' === strtolower( trim( $first_size, " \t\f\r\n" ) );
}
Loading
Loading