|
<?php |
|
/** |
|
* Plugin Name: WPP Column Context |
|
* Version: 0.1 |
|
* Author: Mukesh Panchal |
|
* License: GPL2 |
|
*/ |
|
|
|
namespace WPP_Column_Context; |
|
|
|
use WP_HTML_Tag_Processor; |
|
|
|
// If this file is called directly, abort. |
|
if ( ! defined( 'WPINC' ) ) { |
|
die; |
|
} |
|
|
|
add_filter( |
|
'render_block_context', |
|
function( $context, $block, $parent ) { |
|
// Merge current context into the parent's context. |
|
if ( $parent ) { |
|
$context = array_merge( $parent->context, $context ); |
|
} |
|
|
|
if ( 'core/columns' === $block['blockName'] ) { |
|
$context['wpp-columns'] = count( $block['innerBlocks'] ); |
|
// Extra context for testing. |
|
$context['wpp-columns-extra'] = 'columns-extra'; |
|
} |
|
|
|
// For demo purposes, this assumes all unspecified columns are equal widths |
|
if ( 'core/column' === $block['blockName'] ) { |
|
$context['wpp-col-width'] = $block['attrs']['width'] ?? 'auto'; |
|
// Extra context for testing. |
|
$context['wpp-col-extra'] = 'col-extra'; |
|
} |
|
return $context; |
|
}, |
|
10, |
|
3 |
|
); |
|
|
|
/* |
|
* Inspiration taken from current block binding implementation. |
|
* https://github.com/WordPress/wordpress-develop/blob/6.6/src/wp-includes/class-wp-block-bindings-registry.php#L193-L204 |
|
*/ |
|
add_filter( |
|
'get_block_type_uses_context', |
|
function ( $uses_context, $block_type ) { |
|
if ( 'core/image' === $block_type->name ) { |
|
// Use array_values to reset the array keys. |
|
return array_values( array_unique( array_merge( $uses_context, array( 'wpp-columns','wpp-col-width' ) ) ) ); |
|
} |
|
return $uses_context; |
|
}, |
|
10, |
|
2 |
|
); |
|
|
|
add_filter( 'render_block_core/image', __NAMESPACE__ . '\\wpp_add_image_block_sizes', 10, 3 ); |
|
/** |
|
* Calculate image sizes attribute for an image block during rendering. |
|
* |
|
* @param string $block_content The block content. |
|
* @param array $parsed_block The parsed block data. |
|
* @param WP_Block $wp_block The block instance. |
|
* @return string The updated block content. |
|
*/ |
|
function wpp_add_image_block_sizes( $block_content, $parsed_block, $wp_block ) { |
|
|
|
// If you want to check the context for image block add `?debug` in you url. |
|
if ( isset( $_GET['debug'] ) ) { |
|
echo '<pre>'; |
|
print_r( $wp_block->context ); |
|
echo '</pre>'; |
|
} |
|
/** |
|
* Callback for calculating image sizes attribute value for an image block. |
|
* |
|
* This is a workaround to use block context data when calculating the img sizes attribute. |
|
* |
|
* @since 😎 |
|
* |
|
* @param string $sizes The image sizes attribute value. |
|
* @param array $size The image size data. |
|
*/ |
|
$filter = function( $sizes, $size ) use ( $wp_block ) { |
|
$alignment = $wp_block->attributes['align'] ?? ''; |
|
$columns = $wp_block->context['wpp-columns'] ?? ''; // Consider two columns |
|
$column_width = $wp_block->context['wpp-col-width'] ?? ''; // Consider 50% each width |
|
|
|
// Hypotehtical function to calculate better sizes. |
|
$sizes = wpp_better_sizes_calc( $size, $alignment, $columns, $column_width ); |
|
|
|
return $sizes; |
|
}; |
|
|
|
// Hook this filter early, before default fitlers are run. |
|
add_filter( 'wp_calculate_image_sizes', $filter, 9, 2 ); |
|
|
|
/* |
|
* A performance problem to still be solved with this approach is that |
|
* wp_calculate_image_sizes() will make a DB query to get the image metadata. |
|
* It does this to get the image width, which is needed to calculate |
|
* the sizes attribute. Currently, this function is called from `wp_filter_content_tags` |
|
* which has already primed the cache with the image metadata. That cache priming |
|
* will need to be hanlded earlier if sizes is calculated during block rendering. |
|
*/ |
|
$sizes = wp_calculate_image_sizes( |
|
// If we don't have a size slug, assume the full size was used. |
|
$parsed_block['attrs']['sizeSlug'] ?? 'full', |
|
null, |
|
null, |
|
$parsed_block['attrs']['id'] ?? 0 |
|
); |
|
|
|
remove_filter( 'wp_calculate_image_sizes', $filter, 9 ); |
|
|
|
// Bail early if sizes are not calculated. |
|
if ( ! $sizes ) { |
|
return $block_content; |
|
} |
|
|
|
// Add the sizes attribute to the image tag here. |
|
$processor = new WP_HTML_Tag_Processor( $block_content ); |
|
$processor->next_tag( 'img' ); |
|
$processor->set_attribute( 'sizes', $sizes ); |
|
|
|
$return = $processor->get_updated_html(); |
|
|
|
return $return; |
|
}; |
|
|
|
/** |
|
* Hypothetical function to calculate better sizes. |
|
* |
|
* @param array $size The image size data. |
|
* @param string $alignment The image alignment. |
|
* @param int $columns The column count. |
|
* @param string $column_width The column width. |
|
* @return string The sizes attribute value. |
|
*/ |
|
function wpp_better_sizes_calc( $size, $alignment, $columns, $column_width ) { |
|
switch ( $alignment ) { |
|
case 'full': |
|
return '100vw'; |
|
break; |
|
case 'wide': |
|
// Hard coded wide size from TT4 theme for demo only. |
|
if ( 2 === $columns && '50%' === $column_width ) { // Statically checking for column |
|
return '(max-width: 640px) 100vw, 640px'; |
|
} |
|
return '(max-width: 1280px) 100vw, 1280px'; |
|
break; |
|
default: |
|
// Hard coded wide size from TT4 theme for demo only. |
|
if ( 2 === $columns && '50%' === $column_width ) { // Statically checking for column |
|
return '(max-width: 310px) 100vw, 310px'; |
|
} |
|
return '(max-width: 620px) 100vw, 620px'; |
|
} |
|
} |
@mukeshpanchal27 Some notes on this POC approach:
render_block_context
callback you merge the parent and child contexts. This means that, if you have e.g. a columns block within another column (and thus another columns block), the child columns data will overwrite the parent columns data.block_width_data
.Here's an example for this: Let's say the site's
wideWidth
is 1400px. Let's say we have a group block as the outer most block, withwideWidth
. Then within it a columns block with 3 columns where the first column is 33%, then in the first column another columns block with 2 columns of 50% width. One of these columns contains an image block. Here's what would happen:render_block_context
callback would initialize theblock_width_data
key with a first entry1400px
.33%
toblock_width_data
.50%
toblock_width_data
.block_width_data
and multiply:1400px * 33% * 50% = 231px
sizes
attribute.Here's a rough draft of what the
render_block_context
callback could look like:Curious to get your thoughts on this.