Skip to content

Commit

Permalink
[Block Library - Query Loop]: Connect scoped block variation to `in…
Browse files Browse the repository at this point in the history
…serter` variations (#46410)

* [Block Library - Query Loop]: Connect scoped `block` variation to `inserter` variations

* address feedback and support multiple variations connections

* add docs
  • Loading branch information
ntsekouras authored Dec 20, 2022
1 parent 4cc4c3c commit a83f7fa
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ The Query Loop block determines if there is an active variation of itself and if

In order for a pattern to be “connected” with a Query Loop variation, you should add the name of your variation prefixed with the Query Loop name (e.g. `core/query/$variation_name`) to the pattern's `blockTypes` property. For more details about registering patterns [see here](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-patterns/).

If you have not provided `innerBlocks` in your variation, there is also a way to suggest “connected” variations when the user selects `Start blank` in the setup phase. This is handled in a similar fashion with “connected” patterns, by checking if there is an active variation of Query Loop and if there are any connected variations to suggest.

In order for a variation to be connected to another Query Loop variation we need to define the `scope` attribute with `['block']` as value and the `namespace` attribute defined as an array. This array should contain the names(`name` property) of any variations they want to be connected to.

For example, if we have a Query Loop variation exposed to the inserter(`scope: ['inserter']`) with the name `products`, we can connect a scoped `block` variation by setting its `namespace` attribute to `['products']`. If the user selects this variation after having clicked `Start blank`, the namespace attribute will be overridden by the main inserter variation.

### Making Gutenberg recognize your variation

There is one slight problem you might have realized after implementing this variation: while it is transparent to the user as they are inserting it, Gutenberg will still recognize the variation as a Query Loop block at its core and so, after its insertion, it will show up as a Query Loop block in the tree view of the editor, for instance.
Expand Down
29 changes: 15 additions & 14 deletions packages/block-library/src/query/edit/query-placeholder.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ import {
import { Button, Placeholder } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { useScopedBlockVariations } from '../utils';

export default function QueryPlaceholder( {
attributes,
clientId,
Expand Down Expand Up @@ -57,7 +62,6 @@ export default function QueryPlaceholder( {
return (
<QueryVariationPicker
clientId={ clientId }
name={ name }
attributes={ attributes }
setAttributes={ setAttributes }
icon={ icon }
Expand Down Expand Up @@ -98,41 +102,38 @@ export default function QueryPlaceholder( {

function QueryVariationPicker( {
clientId,
name,
attributes,
setAttributes,
icon,
label,
} ) {
const variations = useSelect(
( select ) => select( blocksStore ).getBlockVariations( name, 'block' ),
[ name ]
);
const scopeVariations = useScopedBlockVariations( attributes );
const { replaceInnerBlocks } = useDispatch( blockEditorStore );
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
<__experimentalBlockVariationPicker
icon={ icon }
label={ label }
variations={ variations }
onSelect={ ( nextVariation ) => {
if ( nextVariation.attributes ) {
variations={ scopeVariations }
onSelect={ ( variation ) => {
if ( variation.attributes ) {
setAttributes( {
...nextVariation.attributes,
...variation.attributes,
query: {
...nextVariation.attributes.query,
...variation.attributes.query,
postType:
attributes.query.postType ||
nextVariation.attributes.query.postType,
variation.attributes.query.postType,
},
namespace: attributes.namespace,
} );
}
if ( nextVariation.innerBlocks ) {
if ( variation.innerBlocks ) {
replaceInnerBlocks(
clientId,
createBlocksFromInnerBlocksTemplate(
nextVariation.innerBlocks
variation.innerBlocks
),
false
);
Expand Down
60 changes: 59 additions & 1 deletion packages/block-library/src/query/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { cloneBlock, store as blocksStore } from '@wordpress/blocks';
*/
import { name as queryLoopName } from './block.json';

/** @typedef {import('@wordpress/blocks').WPBlockVariation} WPBlockVariation */

/**
* @typedef IHasNameAndId
* @property {string|number} id The entity's id.
Expand Down Expand Up @@ -237,7 +239,6 @@ export function useBlockNameForPatterns( clientId, attributes ) {
queryLoopName,
attributes
)?.name,

[ attributes ]
);
const blockName = `${ queryLoopName }/${ activeVariationName }`;
Expand All @@ -260,3 +261,60 @@ export function useBlockNameForPatterns( clientId, attributes ) {
);
return activeVariationPatterns?.length ? blockName : queryLoopName;
}

/**
* Helper hook that determines if there is an active variation of the block
* and if there are available specific scoped `block` variations connected with
* this variation.
*
* If there are, these variations are going to be the only ones suggested
* to the user in setup flow when clicking to `start blank`, without including
* the default ones for Query Loop.
*
* If there are no such scoped `block` variations, the default ones for Query
* Loop are going to be suggested.
*
* The way we determine such variations is with the convention that they have the `namespace`
* attribute defined as an array. This array should contain the names(`name` property) of any
* variations they want to be connected to.
* For example, if we have a `Query Loop` scoped `inserter` variation with the name `products`,
* we can connect a scoped `block` variation by setting its `namespace` attribute to `['products']`.
* If the user selects this variation, the `namespace` attribute will be overridden by the
* main `inserter` variation.
*
* @param {Object} attributes The block's attributes.
* @return {WPBlockVariation[]} The block variations to be suggested in setup flow, when clicking to `start blank`.
*/
export function useScopedBlockVariations( attributes ) {
const { activeVariationName, blockVariations } = useSelect(
( select ) => {
const { getActiveBlockVariation, getBlockVariations } =
select( blocksStore );
return {
activeVariationName: getActiveBlockVariation(
queryLoopName,
attributes
)?.name,
blockVariations: getBlockVariations( queryLoopName, 'block' ),
};
},
[ attributes ]
);
const variations = useMemo( () => {
// Filter out the variations that have defined a `namespace` attribute,
// which means they are 'connected' to specific variations of the block.
const isNotConnected = ( variation ) =>
! variation.attributes?.namespace;
if ( ! activeVariationName ) {
return blockVariations.filter( isNotConnected );
}
const connectedVariations = blockVariations.filter( ( variation ) =>
variation.attributes?.namespace?.includes( activeVariationName )
);
if ( !! connectedVariations.length ) {
return connectedVariations;
}
return blockVariations.filter( isNotConnected );
}, [ activeVariationName, blockVariations ] );
return variations;
}

1 comment on commit a83f7fa

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/3738971008
📝 Reported issues:

Please sign in to comment.