Skip to content

Commit

Permalink
Docs and API: clarify naming around block registration (#842)
Browse files Browse the repository at this point in the history
* Change api/registration `getBlocks` to `getRegisteredBlocks`.

* Update inline documentation in blocks/api.

* Expose getBlocks as getRegisteredBlocks.

* Use getBlockTypes.

* Switch to getBlockType / blockName pair.

* Fix tests.

* Rename (un)registerBlock as (un)registerBlockType

* Convert more blockSettings to blockType

* Rename PHP register_block to register_block_type

* Correct blockType to blockName

* Update block Readme to refer to type.

* Simplify blockName attribute.
  • Loading branch information
mtias committed Jun 1, 2017
1 parent 5b0a31a commit bdabb3f
Show file tree
Hide file tree
Showing 54 changed files with 384 additions and 376 deletions.
8 changes: 4 additions & 4 deletions blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function RandomImage( props ) {
} );
}

wp.blocks.registerBlock( 'myplugin/random-image', {
wp.blocks.registerBlockType( 'myplugin/random-image', {
title: 'Random Image',

icon: 'format-image',
Expand Down Expand Up @@ -121,7 +121,7 @@ In the random image block above, we've given the `alt` attribute of the image a

## API

### `wp.blocks.registerBlock( slug: string, settings: Object )`
### `wp.blocks.registerBlockType( name: string, typeDefinition: Object )`

Registers a new block provided a unique slug and an object defining its behavior. Once registered, the block is made available as an option to any editor interface where blocks are implemented.

Expand All @@ -146,9 +146,9 @@ Registers a new block-level control. Controls appear in a block's toolbar when i

Inline controls for [`Editable`](#editable) elements are identical for every block and cannot be modified.

### `wp.blocks.getBlockSettings( slug: string )`
### `wp.blocks.getBlockType( slug: string )`

Returns settings associated with a registered block.
Returns type definitions associated with a registered block.

### `wp.blocks.getControlSettings( slug: string )`

Expand Down
46 changes: 25 additions & 21 deletions blocks/api/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,30 @@ import { get, castArray, findIndex, isObjectLike, find } from 'lodash';
/**
* Internal dependencies
*/
import { getBlockSettings } from './registration';
import { getBlockType } from './registration';

/**
* Returns a block object given its type and attributes
* Returns a block object given its type and attributes.
*
* @param {String} blockType BlockType
* @param {String} name Block name
* @param {Object} attributes Block attributes
* @return {Object} Block object
*/
export function createBlock( blockType, attributes = {} ) {
const blockSettings = getBlockSettings( blockType );
export function createBlock( name, attributes = {} ) {
// Get the type definition associated with a registered block.
const blockType = getBlockType( name );

// Do we need this? What purpose does it have?
let defaultAttributes;
if ( blockSettings ) {
defaultAttributes = blockSettings.defaultAttributes;
if ( blockType ) {
defaultAttributes = blockType.defaultAttributes;
}

// Blocks are stored with a unique ID, the assigned type name,
// and the block attributes.
return {
uid: uuid(),
blockType,
name,
attributes: {
...defaultAttributes,
...attributes,
Expand All @@ -35,24 +39,24 @@ export function createBlock( blockType, attributes = {} ) {
}

/**
* Switch a block into one or more blocks of the new block type
* Switch a block into one or more blocks of the new block type.
*
* @param {Object} block Block object
* @param {string} blockType BlockType
* @param {string} name Block name
* @return {Array} Block object
*/
export function switchToBlockType( block, blockType ) {
export function switchToBlockType( block, name ) {
// Find the right transformation by giving priority to the "to"
// transformation.
const destinationSettings = getBlockSettings( blockType );
const sourceSettings = getBlockSettings( block.blockType );
const transformationsFrom = get( destinationSettings, 'transforms.from', [] );
const transformationsTo = get( sourceSettings, 'transforms.to', [] );
const destinationType = getBlockType( name );
const sourceType = getBlockType( block.name );
const transformationsFrom = get( destinationType, 'transforms.from', [] );
const transformationsTo = get( sourceType, 'transforms.to', [] );
const transformation =
find( transformationsTo, t => t.blocks.indexOf( blockType ) !== -1 ) ||
find( transformationsFrom, t => t.blocks.indexOf( block.blockType ) !== -1 );
find( transformationsTo, t => t.blocks.indexOf( name ) !== -1 ) ||
find( transformationsFrom, t => t.blocks.indexOf( block.name ) !== -1 );

// If no valid transformation, stop. (How did we get here?)
// Stop if there is no valid transformation. (How did we get here?)
if ( ! transformation ) {
return null;
}
Expand All @@ -71,11 +75,11 @@ export function switchToBlockType( block, blockType ) {

// Ensure that every block object returned by the transformation has a
// valid block type.
if ( transformationResults.some( ( result ) => ! getBlockSettings( result.blockType ) ) ) {
if ( transformationResults.some( ( result ) => ! getBlockType( result.name ) ) ) {
return null;
}

const firstSwitchedBlock = findIndex( transformationResults, ( result ) => result.blockType === blockType );
const firstSwitchedBlock = findIndex( transformationResults, ( result ) => result.name === name );

// Ensure that at least one block object returned by the transformation has
// the expected "destination" block type.
Expand All @@ -88,7 +92,7 @@ export function switchToBlockType( block, blockType ) {
// The first transformed block whose type matches the "destination"
// type gets to keep the existing block's UID.
uid: index === firstSwitchedBlock ? block.uid : result.uid,
blockType: result.blockType,
name: result.name,
attributes: result.attributes,
};
} );
Expand Down
8 changes: 4 additions & 4 deletions blocks/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ export { default as parse } from './parser';
export { default as serialize } from './serializer';
export { getCategories } from './categories';
export {
registerBlock,
unregisterBlock,
registerBlockType,
unregisterBlockType,
setUnknownTypeHandler,
getUnknownTypeHandler,
getBlockSettings,
getBlocks,
getBlockType,
getBlockTypes,
} from './registration';
78 changes: 41 additions & 37 deletions blocks/api/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ import { escape, unescape, pickBy } from 'lodash';
* Internal dependencies
*/
import { parse as grammarParse } from './post.pegjs';
import { getBlockSettings, getUnknownTypeHandler } from './registration';
import { getBlockType, getUnknownTypeHandler } from './registration';
import { createBlock } from './factory';

/**
* Returns the block attributes parsed from raw content.
*
* @param {String} rawContent Raw block content
* @param {Object} blockSettings Block settings
* @param {Object} blockType Block type
* @return {Object} Block attributes
*/
export function parseBlockAttributes( rawContent, blockSettings ) {
const { attributes } = blockSettings;
export function parseBlockAttributes( rawContent, blockType ) {
const { attributes } = blockType;
if ( 'function' === typeof attributes ) {
return attributes( rawContent );
} else if ( attributes ) {
Expand All @@ -39,21 +39,22 @@ export function parseBlockAttributes( rawContent, blockSettings ) {
}

/**
* Returns the block attributes of a registered block node given its settings.
* Returns the block attributes of a registered block node given its type.
*
* @param {?Object} blockSettings Block settings
* @param {?Object} blockType Block type
* @param {string} rawContent Raw block content
* @param {?Object} attributes Known block attributes (from delimiters)
* @return {Object} All block attributes
*/
export function getBlockAttributes( blockSettings, rawContent, attributes ) {
// Merge any attributes from comment delimiters with block implementation
export function getBlockAttributes( blockType, rawContent, attributes ) {
// Merge any attributes present in comment delimiters with those
// that are specified in the block implementation.
attributes = attributes || {};
if ( blockSettings ) {
if ( blockType ) {
attributes = {
...attributes,
...blockSettings.defaultAttributes,
...parseBlockAttributes( rawContent, blockSettings ),
...blockType.defaultAttributes,
...parseBlockAttributes( rawContent, blockType ),
};
}

Expand All @@ -63,32 +64,32 @@ export function getBlockAttributes( blockSettings, rawContent, attributes ) {
/**
* Creates a block with fallback to the unknown type handler.
*
* @param {?String} blockType Block type slug
* @param {?String} name Block type slug
* @param {String} rawContent Raw block content
* @param {?Object} attributes Attributes obtained from block delimiters
* @return {?Object} An initialized block object (if possible)
*/
export function createBlockWithFallback( blockType, rawContent, attributes ) {
// Use type from block content, otherwise find unknown handler
blockType = blockType || getUnknownTypeHandler();

// Try finding settings for known block type, else again fall back
let blockSettings = getBlockSettings( blockType );
const fallbackBlockType = getUnknownTypeHandler();
if ( ! blockSettings ) {
blockType = fallbackBlockType;
blockSettings = getBlockSettings( blockType );
export function createBlockWithFallback( name, rawContent, attributes ) {
// Use type from block content, otherwise find unknown handler.
name = name || getUnknownTypeHandler();

// Try finding type for known block name, else fall back again.
let blockType = getBlockType( name );
const fallbackBlock = getUnknownTypeHandler();
if ( ! blockType ) {
name = fallbackBlock;
blockType = getBlockType( name );
}

// Include in set only if settings were determined
// Include in set only if type were determined.
// TODO do we ever expect there to not be an unknown type handler?
if ( blockSettings && ( rawContent.trim() || blockType !== fallbackBlockType ) ) {
if ( blockType && ( rawContent.trim() || name !== fallbackBlock ) ) {
// TODO allow blocks to opt-in to receiving a tree instead of a string.
// Gradually convert all blocks to this new format, then remove the
// string serialization.
const block = createBlock(
blockType,
getBlockAttributes( blockSettings, rawContent.trim(), attributes )
name,
getBlockAttributes( blockType, rawContent.trim(), attributes )
);
return block;
}
Expand Down Expand Up @@ -123,27 +124,30 @@ export function parseWithTinyMCE( content ) {
}
);

// Create a custom HTML schema
// Create a custom HTML schema.
const schema = new tinymce.html.Schema();
// Add <wp-block> "tags" to our schema

// Add <wp-block> "tags" to our schema.
schema.addCustomElements( 'wp-block' );
// Add valid <wp-block> "attributes" also

// Add valid <wp-block> "attributes" also.
schema.addValidElements( 'wp-block[slug|attributes]' );
// Initialize the parser with our custom schema

// Initialize the parser with our custom schema.
const parser = new tinymce.html.DomParser( { validate: true }, schema );

// Parse the content into an object tree
// Parse the content into an object tree.
const tree = parser.parse( content );

// Create a serializer that we will use to pass strings to blocks.
// TODO: pass parse trees instead, and verify them against the markup
// shapes that each block can accept.
const serializer = new tinymce.html.Serializer( { validate: true }, schema );

// Walk the tree and initialize blocks
// Walk the tree and initialize blocks.
const blocks = [];

// Store markup we found in between blocks
// Store markup we found in between blocks.
let contentBetweenBlocks = null;
function flushContentBetweenBlocks() {
if ( contentBetweenBlocks && contentBetweenBlocks.firstChild ) {
Expand All @@ -164,19 +168,19 @@ export function parseWithTinyMCE( content ) {
while ( currentNode ) {
if ( currentNode.name === 'wp-block' ) {
// Set node type to document fragment so that the TinyMCE
// serializer doesn't output its markup
// serializer doesn't output its markup.
currentNode.type = 11;

// Serialize the content
const rawContent = serializer.serialize( currentNode );

// Retrieve the attributes from the <wp-block> tag
// Retrieve the attributes from the <wp-block> tag.
const nodeAttributes = currentNode.attributes.reduce( ( memo, attr ) => {
memo[ attr.name ] = attr.value;
return memo;
}, {} );

// Retrieve the block attributes from the original delimiters
// Retrieve the block attributes from the original delimiters.
const attributesMatcher = /([a-z0-9_-]+)(="([^"]*)")?/g;
const blockAttributes = {};
let match;
Expand All @@ -187,7 +191,7 @@ export function parseWithTinyMCE( content ) {
}
} while ( !! match );

// Try to create the block
// Try to create the block.
const block = createBlockWithFallback(
nodeAttributes.slug,
rawContent,
Expand Down
12 changes: 6 additions & 6 deletions blocks/api/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ let unknownTypeHandler;
* @return {?WPBlock} The block, if it has been successfully
* registered; otherwise `undefined`.
*/
export function registerBlock( slug, settings ) {
export function registerBlockType( slug, settings ) {
if ( typeof slug !== 'string' ) {
console.error(
'Block slugs must be strings.'
Expand Down Expand Up @@ -55,7 +55,7 @@ export function registerBlock( slug, settings ) {
* @return {?WPBlock} The previous block value, if it has been
* successfully unregistered; otherwise `undefined`.
*/
export function unregisterBlock( slug ) {
export function unregisterBlockType( slug ) {
if ( ! blocks[ slug ] ) {
console.error(
'Block "' + slug + '" is not registered.'
Expand Down Expand Up @@ -87,12 +87,12 @@ export function getUnknownTypeHandler() {
}

/**
* Returns settings associated with a registered block.
* Returns a registered block type.
*
* @param {string} slug Block slug
* @return {?Object} Block settings
* @return {?Object} Block type
*/
export function getBlockSettings( slug ) {
export function getBlockType( slug ) {
return blocks[ slug ];
}

Expand All @@ -101,6 +101,6 @@ export function getBlockSettings( slug ) {
*
* @return {Array} Block settings
*/
export function getBlocks() {
export function getBlockTypes() {
return Object.values( blocks );
}
Loading

0 comments on commit bdabb3f

Please sign in to comment.