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

Patterns: avoid fetching on load #57929

Closed
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
2 changes: 2 additions & 0 deletions packages/block-editor/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import reducer from './reducer';
import * as selectors from './selectors';
import * as privateActions from './private-actions';
import * as privateSelectors from './private-selectors';
import * as resolvers from './resolvers';
import * as actions from './actions';
import { STORE_NAME } from './constants';
import { unlock } from '../lock-unlock';
Expand All @@ -22,6 +23,7 @@ import { unlock } from '../lock-unlock';
export const storeConfig = {
reducer,
selectors,
resolvers,
actions,
};

Expand Down
116 changes: 91 additions & 25 deletions packages/block-editor/src/store/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
import createSelector from 'rememo';

/**
* WordPress dependencies
*/
import { createRegistrySelector } from '@wordpress/data';

/**
* Internal dependencies
*/
Expand All @@ -11,11 +16,12 @@ import {
getBlockParents,
getBlockEditingMode,
getSettings,
__experimentalGetParsedPattern,
canInsertBlockType,
__experimentalGetAllowedPatterns,
} from './selectors';
import { getAllPatterns, checkAllowListRecursive } from './utils';
import { checkAllowListRecursive } from './utils';
import { INSERTER_PATTERN_TYPES } from '../components/inserter/block-patterns-tab/utils';
import { store } from './';
import { unlock } from '../lock-unlock';

/**
* Returns true if the block interface is hidden, or false otherwise.
Expand Down Expand Up @@ -242,6 +248,10 @@ export const getInserterMediaCategories = createSelector(
]
);

export function getFetchedPatterns( state ) {
return state.blockPatterns;
}

/**
* Returns whether there is at least one allowed pattern for inner blocks children.
* This is useful for deferring the parsing of all patterns until needed.
Expand All @@ -251,29 +261,85 @@ export const getInserterMediaCategories = createSelector(
*
* @return {boolean} If there is at least one allowed pattern.
*/
export const hasAllowedPatterns = createSelector(
( state, rootClientId = null ) => {
const patterns = getAllPatterns( state );
const { allowedBlockTypes } = getSettings( state );
return patterns.some( ( { name, inserter = true } ) => {
if ( ! inserter ) {
return false;
}
const { blocks } = __experimentalGetParsedPattern( state, name );
return (
checkAllowListRecursive( blocks, allowedBlockTypes ) &&
blocks.every( ( { name: blockName } ) =>
canInsertBlockType( state, blockName, rootClientId )
)
export const hasAllowedPatterns = createRegistrySelector( ( select ) =>
createSelector(
( state, rootClientId = null ) => {
const { getAllPatterns, __experimentalGetParsedPattern } = unlock(
select( store )
);
} );
},
( state, rootClientId ) => [
...__experimentalGetAllowedPatterns.getDependants(
state,
rootClientId
),
]
const patterns = getAllPatterns();
const { allowedBlockTypes } = getSettings( state );
return patterns.some( ( { name, inserter = true } ) => {
if ( ! inserter ) {
return false;
}
const { blocks } = __experimentalGetParsedPattern( name );
return (
checkAllowListRecursive( blocks, allowedBlockTypes ) &&
blocks.every( ( { name: blockName } ) =>
canInsertBlockType( state, blockName, rootClientId )
)
);
} );
},
( state, rootClientId ) => [
state.blockPatterns,
state.settings.allowedBlockTypes,
state.settings.templateLock,
state.blockListSettings[ rootClientId ],
state.blocks.byClientId.get( rootClientId ),
]
)
);

export const getAllPatterns = createRegistrySelector( ( select ) =>
createSelector(
( state ) => {
// This setting is left for back compat.
const {
__experimentalBlockPatterns,
__experimentalFetchBlockPatterns,
__experimentalUserPatternCategories = [],
__experimentalReusableBlocks = [],
} = state.settings;
const userPatterns = ( __experimentalReusableBlocks ?? [] ).map(
( userPattern ) => {
return {
name: `core/block/${ userPattern.id }`,
id: userPattern.id,
type: INSERTER_PATTERN_TYPES.user,
title: userPattern.title.raw,
categories: userPattern.wp_pattern_category.map(
( catId ) => {
const category = (
__experimentalUserPatternCategories ?? []
).find( ( { id } ) => id === catId );
return category ? category.slug : catId;
}
),
content: userPattern.content.raw,
syncStatus: userPattern.wp_pattern_sync_status,
};
}
);
return [
...userPatterns,
...__experimentalBlockPatterns,
...unlock( select( store ) ).getFetchedPatterns(
__experimentalFetchBlockPatterns
),
];
},
( state ) => {
return [
state.settings.__experimentalBlockPatterns,
state.settings.__experimentalUserPatternCategories,
state.settings.__experimentalReusableBlocks,
state.settings.__experimentalFetchBlockPatterns,
state.blockPatterns,
];
}
)
);

/**
Expand Down
10 changes: 10 additions & 0 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2017,6 +2017,15 @@ export function lastFocus( state = false, action ) {
return state;
}

function blockPatterns( state = [], action ) {
switch ( action.type ) {
case 'RECEIVE_BLOCK_PATTERNS':
return action.patterns;
}

return state;
}

const combinedReducers = combineReducers( {
blocks,
isTyping,
Expand Down Expand Up @@ -2047,6 +2056,7 @@ const combinedReducers = combineReducers( {
blockRemovalRules,
openedBlockSettingsMenu,
registeredInserterMediaCategories,
blockPatterns,
} );

function withAutomaticChangeReset( reducer ) {
Expand Down
6 changes: 6 additions & 0 deletions packages/block-editor/src/store/resolvers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const getFetchedPatterns =
( fetch ) =>
async ( { dispatch } ) => {
const patterns = await fetch();
dispatch( { type: 'RECEIVE_BLOCK_PATTERNS', patterns } );
};
171 changes: 90 additions & 81 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ import { createRegistrySelector } from '@wordpress/data';
/**
* Internal dependencies
*/
import {
getAllPatterns,
checkAllowListRecursive,
checkAllowList,
} from './utils';
import { checkAllowListRecursive, checkAllowList } from './utils';
import { orderBy } from '../utils/sorting';
import { store } from './';
import { unlock } from '../lock-unlock';

/**
* A block selection object.
Expand Down Expand Up @@ -2239,39 +2237,27 @@ export const __experimentalGetDirectInsertBlock = createSelector(
]
);

export const __experimentalGetParsedPattern = createSelector(
( state, patternName ) => {
const patterns = getAllPatterns( state );
const pattern = patterns.find( ( { name } ) => name === patternName );
if ( ! pattern ) {
return null;
}
return {
...pattern,
blocks: parse( pattern.content, {
__unstableSkipMigrationLogs: true,
} ),
};
},
( state ) => [ getAllPatterns( state ) ]
);

const getAllAllowedPatterns = createSelector(
( state ) => {
const patterns = getAllPatterns( state );
const { allowedBlockTypes } = getSettings( state );

const parsedPatterns = patterns
.filter( ( { inserter = true } ) => !! inserter )
.map( ( { name } ) =>
__experimentalGetParsedPattern( state, name )
);
const allowedPatterns = parsedPatterns.filter( ( { blocks } ) =>
checkAllowListRecursive( blocks, allowedBlockTypes )
);
return allowedPatterns;
},
( state ) => [ getAllPatterns( state ), state.settings.allowedBlockTypes ]
export const __experimentalGetParsedPattern = createRegistrySelector(
( select ) =>
createSelector(
( state, patternName ) => {
const { getAllPatterns } = unlock( select( store ) );
const patterns = getAllPatterns();
const pattern = patterns.find(
( { name } ) => name === patternName
);
if ( ! pattern ) {
return null;
}
return {
...pattern,
blocks: parse( pattern.content, {
__unstableSkipMigrationLogs: true,
} ),
};
},
( state ) => [ state.blockPatterns ]
)
);

/**
Expand All @@ -2282,24 +2268,44 @@ const getAllAllowedPatterns = createSelector(
*
* @return {Array?} The list of allowed patterns.
*/
export const __experimentalGetAllowedPatterns = createSelector(
( state, rootClientId = null ) => {
const availableParsedPatterns = getAllAllowedPatterns( state );
const patternsAllowed = availableParsedPatterns.filter(
( { blocks } ) =>
blocks.every( ( { name } ) =>
canInsertBlockType( state, name, rootClientId )
)
);
export const __experimentalGetAllowedPatterns = createRegistrySelector(
( select ) => {
return createSelector(
( state, rootClientId = null ) => {
const {
getAllPatterns,
__experimentalGetParsedPattern: getParsedPattern,
} = unlock( select( store ) );
const patterns = getAllPatterns();
const { allowedBlockTypes } = getSettings( state );

const parsedPatterns = patterns
.filter( ( { inserter = true } ) => !! inserter )
.map( ( { name } ) => getParsedPattern( name ) );
const availableParsedPatterns = parsedPatterns.filter(
( { blocks } ) =>
checkAllowListRecursive( blocks, allowedBlockTypes )
);
const patternsAllowed = availableParsedPatterns.filter(
( { blocks } ) =>
blocks.every( ( { name } ) =>
canInsertBlockType( state, name, rootClientId )
)
);

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

/**
Expand All @@ -2315,32 +2321,35 @@ export const __experimentalGetAllowedPatterns = createSelector(
*
* @return {Array} The list of matched block patterns based on declared `blockTypes` and block name.
*/
export const getPatternsByBlockTypes = createSelector(
( state, blockNames, rootClientId = null ) => {
if ( ! blockNames ) return EMPTY_ARRAY;
const patterns = __experimentalGetAllowedPatterns(
state,
rootClientId
);
const normalizedBlockNames = Array.isArray( blockNames )
? blockNames
: [ blockNames ];
const filteredPatterns = patterns.filter( ( pattern ) =>
pattern?.blockTypes?.some?.( ( blockName ) =>
normalizedBlockNames.includes( blockName )
)
);
if ( filteredPatterns.length === 0 ) {
return EMPTY_ARRAY;
}
return filteredPatterns;
},
( state, blockNames, rootClientId ) => [
...__experimentalGetAllowedPatterns.getDependants(
state,
rootClientId
),
]
export const getPatternsByBlockTypes = createRegistrySelector( ( select ) =>
createSelector(
( state, blockNames, rootClientId = null ) => {
if ( ! blockNames ) return EMPTY_ARRAY;
const patterns = select( store ).__experimentalGetAllowedPatterns(
state,
rootClientId
);
const normalizedBlockNames = Array.isArray( blockNames )
? blockNames
: [ blockNames ];
const filteredPatterns = patterns.filter( ( pattern ) =>
pattern?.blockTypes?.some?.( ( blockName ) =>
normalizedBlockNames.includes( blockName )
)
);
if ( filteredPatterns.length === 0 ) {
return EMPTY_ARRAY;
}
return filteredPatterns;
},
( state, blockNames, rootClientId ) => [
state.blockPatterns,
state.settings.allowedBlockTypes,
state.settings.templateLock,
state.blockListSettings[ rootClientId ],
state.blocks.byClientId.get( rootClientId ),
]
)
);

export const __experimentalGetPatternsByBlockTypes = createSelector(
Expand Down
Loading
Loading