diff --git a/lib/widget-preview-template.php b/lib/widget-preview-template.php new file mode 100644 index 0000000000000..1f74627c97cc1 --- /dev/null +++ b/lib/widget-preview-template.php @@ -0,0 +1,44 @@ + + +> + + + + + + + + +> +
+
+ get_registered( 'core/legacy-widget' ); + echo $block->render( $_GET['widgetPreview'] ); + ?> +
+
+ + + + diff --git a/lib/widgets.php b/lib/widgets.php index a53c870715920..8f88883a21ad4 100644 --- a/lib/widgets.php +++ b/lib/widgets.php @@ -323,3 +323,24 @@ function gutenberg_register_widgets() { } add_action( 'widgets_init', 'gutenberg_register_widgets' ); + +/** + * Overwrites the template WordPress would use to render the currrent request, + * to a widget preview template if widgetPreview parameter was passed in the url. + * + * @param string $template Original template. + * + * @return string The original or the path of widget-preview-template.php file. + */ +function change_post_template_to_widget_preview( $template ) { + if ( + isset( $_GET['widgetPreview'] ) && + current_user_can( 'edit_theme_options' ) + ) { + add_filter( 'show_admin_bar', '__return_false' ); + return dirname( __FILE__ ) . '/widget-preview-template.php'; + } + return $template; +} +add_filter( 'template_include', 'change_post_template_to_widget_preview' ); + diff --git a/package-lock.json b/package-lock.json index ca1fc68cf374f..3b882d659ec8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17466,6 +17466,7 @@ "@wordpress/notices": "file:packages/notices", "@wordpress/plugins": "file:packages/plugins", "@wordpress/server-side-render": "file:packages/server-side-render", + "@wordpress/url": "file:packages/url", "classnames": "^2.2.5", "lodash": "^4.17.19", "rememo": "^3.0.0" diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index f98eabf233038..b81a316a335b4 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -49,6 +49,7 @@ "@wordpress/notices": "file:../notices", "@wordpress/plugins": "file:../plugins", "@wordpress/server-side-render": "file:../server-side-render", + "@wordpress/url": "file:../url", "classnames": "^2.2.5", "lodash": "^4.17.19", "rememo": "^3.0.0" diff --git a/packages/edit-widgets/src/blocks/legacy-widget/edit/index.js b/packages/edit-widgets/src/blocks/legacy-widget/edit/index.js index a7dd12a799148..0863ed992d8b4 100644 --- a/packages/edit-widgets/src/blocks/legacy-widget/edit/index.js +++ b/packages/edit-widgets/src/blocks/legacy-widget/edit/index.js @@ -11,7 +11,6 @@ import { Button, PanelBody, ToolbarGroup } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { withSelect } from '@wordpress/data'; import { BlockControls, InspectorControls } from '@wordpress/block-editor'; -import ServerSideRender from '@wordpress/server-side-render'; import { update } from '@wordpress/icons'; /** @@ -19,6 +18,7 @@ import { update } from '@wordpress/icons'; */ import LegacyWidgetEditHandler from './handler'; import LegacyWidgetPlaceholder from './placeholder'; +import WidgetPreview from './widget-preview'; class LegacyWidgetEdit extends Component { constructor() { @@ -188,15 +188,12 @@ class LegacyWidgetEdit extends Component { } renderWidgetPreview() { - const { widgetId, attributes } = this.props; + const { attributes, widgetAreaId } = this.props; return ( - ); } @@ -211,6 +208,9 @@ export default withSelect( clientId ); const widget = select( 'core/edit-widgets' ).getWidget( widgetId ); + const widgetArea = select( + 'core/edit-widgets' + ).getWidgetAreaForClientId( clientId ); const editorSettings = select( 'core/block-editor' ).getSettings(); const { availableLegacyWidgets, @@ -231,6 +231,7 @@ export default withSelect( hasPermissionsToManageWidgets, availableLegacyWidgets, widgetId, + widgetAreaId: widgetArea?.id, WPWidget, prerenderedEditForm: widget ? widget.rendered_form : '', }; diff --git a/packages/edit-widgets/src/blocks/legacy-widget/edit/widget-preview.js b/packages/edit-widgets/src/blocks/legacy-widget/edit/widget-preview.js new file mode 100644 index 0000000000000..09588a94331da --- /dev/null +++ b/packages/edit-widgets/src/blocks/legacy-widget/edit/widget-preview.js @@ -0,0 +1,47 @@ +/** + * External dependencies + */ +import { get } from 'lodash'; + +/** + * WordPress dependencies + */ +import { addQueryArgs } from '@wordpress/url'; +import { Disabled, FocusableIframe } from '@wordpress/components'; +import { useState } from '@wordpress/element'; + +function WidgetPreview( { widgetAreaId, attributes, ...props } ) { + const DEFAULT_HEIGHT = 300; + const HEIGHT_MARGIN = 20; + const [ height, setHeight ] = useState( DEFAULT_HEIGHT ); + const currentUrl = document.location.href; + const siteUrl = currentUrl.substr( 0, currentUrl.indexOf( 'wp-admin/' ) ); + const iframeUrl = addQueryArgs( siteUrl, { + widgetPreview: { + ...attributes, + sidebarId: widgetAreaId, + }, + } ); + return ( + + { + const iframeContentHeight = get( event, [ + 'currentTarget', + 'contentDocument', + 'body', + 'scrollHeight', + ] ); + if ( iframeContentHeight !== height ) { + setHeight( iframeContentHeight ); + } + } } + src={ iframeUrl } + height={ height + HEIGHT_MARGIN } + { ...props } + /> + + ); +} + +export default WidgetPreview; diff --git a/packages/edit-widgets/src/blocks/legacy-widget/index.php b/packages/edit-widgets/src/blocks/legacy-widget/index.php index 4bf679c0e6677..7f209f3f4fd4b 100644 --- a/packages/edit-widgets/src/blocks/legacy-widget/index.php +++ b/packages/edit-widgets/src/blocks/legacy-widget/index.php @@ -6,41 +6,75 @@ */ /** - * Returns the result of rendering a widget having its instance id. + * Register legacy widget block. + */ +function register_block_core_legacy_widget() { + register_block_type_from_metadata( + __DIR__ . '/legacy-widget', + array( + 'render_callback' => 'render_block_core_legacy_widget', + ) + ); +} + +/** + * Renders the `core/legacy-widget` block on server. * - * @param string $id Widget id. + * @param array $attributes The block attributes. * - * @return string Returns the rendered widget as a string. + * @return string Returns the post content with the legacy widget added. + * @see WP_Widget */ -function block_core_legacy_widget_render_widget_by_id( $id ) { - // Code extracted from src/wp-includes/widgets.php dynamic_sidebar function. - // Todo: When merging to core extract this part of dynamic_sidebar into its own function. - global $wp_registered_widgets; +function render_block_core_legacy_widget( $attributes ) { + global $wp_widget_factory, $wp_registered_sidebars; - if ( ! isset( $wp_registered_widgets[ $id ] ) ) { - return false; + if ( isset( $attributes['widgetId'] ) ) { + return __( 'Rendering legacy widget block using widgetId is unsupported.', 'gutenberg' ); } + $widget_id = - 1; + + if ( ! isset( $attributes['sidebarId'] ) || ! isset( $wp_registered_sidebars[ $attributes['sidebarId'] ] ) ) { + return ''; + } + $sidebar_id = $attributes['sidebarId']; + + if ( ! isset( $attributes['widgetClass'] ) || ! isset( $wp_widget_factory->widgets[ $attributes['widgetClass'] ] ) ) { + return ''; + } + $widget_class = $attributes['widgetClass']; + $widget_obj = $wp_widget_factory->widgets[ $widget_class ]; + + $instance = isset( $attributes['instance'] ) ? $attributes['instance'] : null; + + $widget_params = array_merge( + array( + 'classname' => array(), + ), + $widget_obj->widget_options + ); + + /** This filter is documented in wp-includes/widgets/widgets.php */ + do_action( 'dynamic_sidebar_before', $sidebar_id, true ); + $sidebar = $wp_registered_sidebars[ $sidebar_id ]; + $params = array_merge( array( array_merge( + $sidebar, array( - 'before_widget' => '
', - 'after_widget' => '
', - 'before_title' => '

', - 'after_title' => '

', - ), - array( - 'widget_id' => $id, - 'widget_name' => $wp_registered_widgets[ $id ]['name'], + 'widget_id' => $widget_id, + 'widget_name' => $widget_obj->name, ) ), ), - (array) $wp_registered_widgets[ $id ]['params'] + array( + $instance, + ) ); - // Substitute HTML id and class attributes into before_widget. + // Substitute HTML `id` and `class` attributes into `before_widget`. $classname_ = ''; - foreach ( (array) $wp_registered_widgets[ $id ]['classname'] as $cn ) { + foreach ( (array) $widget_params['classname'] as $cn ) { if ( is_string( $cn ) ) { $classname_ .= '_' . $cn; } elseif ( is_object( $cn ) ) { @@ -48,65 +82,19 @@ function block_core_legacy_widget_render_widget_by_id( $id ) { } } $classname_ = ltrim( $classname_, '_' ); - $params[0]['before_widget'] = sprintf( $params[0]['before_widget'], $id, $classname_ ); + $params[0]['before_widget'] = sprintf( $params[0]['before_widget'], $widget_id, $classname_ ); - $params = apply_filters( 'dynamic_sidebar_params', $params ); - $callback = $wp_registered_widgets[ $id ]['callback']; - do_action( 'dynamic_sidebar', $wp_registered_widgets[ $id ] ); + /** This filter is documented in wp-includes/widgets/widgets.php */ + $params = apply_filters( 'dynamic_sidebar_params', $params ); - if ( is_callable( $callback ) ) { - ob_start(); - call_user_func_array( $callback, $params ); - return ob_get_clean(); - } - return false; -} - -/** - * Renders the `core/legacy-widget` block on server. - * - * @see WP_Widget - * - * @param array $attributes The block attributes. - * - * @return string Returns the post content with the legacy widget added. - */ -function render_block_core_legacy_widget( $attributes ) { - $id = null; - $widget_class = null; - if ( isset( $attributes['widgetId'] ) ) { - $id = $attributes['widgetId']; - } - if ( isset( $attributes['widgetClass'] ) ) { - $widget_class = $attributes['widgetClass']; - } - - if ( $id ) { - return block_core_legacy_widget_render_widget_by_id( $id ); - } - if ( ! $widget_class ) { - return ''; - } + /** This filter is documented in wp-includes/widgets/widgets.php */ + do_action( 'dynamic_sidebar', $widget_params ); ob_start(); - $instance = null; - if ( isset( $attributes['instance'] ) ) { - $instance = $attributes['instance']; - } - the_widget( $widget_class, $instance ); - return ob_get_clean(); -} + $widget_obj->_set( - 1 ); + call_user_func_array( array( $widget_obj, 'widget' ), $params ); -/** - * Register legacy widget block. - */ -function register_block_core_legacy_widget() { - register_block_type_from_metadata( - __DIR__ . '/legacy-widget', - array( - 'render_callback' => 'render_block_core_legacy_widget', - ) - ); + return ob_get_clean(); } add_action( 'init', 'register_block_core_legacy_widget' ); diff --git a/packages/edit-widgets/src/store/selectors.js b/packages/edit-widgets/src/store/selectors.js index 3fb8af255849c..3941524ca5462 100644 --- a/packages/edit-widgets/src/store/selectors.js +++ b/packages/edit-widgets/src/store/selectors.js @@ -60,6 +60,29 @@ export const getWidgetIdForClientId = ( state, clientId ) => { return clientIdToWidgetId[ clientId ]; }; +/** + * Returns widgetArea containing a block identify by given clientId + * + * @param {string} clientId The ID of the block. + * @return {Object} Containing widget area. + */ +export const getWidgetAreaForClientId = createRegistrySelector( + ( select ) => ( state, clientId ) => { + const widgetAreas = select( 'core/edit-widgets' ).getWidgetAreas(); + for ( const widgetArea of widgetAreas ) { + const post = select( 'core' ).getEditedEntityRecord( + KIND, + POST_TYPE, + buildWidgetAreaPostId( widgetArea.id ) + ); + const clientIds = post.blocks.map( ( block ) => block.clientId ); + if ( clientIds.includes( clientId ) ) { + return widgetArea; + } + } + } +); + export const getEditedWidgetAreas = createRegistrySelector( ( select ) => ( state, ids ) => { let widgetAreas = select( 'core/edit-widgets' ).getWidgetAreas();