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

Block.json: Add ancestor prop to schema #39894

Merged
merged 4 commits into from
Apr 4, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
24 changes: 21 additions & 3 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1382,10 +1382,28 @@ const canInsertBlockTypeUnmemoized = (
parentName
);

let hasBlockAllowedAncestor = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

Hi!

Do we need a default value here?

Copy link
Member

Choose a reason for hiding this comment

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

Yes because if not canInsert will always be false if blockType.ancestor is falsy.

const blockAllowedAncestorBlocks = blockType.ancestor;
if ( blockAllowedAncestorBlocks ) {
const ancestors = [
rootClientId,
...getBlockParents( state, rootClientId ),
];

hasBlockAllowedAncestor = some( ancestors, ( ancestorClientId ) =>
checkAllowList(
blockAllowedAncestorBlocks,
getBlockName( state, ancestorClientId )
)
);
}

const canInsert =
( hasParentAllowedBlock === null && hasBlockAllowedParent === null ) ||
hasParentAllowedBlock === true ||
hasBlockAllowedParent === true;
hasBlockAllowedAncestor &&
( ( hasParentAllowedBlock === null &&
hasBlockAllowedParent === null ) ||
hasParentAllowedBlock === true ||
hasBlockAllowedParent === true );

if ( ! canInsert ) {
return canInsert;
Expand Down
237 changes: 237 additions & 0 deletions packages/block-editor/src/store/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,41 @@ describe( 'selectors', () => {
parent: [ 'core/post-content' ],
} );

registerBlockType( 'core/test-block-ancestor', {
save: ( props ) => props.attributes.text,
category: 'text',
title: 'Test Block required as ancestor',
icon: 'test',
keywords: [ 'testing' ],
} );

registerBlockType( 'core/test-block-parent', {
save: ( props ) => props.attributes.text,
category: 'text',
title: 'Test Block required as parent',
icon: 'test',
keywords: [ 'testing' ],
} );

registerBlockType( 'core/test-block-requires-ancestor', {
save: ( props ) => props.attributes.text,
category: 'text',
title: 'Test Block that requires ancestor',
icon: 'test',
keywords: [ 'testing' ],
ancestor: [ 'core/test-block-ancestor' ],
} );

registerBlockType( 'core/test-block-requires-ancestor-parent', {
save: ( props ) => props.attributes.text,
category: 'text',
title: 'Test Block that requires both ancestor and parent',
icon: 'test',
keywords: [ 'testing' ],
parent: [ 'core/test-block-parent' ],
ancestor: [ 'core/test-block-ancestor' ],
} );

setFreeformContentHandlerName( 'core/test-freeform' );

cachedSelectors.forEach( ( { clear } ) => clear() );
Expand All @@ -158,6 +193,10 @@ describe( 'selectors', () => {
unregisterBlockType( 'core/test-block-c' );
unregisterBlockType( 'core/test-freeform' );
unregisterBlockType( 'core/post-content-child' );
unregisterBlockType( 'core/test-block-ancestor' );
unregisterBlockType( 'core/test-block-parent' );
unregisterBlockType( 'core/test-block-requires-ancestor' );
unregisterBlockType( 'core/test-block-requires-ancestor-parent' );

setFreeformContentHandlerName( undefined );
} );
Expand Down Expand Up @@ -2475,6 +2514,198 @@ describe( 'selectors', () => {
canInsertBlockType( state, 'core/post-content-child' )
).toBe( true );
} );

it( 'should allow blocks to be inserted in a descendant of a required ancestor', () => {
const state = {
blocks: {
byClientId: {
block1: { name: 'core/test-block-ancestor' },
block2: { name: 'core/block' },
},
attributes: {
block1: {},
block2: {},
},
parents: {
block2: 'block1',
},
},
blockListSettings: {
block1: {},
block2: {},
},
settings: {},
};
expect(
canInsertBlockType(
state,
'core/test-block-requires-ancestor',
'block2'
)
).toBe( true );
} );

it( 'should allow blocks to be inserted if both parent and ancestor restrictions are met', () => {
const state = {
blocks: {
byClientId: {
block1: { name: 'core/test-block-ancestor' },
block2: { name: 'core/block' },
block3: { name: 'core/test-block-parent' },
},
attributes: {
block1: {},
block2: {},
block3: {},
},
parents: {
block2: 'block1',
block3: 'block2',
},
},
blockListSettings: {
block1: {},
block2: {},
block3: {},
},
settings: {},
};
expect(
canInsertBlockType(
state,
'core/test-block-requires-ancestor-parent',
'block3'
)
).toBe( true );
} );

it( 'should deny blocks from being inserted outside a required ancestor', () => {
const state = {
blocks: {
byClientId: {
block1: { name: 'core/test-block-ancestor' },
block2: { name: 'core/block' },
block3: { name: 'core/block' },
},
attributes: {
block1: {},
block2: {},
block3: {},
},
parents: {
block3: 'block2',
},
},
blockListSettings: {
block1: {},
block2: {},
block3: {},
},
settings: {},
};
expect(
canInsertBlockType(
state,
'core/test-block-requires-ancestor',
'block3'
)
).toBe( false );
} );

it( 'should deny blocks from being inserted outside of a required ancestor, even if parent matches', () => {
const state = {
blocks: {
byClientId: {
block1: { name: 'core/test-block-ancestor' },
block2: { name: 'core/block' },
block3: { name: 'core/test-block-parent' },
},
attributes: {
block1: {},
block2: {},
block3: {},
},
parents: {
block3: 'block2',
},
},
blockListSettings: {
block1: {},
block2: {},
block3: {},
},
settings: {},
};
expect(
canInsertBlockType(
state,
'core/test-block-requires-ancestor-parent',
'block3'
)
).toBe( false );
} );

it( 'should deny blocks from being inserted inside ancestor if parent restricts allowedBlocks', () => {
const state = {
blocks: {
byClientId: {
block1: { name: 'core/test-block-ancestor' },
block2: { name: 'core/block' },
},
attributes: {
block1: {},
block2: {},
},
parents: {
block2: 'block1',
},
},
blockListSettings: {
block1: {},
block2: {
allowedBlocks: [],
},
},
settings: {},
};
expect(
canInsertBlockType(
state,
'core/test-block-requires-ancestor',
'block2'
)
).toBe( false );
} );

it( 'should deny blocks from being inserted inside ancestor if parent restriction is not met', () => {
const state = {
blocks: {
byClientId: {
block1: { name: 'core/test-block-ancestor' },
block2: { name: 'core/block' },
},
attributes: {
block1: {},
block2: {},
},
parents: {
block2: 'block1',
},
},
blockListSettings: {
block1: {},
block2: {},
},
settings: {},
};
expect(
canInsertBlockType(
state,
'core/test-block-requires-ancestor-parent',
'block2'
)
).toBe( false );
} );
} );

describe( 'canInsertBlocks', () => {
Expand Down Expand Up @@ -2681,6 +2912,8 @@ describe( 'selectors', () => {
'core/test-block-a',
'core/test-block-b',
'core/test-freeform',
'core/test-block-ancestor',
'core/test-block-parent',
'core/block/1',
'core/block/2',
] );
Expand All @@ -2695,6 +2928,8 @@ describe( 'selectors', () => {
'core/test-block-a',
'core/test-block-b',
'core/test-freeform',
'core/test-block-ancestor',
'core/test-block-parent',
'core/block/1',
'core/block/2',
] );
Expand Down Expand Up @@ -2727,6 +2962,7 @@ describe( 'selectors', () => {
},
},
controlledInnerBlocks: {},
parents: {},
},
preferences: {
insertUsage: {},
Expand Down Expand Up @@ -2935,6 +3171,7 @@ describe( 'selectors', () => {
},
},
controlledInnerBlocks: {},
parents: {},
},
preferences: {
insertUsage: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "core/comment-author-avatar",
"title": "Comment Author Avatar",
"category": "theme",
"parent": [ "core/comment-template" ],
"ancestor": [ "core/comment-template" ],
"description": "Displays the avatar of the comment's author.",
"textdomain": "default",
"attributes": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "core/comment-author-name",
"title": "Comment Author Name",
"category": "theme",
"parent": [ "core/comment-template" ],
"ancestor": [ "core/comment-template" ],
"description": "Displays the name of the author of the comment.",
"textdomain": "default",
"attributes": {
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/comment-content/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "core/comment-content",
"title": "Comment Content",
"category": "theme",
"parent": [ "core/comment-template" ],
"ancestor": [ "core/comment-template" ],
"description": "Displays the contents of a comment.",
"textdomain": "default",
"usesContext": [ "commentId" ],
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/comment-date/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "core/comment-date",
"title": "Comment Date",
"category": "theme",
"parent": [ "core/comment-template" ],
"ancestor": [ "core/comment-template" ],
"description": "Displays the date on which the comment was posted.",
"textdomain": "default",
"attributes": {
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/comment-edit-link/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "core/comment-edit-link",
"title": "Comment Edit Link",
"category": "theme",
"parent": [ "core/comment-template" ],
"ancestor": [ "core/comment-template" ],
"description": "Displays a link to edit the comment in the WordPress Dashboard. This link is only visible to users with the edit comment capability.",
"textdomain": "default",
"usesContext": [ "commentId" ],
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/comment-reply-link/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "core/comment-reply-link",
"title": "Comment Reply Link",
"category": "theme",
"parent": [ "core/comment-template" ],
"ancestor": [ "core/comment-template" ],
"description": "Displays a link to reply to a comment.",
"textdomain": "default",
"usesContext": [ "commentId" ],
Expand Down
12 changes: 12 additions & 0 deletions packages/blocks/src/api/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,17 @@ export function unstable__bootstrapServerSideBlockDefinitions( definitions ) {
serverSideBlockDefinitions[ blockName ].apiVersion =
definitions[ blockName ].apiVersion;
}
// The `ancestor` prop is not included in the definitions shared
// from the server yet, so it needs to be polyfilled as well.
// @see https://github.com/WordPress/gutenberg/pull/39894
if (
serverSideBlockDefinitions[ blockName ].ancestor ===
undefined &&
definitions[ blockName ].ancestor
) {
serverSideBlockDefinitions[ blockName ].ancestor =
definitions[ blockName ].ancestor;
}
continue;
}
serverSideBlockDefinitions[ blockName ] = mapKeys(
Expand All @@ -187,6 +198,7 @@ function getBlockSettingsFromMetadata( { textdomain, ...metadata } ) {
'title',
'category',
'parent',
'ancestor',
'icon',
'description',
'keywords',
Expand Down
Loading