diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/applying-styles-with-stylesheets.md b/docs/designers-developers/developers/tutorials/block-tutorial/applying-styles-with-stylesheets.md
index 47d2f70876143e..dff770151e8e9c 100644
--- a/docs/designers-developers/developers/tutorials/block-tutorial/applying-styles-with-stylesheets.md
+++ b/docs/designers-developers/developers/tutorials/block-tutorial/applying-styles-with-stylesheets.md
@@ -1,48 +1,56 @@
# Applying Styles From a Stylesheet
-In the previous section, the block had applied its own styles by an inline `style` attribute. While this might be adequate for very simple components, you will quickly find that it becomes easier to write your styles by extracting them to a separate stylesheet file.
+In the previous step, the block had applied its own styles by an inline `style` attribute. While this might be adequate for very simple components, you will quickly find that it becomes easier to write your styles by extracting them to a separate stylesheet file.
-The editor will automatically generate a class name for each block type to simplify styling. It can be accessed from the object argument passed to the edit and save functions:
+The editor will automatically generate a class name for each block type to simplify styling. It can be accessed from the object argument passed to the edit and save functions. In step 2, we will create a stylesheet to use that class name.
{% codetabs %}
{% ES5 %}
```js
-var el = wp.element.createElement,
- registerBlockType = wp.blocks.registerBlockType;
-
-registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-02', {
- title: 'Hello World (Step 2)',
-
- icon: 'universal-access-alt',
-
- category: 'layout',
-
- edit: function( props ) {
- return el( 'p', { className: props.className }, 'Hello editor.' );
- },
-
- save: function() {
- return el( 'p', {}, 'Hello saved content.' );
- }
-} );
+( function( blocks, element ) {
+ var el = element.createElement;
+
+ blocks.registerBlockType( 'gutenberg-examples/example-02-stylesheets', {
+ title: 'Example: Stylesheets',
+ icon: 'universal-access-alt',
+ category: 'layout',
+ edit: function( props ) {
+ return el(
+ 'p',
+ { className: props.className },
+ 'Hello World, step 2 (from the editor, in green).'
+ );
+ },
+ save: function() {
+ return el(
+ 'p',
+ {},
+ 'Hello World, step 2 (from the frontend, in red).'
+ );
+ },
+ } );
+}(
+ window.wp.blocks,
+ window.wp.element
+) );
```
{% ESNext %}
```js
const { registerBlockType } = wp.blocks;
-registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-02', {
- title: 'Hello World (Step 2)',
+registerBlockType( 'gutenberg-examples/example-02-stylesheets', {
+ title: 'Example: Stylesheets',
icon: 'universal-access-alt',
category: 'layout',
edit( { className } ) {
- return
Hello editor.
;
+ return Hello World, step 2 (from the editor, in green).
;
},
save() {
- return Hello saved content.
;
+ return Hello World, step 2 (from the frontend, in red)./p>;
}
} );
```
@@ -50,8 +58,16 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-02', {
The class name is generated using the block's name prefixed with `wp-block-`, replacing the `/` namespace separator with a single `-`.
+## Enqueueing Editor and Front end Assets
+
+Like scripts, you need to enqueue your block's styles. As explained in the section before, you use the `editor_style` handle for styles only relevant in the editor, and the `style` handle for common styles applied both in the editor and the front of your site.
+
+The stylesheets enqueued by `style` are the base styles and are loaded first. The `editor` stylesheet will be loaded after it.
+
+Let's move on into code. Create a file called `editor.css`:
+
```css
-.wp-block-gutenberg-boilerplate-es5-hello-world-step-02 {
+.wp-block-gutenberg-examples-example-02-stylesheets {
color: green;
background: #cfc;
border: 2px solid #9c9;
@@ -59,56 +75,52 @@ The class name is generated using the block's name prefixed with `wp-block-`, re
}
```
-## Enqueueing Editor-only Block Assets
+And a new `style.css` file containing:
-Like scripts, your block's editor-specific styles should be enqueued by assigning the `editor_styles` setting of the registered block type:
+```css
+.wp-block-gutenberg-examples-example-02-stylesheets {
+ color: darkred;
+ background: #fcc;
+ border: 2px solid #c99;
+ padding: 20px;
+}
+```
+
+Configure your plugin to use these new styles:
```php
'gutenberg-boilerplate-es5-step02-editor',
- 'editor_style' => 'gutenberg-boilerplate-es5-step02-editor',
- ) );
-}
-add_action( 'init', 'gutenberg_boilerplate_block' );
-```
-
-## Enqueueing Editor and Front end Assets
-
-While a block's scripts are usually only necessary to load in the editor, you'll want to load styles both on the front of your site and in the editor. You may even want distinct styles in each context.
-
-When registering a block, you can assign one or both of `style` and `editor_style` to respectively assign styles always loaded for a block or styles only loaded in the editor.
-
-```php
- 'gutenberg-boilerplate-es5-step02',
+ register_block_type( 'gutenberg-examples/example-02-stylesheets', array(
+ 'style' => 'gutenberg-examples-02',
+ 'editor_style' => 'gutenberg-examples-02-editor',
+ 'editor_script' => 'gutenberg-examples-02',
) );
}
-add_action( 'init', 'gutenberg_boilerplate_block' );
+add_action( 'init', 'gutenberg_examples_02_register_block' );
```
-
-Since your block is likely to share some styles in both contexts, you can consider `style.css` as the base stylesheet, placing editor-specific styles in `editor.css`.
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 1bad64b3d95329..bfabb7379b40a6 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
@@ -6,57 +6,52 @@ To simplify block customization and ensure a consistent experience for users, th
![Screenshot of the rich text toolbar applied to a paragraph block inside the block editor](https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/assets/toolbar-text.png)
-When the user selects a block, a number of control buttons may be shown in a toolbar above the selected block. Some of these block-level controls are included automatically if the editor is able to transform the block to another type, or if the focused element is an RichText component.
+When the user selects a block, a number of control buttons may be shown in a toolbar above the selected block. Some of these block-level controls are included automatically if the editor is able to transform the block to another type, or if the focused element is a RichText component.
You can also customize the toolbar to include controls specific to your block type. If the return value of your block type's `edit` function includes a `BlockControls` element, those controls will be shown in the selected block's toolbar.
{% 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,99 @@ 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 {
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 (
);
},
diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md b/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md
index ab7543c392c9cb..8c92d48349b7e8 100644
--- a/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md
+++ b/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md
@@ -1,56 +1,59 @@
# Creating dynamic blocks
-It is possible to create dynamic blocks. These are blocks that can change their content even if the post is not saved. One example from WordPress itself is the latest posts block. This block will update everywhere it is used when a new post is published.
+Dynamic blocks are blocks that can change their content even if the post is not saved. One example from WordPress itself is the latest posts block. This block will update everywhere it is used when a new post is published.
-The following code example shows how to create the latest post block dynamic block.
+The following code example shows how to create a dynamic block that shows only the last post as a link.
{% codetabs %}
{% ES5 %}
```js
-// myblock.js
+( function( blocks, element, data ) {
-var el = wp.element.createElement,
- registerBlockType = wp.blocks.registerBlockType,
- withSelect = wp.data.withSelect;
+ var el = element.createElement,
+ registerBlockType = blocks.registerBlockType,
+ withSelect = data.withSelect;
-registerBlockType( 'my-plugin/latest-post', {
- title: 'Latest Post',
- icon: 'megaphone',
- category: 'widgets',
-
- edit: withSelect( function( select ) {
- return {
- posts: select( 'core' ).getEntityRecords( 'postType', 'post' )
- };
- } )( function( props ) {
+ registerBlockType( 'gutenberg-examples/example-05-dynamic', {
+ title: 'Example: last post',
+ icon: 'megaphone',
+ category: 'widgets',
- if ( ! props.posts ) {
- return "Loading...";
- }
-
- if ( props.posts.length === 0 ) {
- return "No posts";
- }
- var className = props.className;
- var post = props.posts[ 0 ];
-
- return el(
- 'a',
- { className: className, href: post.link },
- post.title.rendered
- );
- } ),
-} );
+ edit: withSelect( function( select ) {
+ return {
+ posts: select( 'core' ).getEntityRecords( 'postType', 'post' )
+ };
+ } )( function( props ) {
+
+ if ( ! props.posts ) {
+ return "Loading...";
+ }
+
+ if ( props.posts.length === 0 ) {
+ return "No posts";
+ }
+ var className = props.className;
+ var post = props.posts[ 0 ];
+
+ return el(
+ 'a',
+ { className: className, href: post.link },
+ post.title.rendered
+ );
+ } ),
+ } );
+}(
+ window.wp.blocks,
+ window.wp.element,
+ window.wp.data,
+) );
```
{% ESNext %}
```js
-// myblock.js
-
const { registerBlockType } = wp.blocks;
const { withSelect } = wp.data;
-registerBlockType( 'my-plugin/latest-post', {
- title: 'Latest Post',
+registerBlockType( 'gutenberg-examples/example-05-dynamic', {
+ title: 'Example: last post',
icon: 'megaphone',
category: 'widgets',
@@ -78,13 +81,16 @@ registerBlockType( 'my-plugin/latest-post', {
```
{% end %}
-Because it is a dynamic block it doesn't need to override the default `save` implementation on the client. Instead, it needs a server component. The rendering can be added using the `render_callback` property when using the `register_block_type` function.
+Because it is a dynamic block it doesn't need to override the default `save` implementation on the client. Instead, it needs a server component. The contents in the front of your site depend on the function called by the `render_callback` property of `register_block_type`.
```php
1,
'post_status' => 'publish',
@@ -101,9 +107,21 @@ function my_plugin_render_block_latest_post( $attributes, $content ) {
);
}
-register_block_type( 'my-plugin/latest-post', array(
- 'render_callback' => 'my_plugin_render_block_latest_post',
-) );
+function gutenberg_examples_05_dynamic() {
+ wp_register_script(
+ 'gutenberg-examples-05',
+ plugins_url( 'block.js', __FILE__ ),
+ array( 'wp-blocks', 'wp-element', 'wp-data' )
+ );
+
+ register_block_type( 'gutenberg-examples/example-05-dynamic', array(
+ 'editor_script' => 'gutenberg-examples-05',
+ 'render_callback' => 'gutenberg_examples_05_dynamic_render_callback'
+ ) );
+
+}
+add_action( 'init', 'gutenberg_examples_05_dynamic' );
+
```
There are a few things to notice:
@@ -121,45 +139,47 @@ Gutenberg 2.8 added the [``](/packages/components/src/server-s
{% codetabs %}
{% ES5 %}
```js
-// myblock.js
-
-var el = wp.element.createElement,
- registerBlockType = wp.blocks.registerBlockType,
- ServerSideRender = wp.components.ServerSideRender;
-
-registerBlockType( 'my-plugin/latest-post', {
- title: 'Latest Post',
- icon: 'megaphone',
- category: 'widgets',
-
- edit: function( props ) {
- // ensure the block attributes matches this plugin's name
- return (
- el(ServerSideRender, {
- block: "my-plugin/latest-post",
- attributes: props.attributes
- })
- );
- },
-} );
+( function( blocks, element, components ) {
+
+ var el = element.createElement,
+ registerBlockType = blocks.registerBlockType,
+ ServerSideRender = components.ServerSideRender;
+
+ registerBlockType( 'gutenberg-examples/example-05-dynamic', {
+ title: 'Example: last post',
+ icon: 'megaphone',
+ category: 'widgets',
+
+ edit: function( props ) {
+
+ return (
+ el(ServerSideRender, {
+ block: "gutenberg-examples/example-05-dynamic",
+ attributes: props.attributes
+ } )
+ );
+ },
+ } );
+}(
+ window.wp.blocks,
+ window.wp.element,
+ window.wp.components,
+) );
```
{% ESNext %}
```js
-// myblock.js
-
const { registerBlockType } = wp.blocks;
const { ServerSideRender } = wp.components;
-registerBlockType( 'my-plugin/latest-post', {
- title: 'Latest Post',
+registerBlockType( 'gutenberg-examples/example-05-dynamic', {
+ title: 'Example: last post',
icon: 'megaphone',
category: 'widgets',
edit: function( props ) {
- // ensure the block attributes matches this plugin's name
return (
);
@@ -168,4 +188,4 @@ registerBlockType( 'my-plugin/latest-post', {
```
{% end %}
-The PHP code is the same as above and is automatically handled through the WP REST API.
+Note that this code uses the `wp.components` utility but not `wp.data`. Make sure to update the `wp-data` dependency to `wp-compononents` in the PHP code.
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 c51bd505bdd2e2..738ed6640ce55f 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
@@ -1,6 +1,6 @@
# Introducing Attributes and Editable Fields
-Our example block is still not very interesting because it lacks options to customize the appearance of the message. In this section, we will implement a RichText field allowing the user to specify their own message. Before doing so, it's important to understand how the state of a block (its "attributes") is maintained and changed over time.
+The example blocks so far are still not very interesting because they lack options to customize the appearance of the message. In this section, we will implement a RichText field allowing the user to specify their own message. Before doing so, it's important to understand how the state of a block (its "attributes") is maintained and changed over time.
## Attributes
@@ -8,84 +8,121 @@ Until now, the `edit` and `save` functions have returned a simple representation
One challenge of maintaining the representation of a block as a JavaScript object is that we must be able to extract this object again from the saved content of a post. This is achieved with the block type's `attributes` property:
-{% 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',
+ type: 'array',
+ source: 'children',
selector: 'p',
- }
+ },
},
+```
- edit: function( props ) {
- var content = props.attributes.content;
+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, the `content` value will be extracted from the HTML of the paragraph element in the saved post's markup.
+
+## Components and the `RichText` Component
+
+Earlier examples used the `createElement` function to create DOM nodes, but it's also possible to encapsulate this behavior into "components". This abstraction helps you share common behaviors and hide complexity in self-contained units.
- function onChangeContent( newContent ) {
- props.setAttributes( { content: newContent } );
- }
+There are a number of [components available](/docs/designers-developers/developers/packages/packages-editor.md#components) to use in implementing your blocks. You can see one such component in the code below: the [`RichText` component](/docs/designers-developers/developers/packages/packages-editor.md#richtext).
- return el(
- RichText,
- {
- tagName: 'p',
- className: props.className,
- onChange: onChangeContent,
- value: content,
+The `RichText` component can be considered as a super-powered `textarea` element, enabling rich content editing including bold, italics, hyperlinks, etc.
+
+To use the `RichText` component, add `wp-editor` to the dependency array of registered script handles when calling `wp_register_script`.
+
+```php
+wp_register_script(
+ 'gutenberg-examples-03',
+ plugins_url( 'block.js', __FILE__ ),
+ array(
+ 'wp-blocks',
+ 'wp-element',
+ 'wp-editor' // Note the addition of wp-editor to the dependencies
+ ),
+ filemtime( plugin_dir_path( __FILE__ ) . 'block.js' )
+);
+```
+
+Do not forget to also update the `editor_script` handle in `register_block_type` to `gutenberg-examples-03`.
+
+Implementing this behavior as a component enables you as the block implementer to be much more granular about editable fields. Your block may not need `RichText` at all, or it may need many independent `RichText` elements, each operating on a subset of the overall block state.
+
+Because `RichText` allows for nested nodes, you'll most often use it in conjunction with the `html` attribute source when extracting the value from saved content. You'll also use `RichText.Content` in the `save` function to output RichText values.
+
+Here is the complete block definition for Example 03.
+
+{% codetabs %}
+{% ES5 %}
+```js
+( 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',
+ },
+ },
+
+ 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 ;
},
} );
```
{% end %}
-
-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.
-
-## Components and the `RichText` Component
-
-Earlier examples used the `createElement` function to create DOM nodes, but it's also possible to encapsulate this behavior into ["components"](). This abstraction helps as a pattern to share common behaviors and to hide complexity into self-contained units. There are a number of components available to use in implementing your blocks. You can see one such component in the snippet above: the [`RichText` component]().
-
-The `RichText` component can be considered as a super-powered `textarea` element, enabling rich content editing including bold, italics, hyperlinks, etc.
-
-To use the `RichText` component, add `wp-editor` to the array of registered script handles when calling `wp_register_script`.
-
-```php
-wp_register_script(
- 'gutenberg-boilerplate-es5-step03',
- plugins_url( 'step-03/block.js', __FILE__ ),
- array(
- 'wp-blocks',
- 'wp-element',
- 'wp-editor', // Note the addition of wp-editor to the dependencies
- )
-);
-```
-
-Implementing this behavior as a component enables you as the block implementer to be much more granular about editable fields. Your block may not need `RichText` at all, or it may need many independent `RichText` elements, each operating on a subset of the overall block state.
-
-Because `RichText` allows for nested nodes, you'll most often use it in conjunction with the `html` attribute source when extracting the value from saved content. You'll also use `RichText.Content` in the `save` function to output RichText values.
diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/readme.md b/docs/designers-developers/developers/tutorials/block-tutorial/readme.md
index 0ff9418d01743a..a3ee5191dbca79 100644
--- a/docs/designers-developers/developers/tutorials/block-tutorial/readme.md
+++ b/docs/designers-developers/developers/tutorials/block-tutorial/readme.md
@@ -4,4 +4,6 @@ The purpose of this tutorial is to step through the fundamentals of creating a n
To follow along with this tutorial, you can [download the accompanying WordPress plugin](https://github.com/WordPress/gutenberg-examples) which includes all of the examples for you to try on your own site. At each step along the way, you should feel free to experiment by modifying the examples with your own ideas and observing the effects they have on the block's behavior.
-Code snippets are provided both for "classic" JavaScript (ECMAScript 5, or "ES5"), as well as newer versions of the language standard (ES2015 and newer, or "ESNext"). You can change between them using tabs found above each code example. When choosing to author your blocks with ESNext, you will need a build step in order to support older browsers. Note that it is not required to use ESNext to create a new block, and you are welcome to use classic JavaScript if you so choose.
+Code snippets are provided both for "classic" JavaScript (ECMAScript 5, or "ES5"), as well as newer versions of the language standard (ES2015 and newer, or "ESNext"). You can change between them using tabs found above each code example. When choosing to author your blocks with ESNext, you need to run [the JavaScript build step](/docs/designers-developers/developers/tutorials/javascript/js-build-setup/) in order to support older browsers.
+
+Note that it is not required to use ESNext to create a new block, and you are welcome to use classic JavaScript if you so choose.
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 ea9a18bbf23684..c2ea73cbdd8957 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
@@ -10,19 +10,22 @@ While the block's editor behaviors are implemented in JavaScript, you'll need to
```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' );
```
Note the two script dependencies:
@@ -39,44 +42,58 @@ 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' };
-
-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.' );
- },
-} );
+( 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
+) );
```
{% 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)
;
},
} );
```
@@ -84,6 +101,6 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-01', {
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](/docs/designers-developers/developers/block-api/block-registration.md#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.
+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. In this example, the namespace is `gutenberg-examples`.
The `edit` and `save` functions describe the structure of your block in the context of the editor and the saved content respectively. While the difference is not obvious in this simple example, in the following sections we'll explore how these are used to enable customization of the block in the editor preview.