From 9b4f31aa92af80b234643166f395fd5a1f5cd998 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 24 May 2019 10:05:48 +0100 Subject: [PATCH] Render widget areas referencing blocks in a wp_area post on the website frontend (#15651) Here we implement a simple filter that makes a sidebar referencing a post_id reference a simple widget that renders the content of the post. --- ...-experimental-wp-widget-blocks-manager.php | 120 +++++++++++++++++- lib/class-wp-rest-widget-areas-controller.php | 2 +- lib/widgets.php | 2 + 3 files changed, 118 insertions(+), 6 deletions(-) diff --git a/lib/class-experimental-wp-widget-blocks-manager.php b/lib/class-experimental-wp-widget-blocks-manager.php index bb1ac9fa089f76..f2f26e5ef43728 100644 --- a/lib/class-experimental-wp-widget-blocks-manager.php +++ b/lib/class-experimental-wp-widget-blocks-manager.php @@ -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. * @@ -42,7 +50,7 @@ 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 ) { @@ -50,6 +58,15 @@ public static function get_wp_registered_sidebars_sidebar( $sidebar_id ) { 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. * @@ -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; } @@ -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( @@ -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 ); @@ -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' => '', ); @@ -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/' ) ); @@ -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 ) { + 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; + } } diff --git a/lib/class-wp-rest-widget-areas-controller.php b/lib/class-wp-rest-widget-areas-controller.php index 6d333efa96c145..e191a50305c13d 100644 --- a/lib/class-wp-rest-widget-areas-controller.php +++ b/lib/class-wp-rest-widget-areas-controller.php @@ -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( diff --git a/lib/widgets.php b/lib/widgets.php index 1bce902fe56245..28ebc003674759 100644 --- a/lib/widgets.php +++ b/lib/widgets.php @@ -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' );