diff --git a/docs/designers-developers/developers/data/data-core-block-editor.md b/docs/designers-developers/developers/data/data-core-block-editor.md
index 8fc4996c96df3b..022fcf2cd2db93 100644
--- a/docs/designers-developers/developers/data/data-core-block-editor.md
+++ b/docs/designers-developers/developers/data/data-core-block-editor.md
@@ -253,6 +253,8 @@ _Returns_
Returns all block objects for the current post being edited as an array in
the order they appear in the post.
+Does not include InnerBlocks of blocks which control their own InnerBlocks.
+
Note: It's important to memoize this selector to avoid return a new instance
on each call
@@ -260,6 +262,7 @@ _Parameters_
- _state_ `Object`: Editor state.
- _rootClientId_ `?string`: Optional root client ID of block list.
+- _withControlledInnerBlocks_ `?boolean`: If true, include inner blocks that are controlled by their parent.
_Returns_
@@ -307,6 +310,10 @@ _Returns_
- `?string`: Client ID of block selection start.
+# **getBlockWithoutControlledInnerBlocks**
+
+Undocumented declaration.
+
# **getClientIdsOfDescendants**
Returns an array containing the clientIds of all descendants
diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js
index 0f68df3b37c059..00ecabceebe491 100644
--- a/packages/block-editor/src/store/reducer.js
+++ b/packages/block-editor/src/store/reducer.js
@@ -248,9 +248,7 @@ const withBlockCache = ( reducer ) => ( state = {}, action ) => {
do {
result.push( current );
current = state.parents[ current ];
- // We do not want to include the parent clientID if its inner
- // blocks are controlled so that its cache key stay the same.
- } while ( current && ! state.controlledInnerBlocks[ current ] );
+ } while ( current );
return result;
}, [] );
};
@@ -267,10 +265,7 @@ const withBlockCache = ( reducer ) => ( state = {}, action ) => {
const updatedBlockUids = keys( flattenBlocks( action.blocks ) );
// Only include the rootClientId if its inner blocks are uncontrolled.
- if (
- action.rootClientId &&
- ! state.controlledInnerBlocks[ action.rootClientId ]
- ) {
+ if ( action.rootClientId ) {
updatedBlockUids.push( action.rootClientId );
}
newState.cache = {
diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js
index 244fce9b62a4c9..45acdc6d9c3343 100644
--- a/packages/block-editor/src/store/selectors.js
+++ b/packages/block-editor/src/store/selectors.js
@@ -123,6 +123,9 @@ export function isBlockValid( state, clientId ) {
* @return {Object?} Block attributes.
*/
export function getBlockAttributes( state, clientId ) {
+ if ( ! state.blocks ) {
+ return null;
+ }
const block = state.blocks.byClientId[ clientId ];
if ( ! block ) {
return null;
@@ -137,8 +140,8 @@ export function getBlockAttributes( state, clientId ) {
* is not the block's registration settings, which must be retrieved from the
* blocks module registration store.
*
- * @param {Object} state Editor state.
- * @param {string} clientId Block client ID.
+ * @param {Object} state Editor state.
+ * @param {string} clientId Block client ID.
*
* @return {Object} Parsed block object.
*/
@@ -152,9 +155,7 @@ export const getBlock = createSelector(
return {
...block,
attributes: getBlockAttributes( state, clientId ),
- innerBlocks: areInnerBlocksControlled( state, clientId )
- ? EMPTY_ARRAY
- : getBlocks( state, clientId ),
+ innerBlocks: getBlocks( state, clientId ),
};
},
( state, clientId ) => [
@@ -167,6 +168,28 @@ export const getBlock = createSelector(
]
);
+export const getBlockWithoutControlledInnerBlocks = createSelector(
+ ( state, clientId ) => {
+ const block = state.blocks.byClientId[ clientId ];
+ if ( ! block ) {
+ return null;
+ }
+
+ return {
+ ...block,
+ attributes: getBlockAttributes( state, clientId ),
+ innerBlocks: areInnerBlocksControlled( state, clientId )
+ ? EMPTY_ARRAY
+ : getBlocks( state, clientId, false ),
+ };
+ },
+ ( state, clientId ) => [
+ state.blocks.controlledInnerBlocks[ clientId ]
+ ? getBlockAttributes( clientId )
+ : state.blocks.cache[ clientId ],
+ ]
+);
+
export const __unstableGetBlockWithoutInnerBlocks = createSelector(
( state, clientId ) => {
const block = state.blocks.byClientId[ clientId ];
@@ -189,18 +212,24 @@ 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.
*
+ * Does not include InnerBlocks of blocks which control their own InnerBlocks.
+ *
* Note: It's important to memoize this selector to avoid return a new instance
* on each call
*
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional root client ID of block list.
+ * @param {?boolean} withControlledInnerBlocks If true, include inner blocks that
+ * are controlled by their parent.
*
* @return {Object[]} Post blocks.
*/
export const getBlocks = createSelector(
- ( state, rootClientId ) => {
+ ( state, rootClientId, withControlledInnerBlocks = true ) => {
return map( getBlockOrder( state, rootClientId ), ( clientId ) =>
- getBlock( state, clientId )
+ withControlledInnerBlocks
+ ? getBlock( state, clientId )
+ : getBlockWithoutControlledInnerBlocks( state, clientId )
);
},
( state ) => [