|
<?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'; |
|
} |
|
} |
Thanks @felixarntz for reviewing.
Here the biggest concern is that we don't get the outer most block context in our case for group block. In example you have shown above it didn't get context for group block and it will start adding context for Columns block only.
Note: i have added extra key to check which block set the context, Group or Columns.
If we have Group > Columns > Column ( 66% ) > Image then the result
If we have Group > Columns > Column ( 66% ) > Columns > Column ( 50% ) > Image then the result