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

Block API: Initial explorations to migrate to server-registered blocks #3962

Merged
merged 1 commit into from
Dec 14, 2017
Merged
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
38 changes: 0 additions & 38 deletions bin/get-server-block-attributes.php

This file was deleted.

39 changes: 39 additions & 0 deletions bin/get-server-blocks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env php
<?php
/**
* Generates server-registered blocks, writing to standard output. By default
* assumes plugin exists in a standard install `wp-content/plugins` directory.
* Define ABSPATH environment variable pointing to WordPress install otherwise.
*
* @package gutenberg-build
*/

// Disable error reporting which would otherwise be displayed in stdout along
// with the JSON output.
error_reporting( 0 );

$abspath = getenv( 'ABSPATH' );
define( 'ABSPATH', $abspath ? $abspath : dirname( dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) ) . '/' );
define( 'WPINC', 'wp-includes' );
define( 'WP_SETUP_CONFIG', true );
define( 'WP_USE_THEMES', false );
require_once( ABSPATH . WPINC . '/load.php' );
require_once( ABSPATH . WPINC . '/default-constants.php' );
wp_fix_server_vars();
wp_initial_constants();
require_once( ABSPATH . WPINC . '/functions.php' );
wp_load_translations_early();
wp_set_lang_dir();
require_once( dirname( dirname( __FILE__ ) ) . '/lib/blocks.php' );
require_once( dirname( dirname( __FILE__ ) ) . '/lib/class-wp-block-type-registry.php' );
require_once( dirname( dirname( __FILE__ ) ) . '/lib/class-wp-block-type.php' );
require_once( dirname( dirname( __FILE__ ) ) . '/lib/client-assets.php' );

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

do_action( 'init' );

echo json_encode( gutenberg_prepare_blocks_for_js() );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So why do we need these fixtures? For test purpose?

Maybe the unit tests should not rely on the fixtures (on the default blocks), we'll probably lose some coverage but I think the unit tests should be "isolated" tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So why do we need these fixtures? For test purpose?

Right, without these, the block content fixture tests fail too, since otherwise the Node process has no way to know what are the attributes of a paragraph block.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this PR, but I think we should avoid registering the default blocks in the tests completely and just provide "dummy blocks" in tests.

14 changes: 7 additions & 7 deletions blocks/api/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ let defaultBlockName;
* registered; otherwise `undefined`.
*/
export function registerBlockType( name, settings ) {
settings = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we should update our documentation to favor SSR registration if we go all server side. At that time we could decide to add a "warning" here if the corresponding registration is not found (for a smooth migration)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we should update our documentation to favor SSR registration if we go all server side.

Agree.

At that time we could decide to add a "warning" here if the corresponding registration is not found (for a smooth migration)

Customizer controls are bootstrapped in a very similar way, and I find it interesting there's no inclination for developers to go straight to using the JavaScript APIs. I guess one difference here is that we'd probably assume there is a JavaScript counter-part for defining the UI behaviors. Part of my thinking with #2756 is that by moving the script handle to being a property of the block register API, it would require some unconventional hoop-jumping to register the JS block any other way.

Maybe to your earlier work on feeding the editor components with the registered blocks, it would make sense to warn here, since then the editor would still be generic enough to work with client-only blocks in non-WordPress contexts.

name,
...get( window._wpBlocks, name ),
...settings,
};

if ( typeof name !== 'string' ) {
console.error(
'Block names must be strings.'
Expand Down Expand Up @@ -113,12 +119,6 @@ export function registerBlockType( name, settings ) {
settings.icon = 'block-default';
}

settings = {
name,
attributes: get( window._wpBlocksAttributes, name, {} ),
...settings,
};

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

return blocks[ name ] = settings;
Expand Down Expand Up @@ -223,7 +223,7 @@ export function hasBlockSupport( nameOrType, feature, defaultSupports ) {
* Determines whether or not the given block is a reusable block. This is a
* special block type that is used to point to a global block stored via the
* API.
*
*
* @param {Object} blockOrType Block or Block Type to test
* @return {Boolean} Whether the given block is a reusable block
*/
Expand Down
6 changes: 3 additions & 3 deletions blocks/api/test/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe( 'blocks', () => {
} );
setUnknownTypeHandlerName( undefined );
setDefaultBlockName( undefined );
window._wpBlocksAttributes = {};
window._wpBlocks = {};
console.error = error;
} );

Expand Down Expand Up @@ -163,8 +163,8 @@ describe( 'blocks', () => {

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

const blockType = { settingName: 'settingValue', save: noop, category: 'common', title: 'block title' };
Expand Down
4 changes: 3 additions & 1 deletion blocks/test/fixtures/core__latest-posts.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"displayPostDate": false,
"layout": "list",
"columns": 3,
"align": "center"
"align": "center",
"order": "desc",
"orderBy": "date"
},
"originalContent": ""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"displayPostDate": true,
"layout": "list",
"columns": 3,
"align": "center"
"align": "center",
"order": "desc",
"orderBy": "date"
},
"originalContent": ""
}
Expand Down
2 changes: 1 addition & 1 deletion blocks/test/full-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function normalizeParsedBlocks( blocks ) {

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

// Register all blocks.
require( 'blocks' );
Expand Down
1 change: 0 additions & 1 deletion blocks/test/server-attributes.json

This file was deleted.

1 change: 1 addition & 0 deletions blocks/test/server-registered.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"core\/block":{"attributes":{"ref":{"type":"number"}}},"core\/latest-posts":{"attributes":{"categories":{"type":"string"},"postsToShow":{"type":"number","default":5},"displayPostDate":{"type":"boolean","default":false},"layout":{"type":"string","default":"list"},"columns":{"type":"number","default":3},"align":{"type":"string","default":"center"},"order":{"type":"string","default":"desc"},"orderBy":{"type":"string","default":"date"}}}}
40 changes: 30 additions & 10 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,35 @@ function gutenberg_get_post_to_edit( $post_id ) {
return rest_get_server()->response_to_data( $response, false );
}

/**
* Prepares server-registered blocks for JavaScript, returning an associative
* array of registered block data keyed by block name. Data includes properties
* of a block relevant for client registration.
*
* @return array An associative array of registered block data.
*/
function gutenberg_prepare_blocks_for_js() {
$block_registry = WP_Block_Type_Registry::get_instance();
$blocks = array();
$keys_to_pick = array( 'title', 'icon', 'category', 'keywords', 'supports', 'attributes' );

foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
foreach ( $keys_to_pick as $key ) {
if ( ! isset( $block_type->{ $key } ) ) {
continue;
}

if ( ! isset( $blocks[ $block_name ] ) ) {
$blocks[ $block_name ] = array();
}

$blocks[ $block_name ][ $key ] = $block_type->{ $key };
}
}

return $blocks;
}

/**
* Handles the enqueueing of block scripts and styles that are common to both
* the editor and the front-end.
Expand Down Expand Up @@ -750,16 +779,7 @@ function gutenberg_editor_scripts_and_styles( $hook ) {
);

// 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 );
wp_localize_script( 'wp-blocks', '_wpBlocks', gutenberg_prepare_blocks_for_js() );

// Get admin url for handling meta boxes.
$meta_box_url = admin_url( 'post.php' );
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,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: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:server-registered": "./bin/get-server-blocks.php > blocks/test/server-registered.json",
"fixtures:generate": "npm run fixtures:server-registered && 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",
"test-unit": "jest",
Expand Down
48 changes: 48 additions & 0 deletions phpunit/class-prepare-for-js-test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
/**
* Block types registration Tests
*
* @package Gutenberg
*/

/**
* Test gutenberg_prepare_blocks_for_js()
*/
class Prepare_For_JS_Test extends WP_UnitTestCase {

function setUp() {
parent::setUp();

$this->reset();
}

function tearDown() {
parent::tearDown();

$this->reset();
}

function reset() {
foreach ( WP_Block_Type_Registry::get_instance()->get_all_registered() as $name => $block_type ) {
WP_Block_Type_Registry::get_instance()->unregister( $name );
}
}

function test_gutenberg_prepare_blocks_for_js() {
$name = 'core/paragraph';
$settings = array(
'icon' => 'text',
'render_callback' => 'foo',
);

register_block_type( $name, $settings );

$blocks = gutenberg_prepare_blocks_for_js();

$this->assertEquals( array(
'core/paragraph' => array(
'icon' => 'text',
),
), $blocks );
}
}
3 changes: 3 additions & 0 deletions test/unit/setup-globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,6 @@ global.window.userSettings = { uid: 1 };

// Mock jQuery
global.window.jQuery = { holdReady() {} };

// Bootstrap server-registered blocks
global.window._wpBlocks = require( 'blocks/test/server-registered.json' );