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

Blocks: Try to move filtering blocks until editor mounts #10554

Closed
wants to merge 2 commits into from
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
1 change: 1 addition & 0 deletions packages/blocks/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export {
getBlockTypes,
getBlockSupport,
hasBlockSupport,
isBlockDefinitionValid,
isReusableBlock,
getChildBlockNames,
hasChildBlocks,
Expand Down
109 changes: 60 additions & 49 deletions packages/blocks/src/api/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { get, isFunction, some } from 'lodash';
/**
* WordPress dependencies
*/
import { applyFilters, addFilter } from '@wordpress/hooks';
import { addFilter } from '@wordpress/hooks';
import { select, dispatch } from '@wordpress/data';

/**
Expand Down Expand Up @@ -53,96 +53,107 @@ export function unstable__bootstrapServerSideBlockDefinitions( definitions ) { /
}

/**
* Registers a new block provided a unique name and an object defining its
* behavior. Once registered, the block is made available as an option to any
* editor interface where blocks are implemented.
* Checks whether a block's definition is valid.
*
* @param {string} name Block name.
* @param {Object} settings Block settings.
*
* @return {?WPBlock} The block, if it has been successfully registered;
* otherwise `undefined`.
* @return {boolean} True when block settings are correct.
*/
export function registerBlockType( name, settings ) {
settings = {
name,
...get( serverSideBlockDefinitions, name ),
...settings,
};

if ( typeof name !== 'string' ) {
console.error(
'Block names must be strings.'
);
return;
}
if ( ! /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test( name ) ) {
console.error(
'Block names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-block'
);
return;
}
if ( select( 'core/blocks' ).getBlockType( name ) ) {
console.error(
'Block "' + name + '" is already registered.'
);
return;
}

settings = applyFilters( 'blocks.registerBlockType', settings, name );

export function isBlockDefinitionValid( settings ) {
if ( ! settings || ! isFunction( settings.save ) ) {
console.error(
'The "save" property must be specified and must be a valid function.'
);
return;
return false;
}
if ( 'edit' in settings && ! isFunction( settings.edit ) ) {
console.error(
'The "edit" property must be a valid function.'
);
return;
return false;
}
if ( 'keywords' in settings && settings.keywords.length > 3 ) {
console.error(
'The block "' + name + '" can have a maximum of 3 keywords.'
'The block "' + settings.name + '" can have a maximum of 3 keywords.'
);
return;
return false;
}
if ( ! ( 'category' in settings ) ) {
console.error(
'The block "' + name + '" must have a category.'
'The block "' + settings.name + '" must have a category.'
);
return;
return false;
}
if (
'category' in settings &&
! some( select( 'core/blocks' ).getCategories(), { slug: settings.category } )
) {
console.error(
'The block "' + name + '" must have a registered category.'
'The block "' + settings.name + '" must have a registered category.'
);
return;
return false;
}
if ( ! ( 'title' in settings ) || settings.title === '' ) {
console.error(
'The block "' + name + '" must have a title.'
'The block "' + settings.name + '" must have a title.'
);
return;
return false;
}
if ( typeof settings.title !== 'string' ) {
console.error(
'Block titles must be strings.'
);
return;
return false;
}

settings.icon = normalizeIconObject( settings.icon );
if ( ! isValidIcon( settings.icon.src ) ) {
console.error(
'The icon passed is invalid. ' +
'The icon should be a string, an element, a function, or an object following the specifications documented in https://wordpress.org/gutenberg/handbook/block-api/#icon-optional'
);
return false;
}

return true;
}

/**
* Registers a new block provided a unique name and an object defining its
* behavior. Once registered, the block is made available as an option to any
* editor interface where blocks are implemented.
*
* @param {string} name Block name.
* @param {Object} settings Block settings.
*
* @return {?WPBlock} The block, if it has been successfully registered;
* otherwise `undefined`.
*/
export function registerBlockType( name, settings = {} ) {
if ( typeof name !== 'string' ) {
console.error(
'Block names must be strings.'
);
return;
}
if ( ! /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test( name ) ) {
console.error(
'Block names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-block'
);
return;
}
if ( select( 'core/blocks' ).getBlockType( name ) ) {
console.error(
'Block "' + name + '" is already registered.'
);
return;
}

settings = {
name,
...get( serverSideBlockDefinitions, name ),
...settings,
icon: normalizeIconObject( settings.icon ),
};

if ( ! isBlockDefinitionValid( settings ) ) {
return;
}

Expand Down
74 changes: 74 additions & 0 deletions packages/edit-post/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { registerCoreBlocks } from '@wordpress/block-library';
import { render, unmountComponentAtNode } from '@wordpress/element';
import { dispatch } from '@wordpress/data';
import deprecated from '@wordpress/deprecated';
import { registerBlockType, registerBlockStyle } from '@wordpress/blocks';
import { addFilter } from '@wordpress/hooks';

/**
* Internal dependencies
Expand Down Expand Up @@ -58,8 +60,80 @@ export function initializeEditor( id, postType, postId, settings, overridePost )
const target = document.getElementById( id );
const reboot = reinitializeEditor.bind( null, postType, postId, target, settings, overridePost );

// TODO: <START>Remove this later</START>.
registerBlockStyle( 'core/list', {
label: 'Large',
name: 'large',
} );
registerBlockStyle( 'wp-js-plugin-starter/hello-world', {
label: 'Hello',
name: 'hello',
} );
addFilter( 'blocks.registerBlockType', 'wp-js-plugin-starter/hello-world/filter-name', ( blockType, name ) => {
if ( name === 'wp-js-plugin-starter/hello-world' ) {
return {
...blockType,
category: 'nope',
};
}

return blockType;
} );
addFilter( 'blocks.registerBlockType', 'wp-js-plugin-starter/hello-world2/filter-name', ( blockType, name ) => {
if ( name === 'wp-js-plugin-starter/hello-world2' ) {
return {
...blockType,
category: 'common',
};
}

return blockType;
} );
// TODO: <END>Remove this later</END>.

registerCoreBlocks();

// TODO: <START>Remove this later</START>.
registerBlockType( 'wp-js-plugin-starter/hello-world', {
title: 'Hello World',
description: 'Just another Hello World block',
icon: 'admin-site',
category: 'widgets',

edit: function() {
return (
<p>Hello Editor</p>
);
},

save: function() {
return (
<p>Hello Frontend</p>
);
},
} );
/*
wp.blocks.registerBlockType( 'wp-js-plugin-starter/hello-world2', {
title: 'Hello World 2',
description: 'Just another Hello World block',
icon: 'admin-site',
category: 'widgets',

edit: function() {
return (
'Hello Editor'
);
},

save: function() {
return (
'Hello Frontend'
);
}
} );
*/
// TODO: <END>Remove this later</END>.

dispatch( 'core/nux' ).triggerGuide( [
'core/editor.inserter',
'core/editor.settings',
Expand Down
69 changes: 55 additions & 14 deletions packages/editor/src/components/provider/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
/**
* External dependencies
*/
import { flow, map } from 'lodash';
import { differenceBy, flow, map } from 'lodash';

/**
* WordPress Dependencies
*/
import { isBlockDefinitionValid, normalizeIconObject } from '@wordpress/blocks';
import { compose } from '@wordpress/compose';
import { createElement, Component } from '@wordpress/element';
import { DropZoneProvider, SlotFillProvider } from '@wordpress/components';
import { withDispatch } from '@wordpress/data';
import { withDispatch, withSelect } from '@wordpress/data';
import { applyFilters } from '@wordpress/hooks';
import isShallowEqual from '@wordpress/is-shallow-equal';

/**
* Internal dependencies
Expand All @@ -22,12 +25,33 @@ class EditorProvider extends Component {

// Assume that we don't need to initialize in the case of an error recovery.
if ( ! props.recovery ) {
this.applyFiltersToBlockTypes( props.blockTypes );
this.props.updateEditorSettings( props.settings );
this.props.updatePostLock( props.settings.postLock );
this.props.setupEditor( props.post, props.settings.autosave );
}
}

applyFiltersToBlockTypes( blockTypes ) {
const { addBlockTypes } = this.props;

const modifiedBlockTypes = blockTypes.map( ( blockType ) => {
const modifiedBlockType = applyFilters( 'blocks.registerBlockType', blockType, blockType.name );

if ( isShallowEqual( blockType, modifiedBlockType ) ) {
return null;
}

modifiedBlockType.icon = normalizeIconObject( modifiedBlockType.icon );

return modifiedBlockType;
} )
.filter( ( blockType ) => blockType !== null )
.filter( isBlockDefinitionValid );

addBlockTypes( modifiedBlockTypes );
}

componentDidMount() {
if ( ! this.props.settings.styles ) {
return;
Expand All @@ -54,6 +78,12 @@ class EditorProvider extends Component {
if ( this.props.settings !== prevProps.settings ) {
this.props.updateEditorSettings( this.props.settings );
}
if ( this.props.blockTypes !== prevProps.blockTypes ) {
const newBlockTypes = differenceBy( this.props.blockTypes, prevProps.blockTypes, 'name' );
if ( newBlockTypes.length > 0 ) {
this.applyFiltersToBlockTypes( newBlockTypes );
}
}
}

render() {
Expand Down Expand Up @@ -87,15 +117,26 @@ class EditorProvider extends Component {
}
}

export default withDispatch( ( dispatch ) => {
const {
setupEditor,
updateEditorSettings,
updatePostLock,
} = dispatch( 'core/editor' );
return {
setupEditor,
updateEditorSettings,
updatePostLock,
};
} )( EditorProvider );
export default compose(
withSelect( ( select ) => {
const { getBlockTypes } = select( 'core/blocks' );

return {
blockTypes: getBlockTypes(),
};
} ),
withDispatch( ( dispatch ) => {
const { addBlockTypes } = dispatch( 'core/blocks' );
const {
setupEditor,
updateEditorSettings,
updatePostLock,
} = dispatch( 'core/editor' );
return {
addBlockTypes,
setupEditor,
updateEditorSettings,
updatePostLock,
};
} )
)( EditorProvider );