Skip to content

Commit

Permalink
Framework: Support preloaded server-registered block attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed Sep 1, 2017
1 parent 6e663a4 commit 7b2fd62
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 4 deletions.
38 changes: 38 additions & 0 deletions bin/get-server-block-attributes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env php
<?php
/**
* Generates server-registered block attributes, writing to standard output.
*
* @package gutenberg-build
*/

$attributes = array();

/**
* Register a block type. Substitute for core API in lieu of loading full
* WordPress context.
*
* @param string $name Block type name including namespace.
* @param array $args {
* Optional. Array of block type arguments. Any arguments may be defined, however the
* ones described below are supported by default. Default empty array.
*
* @type callable $render_callback Callback used to render blocks of this block type.
* @type array $attributes Block attributes mapping, property name to schema.
* }
*/
function register_block_type( $name, $args = array() ) {
if ( ! isset( $args['attributes'] ) ) {
return;
}

global $attributes;
$attributes[ $name ] = $args['attributes'];
}

// Register server-side code for individual blocks.
foreach ( glob( dirname( dirname( __FILE__ ) ) . '/blocks/library/*/index.php' ) as $block_logic ) {
require_once $block_logic;
}

echo json_encode( $attributes, JSON_PRETTY_PRINT );
11 changes: 8 additions & 3 deletions blocks/api/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* External dependencies
*/
import { isFunction, some } from 'lodash';
import { get, isFunction, some } from 'lodash';

/**
* WordPress dependencies
Expand Down Expand Up @@ -92,8 +92,13 @@ export function registerBlockType( name, settings ) {
);
return;
}
const block = Object.assign( { name }, settings );
blocks[ name ] = block;

const block = blocks[ name ] = {
name,
attributes: get( window._wpBlocksAttributes, name ),
...settings,
};

return block;
}

Expand Down
18 changes: 18 additions & 0 deletions blocks/api/test/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe( 'blocks', () => {
} );
setUnknownTypeHandlerName( undefined );
setDefaultBlockName( undefined );
window._wpBlocksAttributes = {};
console.error = error;
} );

Expand Down Expand Up @@ -109,6 +110,23 @@ describe( 'blocks', () => {
expect( block ).toBeUndefined();
} );

it( 'should default to browser-initialized global attributes', () => {
const attributes = { ok: { type: 'boolean' } };
window._wpBlocksAttributes = {
'core/test-block-with-attributes': attributes,
};

const blockType = { settingName: 'settingValue', save: noop, category: 'common' };
registerBlockType( 'core/test-block-with-attributes', blockType );
expect( getBlockType( 'core/test-block-with-attributes' ) ).toEqual( {
name: 'core/test-block-with-attributes',
settingName: 'settingValue',
save: noop,
category: 'common',
attributes,
} );
} );

it( 'should store a copy of block type', () => {
const blockType = { settingName: 'settingValue', save: noop, category: 'common' };
registerBlockType( 'core/test-block-with-settings', blockType );
Expand Down
2 changes: 2 additions & 0 deletions blocks/test/full-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ function normalizeParsedBlocks( blocks ) {

describe( 'full post content fixture', () => {
beforeAll( () => {
window._wpBlocksAttributes = require( './server-attributes.json' );

// Register all blocks.
require( 'blocks' );
} );
Expand Down
1 change: 1 addition & 0 deletions blocks/test/server-attributes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions lib/class-wp-block-type-registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ final class WP_Block_Type_Registry {
* ones described below are supported by default. Default empty array.
*
* @type callable $render_callback Callback used to render blocks of this block type.
* @type array $attributes Block attributes mapping, property name to schema.
* }
* @return WP_Block_Type|false The registered block type on success, or false on failure.
*/
Expand Down
45 changes: 45 additions & 0 deletions lib/class-wp-block-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ class WP_Block_Type {
*/
public $render_callback;

/**
* Block type attributes property schemas.
*
* @since 0.10.0
* @access public
* @var array
*/
public $attributes;

/**
* Constructor.
*
Expand Down Expand Up @@ -71,9 +80,45 @@ public function render( $attributes = array(), $content = null ) {
return $content;
}

$attributes = $this->prepare_attributes_for_render( $attributes );

return call_user_func( $this->render_callback, $attributes, $content );
}

/**
* Validates attributes against the current block schema, populating
* defaulted and missing values, and omitting unknown attributes.
*
* @param array $attributes Original block attributes.
* @return array Prepared block attributes.
*/
public function prepare_attributes_for_render( $attributes ) {
if ( ! isset( $this->attributes ) ) {
return $attributes;
}

$prepared_attributes = array();

foreach ( $this->attributes as $attribute_name => $schema ) {
$value = null;

if ( isset( $attributes[ $attribute_name ] ) ) {
$is_valid = rest_validate_value_from_schema( $attributes[ $attribute_name ], $schema );
if ( ! is_wp_error( $is_valid ) ) {
$value = $attributes[ $attribute_name ];
}
}

if ( is_null( $value ) && isset( $schema['default'] ) ) {
$value = $schema['default'];
}

$prepared_attributes[ $attribute_name ] = $value;
}

return $prepared_attributes;
}

/**
* Sets block type properties.
*
Expand Down
10 changes: 10 additions & 0 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,16 @@ function gutenberg_editor_scripts_and_styles( $hook ) {
'before'
);

// Preload server-registered block schemas.
$block_registry = WP_Block_Type_Registry::get_instance();
$schemas = array();
foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
if ( isset( $block_type->attributes ) ) {
$schemas[ $block_name ] = $block_type->attributes;
}
}
wp_localize_script( 'wp-blocks', '_wpBlocksAttributes', $schemas );

// Initialize the editor.
$gutenberg_theme_support = get_theme_support( 'gutenberg' );
$color_palette = gutenberg_color_palette();
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@
"test": "npm run lint && npm run test-unit",
"ci": "concurrently \"npm run lint && npm run build\" \"npm run test-unit:coverage-ci\"",
"fixtures:clean": "rimraf \"blocks/test/fixtures/*.+(json|serialized.html)\"",
"fixtures:generate": "cross-env GENERATE_MISSING_FIXTURES=y npm run test-unit",
"fixtures:server-attributes": "./bin/get-server-block-attributes.php > blocks/test/server-attributes.json",
"fixtures:generate": "npm run fixtures:server-attributes && cross-env GENERATE_MISSING_FIXTURES=y npm run test-unit",
"fixtures:regenerate": "npm run fixtures:clean && npm run fixtures:generate",
"package-plugin": "./bin/build-plugin-zip.sh",
"docs-start": "./docutron/bin/cli.js start",
Expand Down
38 changes: 38 additions & 0 deletions phpunit/class-block-type-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,44 @@ function test_render_without_callback() {
$this->assertSame( $content, $output );
}

function test_prepare_attributes() {
$attributes = array(
'correct' => 'include',
'wrongType' => 5,
'wrongTypeDefaulted' => 5,
/* missingDefaulted */
'undefined' => 'omit',
);

$block_type = new WP_Block_Type( 'core/dummy', array(
'attributes' => array(
'correct' => array(
'type' => 'string',
),
'wrongType' => array(
'type' => 'string',
),
'wrongTypeDefaulted' => array(
'type' => 'string',
'default' => 'defaulted',
),
'missingDefaulted' => array(
'type' => 'string',
'default' => 'define',
),
),
) );

$prepared_attributes = $block_type->prepare_attributes_for_render( $attributes );

$this->assertEquals( array(
'correct' => 'include',
'wrongType' => null,
'wrongTypeDefaulted' => 'defaulted',
'missingDefaulted' => 'define',
), $prepared_attributes );
}

function render_dummy_block( $attributes ) {
return json_encode( $attributes );
}
Expand Down

0 comments on commit 7b2fd62

Please sign in to comment.