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

Show patterns in inserter for non-root level insert destinations #28459

Merged
merged 16 commits into from
Feb 9, 2021
Merged
Show file tree
Hide file tree
Changes from 15 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 @@ -18,12 +18,14 @@ import usePatternsState from './hooks/use-patterns-state';
import BlockPatternList from '../block-patterns-list';

function BlockPatternsCategory( {
rootClientId,
onInsert,
selectedCategory,
onClickCategory,
} ) {
const [ allPatterns, allCategories, onClick ] = usePatternsState(
onInsert
onInsert,
rootClientId
);

// Remove any empty categories
Expand Down Expand Up @@ -120,9 +122,15 @@ function BlockPatternsCategory( {
);
}

function BlockPatternsTabs( { onInsert, onClickCategory, selectedCategory } ) {
function BlockPatternsTabs( {
rootClientId,
onInsert,
onClickCategory,
selectedCategory,
} ) {
return (
<BlockPatternsCategory
rootClientId={ rootClientId }
selectedCategory={ selectedCategory }
onInsert={ onInsert }
onClickCategory={ onClickCategory }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,25 @@ import { store as noticesStore } from '@wordpress/notices';
/**
* Retrieves the block patterns inserter state.
*
* @param {Function} onInsert function called when inserter a list of blocks.
* @param {Function} onInsert function called when inserter a list of blocks.
* @param {string=} rootClientId Insertion's root client ID.
*
* @return {Array} Returns the patterns state. (patterns, categories, onSelect handler)
*/
const usePatternsState = ( onInsert ) => {
const { patternCategories, patterns } = useSelect( ( select ) => {
const {
__experimentalBlockPatterns,
__experimentalBlockPatternCategories,
} = select( 'core/block-editor' ).getSettings();
return {
patterns: __experimentalBlockPatterns,
patternCategories: __experimentalBlockPatternCategories,
};
}, [] );
const usePatternsState = ( onInsert, rootClientId ) => {
const { patternCategories, patterns } = useSelect(
( select ) => {
const { __experimentalGetAllowedPatterns, getSettings } = select(
'core/block-editor'
);
return {
patterns: __experimentalGetAllowedPatterns( rootClientId ),
patternCategories: getSettings()
.__experimentalBlockPatternCategories,
};
},
[ rootClientId ]
);
const { createSuccessNotice } = useDispatch( noticesStore );
const onClickPattern = useCallback( ( pattern, blocks ) => {
onInsert(
Expand Down
37 changes: 24 additions & 13 deletions packages/block-editor/src/components/inserter/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,24 @@ function InserterMenu( {
selectBlockOnInsert: __experimentalSelectBlockOnInsert,
insertionIndex: __experimentalInsertionIndex,
} );
const { hasPatterns, hasReusableBlocks } = useSelect( ( select ) => {
const {
__experimentalBlockPatterns,
__experimentalReusableBlocks,
} = select( 'core/block-editor' ).getSettings();
const { showPatterns, hasReusableBlocks } = useSelect(
( select ) => {
const { __experimentalGetAllowedPatterns, getSettings } = select(
'core/block-editor'
);

return {
hasPatterns: !! __experimentalBlockPatterns?.length,
hasReusableBlocks: !! __experimentalReusableBlocks?.length,
};
}, [] );

const showPatterns = ! destinationRootClientId && hasPatterns;
return {
showPatterns:
! destinationRootClientId ||
!! __experimentalGetAllowedPatterns(
destinationRootClientId
).length,
hasReusableBlocks: !! getSettings().__experimentalReusableBlocks
?.length,
};
},
[ destinationRootClientId ]
);

const onInsert = useCallback(
( blocks ) => {
Expand Down Expand Up @@ -125,12 +130,18 @@ function InserterMenu( {
const patternsTab = useMemo(
() => (
<BlockPatternsTabs
rootClientId={ destinationRootClientId }
onInsert={ onInsertPattern }
onClickCategory={ onClickPatternCategory }
selectedCategory={ selectedPatternCategory }
/>
),
[ onInsertPattern, onClickPatternCategory, selectedPatternCategory ]
[
destinationRootClientId,
onInsertPattern,
onClickPatternCategory,
selectedPatternCategory,
]
);

const reusableBlocksTab = useMemo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ export default function QuickInserter( {
onInsertBlocks
);

const [ patterns ] = usePatternsState( onInsertBlocks );
const showPatterns =
! destinationRootClientId && patterns.length && !! filterValue;
const [ patterns ] = usePatternsState(
onInsertBlocks,
destinationRootClientId
);
const showPatterns = patterns.length && !! filterValue;
const showSearch =
( showPatterns && patterns.length > SEARCH_THRESHOLD ) ||
blockTypes.length > SEARCH_THRESHOLD;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ function InserterSearchResults( {
onSelectBlockType,
] = useBlockTypesState( destinationRootClientId, onInsertBlocks );
const [ patterns, , onSelectBlockPattern ] = usePatternsState(
onInsertBlocks
onInsertBlocks,
destinationRootClientId
);

const filteredBlockTypes = useMemo( () => {
Expand Down
45 changes: 45 additions & 0 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
filter,
mapKeys,
orderBy,
every,
} from 'lodash';
import createSelector from 'rememo';

Expand Down Expand Up @@ -1735,6 +1736,50 @@ export const __experimentalGetAllowedBlocks = createSelector(
]
);

const __experimentalGetParsedPatterns = createSelector(
( state ) => {
const patterns = state.settings.__experimentalBlockPatterns;
return map( patterns, ( pattern ) => ( {
...pattern,
contentBlocks: parse( pattern.content ),
} ) );
},
( state ) => [ state.settings.__experimentalBlockPatterns ]
);

/**
* Returns the list of allowed patterns for inner blocks children
*
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional target root client ID.
*
* @return {Array?} The list of allowed block types.
*/
export const __experimentalGetAllowedPatterns = createSelector(
( state, rootClientId = null ) => {
const patterns = __experimentalGetParsedPatterns( state );

if ( ! rootClientId ) {
return patterns;
}

const patternsAllowed = filter( patterns, ( { contentBlocks } ) => {
return every( contentBlocks, ( { name } ) =>
canInsertBlockType( state, name, rootClientId )
);
} );

return patternsAllowed;
},
( state, rootClientId ) => [
state.settings.__experimentalBlockPatterns,
state.settings.allowedBlockTypes,
state.settings.templateLock,
state.blockListSettings[ rootClientId ],
state.blocks.byClientId[ rootClientId ],
]
);

/**
* Returns the Block List settings of a block, if any exist.
*
Expand Down
53 changes: 53 additions & 0 deletions packages/block-editor/src/store/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const {
getLowestCommonAncestorWithSelectedBlock,
__experimentalGetActiveBlockIdByBlockNames: getActiveBlockIdByBlockNames,
__experimentalGetParsedReusableBlock,
__experimentalGetAllowedPatterns,
} = selectors;

describe( 'selectors', () => {
Expand Down Expand Up @@ -3349,6 +3350,58 @@ describe( 'selectors', () => {
).toEqual( 'client-id-03' );
} );
} );

describe( '__experimentalGetAllowedPatterns', () => {
const state = {
blocks: {
byClientId: {
block1: { name: 'core/test-block-a' },
block2: { name: 'core/test-block-b' },
},
attributes: {
block1: {},
block2: {},
},
},
blockListSettings: {
block1: {
allowedBlocks: [ 'core/test-block-b' ],
},
block2: {
allowedBlocks: [],
},
},
settings: {
__experimentalBlockPatterns: [
{
title: 'pattern with a',
content: `<!-- wp:test-block-a --><!-- /wp:test-block-a -->`,
},
{
title: 'pattern with b',
content:
'<!-- wp:test-block-b --><!-- /wp:test-block-b -->',
},
],
},
};

it( 'should return all patterns for root level', () => {
expect(
__experimentalGetAllowedPatterns( state, null )
).toHaveLength( 2 );
} );

it( 'should return patterns that consists of blocks allowed for the specified client ID', () => {
expect(
__experimentalGetAllowedPatterns( state, 'block1' )
).toHaveLength( 1 );

expect(
__experimentalGetAllowedPatterns( state, 'block2' )
).toHaveLength( 0 );
} );
} );
} );

describe( '__experimentalGetParsedReusableBlock', () => {
Expand Down
4 changes: 4 additions & 0 deletions packages/edit-post/src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ function Editor( {
const isFSETheme = getEditorSettings().isFSETheme;
const isViewable = getPostType( postType )?.viewable ?? false;

// Prefetch and parse patterns. This ensures patterns are loaded and parsed when
// the editor is loaded rather than degrading the performance of the inserter.
select( 'core/block-editor' ).__experimentalGetAllowedPatterns();

return {
hasFixedToolbar:
isFeatureActive( 'fixedToolbar' ) ||
Expand Down
4 changes: 4 additions & 0 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ function Editor() {
const postType = getEditedPostType();
const postId = getEditedPostId();

// Prefetch and parse patterns. This ensures patterns are loaded and parsed when
// the editor is loaded rather than degrading the performance of the inserter.
select( 'core/block-editor' ).__experimentalGetAllowedPatterns();

// The currently selected entity to display. Typically template or template part.
return {
isInserterOpen: isInserterOpened(),
Expand Down