Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Fix moving inner blocks in the customizer
  • Loading branch information
kevin940726 committed Jul 7, 2021
commit f37564e44a7471f96258c2c59a7a820223f6dcf7
Original file line number Diff line number Diff line change
@@ -1,100 +1,19 @@
/**
* External dependencies
*/
import { omit, isEqual } from 'lodash';
import { isEqual } from 'lodash';

/**
* WordPress dependencies
*/
import { serialize, parse, createBlock } from '@wordpress/blocks';
import { useState, useEffect, useCallback } from '@wordpress/element';
import isShallowEqual from '@wordpress/is-shallow-equal';
import { getWidgetIdFromBlock, addWidgetIdToBlock } from '@wordpress/widgets';

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

const isValidLegacyWidgetBlock =
block.name === 'core/legacy-widget' &&
( block.attributes.id || block.attributes.instance );

if ( isValidLegacyWidgetBlock ) {
if ( block.attributes.id ) {
// Widget that does not extend WP_Widget.
widget = {
id: block.attributes.id,
};
} else {
const { encoded, hash, raw, ...rest } = block.attributes.instance;

// Widget that extends WP_Widget.
widget = {
idBase: block.attributes.idBase,
instance: {
...existingWidget?.instance,
// Required only for the customizer.
is_widget_customizer_js_value: true,
encoded_serialized_instance: encoded,
instance_hash_key: hash,
raw_instance: raw,
...rest,
},
};
}
} else {
const instance = {
content: serialize( block ),
};
widget = {
idBase: 'block',
widgetClass: 'WP_Widget_Block',
instance: {
raw_instance: instance,
},
};
}

return {
...omit( existingWidget, [ 'form', 'rendered' ] ),
...widget,
};
}

function widgetToBlock( { id, idBase, number, instance } ) {
let block;

const {
encoded_serialized_instance: encoded,
instance_hash_key: hash,
raw_instance: raw,
...rest
} = instance;

if ( idBase === 'block' ) {
const parsedBlocks = parse( raw.content );
block = parsedBlocks.length
? parsedBlocks[ 0 ]
: createBlock( 'core/paragraph', {} );
} else if ( number ) {
// Widget that extends WP_Widget.
block = createBlock( 'core/legacy-widget', {
idBase,
instance: {
encoded,
hash,
raw,
...rest,
},
} );
} else {
// Widget that does not extend WP_Widget.
block = createBlock( 'core/legacy-widget', {
id,
} );
}

return addWidgetIdToBlock( block, id );
}
/**
* Internal dependencies
*/
import { blockToWidget, widgetToBlock } from '../../utils';

function widgetsToBlocks( widgets ) {
return widgets.map( ( widget ) => widgetToBlock( widget ) );
Expand Down
44 changes: 37 additions & 7 deletions packages/customize-widgets/src/filters/move-to-sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
store as blockEditorStore,
} from '@wordpress/block-editor';
import { createHigherOrderComponent } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { useSelect, useDispatch } from '@wordpress/data';
import { addFilter } from '@wordpress/hooks';
import { MoveToWidgetArea, getWidgetIdFromBlock } from '@wordpress/widgets';

Expand All @@ -22,14 +22,17 @@ import {
useSidebarControls,
useActiveSidebarControl,
} from '../components/sidebar-controls';
import { useFocusControl } from '../components/focus-control';
import { blockToWidget } from '../utils';

const withMoveToSidebarToolbarItem = createHigherOrderComponent(
( BlockEdit ) => ( props ) => {
const widgetId = getWidgetIdFromBlock( props );
let widgetId = getWidgetIdFromBlock( props );
const sidebarControls = useSidebarControls();
const activeSidebarControl = useActiveSidebarControl();
const hasMultipleSidebars = sidebarControls?.length > 1;
const blockName = props.name;
const clientId = props.clientId;
const canInsertBlockInSidebar = useSelect(
( select ) => {
// Use an empty string to represent the root block list, which
Expand All @@ -41,19 +44,46 @@ const withMoveToSidebarToolbarItem = createHigherOrderComponent(
},
[ blockName ]
);
const block = useSelect(
( select ) => select( blockEditorStore ).getBlock( clientId ),
[ clientId ]
);
const { removeBlock } = useDispatch( blockEditorStore );
const [ , focusWidget ] = useFocusControl();

function moveToSidebar( sidebarControlId ) {
const newSidebarControl = sidebarControls.find(
( sidebarControl ) => sidebarControl.id === sidebarControlId
);

const oldSetting = activeSidebarControl.setting;
const newSetting = newSidebarControl.setting;
if ( widgetId ) {
/**
* If there's a widgetId, move it to the other sidebar.
*/
const oldSetting = activeSidebarControl.setting;
const newSetting = newSidebarControl.setting;

oldSetting( without( oldSetting(), widgetId ) );
newSetting( [ ...newSetting(), widgetId ] );
} else {
/**
* If there isn't a widgetId, it's most likely a inner block.
* First, remove the block in the original sidebar,
* then, create a new widget in the new sidebar and get back its widgetId.
*/
const sidebarAdapter = newSidebarControl.sidebarAdapter;

oldSetting( without( oldSetting(), widgetId ) );
newSetting( [ ...newSetting(), widgetId ] );
removeBlock( clientId );
const addedWidgetIds = sidebarAdapter.setWidgets( [
...sidebarAdapter.getWidgets(),
blockToWidget( block ),
] );
// The last non-null id is the added widget's id.
widgetId = addedWidgetIds.reverse().find( ( id ) => !! id );
}

newSidebarControl.expand();
// Move focus to the moved widget and expand the sidebar.
focusWidget( widgetId );
}

return (
Expand Down
112 changes: 112 additions & 0 deletions packages/customize-widgets/src/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
// @ts-check
/**
* WordPress dependencies
*/
import { serialize, parse, createBlock } from '@wordpress/blocks';
import { addWidgetIdToBlock } from '@wordpress/widgets';

/**
* External dependencies
*/
import { omit } from 'lodash';

/**
* Convert settingId to widgetId.
Expand All @@ -18,3 +28,105 @@ export function settingIdToWidgetId( settingId ) {

return settingId;
}

/**
* Transform a block to a customizable widget.
*
* @param {WPBlock} block The block to be transformed from.
* @param {Object} existingWidget The widget to be extended from.
* @return {Object} The transformed widget.
*/
export function blockToWidget( block, existingWidget = null ) {
let widget;

const isValidLegacyWidgetBlock =
block.name === 'core/legacy-widget' &&
( block.attributes.id || block.attributes.instance );

if ( isValidLegacyWidgetBlock ) {
if ( block.attributes.id ) {
// Widget that does not extend WP_Widget.
widget = {
id: block.attributes.id,
};
} else {
const { encoded, hash, raw, ...rest } = block.attributes.instance;

// Widget that extends WP_Widget.
widget = {
idBase: block.attributes.idBase,
instance: {
...existingWidget?.instance,
// Required only for the customizer.
is_widget_customizer_js_value: true,
encoded_serialized_instance: encoded,
instance_hash_key: hash,
raw_instance: raw,
...rest,
},
};
}
} else {
const instance = {
content: serialize( block ),
};
widget = {
idBase: 'block',
widgetClass: 'WP_Widget_Block',
instance: {
raw_instance: instance,
},
};
}

return {
...omit( existingWidget, [ 'form', 'rendered' ] ),
...widget,
};
}

/**
* Transform a widget to a block.
*
* @param {Object} widget The widget to be transformed from.
* @param {string} widget.id The widget id.
* @param {string} widget.idBase The id base of the widget.
* @param {number} widget.number The number/index of the widget.
* @param {Object} widget.instance The instance of the widget.
* @return {WPBlock} The transformed block.
*/
export function widgetToBlock( { id, idBase, number, instance } ) {
let block;

const {
encoded_serialized_instance: encoded,
instance_hash_key: hash,
raw_instance: raw,
...rest
} = instance;

if ( idBase === 'block' ) {
const parsedBlocks = parse( raw.content );
block = parsedBlocks.length
? parsedBlocks[ 0 ]
: createBlock( 'core/paragraph', {} );
} else if ( number ) {
// Widget that extends WP_Widget.
block = createBlock( 'core/legacy-widget', {
idBase,
instance: {
encoded,
hash,
raw,
...rest,
},
} );
} else {
// Widget that does not extend WP_Widget.
block = createBlock( 'core/legacy-widget', {
id,
} );
}

return addWidgetIdToBlock( block, id );
}