wp/wp-includes/class-wp-customize-widgets.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
--- 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<!--dynamic_sidebar_before:%s:%d-->\n", esc_html( $index ), intval( $this->sidebar_instance_count[ $index ] ) );
+			printf( "\n<!--dynamic_sidebar_before:%s:%d-->\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<!--dynamic_sidebar_after:%s:%d-->\n", esc_html( $index ), intval( $this->sidebar_instance_count[ $index ] ) );
+			printf( "\n<!--dynamic_sidebar_after:%s:%d-->\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.