This is a WordPress Plugin that improves the default sizes attribute calculation for nested image block in columns.
Last active
August 23, 2024 08:41
-
-
Save mukeshpanchal27/f92bf08c4a0db919c6f50873a7ac3cc3 to your computer and use it in GitHub Desktop.
WPP Column Image Sizes is a proof of concept WordPress plugin that provides a better calculation for nested image block in columns.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: WPP Column Image Sizes | |
* Description: This is a WordPress Plugin that improves the default sizes attribute calculation for for nested image block in columns. | |
* Version: 0.1 | |
* Author: Mukesh Panchal | |
* License: GPL2 | |
*/ | |
/** | |
* 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']['data-columns-align'] ) ) { | |
$processor->set_attribute( 'data-columns-align', $parsed_block['attrs']['data-columns-align'] ); | |
} | |
if ( isset( $parsed_block['attrs']['data-column-width'] ) ) { | |
$processor->set_attribute( 'data-column-width', $parsed_block['attrs']['data-column-width'] ); | |
} | |
$content = $processor->get_updated_html(); | |
} | |
return $content; | |
} | |
add_filter( 'render_block_core/image', '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. | |
*/ | |
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-columns-align' ); | |
$processor->remove_attribute( 'data-column-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; | |
} | |
$column_align = $processor->get_attribute( 'data-columns-align' ); | |
$layout = wp_get_global_settings( array( 'layout' ) ); | |
$sizes = null; | |
switch ( $column_align ) { | |
case 'full': | |
$column_width = $processor->get_attribute( 'data-column-width' ); | |
$column_width = (float) $column_width / 100; | |
$sizes = sprintf( '(max-width: calc(%1$s * %2$s)) 100vw, calc(%1$s * %2$s)', '100vw', $column_width ); | |
break; | |
case 'wide': | |
if ( array_key_exists( 'wideSize', $layout ) ) { | |
$column_width = $processor->get_attribute( 'data-column-width' ); | |
$column_width = (float) $column_width / 100; | |
$sizes = sprintf( '(max-width: calc(%1$s * %2$s)) 100vw, calc(%1$s * %2$s)', $layout['wideSize'], $column_width ); | |
} | |
break; | |
default: | |
if ( array_key_exists( 'contentSize', $layout ) ) { | |
$column_width = $processor->get_attribute( 'data-column-width' ); | |
$column_width = (float) $column_width / 100; | |
$sizes = sprintf( '(max-width: calc(%1$s * %2$s)) 100vw, calc(%1$s * %2$s)', $layout['contentSize'], $column_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 ); | |
/** | |
* Filters the columns block data attribute and supply it to nested image block. | |
* | |
* @param array $parsed_block The parsed block. | |
* @return array The updated parsed block. | |
*/ | |
function auto_sizes_modify_render_block_data( $parsed_block ) { | |
if ( ! empty( $parsed_block['blockName'] ) && 'core/columns' === $parsed_block['blockName'] ) { | |
$columns_align = $parsed_block['attrs']['align'] ?? ''; | |
$column_count = count( $parsed_block['innerBlocks'] ); | |
$column_width = array(); | |
foreach ( $parsed_block['innerBlocks'] as $column_key => $column_inner_block ) { | |
if ( 'core/column' === $column_inner_block['blockName'] ) { | |
$column_width[] = | |
isset( $parsed_block['innerBlocks'][ $column_key ]['attrs']['width'] ) && $parsed_block['innerBlocks'][ $column_key ]['attrs']['width'] ? | |
(float) $parsed_block['innerBlocks'][ $column_key ]['attrs']['width'] : | |
'auto'; | |
} | |
} | |
$actual_column_width = calculate_column_widths( $column_width ); | |
foreach ( $parsed_block['innerBlocks'] as $column_key => $column_inner_block ) { | |
foreach ( $parsed_block['innerBlocks'][ $column_key ]['innerBlocks'] as $key => $inner_block ) { | |
if ( 'core/image' === $inner_block['blockName'] ) { | |
$parsed_block['innerBlocks'][ $column_key ]['innerBlocks'][ $key ]['attrs']['data-columns-align'] = esc_attr( $columns_align ); | |
$parsed_block['innerBlocks'][ $column_key ]['innerBlocks'][ $key ]['attrs']['data-column-width'] = esc_attr( $actual_column_width[ $key ] ); | |
} | |
} | |
} | |
} | |
return $parsed_block; | |
} | |
add_filter( 'render_block_data', 'auto_sizes_modify_render_block_data' ); | |
function calculate_column_widths( $columns ) { | |
$total_percentage = 100; | |
$auto_columns = 0; | |
$fixed_percentage = 0; | |
// First, calculate the total fixed width and count the auto columns. | |
foreach ( $columns as $column ) { | |
if ( $column === 'auto' ) { | |
$auto_columns++; | |
} else { | |
$fixed_percentage += $column; | |
} | |
} | |
// Calculate the width for auto columns. | |
if ( $auto_columns > 0 ) { | |
$auto_width = ( $total_percentage - $fixed_percentage ) / $auto_columns; | |
} else { | |
$auto_width = 0; // No auto columns, no need to calculate. | |
} | |
// Generate the final widths array. | |
$final_widths = []; | |
foreach ( $columns as $column ) { | |
if ( $column === 'auto' ) { | |
$final_widths[] = $auto_width . '%'; | |
} else { | |
$final_widths[] = $column . '%'; | |
} | |
} | |
return $final_widths; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment