Skip to content
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

Render widget areas referencing blocks in a wp_area post on the website frontend #15651

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
120 changes: 115 additions & 5 deletions lib/class-experimental-wp-widget-blocks-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
* @since 5.7.0
*/
class Experimental_WP_Widget_Blocks_Manager {

/**
* Array of sidebar_widgets as it was before the filter swap_out_sidebars_blocks_for_block_widgets was ever executed.
*
* @var array
*/
private static $unfiltered_sidebar_widgets = null;

/**
* Returns the $wp_registered_widgets global.
*
Expand Down Expand Up @@ -42,14 +50,23 @@ private static function get_wp_registered_sidebars() {
*
* @since 5.7.0
*
* @param string $sidebar_id Indentifier of the sidebar.
* @param string $sidebar_id Identifier of the sidebar.
* @return array Sidebar structure.
*/
public static function get_wp_registered_sidebars_sidebar( $sidebar_id ) {
$wp_registered_sidebars = self::get_wp_registered_sidebars();
return $wp_registered_sidebars[ $sidebar_id ];
}

/**
* Returns the result of wp_get_sidebars_widgets without swap_out_sidebars_blocks_for_block_widgets filter being applied.
*
* @since 5.7.0
*/
private static function get_raw_sidebar_widgets() {
return self::$unfiltered_sidebar_widgets;
}

/**
* Returns a post id being referenced in a sidebar area.
*
Expand All @@ -59,7 +76,7 @@ public static function get_wp_registered_sidebars_sidebar( $sidebar_id ) {
* @return integer Post id.
*/
public static function get_post_id_referenced_in_sidebar( $sidebar_id ) {
$sidebars = wp_get_sidebars_widgets();
$sidebars = self::get_raw_sidebar_widgets();
$sidebar = $sidebars[ $sidebar_id ];
return is_numeric( $sidebar ) ? $sidebar : 0;
}
Expand All @@ -73,7 +90,7 @@ public static function get_post_id_referenced_in_sidebar( $sidebar_id ) {
* @param integer $post_id Post id.
*/
public static function reference_post_id_in_sidebar( $sidebar_id, $post_id ) {
$sidebars = wp_get_sidebars_widgets();
$sidebars = self::get_raw_sidebar_widgets();
$sidebar = $sidebars[ $sidebar_id ];
wp_set_sidebars_widgets(
array_merge(
Expand All @@ -100,7 +117,8 @@ public static function reference_post_id_in_sidebar( $sidebar_id, $post_id ) {
public static function get_sidebar_as_blocks( $sidebar_id ) {
$blocks = array();

$sidebars_items = wp_get_sidebars_widgets();
$sidebars_items = self::get_raw_sidebar_widgets();
$wp_registered_sidebars = self::get_wp_registered_sidebars();

foreach ( $sidebars_items[ $sidebar_id ] as $item ) {
$widget_class = self::get_widget_class( $item );
Expand All @@ -109,7 +127,7 @@ public static function get_sidebar_as_blocks( $sidebar_id ) {
'attrs' => array(
'class' => $widget_class,
'identifier' => $item,
'instance' => self::get_sidebar_widget_instance( $sidebar, $item ),
'instance' => self::get_sidebar_widget_instance( $wp_registered_sidebars[ $sidebar_id ], $item ),
),
'innerHTML' => '',
);
Expand Down Expand Up @@ -245,6 +263,9 @@ public static function serialize_blocks( $blocks ) {
* @return string String representing the block.
*/
public static function serialize_block( $block ) {
if ( ! isset( $block['blockName'] ) ) {
return false;
}
$name = $block['blockName'];
if ( 0 === strpos( $name, 'core/' ) ) {
$name = substr( $name, strlen( 'core/' ) );
Expand All @@ -271,4 +292,93 @@ public static function serialize_block( $block ) {
);
}
}

/**
* Outputs a block widget on the website frontend.
*
* @param array $options Widget options.
* @param array $arguments Arguments array.
*/
public static function output_blocks_widget( $options, $arguments ) {
echo $options['before_widget'];
foreach ( $arguments['blocks'] as $block ) {
echo render_block( $block );
}
echo $options['after_widget'];
}

/**
* Registers of a widget that should represent a set of blocks and returns its id.
*
* @param array $blocks Array of blocks.
*/
public static function convert_blocks_to_widget( $blocks ) {
$widget_id = 'blocks-widget-' . md5( self::serialize_blocks( $blocks ) );
global $wp_registered_widgets;
if ( isset( $wp_registered_widgets[ $widget_id ] ) ) {
return $widget_id;
}
wp_register_sidebar_widget(
$widget_id,
__( 'Blocks Area ', 'gutenberg' ),
'Experimental_WP_Widget_Blocks_Manager::output_blocks_widget',
array(
'classname' => 'widget-area',
'description' => __( 'Displays a set of blocks', 'gutenberg' ),
),
array(
'blocks' => $blocks,
)
);
return $widget_id;
}

/**
* Filters the $sidebars_widgets to exchange wp_area post id with a widget that renders that block area.
*
* @param array $sidebars_widgets_input An associative array of sidebars and their widgets.
*/
public static function swap_out_sidebars_blocks_for_block_widgets( $sidebars_widgets_input ) {
global $sidebars_widgets;
if ( null === self::$unfiltered_sidebar_widgets ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If gutenberg_swap_out_sidebars_blocks_for_block_widgets is called again with a different $sidebars_widgets_input then this won't update its cached copy of self::$unfiltered_sidebar_widgets.

We probably want:

if ( $sidebars_widgets_input !== self::$unfiltered_sidebar_widgets ) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, not sure about this. Maybe it's not a problem. Is global $sidebars_widgets ever updated?

self::$unfiltered_sidebar_widgets = $sidebars_widgets;
}
$filtered_sidebar_widgets = array();
foreach ( $sidebars_widgets_input as $sidebar_id => $item ) {
if ( ! is_numeric( $item ) ) {
$filtered_sidebar_widgets[ $sidebar_id ] = $item;
continue;
}

$filtered_widgets = array();
$last_set_of_blocks = array();
$post = get_post( $item );
$blocks = parse_blocks( $post->post_content );

foreach ( $blocks as $block ) {
if ( ! isset( $block['blockName'] ) ) {
continue;
}
if (
'core/legacy-widget' === $block['blockName'] &&
isset( $block['attrs']['identifier'] )
) {
if ( ! empty( $last_set_of_blocks ) ) {
$filtered_widgets[] = self::convert_blocks_to_widget( $last_set_of_blocks );
$last_set_of_blocks = array();
}
$filtered_widgets[] = $block['attrs']['identifier'];
} else {
$last_set_of_blocks[] = $block;
}
}
if ( ! empty( $last_set_of_blocks ) ) {
$filtered_widgets[] = self::convert_blocks_to_widget( $last_set_of_blocks );
}

$filtered_sidebar_widgets[ $sidebar_id ] = $filtered_widgets;
}
$sidebars_widgets = $filtered_sidebar_widgets;
return $filtered_sidebar_widgets;
}
}
2 changes: 1 addition & 1 deletion lib/class-wp-rest-widget-areas-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function register_routes() {
'description' => __( 'The sidebar’s ID.', 'gutenberg' ),
'type' => 'string',
'required' => true,
'validate_callback' => array( $this, 'is_valid_sidabar_id' ),
'validate_callback' => 'Experimental_WP_Widget_Blocks_Manager::is_valid_sidabar_id',
);

$content_argument = array(
Expand Down
2 changes: 2 additions & 0 deletions lib/widgets.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,5 @@ function gutenberg_create_wp_area_post_type() {
);
}
add_action( 'init', 'gutenberg_create_wp_area_post_type' );

add_filter( 'sidebars_widgets', 'Experimental_WP_Widget_Blocks_Manager::swap_out_sidebars_blocks_for_block_widgets' );