diff -r 34716fd837a4 -r be944660c56a wp/wp-includes/class-wp-customize-widgets.php --- a/wp/wp-includes/class-wp-customize-widgets.php Tue Dec 15 15:52:01 2020 +0100 +++ b/wp/wp-includes/class-wp-customize-widgets.php Wed Sep 21 18:19:35 2022 +0200 @@ -118,6 +118,7 @@ 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 @@ 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 @@ 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,65 @@ $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, + 'label' => $section_args['title'], + 'description' => $section_args['description'], + ) + ); + } 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']; + $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 ); + $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 ); + } } } @@ -605,7 +629,7 @@ if ( preg_match( '/^(.+)-(\d+)$/', $widget_id, $matches ) ) { $parsed['id_base'] = $matches[1]; - $parsed['number'] = intval( $matches[2] ); + $parsed['number'] = (int) $matches[2]; } else { // Likely an old single widget. $parsed['id_base'] = $widget_id; @@ -628,7 +652,7 @@ } $id_base = $matches[2]; - $number = isset( $matches[3] ) ? intval( $matches[3] ) : null; + $number = isset( $matches[3] ) ? (int) $matches[3] : null; return compact( 'id_base', 'number' ); } @@ -805,6 +829,49 @@ '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( + get_legacy_widget_block_editor_settings(), + $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( $block_editor_context ) ) ), + 'after' + ); + + wp_enqueue_script( 'wp-customize-widgets' ); + wp_enqueue_style( 'wp-customize-widgets' ); + + /** This action is documented in edit-form-blocks.php */ + do_action( 'enqueue_block_editor_assets' ); + } } /** @@ -888,8 +955,13 @@ $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'; } @@ -1109,6 +1181,23 @@ } /** + * 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. * * Because wp_get_sidebars_widgets() gets called early at {@see 'init' } (via @@ -1312,18 +1401,42 @@ * only get applied to an instance *once*. * * @since 3.9.0 + * @since 5.8.0 Added the `$id_base` parameter. * - * @param array $value Widget instance to sanitize. + * @global WP_Widget_Factory $wp_widget_factory + * + * @param array $value Widget instance to sanitize. + * @param string $id_base Optional. Base of the ID of the widget being sanitized. Default null. * @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; } - 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'] ) ) { + if ( 'block' === $id_base && ! current_user_can( 'unfiltered_html' ) ) { + /* + * The content of the 'block' widget is not filtered on the + * fly while editing. Filter the content here to prevent + * vulnerabilities. + */ + $value['raw_instance']['content'] = wp_kses_post( $value['raw_instance']['content'] ); + } + + return $value['raw_instance']; + } + } + + if ( + empty( $value['is_widget_customizer_js_value'] ) || + empty( $value['instance_hash_key'] ) || + empty( $value['encoded_serialized_instance'] ) + ) { return; } @@ -1348,21 +1461,37 @@ * Converts a widget instance into JSON-representable format. * * @since 3.9.0 + * @since 5.8.0 Added the `$id_base` parameter. * - * @param array $value Widget instance to convert to JSON. + * @global WP_Widget_Factory $wp_widget_factory + * + * @param array $value Widget instance to convert to JSON. + * @param string $id_base Optional. Base of the ID of the widget being sanitized. Default null. * @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 +1561,7 @@ 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 +1627,7 @@ * 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 +1700,7 @@ } $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' ) ); } @@ -1772,7 +1901,7 @@ } $this->sidebar_instance_count[ $index ] += 1; if ( ! $this->manager->selective_refresh->is_render_partials_request() ) { - printf( "\n\n", esc_html( $index ), intval( $this->sidebar_instance_count[ $index ] ) ); + printf( "\n\n", esc_html( $index ), (int) $this->sidebar_instance_count[ $index ] ); } } @@ -1788,7 +1917,7 @@ public function end_dynamic_sidebar( $index ) { array_shift( $this->current_dynamic_sidebar_id_stack ); if ( ! $this->manager->selective_refresh->is_render_partials_request() ) { - printf( "\n\n", esc_html( $index ), intval( $this->sidebar_instance_count[ $index ] ) ); + printf( "\n\n", esc_html( $index ), (int) $this->sidebar_instance_count[ $index ] ); } } @@ -1851,7 +1980,7 @@ $this->rendering_sidebar_id = $context['sidebar_id']; if ( isset( $context['sidebar_instance_number'] ) ) { - $this->context_sidebar_instance_number = intval( $context['sidebar_instance_number'] ); + $this->context_sidebar_instance_number = (int) $context['sidebar_instance_number']; } // Filter sidebars_widgets so that only the queried widget is in the sidebar.