Skip to content

Commit

Permalink
Use iframes in legacy widget preview. (#14643)
Browse files Browse the repository at this point in the history
* Rebase and refresh

* Don't hardcode sidebar id

* Don't hardcode preview URL

* lint

* Update package-lock.json

* Lint

Co-authored-by: Adam Zieliński <[email protected]>
  • Loading branch information
jorgefilipecosta and adamziel authored Sep 21, 2020
1 parent e5b6da9 commit cc003b2
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 82 deletions.
44 changes: 44 additions & 0 deletions lib/widget-preview-template.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* Start: Include for phase 2
* Template used to render widget previews.
*
* @package gutenberg
* @since 5.4.0
*/

if ( ! function_exists( 'wp_head' ) ) {
exit;
}
?>
<!doctype html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="profile" href="https://gmpg.org/xfn/11" />
<?php wp_head(); ?>
<style>
/* Reset theme styles */
html, body, #page, #content {
background: #FFF !important;
padding: 0 !important;
margin: 0 !important;
}
</style>
</head>

<body <?php body_class(); ?>>
<div id="page" class="site">
<div id="content" class="site-content">
<?php
$registry = WP_Block_Type_Registry::get_instance();
$block = $registry->get_registered( 'core/legacy-widget' );
echo $block->render( $_GET['widgetPreview'] );
?>
</div><!-- #content -->
</div><!-- #page -->

<?php wp_footer(); ?>
</body>
</html>
21 changes: 21 additions & 0 deletions lib/widgets.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' );

1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/edit-widgets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
17 changes: 9 additions & 8 deletions packages/edit-widgets/src/blocks/legacy-widget/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ 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';

/**
* Internal dependencies
*/
import LegacyWidgetEditHandler from './handler';
import LegacyWidgetPlaceholder from './placeholder';
import WidgetPreview from './widget-preview';

class LegacyWidgetEdit extends Component {
constructor() {
Expand Down Expand Up @@ -188,15 +188,12 @@ class LegacyWidgetEdit extends Component {
}

renderWidgetPreview() {
const { widgetId, attributes } = this.props;
const { attributes, widgetAreaId } = this.props;
return (
<ServerSideRender
<WidgetPreview
className="wp-block-legacy-widget__preview"
block="core/legacy-widget"
attributes={ {
widgetId,
...omit( attributes, 'referenceWidgetName' ),
} }
widgetAreaId={ widgetAreaId }
attributes={ omit( attributes, 'widgetId' ) }
/>
);
}
Expand All @@ -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,
Expand All @@ -231,6 +231,7 @@ export default withSelect(
hasPermissionsToManageWidgets,
availableLegacyWidgets,
widgetId,
widgetAreaId: widgetArea?.id,
WPWidget,
prerenderedEditForm: widget ? widget.rendered_form : '',
};
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<Disabled>
<FocusableIframe
onLoad={ ( event ) => {
const iframeContentHeight = get( event, [
'currentTarget',
'contentDocument',
'body',
'scrollHeight',
] );
if ( iframeContentHeight !== height ) {
setHeight( iframeContentHeight );
}
} }
src={ iframeUrl }
height={ height + HEIGHT_MARGIN }
{ ...props }
/>
</Disabled>
);
}

export default WidgetPreview;
136 changes: 62 additions & 74 deletions packages/edit-widgets/src/blocks/legacy-widget/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,107 +6,95 @@
*/

/**
* 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' => '<div class="widget %s">',
'after_widget' => '</div>',
'before_title' => '<h2 class="widgettitle">',
'after_title' => '</h2>',
),
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 ) ) {
$classname_ .= '_' . get_class( $cn );
}
}
$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' );
23 changes: 23 additions & 0 deletions packages/edit-widgets/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit cc003b2

Please sign in to comment.