diff --git a/projects/plugins/jetpack/changelog/update-featured-images-fallback-add-srcset b/projects/plugins/jetpack/changelog/update-featured-images-fallback-add-srcset new file mode 100644 index 0000000000000..89340a389dbeb --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-featured-images-fallback-add-srcset @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Featured images fallback: add srcset diff --git a/projects/plugins/jetpack/class.jetpack-post-images.php b/projects/plugins/jetpack/class.jetpack-post-images.php index e31455bed1667..40474b48197ed 100644 --- a/projects/plugins/jetpack/class.jetpack-post-images.php +++ b/projects/plugins/jetpack/class.jetpack-post-images.php @@ -765,9 +765,10 @@ public static function get_images( $post_id, $args = array() ) { * @param array $image Array containing details of the image. * @param int $base_width Base image width (i.e., the width at 1x). * @param int $base_height Base image height (i.e., the height at 1x). + * @param bool $use_widths Whether to generate the srcset with widths instead of multipliers. * @return string The srcset for the image. */ - public static function generate_cropped_srcset( $image, $base_width, $base_height ) { + public static function generate_cropped_srcset( $image, $base_width, $base_height, $use_widths = false ) { $srcset = ''; if ( ! is_array( $image ) || empty( $image['src'] ) || empty( $image['src_width'] ) ) { @@ -783,12 +784,17 @@ public static function generate_cropped_srcset( $image, $base_width, $base_heigh break; } - $srcset_url = self::fit_image_url( + $srcset_url = self::fit_image_url( $image['src'], $srcset_width, $srcset_height ); - $srcset_values[] = "{$srcset_url} {$multiplier}x"; + + if ( $use_widths ) { + $srcset_values[] = "{$srcset_url} {$srcset_width}w"; + } else { + $srcset_values[] = "{$srcset_url} {$multiplier}x"; + } } if ( count( $srcset_values ) > 1 ) { diff --git a/projects/plugins/jetpack/modules/theme-tools/content-options/featured-images-fallback.php b/projects/plugins/jetpack/modules/theme-tools/content-options/featured-images-fallback.php index 5140914fa5096..59c6e7dd48f31 100644 --- a/projects/plugins/jetpack/modules/theme-tools/content-options/featured-images-fallback.php +++ b/projects/plugins/jetpack/modules/theme-tools/content-options/featured-images-fallback.php @@ -58,12 +58,66 @@ function jetpack_featured_images_fallback_get_image( $html, $post_id, $post_thum $image['crop'] = $_wp_additional_image_sizes[ $size ]['crop']; } - $image_src = Jetpack_PostImages::fit_image_url( $image['src'], $image['width'], $image['height'] ); + // Force `crop` to be a simple boolean, to avoid dealing with WP crop positions. + $image['crop'] = boolval( $image['crop'] ); + + $image_sizes = ''; + + if ( $image['src_width'] && $image['src_height'] && $image['width'] && $image['height'] ) { + $width = intval( $image['width'] ); + $height = intval( $image['height'] ); + $src_width = intval( $image['src_width'] ); + $src_height = intval( $image['src_height'] ); + + // If we're aware of the source dimensions, calculate the final image height and width. + // This allows us to provide them as attributes in the `` tag, to avoid layout shifts. + // It also allows us to calculate a `srcset`. + if ( $image['crop'] ) { + // If we're cropping, the final dimensions are calculated independently of each other. + $width = min( $width, $src_width ); + $height = min( $height, $src_height ); + } else { + // If we're not cropping, we need to preserve aspect ratio. + $dims = wp_constrain_dimensions( $src_width, $src_height, $width, $height ); + $width = $dims[0]; + $height = $dims[1]; + } + + $image_src = Jetpack_PostImages::fit_image_url( $image['src'], $width, $height ); + $image_srcset = Jetpack_PostImages::generate_cropped_srcset( $image, $width, $height, true ); + $image_sizes = 'min(' . $width . 'px, 100vw)'; + } else { + // If we're not aware of the source dimensions, leave the size calculations to the CDN, and + // fall back to a simpler `` tag without `width`/`height` or `srcset`. + $image_src = Jetpack_PostImages::fit_image_url( $image['src'], $image['width'], $image['height'] ); + + // Use the theme's crop setting rather than forcing to true. + $image_src = add_query_arg( 'crop', $image['crop'], $image_src ); + } - // Use the theme's crop setting rather than forcing to true. - $image_src = add_query_arg( 'crop', $image['crop'], $image_src ); + $default_attr = array( + 'srcset' => $image_srcset, + 'sizes' => $image_sizes, + 'loading' => is_singular() ? 'eager' : 'lazy', + 'decoding' => 'async', + 'title' => wp_strip_all_tags( get_the_title() ), + 'alt' => '', + 'class' => "attachment-$size wp-post-image", + ); + + $image_attr = wp_parse_args( $attr, $default_attr ); + $hwstring = image_hwstring( $width, $height ); + + $html = rtrim( " $value ) { + if ( $value ) { + $html .= " $name=" . '"' . esc_attr( $value ) . '"'; + } + } - $html = ''; + $html .= ' />'; return trim( $html ); }