diff --git a/lib/class-experimental-wp-widget-blocks-manager.php b/lib/class-experimental-wp-widget-blocks-manager.php index f2f26e5ef4372..82e9ef0f8b12b 100644 --- a/lib/class-experimental-wp-widget-blocks-manager.php +++ b/lib/class-experimental-wp-widget-blocks-manager.php @@ -308,9 +308,14 @@ public static function output_blocks_widget( $options, $arguments ) { } /** - * Registers of a widget that should represent a set of blocks and returns its id. + * Noop block widget control output function for the necessary call to `wp_register_widget_control`. + */ + public static function output_blocks_widget_control() {} + + /** + * Registers a widget that should represent a set of blocks and returns its ID. * - * @param array $blocks Array of blocks. + * @param array $blocks Array of blocks. */ public static function convert_blocks_to_widget( $blocks ) { $widget_id = 'blocks-widget-' . md5( self::serialize_blocks( $blocks ) ); @@ -320,7 +325,7 @@ public static function convert_blocks_to_widget( $blocks ) { } wp_register_sidebar_widget( $widget_id, - __( 'Blocks Area ', 'gutenberg' ), + __( 'Blocks Area', 'gutenberg' ), 'Experimental_WP_Widget_Blocks_Manager::output_blocks_widget', array( 'classname' => 'widget-area', @@ -330,6 +335,12 @@ public static function convert_blocks_to_widget( $blocks ) { 'blocks' => $blocks, ) ); + wp_register_widget_control( + $widget_id, + __( 'Blocks Area', 'gutenberg' ), + 'Experimental_WP_Widget_Blocks_Manager::output_blocks_widget_control', + array( 'id_base' => 'blocks-widget' ) + ); return $widget_id; } @@ -340,20 +351,34 @@ public static function convert_blocks_to_widget( $blocks ) { */ public static function swap_out_sidebars_blocks_for_block_widgets( $sidebars_widgets_input ) { global $sidebars_widgets; + global $wp_customize; if ( null === self::$unfiltered_sidebar_widgets ) { self::$unfiltered_sidebar_widgets = $sidebars_widgets; } + $changeset_data = null; + if ( function_exists( 'is_customize_preview' ) && is_customize_preview() ) { + $changeset_data = $wp_customize->changeset_data(); + if ( isset( $changeset_data['gutenberg_widget_blocks']['value'] ) ) { + $changeset_data = json_decode( $changeset_data['gutenberg_widget_blocks']['value'] ); + } + } + $filtered_sidebar_widgets = array(); foreach ( $sidebars_widgets_input as $sidebar_id => $item ) { - if ( ! is_numeric( $item ) ) { + $changeset_value = $changeset_data && isset( $changeset_data->$sidebar_id ) + ? $changeset_data->$sidebar_id + : null; + + if ( ! is_numeric( $item ) && ! $changeset_value ) { $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 ); + $blocks = parse_blocks( + $changeset_value ? $changeset_value : get_post( $item )->post_content + ); foreach ( $blocks as $block ) { if ( ! isset( $block['blockName'] ) ) { @@ -379,6 +404,7 @@ public static function swap_out_sidebars_blocks_for_block_widgets( $sidebars_wid $filtered_sidebar_widgets[ $sidebar_id ] = $filtered_widgets; } $sidebars_widgets = $filtered_sidebar_widgets; + return $filtered_sidebar_widgets; } } diff --git a/lib/class-wp-customize-widget-blocks-control.php b/lib/class-wp-customize-widget-blocks-control.php new file mode 100644 index 0000000000000..e92fef67c1577 --- /dev/null +++ b/lib/class-wp-customize-widget-blocks-control.php @@ -0,0 +1,40 @@ + + link(); ?> + /> + add_setting( + 'gutenberg_widget_blocks', + array( + 'default' => '{}', + 'type' => 'gutenberg_widget_blocks', + 'capability' => 'edit_theme_options', + 'transport' => 'postMessage', + 'sanitize_callback' => 'gutenberg_customize_sanitize', + ) + ); + $wp_customize->add_section( + 'gutenberg_widget_blocks', + array( 'title' => __( 'Widget Blocks (Experimental)', 'gutenberg' ) ) + ); + $wp_customize->add_control( + new WP_Customize_Widget_Blocks_Control( + $wp_customize, + 'gutenberg_widget_blocks', + array( + 'section' => 'gutenberg_widget_blocks', + 'settings' => 'gutenberg_widget_blocks', + ) + ) + ); +} +add_action( 'customize_register', 'gutenberg_customize_register' ); + +/** + * Specifies how to save the `gutenberg_widget_blocks` setting. It parses the JSON string and updates the + * referenced widget areas with the new content. + * + * @param string $value The value that is being published. + * @param \WP_Customize_Setting $setting The setting instance. + */ +function gutenberg_customize_update( $value, $setting ) { + foreach ( json_decode( $value ) as $sidebar_id => $sidebar_content ) { + $id_referenced_in_sidebar = Experimental_WP_Widget_Blocks_Manager::get_post_id_referenced_in_sidebar( $sidebar_id ); + + $post_id = wp_insert_post( + array( + 'ID' => $id_referenced_in_sidebar, + 'post_content' => $sidebar_content, + 'post_type' => 'wp_area', + ) + ); + + if ( 0 === $id_referenced_in_sidebar ) { + Experimental_WP_Widget_Blocks_Manager::reference_post_id_in_sidebar( $sidebar_id, $post_id ); + } + } +} +add_action( 'customize_update_gutenberg_widget_blocks', 'gutenberg_customize_update', 10, 2 ); + +/** + * Filters the Customizer widget settings arguments. + * This is needed because the Customizer registers settings for the raw registered widgets, without going through the `sidebars_widgets` filter. + * The `WP_Customize_Widgets` class expects sidebars to have an array of widgets registered, not a post ID. + * This results in the value passed to `sanitize_js_callback` being `null` and throwing an error. + * + * TODO: Figure out why core is not running the `sidebars_widgets` filter for the relevant part of the code. + * Then, either fix it or change this filter to parse the post IDs and then pass them to the original `sanitize_js_callback`. + * + * @param array $args Array of Customizer setting arguments. + * @param string $id Widget setting ID. + * @return array Maybe modified array of Customizer setting arguments. + */ +function filter_widget_customizer_setting_args( $args, $id = null ) { + // Posts won't have a settings ID like widgets. We can use that to remove the sanitization callback. + if ( ! isset( $id ) ) { + unset( $args['sanitize_js_callback'] ); + } + + return $args; +} +add_filter( 'widget_customizer_setting_args', 'filter_widget_customizer_setting_args' ); diff --git a/lib/load.php b/lib/load.php index d93b9dc1f9f0e..7a3c97fb65553 100644 --- a/lib/load.php +++ b/lib/load.php @@ -34,3 +34,4 @@ require dirname( __FILE__ ) . '/demo.php'; require dirname( __FILE__ ) . '/widgets.php'; require dirname( __FILE__ ) . '/widgets-page.php'; +require dirname( __FILE__ ) . '/customizer.php'; diff --git a/lib/widgets-page.php b/lib/widgets-page.php index f790e60d24b7a..27ebadcb9b9aa 100644 --- a/lib/widgets-page.php +++ b/lib/widgets-page.php @@ -9,10 +9,21 @@ * The main entry point for the Gutenberg widgets page. * * @since 5.2.0 + * + * @param string $page The page name the function is being called for, `'gutenberg_customizer'` for the Customizer. */ -function the_gutenberg_widgets() { +function the_gutenberg_widgets( $page = 'gutenberg_page_gutenberg-widgets' ) { ?> -