-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Template Parts: Add an option to import widgets from the sidebars (#4…
…5509) * Template Part: Introduce an option to import widgets * Only display active sidebars with widgets as options * Use the sidebar name as the new template part title * Support legacy widgets * Prefix imported template parts to avoid name collision * Add missing docblock * Update labels * Move settings into the advanced inspector controls panel * Update API response for sidebars and mark them as 'inactive' * A minor design adjustments * Fix the rendering order bug * Transform legacy widgets before importing * Avoid hardcoding names of the blocks with wildcard transformations * Skip 'wp_inactive_widgets' widget area * Use 'HStack' * Allow overriding Legacy Widget block settings during registration * Override only supports settings * Improve spacing * Add the legacy widget to the post editor Co-authored-by: Robert Anderson <[email protected]>
- Loading branch information
1 parent
489d48a
commit 1e6538b
Showing
14 changed files
with
322 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
/** | ||
* Theme overrides for WP 6.2. | ||
* | ||
* @package gutenberg | ||
*/ | ||
|
||
/** | ||
* Store legacy sidebars for later use by block themes. | ||
* | ||
* Note: This can be a part of the `switch_theme` method in `wp-includes/theme.php`. | ||
* | ||
* @param string $new_name Name of the new theme. | ||
* @param WP_Theme $new_theme WP_Theme instance of the new theme. | ||
*/ | ||
function gutenberg_set_legacy_sidebars( $new_name, $new_theme ) { | ||
global $wp_registered_sidebars; | ||
|
||
if ( $new_theme->is_block_theme() ) { | ||
set_theme_mod( 'wp_legacy_sidebars', $wp_registered_sidebars ); | ||
} | ||
} | ||
add_action( 'switch_theme', 'gutenberg_set_legacy_sidebars', 10, 2 ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
/** | ||
* Core Widget APIs for WP 6.2. | ||
* | ||
* @package gutenberg | ||
*/ | ||
|
||
if ( ! function_exists( '_wp_block_theme_stub_sidebars' ) ) { | ||
/** | ||
* Register the previous theme's sidebars for the block themes. | ||
* | ||
* @return void | ||
*/ | ||
function _wp_block_theme_stub_sidebars() { | ||
global $wp_registered_sidebars; | ||
|
||
if ( ! wp_is_block_theme() ) { | ||
return; | ||
} | ||
|
||
$legacy_sidebars = get_theme_mod( 'wp_legacy_sidebars' ); | ||
if ( empty( $legacy_sidebars ) ) { | ||
return; | ||
} | ||
|
||
// Don't use `register_sidebar` since it will enable the `widgets` support for a theme. | ||
foreach ( $legacy_sidebars as $sidebar ) { | ||
$wp_registered_sidebars[ $sidebar['id'] ] = $sidebar; | ||
} | ||
} | ||
add_action( 'widgets_init', '_wp_block_theme_stub_sidebars' ); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
180 changes: 180 additions & 0 deletions
180
packages/block-library/src/template-part/edit/import-controls.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __, sprintf } from '@wordpress/i18n'; | ||
import { useMemo, useState } from '@wordpress/element'; | ||
import { useDispatch, useSelect, useRegistry } from '@wordpress/data'; | ||
import { | ||
Button, | ||
FlexBlock, | ||
FlexItem, | ||
SelectControl, | ||
__experimentalHStack as HStack, | ||
__experimentalSpacer as Spacer, | ||
} from '@wordpress/components'; | ||
import { | ||
switchToBlockType, | ||
getPossibleBlockTransformations, | ||
} from '@wordpress/blocks'; | ||
import { store as coreStore } from '@wordpress/core-data'; | ||
import { store as noticesStore } from '@wordpress/notices'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { useCreateTemplatePartFromBlocks } from './utils/hooks'; | ||
import { transformWidgetToBlock } from './utils/transformers'; | ||
|
||
export function TemplatePartImportControls( { area, setAttributes } ) { | ||
const [ selectedSidebar, setSelectedSidebar ] = useState( '' ); | ||
const [ isBusy, setIsBusy ] = useState( false ); | ||
|
||
const registry = useRegistry(); | ||
const sidebars = useSelect( ( select ) => { | ||
return select( coreStore ).getSidebars( { | ||
per_page: -1, | ||
_fields: 'id,name,description,status,widgets', | ||
} ); | ||
}, [] ); | ||
const { createErrorNotice } = useDispatch( noticesStore ); | ||
|
||
const createFromBlocks = useCreateTemplatePartFromBlocks( | ||
area, | ||
setAttributes | ||
); | ||
|
||
const options = useMemo( () => { | ||
const sidebarOptions = ( sidebars ?? [] ) | ||
.filter( | ||
( widgetArea ) => | ||
widgetArea.id !== 'wp_inactive_widgets' && | ||
widgetArea.widgets.length > 0 | ||
) | ||
.map( ( widgetArea ) => { | ||
return { | ||
value: widgetArea.id, | ||
label: widgetArea.name, | ||
}; | ||
} ); | ||
|
||
if ( ! sidebarOptions.length ) { | ||
return []; | ||
} | ||
|
||
return [ | ||
{ value: '', label: __( 'Select widget area' ) }, | ||
...sidebarOptions, | ||
]; | ||
}, [ sidebars ] ); | ||
|
||
async function createFromWidgets( event ) { | ||
event.preventDefault(); | ||
|
||
if ( isBusy || ! selectedSidebar ) { | ||
return; | ||
} | ||
|
||
setIsBusy( true ); | ||
|
||
const sidebar = options.find( | ||
( { value } ) => value === selectedSidebar | ||
); | ||
const { getWidgets } = registry.resolveSelect( coreStore ); | ||
|
||
// The widgets API always returns a successful response. | ||
const widgets = await getWidgets( { | ||
sidebar: sidebar.value, | ||
_embed: 'about', | ||
} ); | ||
|
||
const skippedWidgets = new Set(); | ||
const blocks = widgets.flatMap( ( widget ) => { | ||
const block = transformWidgetToBlock( widget ); | ||
|
||
if ( block.name !== 'core/legacy-widget' ) { | ||
return block; | ||
} | ||
|
||
const transforms = getPossibleBlockTransformations( [ | ||
block, | ||
] ).filter( ( item ) => { | ||
// The block without any transformations can't be a wildcard. | ||
if ( ! item.transforms ) { | ||
return true; | ||
} | ||
|
||
const hasWildCardFrom = item.transforms?.from?.find( | ||
( from ) => from.blocks && from.blocks.includes( '*' ) | ||
); | ||
const hasWildCardTo = item.transforms?.to?.find( | ||
( to ) => to.blocks && to.blocks.includes( '*' ) | ||
); | ||
|
||
return ! hasWildCardFrom && ! hasWildCardTo; | ||
} ); | ||
|
||
// Skip the block if we have no matching transformations. | ||
if ( ! transforms.length ) { | ||
skippedWidgets.add( widget.id_base ); | ||
return []; | ||
} | ||
|
||
// Try transforming the Legacy Widget into a first matching block. | ||
return switchToBlockType( block, transforms[ 0 ].name ); | ||
} ); | ||
|
||
await createFromBlocks( | ||
blocks, | ||
/* translators: %s: name of the widget area */ | ||
sprintf( __( 'Widget area: %s' ), sidebar.label ) | ||
); | ||
|
||
if ( skippedWidgets.size ) { | ||
createErrorNotice( | ||
sprintf( | ||
/* translators: %s: the list of widgets */ | ||
__( 'Unable to import the following widgets: %s.' ), | ||
Array.from( skippedWidgets ).join( ', ' ) | ||
), | ||
{ | ||
type: 'snackbar', | ||
} | ||
); | ||
} | ||
|
||
setIsBusy( false ); | ||
} | ||
|
||
return ( | ||
<Spacer marginBottom="4"> | ||
<HStack as="form" onSubmit={ createFromWidgets }> | ||
<FlexBlock> | ||
<SelectControl | ||
label={ __( 'Import widget area' ) } | ||
value={ selectedSidebar } | ||
options={ options } | ||
onChange={ ( value ) => setSelectedSidebar( value ) } | ||
disabled={ ! options.length } | ||
__next36pxDefaultSize | ||
__nextHasNoMarginBottom | ||
/> | ||
</FlexBlock> | ||
<FlexItem | ||
style={ { | ||
marginBottom: '8px', | ||
marginTop: 'auto', | ||
} } | ||
> | ||
<Button | ||
variant="primary" | ||
type="submit" | ||
isBusy={ isBusy } | ||
aria-disabled={ isBusy || ! selectedSidebar } | ||
> | ||
{ __( 'Import' ) } | ||
</Button> | ||
</FlexItem> | ||
</HStack> | ||
</Spacer> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
packages/block-library/src/template-part/edit/utils/transformers.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { createBlock, parse } from '@wordpress/blocks'; | ||
|
||
/** | ||
* Converts a widget entity record into a block. | ||
* | ||
* @param {Object} widget The widget entity record. | ||
* @return {Object} a block (converted from the entity record). | ||
*/ | ||
export function transformWidgetToBlock( widget ) { | ||
if ( widget.id_base === 'block' ) { | ||
const parsedBlocks = parse( widget.instance.raw.content, { | ||
__unstableSkipAutop: true, | ||
} ); | ||
if ( ! parsedBlocks.length ) { | ||
return createBlock( 'core/paragraph', {}, [] ); | ||
} | ||
|
||
return parsedBlocks[ 0 ]; | ||
} | ||
|
||
let attributes; | ||
if ( widget._embedded.about[ 0 ].is_multi ) { | ||
attributes = { | ||
idBase: widget.id_base, | ||
instance: widget.instance, | ||
}; | ||
} else { | ||
attributes = { | ||
id: widget.id, | ||
}; | ||
} | ||
|
||
return createBlock( 'core/legacy-widget', attributes, [] ); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.