diff --git a/lib/class-experimental-wp-widget-blocks-manager.php b/lib/class-experimental-wp-widget-blocks-manager.php index e3bdc63b097fe6..8f124305bf6099 100644 --- a/lib/class-experimental-wp-widget-blocks-manager.php +++ b/lib/class-experimental-wp-widget-blocks-manager.php @@ -121,16 +121,26 @@ public static function get_sidebar_as_blocks( $sidebar_id ) { $wp_registered_sidebars = self::get_wp_registered_sidebars(); foreach ( $sidebars_items[ $sidebar_id ] as $item ) { - $widget_class = self::get_widget_class( $item ); - $blocks[] = array( + $widget_class = self::get_widget_class( $item ); + list( $object, $number ) = self::get_widget_info( $item ); + $new_block = array( 'blockName' => 'core/legacy-widget', 'attrs' => array( - 'widgetClass' => $widget_class, - 'identifier' => $item, + 'widgetId' => $item, 'instance' => self::get_sidebar_widget_instance( $wp_registered_sidebars[ $sidebar_id ], $item ), ), 'innerHTML' => '', ); + if ( null !== $widget_class ) { + $new_block['attrs']['widgetClass'] = $widget_class; + } + if ( isset( $object->id_base ) ) { + $new_block['attrs']['idBase'] = $object->id_base; + } + if ( is_int( $number ) ) { + $new_block['attrs']['widgetNumber'] = $number; + } + $blocks[] = $new_block; } return $blocks; } @@ -177,7 +187,7 @@ private static function get_widget_class( $widget_id ) { * @param string $id Identifier of the widget instance. * @return array Array containing the widget instance. */ - public static function get_sidebar_widget_instance( $sidebar, $id ) { + private static function get_sidebar_widget_instance( $sidebar, $id ) { list( $object, $number, $name ) = self::get_widget_info( $id ); if ( ! $object ) { return array(); diff --git a/lib/class-wp-rest-widget-forms.php b/lib/class-wp-rest-widget-forms.php new file mode 100644 index 00000000000000..ed59f6f8ddc739 --- /dev/null +++ b/lib/class-wp-rest-widget-forms.php @@ -0,0 +1,186 @@ +namespace = '__experimental'; + $this->rest_base = 'widget-forms'; + } + + /** + * Registers the necessary REST API route. + * + * @access public + */ + public function register_routes() { + register_rest_route( + $this->namespace, + // Regex representing a PHP class extracted from http://php.net/manual/en/language.oop5.basic.php. + '/' . $this->rest_base . '/(?P[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/', + array( + 'args' => array( + 'widget_class' => array( + 'description' => __( 'Class name of the widget.', 'gutenberg' ), + 'type' => 'string', + 'required' => true, + 'validate_callback' => array( $this, 'is_valid_widget' ), + ), + 'instance' => array( + 'description' => __( 'Current widget instance', 'gutenberg' ), + 'type' => 'object', + 'default' => array(), + ), + 'instance_changes' => array( + 'description' => __( 'Array of instance changes', 'gutenberg' ), + 'type' => 'object', + 'default' => array(), + ), + ), + array( + 'methods' => WP_REST_Server::EDITABLE, + 'permission_callback' => array( $this, 'compute_new_widget_permissions_check' ), + 'callback' => array( $this, 'compute_new_widget' ), + ), + ) + ); + } + + /** + * Checks if the user has permissions to make the request. + * + * @since 5.2.0 + * @access public + * + * @return true|WP_Error True if the request has read access, WP_Error object otherwise. + */ + public function compute_new_widget_permissions_check() { + // Verify if the current user has edit_theme_options capability. + // This capability is required to access the widgets screen. + if ( ! current_user_can( 'edit_theme_options' ) ) { + return new WP_Error( + 'widgets_cannot_access', + __( 'Sorry, you are not allowed to access widgets on this site.', 'gutenberg' ), + array( + 'status' => rest_authorization_required_code(), + ) + ); + } + return true; + } + + /** + * Checks if the widget being referenced is valid. + * + * @since 5.2.0 + * @param string $widget_class Name of the class the widget references. + * + * @return boolean| True if the widget being referenced exists and false otherwise. + */ + private function is_valid_widget( $widget_class ) { + global $wp_widget_factory, $wp_registered_widgets; + if ( ! $widget_class ) { + return false; + } + return isset( $wp_widget_factory->widgets[ $widget_class ] ) && + ( $wp_widget_factory->widgets[ $widget_class ] instanceof WP_Widget ); + } + + /** + * Returns the new widget instance and the form that represents it. + * + * @since 5.7.0 + * @access public + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + */ + public function compute_new_widget( $request ) { + $widget_class = $request->get_param( 'widget_class' ); + $instance = $request->get_param( 'instance' ); + $instance_changes = $request->get_param( 'instance_changes' ); + + global $wp_widget_factory; + $widget_obj = $wp_widget_factory->widgets[ $widget_class ]; + + $widget_obj->_set( -1 ); + ob_start(); + + if ( ! empty( $instance_changes ) ) { + $old_instance = $instance; + $instance = $widget_obj->update( $instance_changes, $old_instance ); + + /** + * Filters a widget's settings before saving. + * + * Returning false will effectively short-circuit the widget's ability + * to update settings. The old setting will be returned. + * + * @since 5.2.0 + * + * @param array $instance The current widget instance's settings. + * @param array $instance_changes Array of new widget settings. + * @param array $old_instance Array of old widget settings. + * @param WP_Widget $widget_ob The widget instance. + */ + $instance = apply_filters( 'widget_update_callback', $instance, $instance_changes, $old_instance, $widget_obj ); + if ( false === $instance ) { + $instance = $old_instance; + } + } + + $instance = apply_filters( 'widget_form_callback', $instance, $widget_obj ); + + $return = null; + if ( false !== $instance ) { + $return = $widget_obj->form( $instance ); + + /** + * Fires at the end of the widget control form. + * + * Use this hook to add extra fields to the widget form. The hook + * is only fired if the value passed to the 'widget_form_callback' + * hook is not false. + * + * Note: If the widget has no form, the text echoed from the default + * form method can be hidden using CSS. + * + * @since 5.2.0 + * + * @param WP_Widget $widget_obj The widget instance (passed by reference). + * @param null $return Return null if new fields are added. + * @param array $instance An array of the widget's settings. + */ + do_action_ref_array( 'in_widget_form', array( &$widget_obj, &$return, $instance ) ); + } + $form = ob_get_clean(); + + return rest_ensure_response( + array( + 'instance' => $instance, + 'form' => $form, + ) + ); + } +} +/** + * End: Include for phase 2 + */ diff --git a/lib/class-wp-rest-widget-updater-controller.php b/lib/class-wp-rest-widget-updater-controller.php deleted file mode 100644 index 0147da435734eb..00000000000000 --- a/lib/class-wp-rest-widget-updater-controller.php +++ /dev/null @@ -1,302 +0,0 @@ -namespace = '__experimental'; - $this->rest_base = 'widget-forms'; - } - - /** - * Registers the necessary REST API route. - * - * @access public - */ - public function register_routes() { - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/', - array( - 'args' => array( - 'widget_class' => array( - 'description' => __( 'Class name of the widget.', 'gutenberg' ), - 'type' => 'string', - 'required' => false, - 'default' => null, - ), - 'identifier' => array( - 'description' => __( 'Identifier of the widget.', 'gutenberg' ), - 'type' => 'string', - 'required' => false, - 'default' => null, - ), - 'instance' => array( - 'description' => __( 'Current widget instance', 'gutenberg' ), - 'type' => 'object', - 'default' => array(), - ), - 'instance_changes' => array( - 'description' => __( 'Array of instance changes', 'gutenberg' ), - 'type' => 'object', - 'default' => array(), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'permission_callback' => array( $this, 'compute_new_widget_permissions_check' ), - 'callback' => array( $this, 'compute_new_widget' ), - ), - ) - ); - } - - /** - * Checks if the user has permissions to make the request. - * - * @since 5.2.0 - * @access public - * - * @return true|WP_Error True if the request has read access, WP_Error object otherwise. - */ - public function compute_new_widget_permissions_check() { - // Verify if the current user has edit_theme_options capability. - // This capability is required to access the widgets screen. - if ( ! current_user_can( 'edit_theme_options' ) ) { - return new WP_Error( - 'widgets_cannot_access', - __( 'Sorry, you are not allowed to access widgets on this site.', 'gutenberg' ), - array( - 'status' => rest_authorization_required_code(), - ) - ); - } - return true; - } - - /** - * Checks if the widget being referenced is valid. - * - * @since 5.2.0 - * @param string $identifier Instance identifier of the widget. - * @param string $widget_class Name of the class the widget references. - * - * @return boolean True if the widget being referenced exists and false otherwise. - */ - private function is_valid_widget( $identifier, $widget_class ) { - global $wp_widget_factory, $wp_registered_widgets; - if ( ! $identifier && ! $widget_class ) { - return false; - } - if ( $identifier ) { - return isset( $wp_registered_widgets[ $identifier ] ); - } - return isset( $wp_widget_factory->widgets[ $widget_class ] ) && - ( $wp_widget_factory->widgets[ $widget_class ] instanceof WP_Widget ); - } - - /** - * Computes an array with instance changes cleaned of widget specific prefixes and sufixes. - * - * @since 5.7.0 - * @param string $id_base Widget ID Base. - * @param string $id Widget instance identifier. - * @param array $instance_changes Array with the form values being being changed. - * - * @return array An array based on $instance_changes whose keys have the widget specific sufixes and prefixes removed. - */ - private function parse_instance_changes( $id_base, $id, $instance_changes ) { - $instance_changes_parsed = array(); - $start_position = strlen( 'widget-' . $id_base . '[' . $id . '][' ); - foreach ( $instance_changes as $key => $value ) { - $key_parsed = substr( $key, $start_position, -1 ); - $instance_changes_parsed[ $key_parsed ] = $value; - } - return $instance_changes_parsed; - } - - /** - * Returns the edit form of the widget being referenced. - * - * @since 5.7.0 - * @param string $identifier Instance identifier of the widget. - * - * @return WP_REST_Response Response object. - */ - private function handle_reference_widgets( $identifier ) { - global $wp_registered_widget_controls; - $form = ''; - $id_base = $identifier; - $id = $identifier; - $number = null; - if ( - isset( $wp_registered_widget_controls[ $identifier ]['callback'] ) && - is_callable( $wp_registered_widget_controls[ $identifier ]['callback'] ) - ) { - $control = $wp_registered_widget_controls[ $identifier ]; - ob_start(); - call_user_func_array( $control['callback'], $control['params'] ); - $form = ob_get_clean(); - if ( isset( $control['id_base'] ) ) { - $id_base = $control['id_base']; - } - if ( isset( $control['params'][0]['number'] ) ) { - $number = $control['params'][0]['number']; - } - } - - return rest_ensure_response( - array( - 'instance' => array(), - 'form' => $form, - 'id_base' => $id_base, - 'id' => $id, - 'number' => $number, - ) - ); - } - - /** - * Returns the new class widget instance and the form that represents it. - * - * @since 5.7.0 - * @access public - * - * @param string $widget_class Widget id for callback widgets or widget class name for class widgets. - * @param array $instance Previous widget instance. - * @param array $instance_changes Array with the form values being being changed. - * @param string $id_to_use Identifier of the specific widget instance. - * @return WP_REST_Response Response object on success, or WP_Error object on failure. - */ - private function handle_class_widgets( $widget_class, $instance, $instance_changes, $id_to_use ) { - if ( null === $instance ) { - $instance = array(); - } - if ( null === $id_to_use ) { - $id_to_use = -1; - } - - global $wp_widget_factory; - $widget_obj = $wp_widget_factory->widgets[ $widget_class ]; - - $widget_obj->_set( $id_to_use ); - $id_base = $widget_obj->id_base; - $id = $widget_obj->id; - ob_start(); - - if ( null !== $instance_changes ) { - $instance_changes = $this->parse_instance_changes( $id_base, $id_to_use, $instance_changes ); - $old_instance = $instance; - $instance = $widget_obj->update( $instance_changes, $old_instance ); - - /** - * Filters a widget's settings before saving. - * - * Returning false will effectively short-circuit the widget's ability - * to update settings. The old setting will be returned. - * - * @since 5.2.0 - * - * @param array $instance The current widget instance's settings. - * @param array $instance_changes Array of new widget settings. - * @param array $old_instance Array of old widget settings. - * @param WP_Widget $widget_ob The widget instance. - */ - $instance = apply_filters( 'widget_update_callback', $instance, $instance_changes, $old_instance, $widget_obj ); - if ( false === $instance ) { - $instance = $old_instance; - } - } - - $instance = apply_filters( 'widget_form_callback', $instance, $widget_obj ); - - $return = null; - if ( false !== $instance ) { - $return = $widget_obj->form( $instance ); - - /** - * Fires at the end of the widget control form. - * - * Use this hook to add extra fields to the widget form. The hook - * is only fired if the value passed to the 'widget_form_callback' - * hook is not false. - * - * Note: If the widget has no form, the text echoed from the default - * form method can be hidden using CSS. - * - * @since 5.2.0 - * - * @param WP_Widget $widget_obj The widget instance (passed by reference). - * @param null $return Return null if new fields are added. - * @param array $instance An array of the widget's settings. - */ - do_action_ref_array( 'in_widget_form', array( &$widget_obj, &$return, $instance ) ); - } - $form = ob_get_clean(); - - return rest_ensure_response( - array( - 'instance' => $instance, - 'form' => $form, - 'id_base' => $id_base, - 'id' => $id, - 'number' => $id_to_use, - ) - ); - } - - /** - * Returns the new widget instance and the form that represents it. - * - * @since 5.7.0 - * @access public - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. - */ - public function compute_new_widget( $request ) { - $identifier = $request->get_param( 'identifier' ); - $widget_class = $request->get_param( 'widget_class' ); - - if ( ! $this->is_valid_widget( $identifier, $widget_class ) ) { - return new WP_Error( - 'widget_invalid', - __( 'Invalid widget.', 'gutenberg' ), - array( - 'status' => 404, - ) - ); - } - - if ( $identifier ) { - return $this->handle_reference_widgets( $identifier ); - } - return $this->handle_class_widgets( - $widget_class, - $request->get_param( 'instance' ), - $request->get_param( 'instance_changes' ), - $request->get_param( 'id_to_use' ) - ); - } -} -/** - * End: Include for phase 2 - */ diff --git a/lib/load.php b/lib/load.php index 58e545b38a6f7a..8eceb1203c7143 100644 --- a/lib/load.php +++ b/lib/load.php @@ -29,8 +29,8 @@ function gutenberg_is_experiment_enabled( $name ) { /** * Start: Include for phase 2 */ - if ( ! class_exists( 'WP_REST_Widget_Updater_Controller' ) ) { - require dirname( __FILE__ ) . '/class-wp-rest-widget-updater-controller.php'; + if ( ! class_exists( 'WP_REST_Widget_Forms' ) ) { + require dirname( __FILE__ ) . '/class-wp-rest-widget-forms.php'; } if ( ! class_exists( 'WP_REST_Widget_Areas_Controller' ) ) { require dirname( __FILE__ ) . '/class-experimental-wp-widget-blocks-manager.php'; diff --git a/lib/rest-api.php b/lib/rest-api.php index 6ad5e6d0e6f0ef..e0b6e7be592e7b 100644 --- a/lib/rest-api.php +++ b/lib/rest-api.php @@ -63,8 +63,8 @@ function gutenberg_filter_oembed_result( $response, $handler, $request ) { * @since 5.0.0 */ function gutenberg_register_rest_widget_updater_routes() { - $widgets_controller = new WP_REST_Widget_Updater_Controller(); - $widgets_controller->register_routes(); + $widget_forms = new WP_REST_Widget_Forms(); + $widget_forms->register_routes(); } add_action( 'rest_api_init', 'gutenberg_register_rest_widget_updater_routes' ); diff --git a/lib/widgets.php b/lib/widgets.php index de6d08306a9717..a2dbf475ac1a63 100644 --- a/lib/widgets.php +++ b/lib/widgets.php @@ -118,21 +118,22 @@ function gutenberg_get_legacy_widget_settings() { if ( ! empty( $wp_widget_factory ) ) { foreach ( $wp_widget_factory->widgets as $class => $widget_obj ) { $available_legacy_widgets[ $class ] = array( - 'name' => html_entity_decode( $widget_obj->name ), + 'name' => html_entity_decode( $widget_obj->name ), // wp_widget_description is not being used because its input parameter is a Widget Id. // Widgets id's reference to a specific widget instance. // Here we are iterating on all the available widget classes even if no widget instance exists for them. - 'description' => isset( $widget_obj->widget_options['description'] ) ? + 'description' => isset( $widget_obj->widget_options['description'] ) ? html_entity_decode( $widget_obj->widget_options['description'] ) : null, - 'isCallbackWidget' => false, - 'isHidden' => in_array( $class, $core_widgets, true ), + 'isReferenceWidget' => false, + 'isHidden' => in_array( $class, $core_widgets, true ), ); } } global $wp_registered_widgets; if ( ! empty( $wp_registered_widgets ) ) { foreach ( $wp_registered_widgets as $widget_id => $widget_obj ) { + $block_widget_start = 'blocks-widget-'; if ( ( is_array( $widget_obj['callback'] ) && @@ -144,9 +145,9 @@ function gutenberg_get_legacy_widget_settings() { continue; } $available_legacy_widgets[ $widget_id ] = array( - 'name' => html_entity_decode( $widget_obj['name'] ), - 'description' => html_entity_decode( wp_widget_description( $widget_id ) ), - 'isCallbackWidget' => true, + 'name' => html_entity_decode( $widget_obj['name'] ), + 'description' => html_entity_decode( wp_widget_description( $widget_id ) ), + 'isReferenceWidget' => true, ); } } diff --git a/packages/block-library/src/legacy-widget/edit/dom-manager.js b/packages/block-library/src/legacy-widget/edit/dom-manager.js index caf8f6ed56317c..1d6586f24c2779 100644 --- a/packages/block-library/src/legacy-widget/edit/dom-manager.js +++ b/packages/block-library/src/legacy-widget/edit/dom-manager.js @@ -54,7 +54,7 @@ class LegacyWidgetEditDomManager extends Component { } render() { - const { id, idBase, widgetNumber, form, identifier } = this.props; + const { id, idBase, widgetNumber, form, isReferenceWidget } = this.props; return (
@@ -63,7 +63,7 @@ class LegacyWidgetEditDomManager extends Component { method="post" onBlur={ () => { if ( this.shouldTriggerInstanceUpdate() ) { - if ( identifier ) { + if ( isReferenceWidget ) { if ( this.containerRef.current ) { window.wpWidgets.save( window.jQuery( this.containerRef.current ) ); } @@ -79,11 +79,12 @@ class LegacyWidgetEditDomManager extends Component { className="widget-content" dangerouslySetInnerHTML={ { __html: form } } /> - - - - - + { isReferenceWidget && ( <> + + + + + ) }
@@ -131,21 +132,22 @@ class LegacyWidgetEditDomManager extends Component { const form = this.formRef.current; const formData = new window.FormData( form ); const updatedInstance = {}; - for ( const key of formData.keys() ) { + for ( const rawKey of formData.keys() ) { // This fields are added to the form because the widget JavaScript code may use this values. // They are not relevant for the update mechanism. if ( includes( [ 'widget-id', 'id_base', 'widget_number', 'multi_number', 'add_new' ], - key, + rawKey, ) ) { continue; } - - const value = formData.getAll( key ); + const matches = rawKey.match( /[^\[]*\[[-\d]*\]\[([^\]]*)\]/ ); + const keyParsed = matches && matches[ 1 ] ? matches[ 1 ] : rawKey; + const value = formData.getAll( rawKey ); if ( value.length > 1 ) { - updatedInstance[ key ] = value; + updatedInstance[ keyParsed ] = value; } else { - updatedInstance[ key ] = value[ 0 ]; + updatedInstance[ keyParsed ] = value[ 0 ]; } } return updatedInstance; diff --git a/packages/block-library/src/legacy-widget/edit/handler.js b/packages/block-library/src/legacy-widget/edit/handler.js index 8202c845a5c43c..97cb024ffb45c6 100644 --- a/packages/block-library/src/legacy-widget/edit/handler.js +++ b/packages/block-library/src/legacy-widget/edit/handler.js @@ -15,14 +15,15 @@ import { withInstanceId } from '@wordpress/compose'; */ import LegacyWidgetEditDomManager from './dom-manager'; +const { XMLHttpRequest, FormData } = window; + class LegacyWidgetEditHandler extends Component { constructor() { super( ...arguments ); this.state = { form: null, - idBase: null, - widgetNumber: null, }; + this.widgetNonce = null; this.instanceUpdating = null; this.onInstanceChange = this.onInstanceChange.bind( this ); this.requestWidgetUpdater = this.requestWidgetUpdater.bind( this ); @@ -30,12 +31,16 @@ class LegacyWidgetEditHandler extends Component { componentDidMount() { this.isStillMounted = true; + this.trySetNonce(); this.requestWidgetUpdater( undefined, ( response ) => { this.props.onInstanceChange( null, !! response.form ); } ); } componentDidUpdate( prevProps ) { + if ( ! this.widgetNonce ) { + this.trySetNonce(); + } if ( prevProps.instance !== this.props.instance && this.instanceUpdating !== this.props.instance @@ -54,8 +59,8 @@ class LegacyWidgetEditHandler extends Component { } render() { - const { instanceId, identifier, instance, isSelected, widgetName } = this.props; - const { id, idBase, form, widgetNumber } = this.state; + const { instanceId, widgetId, widgetNumber, idBase, instance, isSelected, widgetName } = this.props; + const { form } = this.state; if ( ! form ) { return null; @@ -91,22 +96,37 @@ class LegacyWidgetEditHandler extends Component { > { this.widgetEditDomManagerRef = ref; } } onInstanceChange={ this.onInstanceChange } widgetNumber={ widgetNumber ? widgetNumber : instanceId * -1 } - id={ id } + id={ widgetId } idBase={ idBase } form={ form } - identifier={ identifier } + widgetId={ widgetId } /> ); } + trySetNonce() { + const element = document.getElementById( '_wpnonce_widgets' ); + if ( element && element.value ) { + this.widgetNonce = element.value; + } + } + onInstanceChange( instanceChanges ) { + const { widgetId } = this.props; + if ( widgetId ) { + // For reference widgets there is no need to query an endpoint, + // the widget is already saved with ajax. + this.props.onInstanceChange( instanceChanges, true ); + return; + } this.requestWidgetUpdater( instanceChanges, ( response ) => { this.instanceUpdating = response.instance; this.props.onInstanceChange( response.instance, !! response.form ); @@ -114,39 +134,60 @@ class LegacyWidgetEditHandler extends Component { } requestWidgetUpdater( instanceChanges, callback ) { - const { identifier, instanceId, instance, widgetClass } = this.props; - if ( ! identifier && ! widgetClass ) { + const { widgetId, idBase, instance, widgetClass } = this.props; + const { isStillMounted } = this; + if ( ! widgetId && ! widgetClass ) { return; } - apiFetch( { - path: `/__experimental/widget-forms/`, - data: { - identifier, - instance, - // use negative ids to make sure the id does not exist on the database. - id_to_use: instanceId * -1, - widget_class: widgetClass, - instance_changes: instanceChanges, - }, - method: 'POST', - } ).then( - ( response ) => { - if ( this.isStillMounted ) { - this.setState( { - form: response.form, - idBase: response.id_base, - id: response.id, - widgetNumber: response.number, - } ); + // If we are in the presence of a reference widget, do a save ajax request + // with empty changes so we retrieve the widget edit form. + if ( widgetId ) { + const httpRequest = new XMLHttpRequest(); + const formData = new FormData(); + formData.append( 'action', 'save-widget' ); + formData.append( 'id_base', idBase ); + formData.append( 'widget-id', widgetId ); + formData.append( 'widget-width', '250' ); + formData.append( 'widget-height', '200' ); + formData.append( 'savewidgets', this.widgetNonce ); + httpRequest.open( 'POST', window.ajaxurl ); + const self = this; + httpRequest.addEventListener( 'load', function() { + if ( isStillMounted ) { + const form = httpRequest.responseText; + self.setState( { form } ); if ( callback ) { - callback( response ); + callback( { form } ); } } - } - ); + } ); + httpRequest.send( formData ); + return; + } + + if ( widgetClass ) { + apiFetch( { + path: `/__experimental/widget-forms/${ widgetClass }/`, + data: { + instance, + instance_changes: instanceChanges, + }, + method: 'POST', + } ).then( + ( response ) => { + if ( isStillMounted ) { + this.setState( { + form: response.form, + } ); + if ( callback ) { + callback( response ); + } + } + } + ); + } } } export default withInstanceId( LegacyWidgetEditHandler ); - diff --git a/packages/block-library/src/legacy-widget/edit/index.js b/packages/block-library/src/legacy-widget/edit/index.js index 85247f2aa86bcb..e2c960080c011b 100644 --- a/packages/block-library/src/legacy-widget/edit/index.js +++ b/packages/block-library/src/legacy-widget/edit/index.js @@ -48,22 +48,22 @@ class LegacyWidgetEdit extends Component { setAttributes, } = this.props; const { isPreview, hasEditForm } = this.state; - const { identifier, widgetClass } = attributes; + const { widgetId, widgetClass } = attributes; const widgetObject = - ( identifier && availableLegacyWidgets[ identifier ] ) || + ( widgetId && availableLegacyWidgets[ widgetId ] ) || ( widgetClass && availableLegacyWidgets[ widgetClass ] ); - if ( ! identifier && ! widgetClass ) { + if ( ! widgetId && ! widgetClass ) { return ( { - const { isCallbackWidget } = availableLegacyWidgets[ newWidget ]; + const { isReferenceWidget } = availableLegacyWidgets[ newWidget ]; setAttributes( { instance: {}, - identifier: isCallbackWidget ? newWidget : undefined, - widgetClass: isCallbackWidget ? undefined : newWidget, + widgetId: isReferenceWidget ? newWidget : undefined, + widgetClass: isReferenceWidget ? undefined : newWidget, } ); } } /> @@ -120,7 +120,9 @@ class LegacyWidgetEdit extends Component { '', - 'after_widget' => '', - 'class' => '', - 'before_title' => '', - 'after_title' => '', - ), - array( - 'widget_id' => $id, - 'widget_name' => $wp_registered_widgets[ $id ]['name'], + array_merge( + array( + 'before_widget' => '
', + 'after_widget' => '
', + 'before_title' => '

', + 'after_title' => '

', + ), + array( + 'widget_id' => $id, + 'widget_name' => $wp_registered_widgets[ $id ]['name'], + ) ), ), (array) $wp_registered_widgets[ $id ]['params'] @@ -49,10 +50,8 @@ function render_widget_by_id( $id ) { $classname_ = ltrim( $classname_, '_' ); $params[0]['before_widget'] = sprintf( $params[0]['before_widget'], $id, $classname_ ); - $params = apply_filters( 'dynamic_sidebar_params', $params ); - + $params = apply_filters( 'dynamic_sidebar_params', $params ); $callback = $wp_registered_widgets[ $id ]['callback']; - do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] ); if ( is_callable( $callback ) ) { @@ -73,29 +72,27 @@ function render_widget_by_id( $id ) { * @return string Returns the post content with the legacy widget added. */ function render_block_legacy_widget( $attributes ) { - $identifier = null; + $widget_id = null; $widget_class = null; - if ( isset( $attributes['identifier'] ) ) { - $identifier = $attributes['identifier']; + if ( isset( $attributes['widgetId'] ) ) { + $widget_id = $attributes['widgetId']; } if ( isset( $attributes['widgetClass'] ) ) { $widget_class = $attributes['widgetClass']; } + if ( $widget_id ) { + return render_widget_by_id( $widget_id ); + } if ( ! $widget_class ) { - if ( ! $identifier ) { - return ''; - } - return render_widget_by_id( $attributes['identifier'] ); + return ''; } + ob_start(); $instance = null; if ( isset( $attributes['instance'] ) ) { $instance = $attributes['instance']; } - if ( $identifier ) { - $instance = Experimental_WP_Widget_Blocks_Manager::get_sidebar_widget_instance( array(), $identifier ); - } the_widget( $widget_class, $instance ); return ob_get_clean(); } @@ -108,13 +105,19 @@ function register_block_core_legacy_widget() { 'core/legacy-widget', array( 'attributes' => array( - 'widgetClass' => array( + 'widgetClass' => array( 'type' => 'string', ), - 'identifier' => array( + 'widgetId' => array( 'type' => 'string', ), - 'instance' => array( + 'idBase' => array( + 'type' => 'string', + ), + 'widgetNumber' => array( + 'type' => 'number', + ), + 'instance' => array( 'type' => 'object', ), ), diff --git a/test/integration/full-content/server-registered.json b/test/integration/full-content/server-registered.json index 9d17c64f5d6ba5..89bcf700b43a62 100644 --- a/test/integration/full-content/server-registered.json +++ b/test/integration/full-content/server-registered.json @@ -1 +1 @@ -{"core\/archives":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"displayAsDropdown":{"type":"boolean","default":false},"showPostCounts":{"type":"boolean","default":false}}},"core\/block":{"attributes":{"ref":{"type":"number"}}},"core\/calendar":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"month":{"type":"integer"},"year":{"type":"integer"}}},"core\/categories":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"displayAsDropdown":{"type":"boolean","default":false},"showHierarchy":{"type":"boolean","default":false},"showPostCounts":{"type":"boolean","default":false}}},"core\/latest-comments":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"commentsToShow":{"type":"number","default":5,"minimum":1,"maximum":100},"displayAvatar":{"type":"boolean","default":true},"displayDate":{"type":"boolean","default":true},"displayExcerpt":{"type":"boolean","default":true}}},"core\/latest-posts":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"categories":{"type":"string"},"postsToShow":{"type":"number","default":5},"displayPostContent":{"type":"boolean","default":false},"displayPostContentRadio":{"type":"string","default":"excerpt"},"excerptLength":{"type":"number","default":55},"displayPostDate":{"type":"boolean","default":false},"postLayout":{"type":"string","default":"list"},"columns":{"type":"number","default":3},"order":{"type":"string","default":"desc"},"orderBy":{"type":"string","default":"date"}}},"core\/legacy-widget":{"attributes":{"identifier":{"type":"string"},"instance":{"type":"object"},"isCallbackWidget":{"type":"boolean"}}},"core\/navigation-menu":{"category":"layout","attributes":{"automaticallyAdd":{"type":"boolean","default":false}}},"core\/rss":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"columns":{"type":"number","default":2},"blockLayout":{"type":"string","default":"list"},"feedURL":{"type":"string","default":""},"itemsToShow":{"type":"number","default":5},"displayExcerpt":{"type":"boolean","default":false},"displayAuthor":{"type":"boolean","default":false},"displayDate":{"type":"boolean","default":false},"excerptLength":{"type":"number","default":55}}},"core\/search":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"label":{"type":"string","default":"Search"},"placeholder":{"type":"string","default":""},"buttonText":{"type":"string","default":"Search"}}},"core\/shortcode":{"attributes":{"text":{"type":"string","source":"html"}}},"core\/social-link-amazon":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"amazon"}}},"core\/social-link-bandcamp":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"bandcamp"}}},"core\/social-link-behance":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"behance"}}},"core\/social-link-chain":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"chain"}}},"core\/social-link-codepen":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"codepen"}}},"core\/social-link-deviantart":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"deviantart"}}},"core\/social-link-dribbble":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"dribbble"}}},"core\/social-link-dropbox":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"dropbox"}}},"core\/social-link-etsy":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"etsy"}}},"core\/social-link-facebook":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"facebook"}}},"core\/social-link-feed":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"feed"}}},"core\/social-link-fivehundredpx":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"fivehundredpx"}}},"core\/social-link-flickr":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"flickr"}}},"core\/social-link-foursquare":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"foursquare"}}},"core\/social-link-goodreads":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"goodreads"}}},"core\/social-link-google":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"google"}}},"core\/social-link-github":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"github"}}},"core\/social-link-instagram":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"instagram"}}},"core\/social-link-lastfm":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"lastfm"}}},"core\/social-link-linkedin":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"linkedin"}}},"core\/social-link-mail":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"mail"}}},"core\/social-link-mastodon":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"mastodon"}}},"core\/social-link-meetup":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"meetup"}}},"core\/social-link-medium":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"medium"}}},"core\/social-link-pinterest":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"pinterest"}}},"core\/social-link-pocket":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"pocket"}}},"core\/social-link-reddit":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"reddit"}}},"core\/social-link-skype":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"skype"}}},"core\/social-link-snapchat":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"snapchat"}}},"core\/social-link-soundcloud":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"soundcloud"}}},"core\/social-link-spotify":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"spotify"}}},"core\/social-link-tumblr":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"tumblr"}}},"core\/social-link-twitch":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"twitch"}}},"core\/social-link-twitter":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"twitter"}}},"core\/social-link-vimeo":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"vimeo"}}},"core\/social-link-vk":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"vk"}}},"core\/social-link-wordpress":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"wordpress"}}},"core\/social-link-yelp":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"yelp"}}},"core\/social-link-youtube":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"youtube"}}},"core\/tag-cloud":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"taxonomy":{"type":"string","default":"post_tag"},"showTagCounts":{"type":"boolean","default":false}}}} \ No newline at end of file +{"core\/archives":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"displayAsDropdown":{"type":"boolean","default":false},"showPostCounts":{"type":"boolean","default":false}}},"core\/block":{"attributes":{"ref":{"type":"number"}}},"core\/calendar":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"month":{"type":"integer"},"year":{"type":"integer"}}},"core\/categories":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"displayAsDropdown":{"type":"boolean","default":false},"showHierarchy":{"type":"boolean","default":false},"showPostCounts":{"type":"boolean","default":false}}},"core\/latest-comments":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"commentsToShow":{"type":"number","default":5,"minimum":1,"maximum":100},"displayAvatar":{"type":"boolean","default":true},"displayDate":{"type":"boolean","default":true},"displayExcerpt":{"type":"boolean","default":true}}},"core\/latest-posts":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"categories":{"type":"string"},"postsToShow":{"type":"number","default":5},"displayPostContent":{"type":"boolean","default":false},"displayPostContentRadio":{"type":"string","default":"excerpt"},"excerptLength":{"type":"number","default":55},"displayPostDate":{"type":"boolean","default":false},"postLayout":{"type":"string","default":"list"},"columns":{"type":"number","default":3},"order":{"type":"string","default":"desc"},"orderBy":{"type":"string","default":"date"}}},"core\/legacy-widget":{"attributes":{"identifier":{"type":"string"},"instance":{"type":"object"},"isReferenceWidget":{"type":"boolean"}}},"core\/navigation-menu":{"category":"layout","attributes":{"automaticallyAdd":{"type":"boolean","default":false}}},"core\/rss":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"columns":{"type":"number","default":2},"blockLayout":{"type":"string","default":"list"},"feedURL":{"type":"string","default":""},"itemsToShow":{"type":"number","default":5},"displayExcerpt":{"type":"boolean","default":false},"displayAuthor":{"type":"boolean","default":false},"displayDate":{"type":"boolean","default":false},"excerptLength":{"type":"number","default":55}}},"core\/search":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"label":{"type":"string","default":"Search"},"placeholder":{"type":"string","default":""},"buttonText":{"type":"string","default":"Search"}}},"core\/shortcode":{"attributes":{"text":{"type":"string","source":"html"}}},"core\/social-link-amazon":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"amazon"}}},"core\/social-link-bandcamp":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"bandcamp"}}},"core\/social-link-behance":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"behance"}}},"core\/social-link-chain":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"chain"}}},"core\/social-link-codepen":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"codepen"}}},"core\/social-link-deviantart":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"deviantart"}}},"core\/social-link-dribbble":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"dribbble"}}},"core\/social-link-dropbox":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"dropbox"}}},"core\/social-link-etsy":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"etsy"}}},"core\/social-link-facebook":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"facebook"}}},"core\/social-link-feed":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"feed"}}},"core\/social-link-fivehundredpx":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"fivehundredpx"}}},"core\/social-link-flickr":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"flickr"}}},"core\/social-link-foursquare":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"foursquare"}}},"core\/social-link-goodreads":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"goodreads"}}},"core\/social-link-google":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"google"}}},"core\/social-link-github":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"github"}}},"core\/social-link-instagram":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"instagram"}}},"core\/social-link-lastfm":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"lastfm"}}},"core\/social-link-linkedin":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"linkedin"}}},"core\/social-link-mail":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"mail"}}},"core\/social-link-mastodon":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"mastodon"}}},"core\/social-link-meetup":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"meetup"}}},"core\/social-link-medium":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"medium"}}},"core\/social-link-pinterest":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"pinterest"}}},"core\/social-link-pocket":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"pocket"}}},"core\/social-link-reddit":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"reddit"}}},"core\/social-link-skype":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"skype"}}},"core\/social-link-snapchat":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"snapchat"}}},"core\/social-link-soundcloud":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"soundcloud"}}},"core\/social-link-spotify":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"spotify"}}},"core\/social-link-tumblr":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"tumblr"}}},"core\/social-link-twitch":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"twitch"}}},"core\/social-link-twitter":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"twitter"}}},"core\/social-link-vimeo":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"vimeo"}}},"core\/social-link-vk":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"vk"}}},"core\/social-link-wordpress":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"wordpress"}}},"core\/social-link-yelp":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"yelp"}}},"core\/social-link-youtube":{"attributes":{"url":{"type":"string"},"site":{"type":"string","default":"youtube"}}},"core\/tag-cloud":{"attributes":{"align":{"type":"string","enum":["left","center","right","wide","full"]},"className":{"type":"string"},"taxonomy":{"type":"string","default":"post_tag"},"showTagCounts":{"type":"boolean","default":false}}}}