Adds the widgets block editor to widgets.php and customize.php

Moves the widgets block editor from Gutenberg into WordPress Core.

- Adds @wordpress/edit-widgets, @wordpress/customize-widgets and
  @wordpress/widgets.
- Modifies wp-admin/widgets.php to branch between the old editor and new editor
  depending on wp_use_widgets_block_editor().
- Modifies WP_Customize_Widgets to branch between the old editor control and new
  editor control depending on wp_use_widgets_block_editor().

Fixes #51506.
Props isabel_brison, TimothyBlynJacobs, andraganescu, kevin940726, talldanwp.

Built from https://develop.svn.wordpress.org/trunk@50996


git-svn-id: http://core.svn.wordpress.org/trunk@50605 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
noisysocks
2021-05-25 08:40:25 +00:00
parent 1314542c50
commit 81f62198c3
43 changed files with 12693 additions and 1742 deletions

View File

@@ -118,6 +118,7 @@ final class WP_Customize_Widgets {
add_action( 'customize_controls_print_footer_scripts', array( $this, 'output_widget_control_templates' ) );
add_action( 'customize_preview_init', array( $this, 'customize_preview_init' ) );
add_filter( 'customize_refresh_nonces', array( $this, 'refresh_nonces' ) );
add_filter( 'should_load_block_editor_scripts_and_styles', array( $this, 'should_load_block_editor_scripts_and_styles' ) );
add_action( 'dynamic_sidebar', array( $this, 'tally_rendered_widgets' ) );
add_filter( 'is_active_sidebar', array( $this, 'tally_sidebars_via_is_active_sidebar_calls' ), 10, 2 );
@@ -368,6 +369,8 @@ final class WP_Customize_Widgets {
public function customize_register() {
global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_sidebars;
$use_widgets_block_editor = wp_use_widgets_block_editor();
add_filter( 'sidebars_widgets', array( $this, 'preview_sidebars_widgets' ), 1 );
$sidebars_widgets = array_merge(
@@ -446,13 +449,18 @@ final class WP_Customize_Widgets {
if ( $is_active_sidebar ) {
$section_args = array(
'title' => $wp_registered_sidebars[ $sidebar_id ]['name'],
'description' => $wp_registered_sidebars[ $sidebar_id ]['description'],
'priority' => array_search( $sidebar_id, array_keys( $wp_registered_sidebars ), true ),
'panel' => 'widgets',
'sidebar_id' => $sidebar_id,
'title' => $wp_registered_sidebars[ $sidebar_id ]['name'],
'priority' => array_search( $sidebar_id, array_keys( $wp_registered_sidebars ), true ),
'panel' => 'widgets',
'sidebar_id' => $sidebar_id,
);
if ( $use_widgets_block_editor ) {
$section_args['description'] = '';
} else {
$section_args['description'] = $wp_registered_sidebars[ $sidebar_id ]['description'];
}
/**
* Filters Customizer widget section arguments for a given sidebar.
*
@@ -467,49 +475,63 @@ final class WP_Customize_Widgets {
$section = new WP_Customize_Sidebar_Section( $this->manager, $section_id, $section_args );
$this->manager->add_section( $section );
$control = new WP_Widget_Area_Customize_Control(
$this->manager,
$setting_id,
array(
'section' => $section_id,
'sidebar_id' => $sidebar_id,
'priority' => count( $sidebar_widget_ids ), // place 'Add Widget' and 'Reorder' buttons at end.
)
);
$new_setting_ids[] = $setting_id;
if ( $use_widgets_block_editor ) {
$control = new WP_Sidebar_Block_Editor_Control(
$this->manager,
$setting_id,
array(
'section' => $section_id,
'sidebar_id' => $sidebar_id,
)
);
} else {
$control = new WP_Widget_Area_Customize_Control(
$this->manager,
$setting_id,
array(
'section' => $section_id,
'sidebar_id' => $sidebar_id,
'priority' => count( $sidebar_widget_ids ), // place 'Add Widget' and 'Reorder' buttons at end.
)
);
}
$this->manager->add_control( $control );
$new_setting_ids[] = $setting_id;
}
}
// Add a control for each active widget (located in a sidebar).
foreach ( $sidebar_widget_ids as $i => $widget_id ) {
if ( ! $use_widgets_block_editor ) {
// Add a control for each active widget (located in a sidebar).
foreach ( $sidebar_widget_ids as $i => $widget_id ) {
// Skip widgets that may have gone away due to a plugin being deactivated.
if ( ! $is_active_sidebar || ! isset( $wp_registered_widgets[ $widget_id ] ) ) {
continue;
// Skip widgets that may have gone away due to a plugin being deactivated.
if ( ! $is_active_sidebar || ! isset( $wp_registered_widgets[ $widget_id ] ) ) {
continue;
}
$registered_widget = $wp_registered_widgets[ $widget_id ];
$setting_id = $this->get_setting_id( $widget_id );
$id_base = $wp_registered_widget_controls[ $widget_id ]['id_base'];
$control = new WP_Widget_Form_Customize_Control(
$this->manager,
$setting_id,
array(
'label' => $registered_widget['name'],
'section' => $section_id,
'sidebar_id' => $sidebar_id,
'widget_id' => $widget_id,
'widget_id_base' => $id_base,
'priority' => $i,
'width' => $wp_registered_widget_controls[ $widget_id ]['width'],
'height' => $wp_registered_widget_controls[ $widget_id ]['height'],
'is_wide' => $this->is_wide_widget( $widget_id ),
)
);
$this->manager->add_control( $control );
}
$registered_widget = $wp_registered_widgets[ $widget_id ];
$setting_id = $this->get_setting_id( $widget_id );
$id_base = $wp_registered_widget_controls[ $widget_id ]['id_base'];
$control = new WP_Widget_Form_Customize_Control(
$this->manager,
$setting_id,
array(
'label' => $registered_widget['name'],
'section' => $section_id,
'sidebar_id' => $sidebar_id,
'widget_id' => $widget_id,
'widget_id_base' => $id_base,
'priority' => $i,
'width' => $wp_registered_widget_controls[ $widget_id ]['width'],
'height' => $wp_registered_widget_controls[ $widget_id ]['height'],
'is_wide' => $this->is_wide_widget( $widget_id ),
)
);
$this->manager->add_control( $control );
}
}
@@ -805,6 +827,46 @@ final class WP_Customize_Widgets {
'data',
sprintf( 'var _wpCustomizeWidgetsSettings = %s;', wp_json_encode( $settings ) )
);
// TODO: Update 'wp-customize-widgets' to not rely so much on things in
// 'customize-widgets'. This will let us skip most of the above and not
// enqueue 'customize-widgets' which saves bytes.
if ( wp_use_widgets_block_editor() ) {
$block_editor_context = new WP_Block_Editor_Context();
$editor_settings = get_block_editor_settings( array(), $block_editor_context );
wp_add_inline_script(
'wp-customize-widgets',
sprintf(
'wp.domReady( function() {
wp.customizeWidgets.initialize( "widgets-customizer", %s );
} );',
wp_json_encode( $editor_settings )
)
);
// Preload server-registered block schemas.
wp_add_inline_script(
'wp-blocks',
'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings() ) . ');'
);
wp_add_inline_script(
'wp-blocks',
sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( get_block_categories( 'widgets-customizer' ) ) ),
'after'
);
wp_enqueue_script( 'wp-customize-widgets' );
wp_enqueue_style( 'wp-customize-widgets' );
wp_enqueue_script( 'wp-format-library' );
wp_enqueue_style( 'wp-format-library' );
/** This action is documented in edit-form-blocks.php */
do_action( 'enqueue_block_editor_assets' );
}
}
/**
@@ -888,8 +950,13 @@ final class WP_Customize_Widgets {
$args['sanitize_js_callback'] = array( $this, 'sanitize_sidebar_widgets_js_instance' );
$args['transport'] = current_theme_supports( 'customize-selective-refresh-widgets' ) ? 'postMessage' : 'refresh';
} elseif ( preg_match( $this->setting_id_patterns['widget_instance'], $id, $matches ) ) {
$args['sanitize_callback'] = array( $this, 'sanitize_widget_instance' );
$args['sanitize_js_callback'] = array( $this, 'sanitize_widget_js_instance' );
$id_base = $matches['id_base'];
$args['sanitize_callback'] = function( $value ) use ( $id_base ) {
return $this->sanitize_widget_instance( $value, $id_base );
};
$args['sanitize_js_callback'] = function( $value ) use ( $id_base ) {
return $this->sanitize_widget_js_instance( $value, $id_base );
};
$args['transport'] = $this->is_widget_selective_refreshable( $matches['id_base'] ) ? 'postMessage' : 'refresh';
}
@@ -1108,6 +1175,23 @@ final class WP_Customize_Widgets {
return $nonces;
}
/**
* Tells the script loader to load the scripts and styles of custom blocks
* if the widgets block editor is enabled.
*
* @since 5.8.0
*
* @param bool $is_block_editor_screen Current decision about loading block assets.
* @return bool Filtered decision about loading block assets.
*/
public function should_load_block_editor_scripts_and_styles( $is_block_editor_screen ) {
if ( wp_use_widgets_block_editor() ) {
return true;
}
return $is_block_editor_screen;
}
/**
* When previewing, ensures the proper previewing widgets are used.
*
@@ -1314,16 +1398,28 @@ final class WP_Customize_Widgets {
* @since 3.9.0
*
* @param array $value Widget instance to sanitize.
* @param string $id_base Base of the ID of the widget being sanitized.
* @return array|void Sanitized widget instance.
*/
public function sanitize_widget_instance( $value ) {
public function sanitize_widget_instance( $value, $id_base = null ) {
global $wp_widget_factory;
if ( array() === $value ) {
return $value;
return;
}
if ( empty( $value['is_widget_customizer_js_value'] )
|| empty( $value['instance_hash_key'] )
|| empty( $value['encoded_serialized_instance'] ) ) {
if ( isset( $value['raw_instance'] ) && $id_base && wp_use_widgets_block_editor() ) {
$widget_object = $wp_widget_factory->get_widget_object( $id_base );
if ( ! empty( $widget_object->widget_options['show_instance_in_rest'] ) ) {
return $value['raw_instance'];
}
}
if (
empty( $value['is_widget_customizer_js_value'] ) ||
empty( $value['instance_hash_key'] ) ||
empty( $value['encoded_serialized_instance'] )
) {
return;
}
@@ -1350,19 +1446,32 @@ final class WP_Customize_Widgets {
* @since 3.9.0
*
* @param array $value Widget instance to convert to JSON.
* @param string $id_base Base of the ID of the widget being sanitized.
* @return array JSON-converted widget instance.
*/
public function sanitize_widget_js_instance( $value ) {
public function sanitize_widget_js_instance( $value, $id_base = null ) {
global $wp_widget_factory;
if ( empty( $value['is_widget_customizer_js_value'] ) ) {
$serialized = serialize( $value );
$value = array(
$js_value = array(
'encoded_serialized_instance' => base64_encode( $serialized ),
'title' => empty( $value['title'] ) ? '' : $value['title'],
'is_widget_customizer_js_value' => true,
'instance_hash_key' => $this->get_instance_hash_key( $serialized ),
);
if ( $id_base && wp_use_widgets_block_editor() ) {
$widget_object = $wp_widget_factory->get_widget_object( $id_base );
if ( ! empty( $widget_object->widget_options['show_instance_in_rest'] ) ) {
$js_value['raw_instance'] = (object) $value;
}
}
return $js_value;
}
return $value;
}
@@ -1432,7 +1541,7 @@ final class WP_Customize_Widgets {
return new WP_Error( 'widget_setting_malformed' );
}
$instance = $this->sanitize_widget_instance( $sanitized_widget_setting );
$instance = $this->sanitize_widget_instance( $sanitized_widget_setting, $parsed_id['id_base'] );
if ( is_null( $instance ) ) {
$this->stop_capturing_option_updates();
return new WP_Error( 'widget_setting_unsanitized' );
@@ -1498,7 +1607,7 @@ final class WP_Customize_Widgets {
* in place from WP_Customize_Setting::preview() will use this value
* instead of the default widget instance value (an empty array).
*/
$this->manager->set_post_value( $setting_id, $this->sanitize_widget_js_instance( $instance ) );
$this->manager->set_post_value( $setting_id, $this->sanitize_widget_js_instance( $instance, $parsed_id['id_base'] ) );
// Obtain the widget control with the updated instance in place.
ob_start();
@@ -1571,7 +1680,7 @@ final class WP_Customize_Widgets {
}
$form = $updated_widget['form'];
$instance = $this->sanitize_widget_js_instance( $updated_widget['instance'] );
$instance = $this->sanitize_widget_js_instance( $updated_widget['instance'], $id_base );
wp_send_json_success( compact( 'form', 'instance' ) );
}