Skip to content

Commit

Permalink
Experiment: Temporary hack to render blocks in customizer (#29365)
Browse files Browse the repository at this point in the history
Co-authored-by: Robert Anderson <[email protected]>
  • Loading branch information
kevin940726 and noisysocks authored Mar 3, 2021
1 parent 956d556 commit 9ce75be
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 62 deletions.
60 changes: 60 additions & 0 deletions lib/widgets-customize.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,66 @@ function gutenberg_widgets_customize_register( $manager ) {
}
}

/**
* Our own implementation of WP_Customize_Widgets::sanitize_widget_instance
* which uses __unstable_instance if it exists.
*
* @param array $value Widget instance to sanitize.
* @return array|void Sanitized widget instance.
*/
function gutenberg_widgets_customize_sanitize_widget_instance( $value ) {
global $wp_customize;

if ( isset( $value['__unstable_instance'] ) ) {
return $value['__unstable_instance'];
}

return $wp_customize->widgets->sanitize_widget_instance( $value );
}

/**
* Our own implementation of WP_Customize_Widgets::sanitize_widget_js_instance
* which adds __unstable_instance.
*
* @param array $value Widget instance to convert to JSON.
* @return array JSON-converted widget instance.
*/
function gutenberg_widgets_customize_sanitize_widget_js_instance( $value ) {
global $wp_customize;

$sanitized_value = $wp_customize->widgets->sanitize_widget_js_instance( $value );

$sanitized_value['__unstable_instance'] = $value;

return $sanitized_value;
}

/**
* TEMPORARY HACK! \o/
*
* Swaps the customizer setting's sanitize_callback and sanitize_js_callback
* arguments with our own implementation that adds __unstable_instance to the
* sanitized value.
*
* This lets the block editor use __unstable_instance to create blocks.
*
* A proper fix would be to only add the raw instance when the widget is a block
* widget and to update the Legacy Widget block to work with encoded instance
* values. See https://github.com/WordPress/gutenberg/issues/28902.
*
* @param array $args Array of Customizer setting arguments.
* @param string $id Widget setting ID.
*/
function gutenberg_widgets_customize_add_unstable_instance( $args, $id ) {
if ( 0 === strpos( $id, 'widget_' ) ) {
$args['sanitize_callback'] = 'gutenberg_widgets_customize_sanitize_widget_instance';
$args['sanitize_js_callback'] = 'gutenberg_widgets_customize_sanitize_widget_js_instance';
}

return $args;
}

if ( gutenberg_is_experiment_enabled( 'gutenberg-widgets-in-customizer' ) ) {
add_action( 'customize_register', 'gutenberg_widgets_customize_register' );
add_filter( 'widget_customizer_setting_args', 'gutenberg_widgets_customize_add_unstable_instance', 10, 2 );
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export default class SidebarAdapter {
};
}

addWidget( widget ) {
addWidget( widget, index ) {
const widgetModel = wp.customize.Widgets.availableWidgets.findWhere( {
id_base: widget.idBase,
} );
Expand Down Expand Up @@ -169,9 +169,10 @@ export default class SidebarAdapter {
);
setting.set( {} );

const widgetIds = this.setting.get();
const widgetIds = [ ...this.setting.get() ];
const widgetId = settingIdToWidgetId( settingId );
this.setting.set( [ ...widgetIds, widgetId ] );
widgetIds.splice( index, 0, widgetId );
this.setting.set( widgetIds );

return widgetId;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
/**
* External dependencies
*/
import { invert, omit, keyBy, isEqual } from 'lodash';
import { omit, keyBy, isEqual } from 'lodash';

/**
* WordPress dependencies
*/
import { serialize, parse, createBlock } from '@wordpress/blocks';
import { useState, useEffect, useCallback, useRef } from '@wordpress/element';

function addWidgetIdToBlock( block, widgetId ) {
return {
...block,
attributes: {
...( block.attributes || {} ),
__internalWidgetId: widgetId,
},
};
}

function blockToWidget( block, existingWidget = null ) {
let widget;

Expand All @@ -27,10 +37,16 @@ function blockToWidget( block, existingWidget = null ) {
};
}
} else {
const instance = {
content: serialize( block ),
};
widget = {
idBase: 'block',
widgetClass: 'WP_Widget_Block',
instance: { content: serialize( block ) },
instance: {
...instance,
__unstable_instance: instance,
},
};
}

Expand All @@ -40,12 +56,13 @@ function blockToWidget( block, existingWidget = null ) {
};
}

function widgetToBlock( widget, existingBlock = null ) {
function widgetToBlock( widget ) {
let block;

// FIXME: We'll never get it here with blocks, we need to update this.
if ( widget.widgetClass === 'WP_Widget_Block' ) {
const parsedBlocks = parse( widget.instance.content );
if ( widget.idBase === 'block' ) {
const parsedBlocks = parse(
widget.instance.__unstable_instance.content
);
block = parsedBlocks.length
? parsedBlocks[ 0 ]
: createBlock( 'core/paragraph', {} );
Expand All @@ -68,20 +85,16 @@ function widgetToBlock( widget, existingBlock = null ) {
block = createBlock( 'core/legacy-widget', attributes, [] );
}

return {
...block,
clientId: existingBlock?.clientId ?? block.clientId,
};
return addWidgetIdToBlock( block, widget.id );
}

function initState( sidebar ) {
const state = { blocks: [], widgetIds: {} };
const state = { blocks: [] };

for ( const widgetId of sidebar.getWidgetIds() ) {
const widget = sidebar.getWidget( widgetId );
const block = widgetToBlock( widget );
state.blocks.push( block );
state.widgetIds[ block.clientId ] = widgetId;
}

return state;
Expand Down Expand Up @@ -109,60 +122,55 @@ export default function useSidebarBlockEditor( sidebar ) {
);
setState( ( lastState ) => ( {
blocks: [ ...lastState.blocks, block ],
widgetIds: {
...lastState.widgetIds,
[ block.clientId ]: widgetId,
},
} ) );
break;
}

case 'widgetRemoved': {
const { widgetId } = event;
const blockClientId = invert( state.widgetIds )[ widgetId ];
setState( ( lastState ) => ( {
blocks: lastState.blocks.filter(
( { clientId } ) => clientId !== blockClientId
( { attributes: { __internalWidgetId } } ) =>
__internalWidgetId !== widgetId
),
widgetIds: omit( lastState.widgetIds, blockClientId ),
} ) );
break;
}

case 'widgetChanged': {
const { widgetId } = event;
const blockClientIdToUpdate = invert( state.widgetIds )[
widgetId
];
const blockToUpdate = state.blocks.find(
( { clientId } ) => clientId === blockClientIdToUpdate
( { attributes: { __internalWidgetId } } ) =>
__internalWidgetId === widgetId
);
const updatedBlock = widgetToBlock(
sidebar.getWidget( widgetId ),
blockToUpdate
);
setState( ( lastState ) => ( {
...lastState,
blocks: lastState.blocks.map( ( block ) =>
block.clientId === blockClientIdToUpdate
? updatedBlock
: block
block === blockToUpdate ? updatedBlock : block
),
} ) );
break;
}

case 'widgetsReordered':
const { widgetIds } = event;
const blockClientIds = invert( state.widgetIds );
const blocksByClientId = keyBy( state.blocks, 'clientId' );
setState( ( lastState ) => ( {
...lastState,
blocks: widgetIds.map(
( widgetId ) =>
blocksByClientId[ blockClientIds[ widgetId ] ]
),
} ) );

setState( ( lastState ) => {
const blocksByWidgetId = keyBy(
lastState.blocks,
'attributes.__internalWidgetId'
);

return {
...lastState,
blocks: widgetIds.map(
( widgetId ) => blocksByWidgetId[ widgetId ]
),
};
} );
break;
}
};
Expand All @@ -175,17 +183,23 @@ export default function useSidebarBlockEditor( sidebar ) {
( nextBlocks ) => {
ignoreIncoming.current = true;

let nextWidgetIds = state.widgetIds;

const blocksByClientId = keyBy( state.blocks, 'clientId' );

const seen = {};

for ( const nextBlock of nextBlocks ) {
if ( nextBlock.clientId in blocksByClientId ) {
const block = blocksByClientId[ nextBlock.clientId ];
const blocksByWidgetId = keyBy(
state.blocks,
( block ) => block.attributes.__internalWidgetId
);

nextBlocks.forEach( ( nextBlock, index ) => {
if (
nextBlock.attributes.__internalWidgetId &&
nextBlock.attributes.__internalWidgetId in blocksByWidgetId
) {
const block =
blocksByWidgetId[
nextBlock.attributes.__internalWidgetId
];
if ( ! isEqual( block, nextBlock ) ) {
const widgetId = state.widgetIds[ nextBlock.clientId ];
const widgetId =
nextBlock.attributes.__internalWidgetId;
const widgetToUpdate = sidebar.getWidget( widgetId );
const widget = blockToWidget(
nextBlock,
Expand All @@ -195,40 +209,44 @@ export default function useSidebarBlockEditor( sidebar ) {
}
} else {
const widget = blockToWidget( nextBlock );
const widgetId = sidebar.addWidget( widget );
if ( nextWidgetIds === state.widgetIds ) {
nextWidgetIds = { ...state.widgetIds };
}
nextWidgetIds[ nextBlock.clientId ] = widgetId;
sidebar.addWidget( widget, index );
}
} );

seen[ nextBlock.clientId ] = true;
}
const seen = nextBlocks.map(
( block ) => block.attributes.__internalWidgetId
);

for ( const block of state.blocks ) {
if ( ! seen[ block.clientId ] ) {
const widgetId = state.widgetIds[ block.clientId ];
const widgetId = block.attributes.__internalWidgetId;
if ( ! seen.includes( widgetId ) ) {
sidebar.removeWidget( widgetId );
}
}

if (
nextBlocks.length === state.blocks.length &&
! isEqual(
nextBlocks.map( ( { clientId } ) => clientId ),
state.blocks.map( ( { clientId } ) => clientId )
nextBlocks.map(
( { attributes: { __internalWidgetId } } ) =>
__internalWidgetId
),
state.blocks.map(
( { attributes: { __internalWidgetId } } ) =>
__internalWidgetId
)
)
) {
const order = nextBlocks.map(
( { clientId } ) => state.widgetIds[ clientId ]
( { attributes: { __internalWidgetId } } ) =>
__internalWidgetId
);
sidebar.setWidgetIds( order );
}

setState( ( lastState ) => ( {
...lastState,
blocks: nextBlocks,
widgetIds: nextWidgetIds,
} ) );

ignoreIncoming.current = false;
Expand Down

0 comments on commit 9ce75be

Please sign in to comment.