From 3ce9dc7c9cc3c815a8d13f99d8445f78a3592aa6 Mon Sep 17 00:00:00 2001 From: Terri Ann Date: Sun, 9 Dec 2018 11:58:01 -0600 Subject: [PATCH 1/4] Updating documentation to be more consistent with the example repo WordPress/gutenberg-examples --- .../writing-your-first-block-type.md | 104 ++++++++++++------ 1 file changed, 70 insertions(+), 34 deletions(-) diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md b/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md index e696b73e4e911d..40b5f240ede0e5 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md @@ -8,22 +8,43 @@ Blocks containing static content are implemented entirely in JavaScript using th While the block's editor behaviors are implemented in JavaScript, you'll need to register your block server-side to ensure that the script is enqueued when the editor loads. Register scripts and styles using [`wp_register_script`](https://developer.wordpress.org/reference/functions/wp_register_script/) and [`wp_register_style`](https://developer.wordpress.org/reference/functions/wp_register_style/), then assign these as handles associated with your block using the `script`, `style`, `editor_script`, and `editor_style` block type registration settings. The `editor_`-prefixed handles will only be enqueued in the context of the editor, while `script` and `style` will be enqueued both in the editor and when viewing a post on the front of your site. +{% codetabs %} +{% ES5 %} ```php - 'gutenberg-boilerplate-es5-step01', + register_block_type( 'gutenberg-examples/example-01-basic', array( + 'editor_script' => 'gutenberg-examples-01', ) ); } -add_action( 'init', 'gutenberg_boilerplate_block' ); +add_action( 'init', 'gutenberg_examples_01_register_block' ); ``` +{% ESNext %} +```php +function gutenberg_examples_01_esnext_register_block() { + + wp_register_script( + 'gutenberg-examples-01-esnext', + plugins_url( 'block.build.js', __FILE__ ), + array( 'wp-blocks', 'wp-element' ), + filemtime( plugin_dir_path( __FILE__ ) . 'block.build.js' ) + ); + + register_block_type( 'gutenberg-examples/example-01-basic-esnext', array( + 'editor_script' => 'gutenberg-examples-01-esnext', + ) ); + +} +add_action( 'init', 'gutenberg_examples_01_esnext_register_block' ); +``` +{% end %} Note the two script dependencies: @@ -39,44 +60,59 @@ With the script enqueued, let's look at the implementation of the block itself: {% codetabs %} {% ES5 %} ```js -var el = wp.element.createElement, - registerBlockType = wp.blocks.registerBlockType, - blockStyle = { backgroundColor: '#900', color: '#fff', padding: '20px' }; +( function( blocks, element ) { + var el = element.createElement; + + var blockStyle = { + backgroundColor: '#900', + color: '#fff', + padding: '20px', + }; + + blocks.registerBlockType( 'gutenberg-examples/example-01-basic', { + title: 'Example: Basic', + icon: 'universal-access-alt', + category: 'layout', + edit: function() { + return el( + 'p', + { style: blockStyle }, + 'Hello World, step 1 (from the editor).' + ); + }, + save: function() { + return el( + 'p', + { style: blockStyle }, + 'Hello World, step 1 (from the frontend).' + ); + }, + } ); +}( + window.wp.blocks, + window.wp.element +) ); -registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-01', { - title: 'Hello World (Step 1)', - - icon: 'universal-access-alt', - - category: 'layout', - - edit: function() { - return el( 'p', { style: blockStyle }, 'Hello editor.' ); - }, - - save: function() { - return el( 'p', { style: blockStyle }, 'Hello saved content.' ); - }, -} ); ``` {% ESNext %} ```js const { registerBlockType } = wp.blocks; -const blockStyle = { backgroundColor: '#900', color: '#fff', padding: '20px' }; -registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-01', { - title: 'Hello World (Step 1)', +const blockStyle = { + backgroundColor: '#900', + color: '#fff', + padding: '20px', +}; +registerBlockType( 'gutenberg-examples/example-01-basic-esnext', { + title: 'Example: Basic (esnext)', icon: 'universal-access-alt', - category: 'layout', - edit() { - return

Hello editor.

; + return
Basic example with JSX! (editor)
; }, - save() { - return

Hello saved content.

; + return
Basic example with JSX! (front)
; }, } ); ``` From a394cd04356ada52470ad64a1b1cce3b499861c2 Mon Sep 17 00:00:00 2001 From: Terri Ann Date: Sun, 9 Dec 2018 13:33:19 -0600 Subject: [PATCH 2/4] Updating documentation to be more consistent with the example repo WordPress/gutenberg-examples --- ...roducing-attributes-and-editable-fields.md | 118 ++++++++---------- 1 file changed, 51 insertions(+), 67 deletions(-) diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md b/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md index 3a993ce1c2b71a..175e61562445e8 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md @@ -11,81 +11,73 @@ One challenge of maintaining the representation of a block as a JavaScript objec {% codetabs %} {% ES5 %} ```js -var el = wp.element.createElement, - registerBlockType = wp.blocks.registerBlockType, - RichText = wp.editor.RichText; - -registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-03', { - title: 'Hello World (Step 3)', - - icon: 'universal-access-alt', - - category: 'layout', - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p', - } - }, - - edit: function( props ) { - var content = props.attributes.content; - - function onChangeContent( newContent ) { - props.setAttributes( { content: newContent } ); - } +( function( blocks, editor, element ) { + var el = element.createElement; + var RichText = editor.RichText; + + blocks.registerBlockType( 'gutenberg-examples/example-03-editable', { + title: 'Example: Editable', + icon: 'universal-access-alt', + category: 'layout', + + attributes: { + content: { + type: 'array', + source: 'children', + selector: 'p', + }, + }, - return el( - RichText, - { - tagName: 'p', - className: props.className, - onChange: onChangeContent, - value: content, + edit: function( props ) { + var content = props.attributes.content; + function onChangeContent( newContent ) { + props.setAttributes( { content: newContent } ); } - ); - }, - save: function( props ) { - var content = props.attributes.content; + return el( + RichText, + { + tagName: 'p', + className: props.className, + onChange: onChangeContent, + value: content, + } + ); + }, - return el( RichText.Content, { - tagName: 'p', - className: props.className, - value: content - } ); - }, -} ); + save: function( props ) { + return el( RichText.Content, { + tagName: 'p', value: props.attributes.content, + } ); + }, + } ); +}( + window.wp.blocks, + window.wp.editor, + window.wp.element +) ); ``` {% ESNext %} ```js const { registerBlockType } = wp.blocks; const { RichText } = wp.editor; -registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-03', { - title: 'Hello World (Step 3)', - +registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { + title: 'Example: Editable (esnext)', icon: 'universal-access-alt', - category: 'layout', - attributes: { content: { - type: 'string', - source: 'html', + type: 'array', + source: 'children', selector: 'p', }, }, - - edit( { attributes, className, setAttributes } ) { - const { content } = attributes; - - function onChangeContent( newContent ) { + edit: ( props ) => { + const { attributes: { content }, setAttributes, className } = props; + const onChangeContent = ( newContent ) => { setAttributes( { content: newContent } ); - } - + }; return ( ); }, - - save( { attributes } ) { - const { content } = attributes; - - return ( - - ); + save: ( props ) => { + return ; }, } ); ``` From 1b05c179a5cadb913cf64cf22399abf534270908 Mon Sep 17 00:00:00 2001 From: Terri Ann Date: Sun, 9 Dec 2018 13:49:36 -0600 Subject: [PATCH 3/4] Updating documentation to be more consistent with the example repo WordPress/gutenberg-examples --- .../block-controls-toolbars-and-inspector.md | 180 +++++++++--------- 1 file changed, 89 insertions(+), 91 deletions(-) diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md b/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md index de6509e4c42b73..40895f6325b39c 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md @@ -13,50 +13,45 @@ You can also customize the toolbar to include controls specific to your block ty {% codetabs %} {% ES5 %} ```js -var el = wp.element.createElement, - Fragment = wp.element.Fragment - registerBlockType = wp.blocks.registerBlockType, - RichText = wp.editor.RichText, - BlockControls = wp.editor.BlockControls, - AlignmentToolbar = wp.editor.AlignmentToolbar; - -registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-04', { - title: 'Hello World (Step 4)', - - icon: 'universal-access-alt', - - category: 'layout', - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p', +( function( blocks, editor, element ) { + var el = element.createElement; + var RichText = editor.RichText; + var AlignmentToolbar = editor.AlignmentToolbar; + var BlockControls = editor.BlockControls; + + blocks.registerBlockType( 'gutenberg-examples/example-04-controls', { + title: 'Example: Controls',, + icon: 'universal-access-alt', + category: 'layout', + + attributes: { + content: { + type: 'array', + source: 'children', + selector: 'p', + }, + alignment: { + type: 'string', + default: 'none', + }, }, - alignment: { - type: 'string', - }, - }, - edit: function( props ) { - var content = props.attributes.content, - alignment = props.attributes.alignment; + edit: function( props ) { + var content = props.attributes.content; + var alignment = props.attributes.alignment; - function onChangeContent( newContent ) { - props.setAttributes( { content: newContent } ); - } + function onChangeContent( newContent ) { + props.setAttributes( { content: newContent } ); + } - function onChangeAlignment( newAlignment ) { - props.setAttributes( { alignment: newAlignment } ); - } + function onChangeAlignment( newAlignment ) { + props.setAttributes( { alignment: newAlignment === undefined ? 'none' : newAlignment } ); + } - return ( - el( - Fragment, - null, + return [ el( BlockControls, - null, + { key: 'controls' }, el( AlignmentToolbar, { @@ -68,98 +63,101 @@ registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-04', { el( RichText, { - key: 'editable', + key: 'richtext', tagName: 'p', - className: props.className, style: { textAlign: alignment }, + className: props.className, onChange: onChangeContent, value: content, } - ) - ) - ); - }, - - save: function( props ) { - var content = props.attributes.content, - alignment = props.attributes.alignment; + ), + ]; + }, - return el( RichText.Content, { - tagName: 'p', - className: props.className, - style: { textAlign: alignment }, - value: content - } ); - }, -} ); + save: function( props ) { + return el( RichText.Content, { + tagName: 'p', + className: 'gutenberg-examples-align-' + props.attributes.alignment, + value: props.attributes.content, + } ); + }, + } ); +}( + window.wp.blocks, + window.wp.editor, + window.wp.element +) ); ``` {% ESNext %} ```js -const { registerBlockType } = wp.blocks; -const { Fragment } = wp.element; +const { + registerBlockType, +} = wp.blocks; + const { RichText, - BlockControls, AlignmentToolbar, + BlockControls, } = wp.editor; -registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-04', { - title: 'Hello World (Step 4)', - +registerBlockType( 'gutenberg-examples/example-04-controls-esnext', { + title: 'Example: Controls (esnext)', icon: 'universal-access-alt', - category: 'layout', - attributes: { content: { - type: 'string', - source: 'html', + type: 'array', + source: 'children', selector: 'p', }, alignment: { type: 'string', + default: 'none', }, }, + edit: ( props ) => { + const { + attributes: { + content, + alignment, + }, + className, + } = props; + + const onChangeContent = ( newContent ) => { + props.setAttributes( { content: newContent } ); + }; - edit( { attributes, className, setAttributes } ) { - const { content, alignment } = attributes; - - function onChangeContent( newContent ) { - setAttributes( { content: newContent } ); - } - - function onChangeAlignment( newAlignment ) { - setAttributes( { alignment: newAlignment } ); - } + const onChangeAlignment = ( newAlignment ) => { + props.setAttributes( { alignment: newAlignment === undefined ? 'none' : newAlignment } ); + }; return ( - - - - +
+ { + + + + } - +
); }, - - save( { attributes } ) { - const { content, alignment } = attributes; - + save: ( props ) => { return ( ); }, From 8a9fdb516333b87569ca37e53ade299a90d756b1 Mon Sep 17 00:00:00 2001 From: Terri Ann Date: Sun, 9 Dec 2018 14:10:50 -0600 Subject: [PATCH 4/4] Adding note documenting the discremency between the example repo containing internationalization and it not being present in the documentation. --- .../block-tutorial/block-controls-toolbars-and-inspector.md | 2 ++ .../introducing-attributes-and-editable-fields.md | 2 ++ .../tutorials/block-tutorial/writing-your-first-block-type.md | 2 ++ 3 files changed, 6 insertions(+) diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md b/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md index 40895f6325b39c..8561ea356e6262 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md @@ -165,6 +165,8 @@ registerBlockType( 'gutenberg-examples/example-04-controls-esnext', { ``` {% end %} +Note that internationalization is an important consideration for WordPress development. While the examples in this documentation do not include internationalization, the [accompanying WordPress example block plugin](https://github.com/WordPress/gutenberg-examples) includes the code necessary to support internationalization. + Note that `BlockControls` is only visible when the block is currently selected and in visual editing mode. `BlockControls` are not shown when editing a block in HTML editing mode. ## Inspector diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md b/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md index 175e61562445e8..ebf4048a050c0c 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md @@ -94,6 +94,8 @@ registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { ``` {% end %} +Note that internationalization is an important consideration for WordPress development. While the examples in this documentation do not include internationalization, the [accompanying WordPress example block plugin](https://github.com/WordPress/gutenberg-examples) includes the code necessary to support internationalization. + When registering a new block type, the `attributes` property describes the shape of the attributes object you'd like to receive in the `edit` and `save` functions. Each value is a [source function](../../../../../docs/designers-developers/developers/block-api/block-attributes.md) to find the desired value from the markup of the block. In the code snippet above, when loading the editor, we will extract the `content` value as the HTML of the paragraph element in the saved post's markup. diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md b/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md index 40b5f240ede0e5..7d392e3dd1b439 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md @@ -118,6 +118,8 @@ registerBlockType( 'gutenberg-examples/example-01-basic-esnext', { ``` {% end %} +Note that internationalization is an important consideration for WordPress development. While the examples in this documentation do not include internationalization, the [accompanying WordPress example block plugin](https://github.com/WordPress/gutenberg-examples) includes the code necessary to support internationalization. + Once a block is registered, you should immediately see that it becomes available as an option in the editor inserter dialog, using values from `title`, `icon`, and `category` to organize its display. You can choose an icon from any included in the built-in [Dashicons icon set](https://developer.wordpress.org/resource/dashicons/), or provide a [custom svg element](https://wordpress.org/gutenberg/handbook/block-api/#icon-optional). A block name must be prefixed with a namespace specific to your plugin. This helps prevent conflicts when more than one plugin registers a block with the same name.