Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create unstable selectors for getting all controlled inner blocks #24835

Merged
merged 4 commits into from
Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,10 @@ then the nested template part's child blocks will not be returned. This way,
the template block itself is considered part of the parent, but the children
are not.

You can override this behavior with the includeControlledInnerBlocks setting.
So if you call `getBlock( TP, { WPGetBlockSettings: true } )`, it will return
all nested blocks, including all child inner block controllers and their children.

_Parameters_

- _state_ `Object`: Editor state.
- _clientId_ `string`: Block client ID.
- _settings_ `?WPGetBlockSettings`: A settings object.

_Returns_

Expand Down Expand Up @@ -282,8 +277,7 @@ _Returns_

Returns all block objects for the current post being edited as an array in
the order they appear in the post. Note that this will exclude child blocks
of nested inner block controllers unless the `includeControlledInnerBlocks`
setting is set to true.
of nested inner block controllers.

Note: It's important to memoize this selector to avoid return a new instance
on each call. We use the block cache state for each top-level block of the
Expand All @@ -295,7 +289,6 @@ _Parameters_

- _state_ `Object`: Editor state.
- _rootClientId_ `?string`: Optional root client ID of block list.
- _settings_ `?WPGetBlockSettings`: A settings object.

_Returns_

Expand Down
11 changes: 5 additions & 6 deletions packages/block-editor/src/components/block-navigation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,15 @@ export default compose(
const {
getSelectedBlockClientId,
getBlockHierarchyRootClientId,
getBlock,
getBlocks,
__unstableGetBlockWithBlockTree,
__unstableGetBlockTree,
} = select( 'core/block-editor' );
const selectedBlockClientId = getSelectedBlockClientId();
return {
rootBlocks: getBlocks( '', { includeControlledInnerBlocks: true } ),
rootBlocks: __unstableGetBlockTree(),
rootBlock: selectedBlockClientId
? getBlock(
getBlockHierarchyRootClientId( selectedBlockClientId ),
{ includeControlledInnerBlocks: true }
? __unstableGetBlockWithBlockTree(
getBlockHierarchyRootClientId( selectedBlockClientId )
)
: null,
selectedBlockClientId,
Expand Down
91 changes: 59 additions & 32 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,6 @@ import { Platform } from '@wordpress/element';
* text value. See `wp.richText.create`.
*/

/**
* Settings which can be passed to the getBlock or getBlocks selectors.
*
* @typedef {Object} WPGetBlockSettings
* @property {boolean} includeControlledInnerBlocks If true, include nested child
* blocks of inner block controllers.
* The default of false excludes
* nested blocks of inner block controllers.
*/

// Module constants
const MILLISECONDS_PER_HOUR = 3600 * 1000;
const MILLISECONDS_PER_DAY = 24 * 3600 * 1000;
Expand Down Expand Up @@ -143,18 +133,13 @@ export function getBlockAttributes( state, clientId ) {
* the template block itself is considered part of the parent, but the children
* are not.
*
* You can override this behavior with the includeControlledInnerBlocks setting.
* So if you call `getBlock( TP, { WPGetBlockSettings: true } )`, it will return
* all nested blocks, including all child inner block controllers and their children.
*
* @param {Object} state Editor state.
* @param {string} clientId Block client ID.
* @param {?WPGetBlockSettings} settings A settings object.
* @param {Object} state Editor state.
* @param {string} clientId Block client ID.
*
* @return {Object} Parsed block object.
*/
export const getBlock = createSelector(
( state, clientId, { includeControlledInnerBlocks = false } = {} ) => {
( state, clientId ) => {
const block = state.blocks.byClientId[ clientId ];
if ( ! block ) {
return null;
Expand All @@ -163,13 +148,9 @@ export const getBlock = createSelector(
return {
...block,
attributes: getBlockAttributes( state, clientId ),
innerBlocks:
! includeControlledInnerBlocks &&
areInnerBlocksControlled( state, clientId )
? EMPTY_ARRAY
: getBlocks( state, clientId, {
includeControlledInnerBlocks,
} ),
innerBlocks: areInnerBlocksControlled( state, clientId )
? EMPTY_ARRAY
: getBlocks( state, clientId ),
};
},
( state, clientId ) => [
Expand Down Expand Up @@ -203,25 +184,23 @@ export const __unstableGetBlockWithoutInnerBlocks = createSelector(
/**
* Returns all block objects for the current post being edited as an array in
* the order they appear in the post. Note that this will exclude child blocks
* of nested inner block controllers unless the `includeControlledInnerBlocks`
* setting is set to true.
* of nested inner block controllers.
*
* Note: It's important to memoize this selector to avoid return a new instance
* on each call. We use the block cache state for each top-level block of the
* given clientID. This way, the selector only refreshes on changes to blocks
* associated with the given entity, and does not refresh when changes are made
* to blocks which are part of different inner block controllers.
*
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional root client ID of block list.
* @param {?WPGetBlockSettings} settings A settings object.
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional root client ID of block list.
*
* @return {Object[]} Post blocks.
*/
export const getBlocks = createSelector(
( state, rootClientId, { includeControlledInnerBlocks = false } = {} ) => {
( state, rootClientId ) => {
return map( getBlockOrder( state, rootClientId ), ( clientId ) =>
getBlock( state, clientId, { includeControlledInnerBlocks } )
getBlock( state, clientId )
);
},
( state, rootClientId ) =>
Expand All @@ -231,6 +210,54 @@ export const getBlocks = createSelector(
)
);

/**
* Similar to getBlock, except it will include the entire nested block tree as
* inner blocks. The normal getBlock selector will exclude sections of the block
* tree which belong to different entities.
*
* @param {Object} state Editor state.
* @param {string} clientId Client ID of the block to get.
*
* @return {Object} The block with all
*/
export const __unstableGetBlockWithBlockTree = createSelector(
( state, clientId ) => {
const block = state.blocks.byClientId[ clientId ];
if ( ! block ) {
return null;
}

return {
...block,
attributes: getBlockAttributes( state, clientId ),
innerBlocks: __unstableGetBlockTree( state, clientId ),
};
},
( state, clientId ) => [ state.blocks.cache[ clientId ] ]
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
);

/**
* Similar to getBlocks, except this selector returns the entire block tree
* represented in the block-editor store from the given root regardless of any
* inner block controllers.
*
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional root client ID of block list.
*
* @return {Object[]} Post blocks.
*/
export const __unstableGetBlockTree = createSelector(
( state, rootClientId = '' ) =>
map( getBlockOrder( state, rootClientId ), ( clientId ) =>
__unstableGetBlockWithBlockTree( state, clientId )
),
( state ) => [
state.blocks.byClientId,
state.blocks.order,
state.blocks.attributes,
]
);

/**
* Returns an array containing the clientIds of all descendants
* of the blocks given.
Expand Down