Skip to content

Latest commit

 

History

History

blocks

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Blocks

Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage. The idea combines concepts of what in WordPress today we achieve with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience.

For more context, refer to What Are Little Blocks Made Of? from the Make WordPress Design blog.

The following documentation outlines steps you as a developer will need to follow to add your own custom blocks to WordPress's editor interfaces.

Getting Started

If you're not already accustomed to working with JavaScript in your WordPress plugins, you may first want to reference the guide on Including CSS & JavaScript in the Theme Handbook.

At a minimum, you will need to enqueue scripts for your block as part of a block_enqueue_scripts action callback, with a dependency on the wp-blocks script handle:

<?php
// plugin.php

function myplugin_block_enqueue_scripts() {
	wp_enqueue_script( 'myplugin-block', plugins_url( 'block.js', __FILE__ ), array( 'wp-blocks' ) );
}
add_action( 'block_enqueue_scripts', 'myplugin_block_enqueue_scripts' );

The following sections will describe what you'll need to include in block.js to describe the behavior of your custom block.

Example

Let's imagine you wanted to define a block to show a randomly generated image in a post's content using lorempixel.com. The service provides a choice of category and you'd like to offer this as an option when editing the post.

Take a step back and consider the ideal workflow for adding a new random image. After inserting the block, as a user I'd expect it to be shown in some empty state, with an option to choose a category in a select dropdown. Upon confirming my selection, a preview of the image should be shown next to the dropdown. At this point, you might realize that while you'd want some controls to be shown when editing content, the markup included in the published post might not appear the same (your visitors should not see a dropdown field when reading your content). This leads to the first requirement of describing a block: you will need to provide implementations both for what's to be shown in an editor and what's to be saved with the published content. You needn't worry about redundant effort here, as concepts of Elements and componentization provide an avenue for sharing common behaviors.

Now that we've considered user interaction, you should think about the underlying values that determine the markup generated by your block. In our example, the output is affected only when the category changes. Put another way: the output of a block is a function of its attributes. The category, a simple string, is the only thing we require to be able to generate the image we want to include in the published content. We call these underlying values of a block instance its attributes.

With these concepts in mind, let's explore an implementation of our random image block:

<?php
// plugin.php

function random_image_block_enqueue_scripts() {
	wp_enqueue_script( 'random-image-block', plugins_url( 'block.js', __FILE__ ), array( 'wp-blocks', 'wp-element' ) );
}
add_action( 'block_enqueue_scripts', 'random_image_block_enqueue_scripts' );
// block.js
var el = wp.element.createElement,
	query = wp.blocks.query;

function RandomImage( props ) {
	var src = 'http://lorempixel.com/400/200/' + props.category;

	return el( 'img', {
		src: src,
		alt: props.category
	} );
}

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

	icon: 'format-image',

	category: 'media',

	attributes: {
		category: query.attr( 'img', 'alt' )
	},

	edit: function( block ) {
		var category = block.attributes.category,
			children;

		function setCategory( event ) {
			var selected = event.target.querySelector( 'option:checked' );
			block.setAttributes( { category: selected.value } );
			event.preventDefault();
		}

		children = [];
		if ( category ) {
			children.push( RandomImage( { category: category } ) );
		}

		children.push(
			el( 'select', { value: category, onChange: setCategory },
				el( 'option', null, '- Select -' ),
				el( 'option', { value: 'sports' }, 'Sports' ),
				el( 'option', { value: 'animals' }, 'Animals' ),
				el( 'option', { value: 'nature' }, 'Nature' )
			)
		);

		return el( 'form', { onSubmit: setCategory }, children );
	},

	save: function( block ) {
		return RandomImage( { category: block.attributes.category } );
	}
} );

(Example in ES2015+, JSX)

Let's briefly review a few items you might observe in the implementation:

  • When registering a new block, you must prefix its slug with a namespace for your plugin. This helps prevent conflicts when more than one plugin registers a block with the same slug.
  • You will use createElement to describe the structure of your block's markup. See the Element documentation for more information.
  • Extracting RandomImage to a separate function allows us to reuse it in both the editor-specific interface and the published content.
  • The edit function should handle any case where an attribute is unset, as in the case of the block being newly inserted.
  • We only change the attributes of a block by calling the setAttributes helper. Never assign a value on the attributes object directly.
  • React provides conveniences for working with select element with value and onChange props.

By concerning yourself only with describing the markup of a block given its attributes, you need not worry about maintaining the state of the page, or how your block interacts in the context of the surrounding editor.

But how does the markup become an object of attributes? We need a pattern for encoding the values into the published post's markup, and then retrieving them the next time the post is edited. This is the motivation for the block's attributes property. The shape of this object matches that of the attributes object we'd like to receive, where each value is a matcher which tries to find the desired value from the markup of the block.

In the random image block above, we've given the alt attribute of the image a secondary responsibility of tracking the selected category. There are a few other ways we could have achieved this, but the category value happens to work well as an alt descriptor. In the attributes property, we define an object with a key of category whose value tries to find this alt attribute of the markup. If it's successful, the category's value in our edit and save functions will be assigned. In the case of a new block or invalid markup, this value would be undefined, so we adjust our return value accordingly.

API

wp.blocks.registerBlock( slug: string, settings: 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.

  • title: string - A human-readable localized label for the block. Shown in the block picker.
  • icon: string | WPElement | Function - Slug of the Dashicon to be shown in the control's button, or an element (or function returning an element) if you choose to render your own SVG.
  • attributes: Object | Function - An object of matchers or a function which, when passed the raw content of the block, returns block attributes as an object. When defined as an object of matchers, the attributes object is generated with values corresponding to the shape of the matcher object keys.
  • category: string - Slug of the block's category. The category is used to organize the blocks in the block inserter.
  • edit( { attributes: Object, setAttributes: Function } ): WPElement - Returns an element describing the markup of a block to be shown in the editor. A block can update its own state in response to events using the setAttributes function, passing an object of properties to be applied as a partial update.
  • save( { attributes: Object } ): WPElement - Returns an element describing the markup of a block to be saved in the published content. This function is called before save and when switching to an editor's HTML view.
  • controls: string[] - Slugs for controls to be made available to block. See also: wp.blocks.registerControl
  • encodeAttributes( attributes: Object ): Object - Called when save markup is generated, this function allows you to control which attributes are to be encoded in the block comment metadata. By default, all attribute values not defined in the block's attributes property are serialized to the comment metadata. If defined, this function should return the subset of attributes to encode, or null to bypass default behavior.

wp.blocks.registerControl( slug: string, settings: Object )

Registers a new block-level control. Controls appear in a block's toolbar when it receives focus if it is included in the block's controls option.

  • title: string - A human-readable localized label for the control. Shown in help tooltips.
  • icon: string | WPElement | Function - Slug of the Dashicon to be shown in the control's button, or an element (or function returning an element) if you choose to render your own SVG.
  • onClick( attributes: Object, setAttributes: Function ) - Click behavior for control. Use this to change or toggle an attribute of the block.
  • isVisible( attributes: Object ): boolean - Called when a block receives focus or changes. Return false to prevent the control's button from being shown. If this option is not defined for a control, the button will always be shown.
  • isActive( attributes: Object ): boolean - Called when a block receives focus or changes. Return true to apply an active effect to the control's button, in the case that the control's behavior is a toggle.

Inline controls for Editable elements are identical for every block and cannot be modified.

wp.blocks.getBlockSettings( slug: string )

Returns settings associated with a registered block.

wp.blocks.getControlSettings( slug: string )

Returns settings associated with a registered control.

Components

Because many blocks share the same complex behaviors, the following components are made available to simplify implementations of your block's edit function.

Editable

Render a rich contenteditable input, providing users the option to add emphasis to content or links to content. It behaves similar to a controlled component, except that onChange is triggered less frequently than would be expected from a traditional input field, usually when the user exits the field.

The following props are made available:

  • inline: boolean - If true, only inline elements are allowed to be used in inserted into the text, effectively disabling the behavior of the "Enter" key.
  • placeholder: string - A text hint to be shown to the user when the field value is empty, similar to the input and textarea attribute of the same name
  • value: string - Markup value of the editable field. Only valid markup is allowed, as determined by inline value and available controls.
  • onChange: Function - Callback handler when the value of the field changes, passing the new value as its only argument.

Example:

var el = wp.element.createElement,
	Editable = wp.blocks.Editable;

function edit( attributes, setAttributes ) {
	function onChange( value ) {
		setAttributes( { text: value } );
	}

	return el( Editable, {
		value: attributes.text,
		onChange: onChange
	} );
}