# Block Editor Handbook
Source: https://developer.wordpress.org/block-editor/
Welcome to the Block Editor Handbook.
The [**Block Editor**](https://wordpress.org/gutenberg/) is a modern paradigm for WordPress site building and publishing. It uses a modular system of **blocks** to compose and format content and is designed to create rich and flexible layouts for websites and digital products.
The Block Editor consists of several primary elements, as shown in the following figure:

The elements highlighted are:
1. **Inserter:** A panel for inserting blocks into the content canvas
2. **Content canvas:** The content editor, which holds content created with blocks
3. **Settings Panel** A panel for configuring a block’s settings when selected or the settings of the post
Through the Block Editor, you create content modularly using blocks. Many [blocks](https://developer.wordpress.org/block-editor/reference-guides/core-blocks/) are available in WordPress by default, and you can also [create your own](https://developer.wordpress.org/block-editor/getting-started/create-block/).
A [block](https://developer.wordpress.org/block-editor/explanations/architecture/key-concepts/#blocks) is a discrete element such as a Paragraph, Heading, Media, or Embed. Each block is treated as a separate element with individual editing and format controls. When all these components are pieced together, they make up the content of the page or post, which is then [stored in the WordPress database](https://developer.wordpress.org/block-editor/explanations/architecture/data-flow/#serialization-and-parsing).
The Block Editor is the result of the work done on the [**Gutenberg project**](https://developer.wordpress.org/block-editor/getting-started/faq/#what-is-gutenberg), which aims to revolutionize the WordPress editing experience.
Besides offering an [enhanced editing experience](https://wordpress.org/gutenberg/) through visual content creation tools, the Block Editor is also a powerful developer platform with a [rich feature set of APIs](https://developer.wordpress.org/block-editor/reference-guides/) that allow it to be manipulated and extended in countless ways.
## Navigating this handbook
This handbook is focused on block development and is divided into five major sections.
- **[Getting Started](https://developer.wordpress.org/block-editor/getting-started/):** For those just starting out with block development, this is where you can get set up with a [development environment](https://developer.wordpress.org/block-editor/getting-started/devenv/) and learn the [fundamentals of block development](https://developer.wordpress.org/block-editor/getting-started/fundamentals/). Its [Quick Start Guide](https://developer.wordpress.org/block-editor/getting-started/quick-start-guide/) and [Tutorial: Build your first block](https://developer.wordpress.org/block-editor/getting-started/tutorial/) are great places to start learning block development.
- **[How-to Guides](https://developer.wordpress.org/block-editor/how-to-guides/):** Here, you can build on what you learned in the Getting Started section and learn how to solve particular problems. You will also find tutorials and example code to reuse in your own projects, such as [working with WordPress data](https://developer.wordpress.org/block-editor/how-to-guides/data-basics/) or [Curating the Editor Experience](https://developer.wordpress.org/block-editor/how-to-guides/curating-the-editor-experience/).
- **[Reference Guides](https://developer.wordpress.org/block-editor/reference-guides/):** This section is the heart of the handbook and is where you can get down to the nitty-gritty and look up the details of the particular API you’re working with or need information on. Among other things, the [Block API Reference](https://developer.wordpress.org/block-editor/reference-guides/block-api/) covers most of what you will want to do with a block, and each [component](https://developer.wordpress.org/block-editor/reference-guides/components/) and [package](https://developer.wordpress.org/block-editor/reference-guides/packages/) is also documented here. *Components are also documented via [Storybook](https://wordpress.github.io/gutenberg/?path=/story/docs-introduction--page).*
- **[Explanations](https://developer.wordpress.org/block-editor/explanations/):** This section enables you to go deeper and reinforce your practical knowledge with a theoretical understanding of the [Architecture](https://developer.wordpress.org/block-editor/explanations/architecture/) of the Block Editor.
- **[Contributor Guide](https://developer.wordpress.org/block-editor/contributors/):** Gutenberg is open-source software, and everyone is welcome to contribute to the project. This section details how to contribute, whether with [code](https://developer.wordpress.org/block-editor/contributors/code/), [design](https://developer.wordpress.org/block-editor/contributors/design/), [documentation](https://developer.wordpress.org/block-editor/contributors/documentation/), or in some other way.
## Further resources
This handbook should be considered the canonical resource for all things related to block development. However, there are other resources that can help you.
- **[WordPress Developer Blog](https://developer.wordpress.org/news/):** An ever-growing resource of technical articles covering specific topics related to block development and a wide variety of use cases. The blog is also an excellent way to [keep up with the latest developments in WordPress](https://developer.wordpress.org/news/tag/roundup/).
- **[Learn WordPress](https://learn.wordpress.org/):** The WordPress hub for learning resources where you can find courses like [Introduction to Block Development: Build your first custom block](https://learn.wordpress.org/course/introduction-to-block-development-build-your-first-custom-block/), [Converting a Shortcode to a Block](https://learn.wordpress.org/course/converting-a-shortcode-to-a-block/), or [Using the WordPress Data Layer](https://learn.wordpress.org/course/using-the-wordpress-data-layer/)
- **[WordPress.tv](https://wordpress.tv/):** A hub of WordPress-related videos (from talks at WordCamps to recordings of online workshops) curated and moderated by the WordPress community. You’re sure to find something to aid your learning about [block development](https://wordpress.tv/?s=block%20development&sort=newest) or the [Block Editor](https://wordpress.tv/?s=block%20editor&sort=relevance) here.
- **[Gutenberg repository](https://github.com/WordPress/gutenberg/):** Development of the Block Editor takes place on GitHub. The repository contains the code of interesting packages such as [`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) (core blocks) or [`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components) (common UI elements). *The [block-development-examples](https://github.com/WordPress/block-development-examples) repository is another useful reference.*
- **[End User Documentation](https://wordpress.org/documentation/):** This documentation site is targeted to the end user (not developers), where you can also find documentation about the [Block Editor](https://wordpress.org/documentation/category/block-editor/) and [working with blocks](https://wordpress.org/documentation/article/work-with-blocks/).
## Are you in the right place?
The Block Editor Handbook is designed for those looking to create and develop for the Block Editor. However, it’s important to note that there are multiple other handbooks available within the [Developer Resources](https://developer.wordpress.org/) that you may find beneficial:
- [Theme Handbook](https://developer.wordpress.org/themes)
- [Plugin Handbook](https://developer.wordpress.org/plugins)
- [Common APIs Handbook](https://developer.wordpress.org/apis)
- [Advanced Administration Handbook](https://developer.wordpress.org/advanced-administration)
- [REST API Handbook](https://developer.wordpress.org/rest-api/)
- [Coding Standards Handbook](https://developer.wordpress.org/coding-standards)
---
# Triage
Source: https://developer.wordpress.org/block-editor/contributors/triage/
To keep the repository healthy, it needs to be triaged regularly. **Triage is the practice of reviewing existing issues and pull requests to make sure they’re relevant, actionable, and have all the information they need**. Anyone can help triage, although you’ll need to be a member of the triage team for the Gutenberg repository to modify an issue’s labels or edit its title.
> Besides this page, the [How to do triage on GitHub](https://learn.wordpress.org/tutorial/how-to-do-triage-on-github/) tutorial is another great resource to get introduced to triage
## Join the triage team
The triage team is an open group of people with a particular role of making sure triage is done consistently across the Gutenberg repo. There are various types of triage which happen:
- Regular self triage sessions done by members on their own time.
- Organized triage sessions done as a group at a set time. You can [review the meetings page](https://make.wordpress.org/meetings/) to find these triage sessions and appropriate slack channels.
- Focused triage sessions on a specific board, label or feature.
These are the expectations of being a triage team member:
- You are expected to do some triage even if it is self triage at least once a week.
- As you can, try to join organized triage sessions.
- If you join the triage team to focus on a specific label or board, the expectation is that your focus will be there. Please make this known to fellow triage team members.
If you would like to join this team, simply ask in #core-editor [Slack](https://make.wordpress.org/chat/) at any time.
## Triage your first issues
To start simply choose from one of these filtered lists below. Note: You can find most of these filters by selecting the “Sort” option from the [overall Issues page](https://github.com/wordpress/gutenberg/issues).
- **All Gutenberg issues [without an assigned label](https://github.com/WordPress/gutenberg/issues?q=is%3Aopen+is%3Aissue+no%3Alabel+sort%3Aupdated-asc)**. Triaging by simply adding labels helps people focused on certain aspects of Gutenberg find relevant issues easier and start working on them.
- **All Gutenberg pull requests [without an assigned label](https://github.com/WordPress/gutenberg/pulls?q=is%3Aopen+is%3Apr+no%3Alabel)**. This requires a level of comfortability with code. For more guidance on which labels are best to use, please [review this section on labeling pull requests](https://developer.wordpress.org/block-editor/contributors/repository-management/#pull-requests) for contributors. You can also always check with the person authoring the pull request to make sure the labels match what they are intending to do.
- **[The least recently updated](https://github.com/WordPress/gutenberg/issues?q=is%3Aopen+is%3Aissue+sort%3Aupdated-asc) Gutenberg issues**. Triaging issues that are getting old and possibly out of date keeps important work from being overlooked.
- **All Gutenberg issues [with no comments](https://github.com/wordpress/gutenberg/issues?q=is%3Aissue+is%3Aopen+comments%3A0+)**. Triaging this list helps make sure all issues are acknowledged, and can help identify issues that may need more information or discussion before they are actionable.
- **[The least commented](https://github.com/wordpress/gutenberg/issues?q=is%3Aissue+is%3Aopen+sort%3Acomments-asc) on Gutenberg issues**. Triaging this list helps the community figure out what things might still need traction for certain proposals.
- **[The most commented](https://github.com/wordpress/gutenberg/issues?q=is%3Aissue+is%3Aopen+sort%3Acomments-desc) on Gutenberg issues**. If you feel comfortable chiming in and the conversation has stagnated, the best way to triage these kinds of issues is to summarize the discussion thus far and do your best to identify action items, blockers, etc. Triaging this list allows finding solutions to important and complex issues to move forward.
- You can also **create your own custom set of filters on GitHub**. If you have a filter you think might be useful for the community, feel free to submit a PR to add it to this list.
## General triage process
When triaging, either one of the lists above or issues in general, work through issues one-by-one. Here are some steps you can perform for each issue:
1. First **search for duplicates**. If the issue is duplicate, close it by commenting with “Duplicate of #” and add any relevant new details to the existing issue. (Don’t forget to search for duplicates among closed issues as well!).
2. If the **issue is missing labels, add some** to better categorize it (requires proper permissions given after joining the triage team). A good starting place when adding labels is to apply one of the labels prefixed \[Type\] (e.g. \[Type\] Enhancement or \[Type\] Bug) to indicate what kind of issue it is. After that consider adding more descriptive labels. If the issue concerns a particular core block, add one of the labels prefixed \[Block\]. Or if the issue affects a particular feature there are \[Feature\] labels. Finally, there are labels that affect particular interest areas, like Accessibility and Internationalization. You can view all possible labels [here](https://github.com/WordPress/gutenberg/labels).
3. If the **title doesn’t communicate the issue clearly enough, edit it for clarity** (requires proper permissions). Specifically, we’d recommend having the main feature the issue relates to in the beginning of the title ([example](https://github.com/WordPress/gutenberg/issues/6193)) and for the title to generally be as succinct yet descriptive as possible ([example](https://github.com/WordPress/gutenberg/issues/6193)).
4. If it’s a **bug report, test to confirm the report or add the `Needs Testing` label**. If there is not enough information to confirm the report, add the `[Status] Needs More Info` label and ask for the details needed. It’s particularly beneficial when a bug report has steps for reproduction so ask the reporter to add those if they’re missing.
5. **Remove the `[Status] Needs More Info` when is no longer needed**, for example if the author of the issue has responded with enough details.
6. **Close the inactive `[Status] Needs More Info` issues with a note** if the author didn’t respond in 2+ weeks.
7. If there was a conversation on the issue but **no actionable steps identified, follow up with the participants to see what’s actionable**. Make sure to @ each participant when responding in a comment.
8. If you feel comfortable triaging the issue further, then you can also:
- Check that the bug report is valid by debugging it to see if you can track down the technical specifics.
- Check if the issue is missing some detail and see if you can fill in those details. For instance, if a bug report is missing visual detail, it’s helpful to reproduce the issue locally and upload a screenshot or GIF.
- Consider adding the Good First Issue label if you believe this is a relatively easy issue for a first-time contributor to try to solve.
**Commonly used labels**
Generally speaking, the following labels are very useful for triaging issues and will likely be the ones you use the most consistently. You can view all possible labels [here](https://github.com/WordPress/gutenberg/labels).
| Label | Reason |
|---|---|
| `[Type] Bug` | When an intended feature is broken. |
| `[Type] Enhancement` | When someone is suggesting an enhancement to a current feature. |
| `[Type] Help Request` | When someone is asking for general help with setup/implementation. |
| `Needs Technical Feedback` | When you see new features or API changes proposed. |
| `Needs More Info` | When it’s not clear what the issue is or it would help to provide additional details. |
| `Needs Testing` | When a new issue needs to be confirmed or old bugs seem like they are no longer relevant. |
**Determining priority labels**
If you have enough knowledge about the report at hand and feel confident in doing so, you can consider adding priority. Note that it’s on purpose that no priority label infers a normal level.
| Label | Reason |
|---|---|
| `Priority: High` | Fits one of the current focuses and is causing a major broken experience (including flow, visual bugs and blocks). |
| `Priority: Low` | Enhancements that aren’t part of focuses, niche bugs, problems with old browsers. |
## Closing issues
Issues are closed for the following reasons:
- A PR and/or latest release resolved the reported issue.
- Duplicate of a current report.
- Help request that is best handled in the WordPress.org forums.
- An issue that’s not able to be replicated.
- An issue that needs more information that the author of the issue hasn’t responded to for 2+ weeks.
- An item that is determined as unable to be fixed or is working as intended.
## Specific triages
### Release specific triage
Here are some guidelines to follow when doing triage specifically around the time of a release. This is important to differentiate compared to general triage so problematic, release blocking bugs are properly identified and solutions are found.
- **If a bug is introduced in a release candidate (RC) and it’s going to break many workflows**, add it to the version milestone and flag in the [\#core-editor](https://wordpress.slack.com/archives/C02QB2JS7) channel in WordPress.org slack.
- **If a bug was introduced in the most recent version, and a next RC hasn’t yet happened**, ideally the developers can push to fix it prior to RC! The amount of push for a fix should scale proportional to the potential of breakage. In this case, add to the RC milestone and, if deemed urgent, ping in the [\#core-editor](https://wordpress.slack.com/archives/C02QB2JS7) channel in WordPress.org slack.
- **If a bug wasn’t introduced in the most recent version**, do not add a milestone. Instead, use labels like `[Priority] High` if it’s a pressing issue, and if needed you can call attention to it in the weekly core meetings.
### Design specific triage
Along with the general triage flows listed previously, there are some specific additions to the flows for more design-centric triage for design minded folks participating in triage.
- PR testing and reviews: this should be your first stop for daily self triage.
- Label `Needs Design Feedback`: check if the issue does need design feedback and, if possible, give it. You can organize this by priority, project boards or by least commented. Once there are enough opinions, please remove this label and decide on next steps (ie adding the Needs Design label).
- Label `Needs Design`: Does it really need a design? Does this fit a focus? If it has a design mark as `Needs Design Feedback` to better categorize the issue.
Reminders:
- Ask for screenshots as needed.
- Ask for iterations and note any changes before merging.
- If the issue isn’t in a board, check to see if it doesn’t fit in a specific focus.
- If the issue/pull has not been prioritized yet, consider adding a priority label to help move the issue forward.
For more detailed information about weekly design triage and to join in, please [review this guide](https://make.wordpress.org/design/handbook/workflows/weekly-gutenberg-design-triage/).
---
# Block Development Environment
Source: https://developer.wordpress.org/block-editor/getting-started/devenv/
This guide will help you set up the right development environment to create blocks and other plugins that extend and modify the Block Editor in WordPress.
A block development environment includes the tools you need on your computer to successfully develop for the Block Editor. The three essential requirements are:
1. [Code editor](#code-editor)
2. [Node.js development tools](#node-js-development-tools)
3. [Local WordPress environment (site)](#local-wordpress-environment)
To contribute to the Gutenberg project itself, refer to the additional documentation in the [code contribution guide](https://developer.wordpress.org/block-editor/contributors/code/getting-started-with-code-contribution).
## Code editor
A code editor is used to write code. You can use whichever editor you’re most comfortable with. The key is having a way to open, edit, and save text files.
If you do not already have a preferred code editor, [Visual Studio Code](https://code.visualstudio.com/) (VS Code) is a popular choice for JavaScript development among Core contributors. It works well across the three major platforms (Windows, Linux, and Mac), is open-source, and is actively maintained by Microsoft. VS Code also has a vibrant community providing plugins and extensions, including many for WordPress development.
## Node.js development tools
Node.js (`node`) is an open-source runtime environment that allows you to execute JavaScript outside of the web browser. While Node.js is not required for all WordPress JavaScript development, it’s essential when working with modern JavaScript tools and developing for the Block Editor.
Node.js and its accompanying development tools allow you to:
- Install and run WordPress packages needed for Block Editor development, such as `wp-scripts`
- Setup local WordPress environments with `wp-env` and `wp-now`
- Use the latest ECMAScript features and write code in ESNext
- Lint, format, and test JavaScript code
- Scaffold custom blocks with the `create-block` package
The list goes on. While modern JavaScript development can be challenging, WordPress provides several tools, like [`wp-scripts`](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-scripts/) and [`create-block`](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-create-block/), that streamline the process and are made possible by Node.js development tools.
**The recommended Node.js version for block development is [Active LTS](https://nodejs.org/en/about/previous-releases) (Long Term Support)**. However, there are times when you need to use different versions. A Node.js version manager tool like `nvm` is strongly recommended and allows you to change your `node` version when required. You will also need Node Package Manager (`npm`) and the Node Package eXecute (`npx`) to work with some WordPress packages. Both are installed automatically with Node.js.
To be able to use the Node.js tools and [packages provided by WordPress](https://github.com/WordPress/gutenberg/tree/trunk/packages) for block development, you’ll need to set a proper Node.js runtime environment on your machine. To learn more about how to do this, refer to the links below.
- [Install Node.js for Mac and Linux](https://developer.wordpress.org/block-editor/getting-started/devenv/nodejs-development-environment/#node-js-installation-on-mac-and-linux-with-nvm)
- [Install Node.js for Windows](https://developer.wordpress.org/block-editor/getting-started/devenv/nodejs-development-environment/#node-js-installation-on-windows-and-others)
## Local WordPress environment
A local WordPress environment (site) provides a controlled, efficient, and secure space for development, allowing you to build and test your code before deploying it to a production site. The same [requirements](https://en-gb.wordpress.org/about/requirements/) for WordPress apply to local sites.
In the broader WordPress community, many tools are available for setting up a local WordPress environment on your computer. The Block Editor Handbook covers `wp-env`, which is open-source and maintained by the WordPress project itself. It’s also the recommended tool for Gutenberg development.
Refer to the [Get started with `wp-env`](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-env/) guide for setup instructions.
Throughout the Handbook, you may also see references to `wp-now`. This is a lightweight tool powered by WordPress Playground that streamlines setting up a simple local WordPress environment. While still experimental, this tool is great for quickly testing WordPress releases, plugins, and themes.
This list is not exhaustive, but here are several additional options to choose from if you prefer not to use `wp-env`:
- [Local](https://localwp.com/)
- [WP Studio](https://developer.wordpress.com/studio/)
- [XAMPP](https://www.apachefriends.org/)
- [MAMP](https://www.mamp.info/en/mamp/mac/)
- [Varying Vagrant Vagrants](https://varyingvagrantvagrants.org/) (VVV)
---
# How-to Guides
Source: https://developer.wordpress.org/block-editor/how-to-guides/
The new editor is highly flexible, like most of WordPress. You can build custom blocks, modify the editor’s appearance, add special plugins, and much more.
## Creating blocks
The editor is about blocks, and the main extensibility API is the Block API. It allows you to create your own static blocks, [Dynamic Blocks](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/creating-dynamic-blocks/) ( rendered on the server ) and also blocks capable of saving data to Post Meta for more structured content.
If you want to learn more about block creation, see the [Create a Block tutorial](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-create-block/) for the best place to start.
## Extending blocks
It is also possible to modify the behavior of existing blocks or even remove them completely using filters.
Learn more in the [Block Filters](https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/) section.
Specifically for `Query Loop` block, besides the available filters, there are more ways to extend it and create bespoke versions of it. Learn more in the [Extending the Query Loop block](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/extending-the-query-loop-block/) section.
## Extending the Editor UI
Extending the editor UI can be accomplished with the `registerPlugin` API, allowing you to define all your plugin’s UI elements in one place.
Refer to the [Plugins](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-plugins/) and [Edit Post](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-edit-post/) section for more information.
You can also filter certain aspects of the editor; this is documented on the [Editor Filters](https://developer.wordpress.org/block-editor/reference-guides/filters/editor-filters/) page.
## Meta boxes
Porting PHP meta boxes to blocks or sidebar plugins is highly encouraged, learn how in the [meta box](https://developer.wordpress.org/block-editor/how-to-guides/metabox/) and [sidebar plugin](https://developer.wordpress.org/block-editor/how-to-guides/plugin-sidebar-0/) guides.
## Theme support
By default, blocks provide their styles to enable basic support for blocks in themes without any change. Themes can add/override these styles, or rely on defaults.
There are some advanced block features which require opt-in support in the theme. See [theme support](https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-support/) and [how to filter global styles](https://developer.wordpress.org/block-editor/reference-guides/filters/global-styles-filters/).
## Autocomplete
Autocompleters within blocks may be extended and overridden. Learn more about the [autocomplete](https://developer.wordpress.org/block-editor/reference-guides/filters/autocomplete-filters/) filters.
## Block parsing and serialization
Posts in the editor move through a couple of different stages between being stored in `post_content` and appearing in the editor. Since the blocks themselves are data structures that live in memory it takes a parsing and serialization step to transform out from and into the stored format in the database.
Customizing the parser is an advanced topic that you can learn more about in the [Extending the Parser](https://developer.wordpress.org/block-editor/reference-guides/filters/parser-filters/) section.
---
# Notices
Source: https://developer.wordpress.org/block-editor/how-to-guides/notices/
Notices are informational UI displayed near the top of admin pages. WordPress core, themes, and plugins all use notices to indicate the result of an action, or to draw the user’s attention to necessary information.
In the classic editor, notices hooked onto the `admin_notices` action can render whatever HTML they’d like. In the block editor, notices are restricted to a more formal API.
## Notices in the Classic Editor
In the classic editor, here’s an example of the “Post draft updated” notice:

Producing an equivalent “Post draft updated” notice would require code like this:
```php
/**
* Hook into the 'admin_notices' action to render
* a generic HTML notice.
*/
function myguten_admin_notice() {
$screen = get_current_screen();
// Only render this notice in the post editor.
if ( ! $screen || 'post' !== $screen->base ) {
return;
}
// Render the notice's HTML.
// Each notice should be wrapped in a
';
};
add_action( 'admin_notices', 'myguten_admin_notice' );
```
Importantly, the `admin_notices` hook allows a developer to render whatever HTML they’d like. One advantage is that the developer has a great amount of flexibility. The key disadvantage is that arbitrary HTML makes future iterations on notices more difficult, if not possible, because the iterations need to accommodate for arbitrary HTML. This is why the block editor has a formal API.
## Notices in the Block Editor
In the block editor, here’s an example of the “Post published” notice:

Producing an equivalent “Post published” notice would require code like this:
```js
( function ( wp ) {
wp.data.dispatch( 'core/notices' ).createNotice(
'success', // Can be one of: success, info, warning, error.
'Post published.', // Text string to display.
{
isDismissible: true, // Whether the user can dismiss the notice.
// Any actions the user can perform.
actions: [
{
url: '#',
label: 'View post',
},
],
}
);
} )( window.wp );
```
You’ll want to use this *Notices Data API* when producing a notice from within the JavaScript application lifecycle.
To better understand the specific code example above:
- `wp` is WordPress global window variable.
- `wp.data` is an object provided by the block editor for accessing the block editor data store.
- `wp.data.dispatch('core/notices')` accesses functionality registered to the block editor data store by the Notices package.
- `createNotice()` is a function offered by the Notices package to register a new notice. The block editor reads from the notice data store in order to know which notices to display.
Check out the [*Enqueueing assets in the Editor*](https://developer.wordpress.org/block-editor/how-to-guides/enqueueing-assets-in-the-editor/) tutorial for a primer on how to load your custom JavaScript into the block editor.
## Learn more
The block editor offers a complete API for generating notices. The official documentation is a great place to review what’s possible.
For a full list of the available actions and selectors, refer to the [Notices Data Handbook](https://developer.wordpress.org/block-editor/reference-guides/data/data-core-notices/) page.
---
# Blocks
Source: https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/
The purpose of this tutorial is to step through the fundamentals of creating a new block type. Beginning with the simplest possible example, each new section will incrementally build upon the last to include more of the common functionality you could expect to need when implementing your own block types.
To follow along with this tutorial, you can download the [accompanying WordPress plugin](https://github.com/WordPress/block-development-examples) which includes all of the examples for you to try on your own site. At each step along the way, experiment by modifying the examples with your own ideas, and observe the effects they have on the block’s behavior.
> To find the latest version of the .zip file go to the repo’s [releases page](https://github.com/WordPress/block-development-examples/releases) and look in the latest release under ‘Assets’.
Code snippets are provided in two formats “JSX” and “Plain”. JSX refers to JavaScript code that uses JSX syntax which requires a build step. Plain refers to “classic” JavaScript that does not require building. You can change between them using tabs found above each code example. Using JSX, does require you to run [the JavaScript build step](https://developer.wordpress.org/block-editor/how-to-guides/javascript/js-build-setup/) to compile your code to a browser compatible format.
Note that it is not required to use JSX to create blocks or extend the editor, you can use classic JavaScript. However, once familiar with JSX and the build step, many developers tend to find it is easier to read and write, thus most code examples you’ll find use the JSX syntax.
---
# Use styles and stylesheets
Source: https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/applying-styles-with-stylesheets/
## Overview
A block typically inserts markup (HTML) into post content that you want to style in some way. This guide walks through a few different ways you can use CSS with the block editor and how to work with styles and stylesheets.
## Before you start
You will need a basic block and WordPress development environment to implement the examples shown in this guide. See the [Quick Start Guide](https://developer.wordpress.org/block-editor/getting-started/quick-start-guide/) or [block tutorial](https://developer.wordpress.org/block-editor/getting-started/tutorial/) to get set up.
## Methods to add style
The following are different methods you can use to add style to your block, either in the editor or when saved.
## Method 1: Inline style
The first method shows adding the style inline. This transforms the defined style into a property on the element inserted.
The `useBlockProps` React hook is used to set and apply properties on the block’s wrapper element. The following example shows how:
```jsx
import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-02-stylesheets', {
edit() {
const greenBackground = {
backgroundColor: '#090',
color: '#fff',
padding: '20px',
};
const blockProps = useBlockProps( { style: greenBackground } );
return (
);
},
} );
```
## Method 2: Block classname
The inline style works well for a small amount of CSS to apply. If you have much more than the above you will likely find that it is easier to manage with them in a separate stylesheet file.
The `useBlockProps` hooks includes the classname for the block automatically, it generates a name for each block using the block’s name prefixed with `wp-block-`, replacing the `/` namespace separator with a single `-`.
For example the block name: `gutenberg-examples/example-02-stylesheets` would get the classname: `wp-block-gutenberg-examples-example-02-stylesheets`. It might be a bit long but best to avoid conflicts with other blocks.
```jsx
import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-02-stylesheets', {
edit() {
const blockProps = useBlockProps();
return (
);
},
} );
```
### Build or add dependency
In order to include the blockEditor as a dependency, make sure to run the build step, or update the asset php file.
Build the scripts and update the asset file which is used to keep track of dependencies and the build version.
```bash
npm run build
```
### Enqueue stylesheets
Like scripts, you can enqueue your block’s styles using the `block.json` file.
Use the `editorStyle` property to a CSS file you want to load in the editor view only, use the `style` property for a CSS file you want to load both in the editor view and on the frontend when the block is used, and use the `viewStyle` property for a CSS file you want to load only on the frontend when the block is used.
It is worth noting that, if the editor content is iframed, both the `style` and `editorStyle` will load in the iframe. `editorStyle` will also load outside the iframe, so it can be used for editor content as well as UI.
For example:
```json
{
"apiVersion": 3,
"name": "gutenberg-examples/example-02-stylesheets",
"title": "Example: Stylesheets",
"icon": "universal-access-alt",
"category": "layout",
"editorScript": "file:./block.js",
"editorStyle": "file:./editor.css",
"style": "file:./style.css"
}
```
So in your plugin directory, create an `editor.css` file to load in editor view:
```css
/* green background */
.wp-block-gutenberg-examples-example-02-stylesheets {
background: #090;
color: white;
padding: 20px;
}
```
And a `style.css` file to load on the frontend:
```css
/* red background */
.wp-block-gutenberg-examples-example-02-stylesheets {
background: #900;
color: white;
padding: 20px;
}
```
The files will automatically be enqueued when specified in the block.json.
If you are using `@wordpress/scripts` you will need to import your stylesheet within your corresponding JavaScript file in order for `@wordpress/scripts` to process the stylesheet.
Example:
– In `edit.js` you would place `import ‘./editor.scss’;`
– In `index.js` you would place `import ‘./style.scss’;`
– In `view.js` you would place `import ‘./view.scss’;` (interactive block template)
**Note:** If you have multiple files to include, you can use standard `wp_enqueue_style` functions like any other plugin or theme. You will want to use the following hooks for the block editor:
- `enqueue_block_editor_assets` – to load only in editor view
- `enqueue_block_assets` – loads both on frontend and editor view
## Conclusion
This guide showed a couple of different ways to apply styles to your block, by either inline or in its own style sheet. Both of these methods use the `useBlockProps` hook, see the [block wrapper reference documentation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#block-wrapper-props) for additional details.
See the complete [stylesheets-79a4c3](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/stylesheets-79a4c3) code in the [block-development-examples repository](https://github.com/WordPress/block-development-examples).
---
# Creating dynamic blocks
Source: https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/creating-dynamic-blocks/
Dynamic blocks are blocks that build their structure and content on the fly when the block is rendered on the front end.
There are two primary uses for dynamic blocks:
1. Blocks where content should change even if a post has not been updated. One example from WordPress itself is the Latest Posts block. This block will update everywhere it is used when a new post is published.
2. Blocks where updates to the code (HTML, CSS, JS) should be immediately shown on the front end of the website. For example, if you update the structure of a block by adding a new class, adding an HTML element, or changing the layout in any other way, using a dynamic block ensures those changes are applied immediately on all occurrences of that block across the site. (If a dynamic block is not used then when block code is updated Gutenberg’s [validation process](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#validation) generally applies, causing users to see the validation message, “This block appears to have been modified externally”).
For many dynamic blocks, the `save` callback function should be returned as `null`, which tells the editor to save only the [block attributes](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/) to the database. These attributes are then passed into the server-side rendering callback, so you can decide how to display the block on the front end of your site. When you return `null`, the editor will skip the block markup validation process, avoiding issues with frequently-changing markup.
If you are using [InnerBlocks](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/nested-blocks-inner-blocks/) in a dynamic block you will need to save the `InnerBlocks` in the `save` callback function using ``
You can also save an HTML representation of the block. If you provide a server-side rendering callback, this HTML will be replaced with the output of your callback, but will be rendered if your block is deactivated or your render callback is removed.
Block attributes can be used for any content or setting you want to save for that block. In the first example above, with the latest posts block, the number of latest posts you want to show could be saved as an attribute. Or in the second example, attributes can be used for each piece of content you want to show in the front end – such as heading text, paragraph text, an image, a URL, etc.
The following code example shows how to create a dynamic block that shows only the last post as a link.
```jsx
import { registerBlockType } from '@wordpress/blocks';
import { useSelect } from '@wordpress/data';
import { useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-dynamic', {
apiVersion: 3,
title: 'Example: last post',
icon: 'megaphone',
category: 'widgets',
edit: () => {
const blockProps = useBlockProps();
const posts = useSelect( ( select ) => {
return select( 'core' ).getEntityRecords( 'postType', 'post' );
}, [] );
return (
);
},
} );
```
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',
) );
if ( count( $recent_posts ) === 0 ) {
return 'No posts';
}
$post = $recent_posts[ 0 ];
$post_id = $post['ID'];
return sprintf(
'%2$s',
esc_url( get_permalink( $post_id ) ),
esc_html( get_the_title( $post_id ) )
);
}
function gutenberg_examples_dynamic() {
// automatically load dependencies and version
$asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');
wp_register_script(
'gutenberg-examples-dynamic',
plugins_url( 'build/block.js', __FILE__ ),
$asset_file['dependencies'],
$asset_file['version']
);
register_block_type( 'gutenberg-examples/example-dynamic', array(
'api_version' => 3,
'editor_script' => 'gutenberg-examples-dynamic',
'render_callback' => 'gutenberg_examples_dynamic_render_callback'
) );
}
add_action( 'init', 'gutenberg_examples_dynamic' );
```
There are a few things to notice:
- The `edit` function still shows a representation of the block in the editor’s context (this could be very different from the rendered version, it’s up to the block’s author)
- The built-in `save` function just returns `null` because the rendering is performed server-side.
- The server-side rendering is a function taking the block and the block inner content as arguments, and returning the markup (quite similar to shortcodes)
**Note :** For common customization settings including color, border, spacing customization and more, we will see on the [next chapter](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks/) how you can rely on block supports to provide such functionality in an efficient way.
## Live rendering in the block editor
Gutenberg 2.8 added the [``](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-server-side-render/) block which enables rendering to take place on the server using PHP rather than in JavaScript.
*Server-side render is meant as a fallback; client-side rendering in JavaScript is always preferred (client rendering is faster and allows better editor manipulation).*
```jsx
import { registerBlockType } from '@wordpress/blocks';
import ServerSideRender from '@wordpress/server-side-render';
import { useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-dynamic', {
apiVersion: 3,
title: 'Example: last post',
icon: 'megaphone',
category: 'widgets',
edit: function ( props ) {
const blockProps = useBlockProps();
return (
);
},
} );
```
Note that this code uses the `wp-server-side-render` package but not `wp-data`. Make sure to update the dependencies in the PHP code. You can use wp-scripts to automatically build dependencies (see the [block-development-examples repo](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/basic-esnext-a2ab62) for PHP code setup).
---
# Nested Blocks: Using InnerBlocks
Source: https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/nested-blocks-inner-blocks/
You can create a single block that nests other blocks using the [InnerBlocks](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-editor/src/components/inner-blocks/README.md) component. This is used in the Columns block, Social Links block, or any block you want to contain other blocks.
Note: A single block can only contain one `InnerBlocks` component.
Here is the basic InnerBlocks usage.
```js
import { registerBlockType } from '@wordpress/blocks';
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-06', {
// ...
edit: () => {
const blockProps = useBlockProps();
return (
);
},
} );
```
## Allowed blocks
Using the `allowedBlocks` prop, you can further limit, in addition to the `allowedBlocks` field in `block.json`, which blocks can be inserted as direct descendants of this block. It is useful to determine the list of allowed blocks dynamically, individually for each block. For example, determined by a block attribute:
```js
const { allowedBlocks } = attributes;
//...
;
```
If the list of allowed blocks is always the same, prefer the [`allowedBlocks` block setting](#defining-a-children-block-relationship) instead.
## Orientation
By default, `InnerBlocks` expects its blocks to be shown in a vertical list. A valid use-case is to style inner blocks to appear horizontally, for instance by adding CSS flex or grid properties to the inner blocks wrapper. When blocks are styled in such a way, the `orientation` prop can be set to indicate that a horizontal layout is being used:
```js
```
Specifying this prop does not affect the layout of the inner blocks, but results in the block mover icons in the child blocks being displayed horizontally, and also ensures that drag and drop works correctly.
## Default block
By default `InnerBlocks` opens a list of permitted blocks via `allowedBlocks` when the block appender is clicked. You can modify the default block and its attributes that are inserted when the initial block appender is clicked by using the `defaultBlock` property. For example:
```js
```
By default this behavior is disabled until the `directInsert` prop is set to `true`. This allows you to specify conditions for when the default block should or should not be inserted.
## Template
Use the template property to define a set of blocks that prefill the InnerBlocks component when it has no existing content.. You can set attributes on the blocks to define their use. The example below shows a book review template using InnerBlocks component and setting placeholders values to show the block usage.
```js
const MY_TEMPLATE = [
[ 'core/image', {} ],
[ 'core/heading', { placeholder: 'Book Title' } ],
[ 'core/paragraph', { placeholder: 'Summary' } ],
];
//...
edit: () => {
return (
);
},
```
Use the `templateLock` property to lock down the template. Using `all` locks the template completely so no changes can be made. Using `insert` prevents additional blocks from being inserted, but existing blocks can be reordered. See [templateLock documentation](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-editor/src/components/inner-blocks/README.md#templatelock) for additional information.
### Post template
Unrelated to `InnerBlocks` but worth mentioning here, you can create a [post template](https://developer.wordpress.org/block-editor/developers/block-api/block-templates/) by post type, that preloads the block editor with a set of blocks.
The `InnerBlocks` template is for the component in the single block that you created, the rest of the post can include any blocks the user likes. Using a post template, can lock the entire post to just the template you define.
```php
add_action( 'init', function() {
$post_type_object = get_post_type_object( 'post' );
$post_type_object->template = array(
array( 'core/image' ),
array( 'core/heading' )
);
} );
```
## Using parent, ancestor and children relationships in blocks
A common pattern for using InnerBlocks is to create a custom block that will only be available if its parent block is inserted. This allows builders to establish a relationship between blocks, while limiting a nested block’s discoverability. There are three relationships that builders can use: `parent`, `ancestor` and `allowedBlocks`. The differences are:
- If you assign a `parent` then you’re stating that the nested block can only be used and inserted as a **direct descendant of the parent**.
- If you assign an `ancestor` then you’re stating that the nested block can only be used and inserted as a **descendent of the parent**.
- If you assign the `allowedBlocks` then you’re stating a relationship in the opposite direction, i.e., which blocks can be used and inserted as **direct descendants of this block**.
The key difference between `parent` and `ancestor` is `parent` has finer specificity, while an `ancestor` has greater flexibility in its nested hierarchy.
### Defining parent block relationship
An example of this is the Column block, which is assigned the `parent` block setting. This allows the Column block to only be available as a nested direct descendant in its parent Columns block. Otherwise, the Column block will not be available as an option within the block inserter. See [Column code for reference](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-library/src/column).
When defining a direct descendent block, use the `parent` block setting to define which block is the parent. This prevents the nested block from showing in the inserter outside of the InnerBlock it is defined for.
```json
{
"title": "Column",
"name": "core/column",
"parent": [ "core/columns" ],
// ...
}
```
### Defining an ancestor block relationship
An example of this is the Comment Author Name block, which is assigned the `ancestor` block setting. This allows the Comment Author Name block to only be available as a nested descendant in its ancestral Comment Template block. Otherwise, the Comment Author Name block will not be available as an option within the block inserter. See [Comment Author Name code for reference](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-library/src/comment-author-name).
The `ancestor` relationship allows the Comment Author Name block to be anywhere in the hierarchical tree, and not *just* a direct child of the parent Comment Template block, while still limiting its availability within the block inserter to only be visible an an option to insert if the Comment Template block is available.
When defining a descendent block, use the `ancestor` block setting. This prevents the nested block from showing in the inserter outside of the InnerBlock it is defined for.
```json
{
"title": "Comment Author Name",
"name": "core/comment-author-name",
"ancestor": [ "core/comment-template" ],
// ...
}
```
### Defining a children block relationship
An example of this is the Navigation block, which is assigned the `allowedBlocks` block setting. This makes only a certain subset of block types to be available as direct descendants of the Navigation block. See [Navigation code for reference](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-library/src/navigation).
The `allowedBlocks` setting can be extended by builders of custom blocks. The custom block can hook into the `blocks.registerBlockType` filter and add itself to the available children of the Navigation.
When defining a set of possible descendant blocks, use the `allowedBlocks` block setting. This limits what blocks are showing in the inserter when inserting a new child block.
```json
{
"title": "Navigation",
"name": "core/navigation",
"allowedBlocks": [ "core/navigation-link", "core/search", "core/social-links", "core/page-list", "core/spacer" ],
// ...
}
```
## Using a React hook
You can use a react hook called `useInnerBlocksProps` instead of the `InnerBlocks` component. This hook allows you to take more control over the markup of inner blocks areas.
The `useInnerBlocksProps` is exported from the `@wordpress/block-editor` package same as the `InnerBlocks` component itself and supports everything the component does. It also works like the `useBlockProps` hook.
Here is the basic `useInnerBlocksProps` hook usage.
```js
import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-06', {
// ...
edit: () => {
const blockProps = useBlockProps();
const innerBlocksProps = useInnerBlocksProps();
return (
);
},
} );
```
This hook can also pass objects returned from the `useBlockProps` hook to the `useInnerBlocksProps` hook. This reduces the number of elements we need to create.
```js
import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-06', {
// ...
edit: () => {
const blockProps = useBlockProps();
const innerBlocksProps = useInnerBlocksProps( blockProps );
return (
);
},
save: () => {
const blockProps = useBlockProps.save();
const innerBlocksProps = useInnerBlocksProps.save( blockProps );
return (
);
},
} );
```
The above code will render to the following markup in the editor:
```html
```
Another benefit to using the hook approach is using the returned value, which is just an object, and deconstruct to get the react children from the object. This property contains the actual child inner blocks thus we can place elements on the same level as our inner blocks.
```js
import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
registerBlockType( 'gutenberg-examples/example-06', {
// ...
edit: () => {
const blockProps = useBlockProps();
const { children, ...innerBlocksProps } = useInnerBlocksProps( blockProps );
return (
{ children }
);
},
// ...
} );
```
```html
```
---
# Feature Flags
Source: https://developer.wordpress.org/block-editor/how-to-guides/feature-flags/
‘Feature flags’ are variables that allow you to prevent specific code in the Gutenberg project from being shipped to WordPress core, and to run certain experimental features only in the plugin.
## Introducing `globalThis.IS_GUTENBERG_PLUGIN`
The `globalThis.IS_GUTENBERG_PLUGIN` is an environment variable whose value ‘flags’ whether code is running within the Gutenberg plugin.
When the codebase is built for the plugin, this variable will be set to `true`. When building for WordPress core, it will be set to `false` or `undefined`.
## Basic usage
### Exporting features
A plugin-only function or constant should be exported using the following ternary syntax:
```js
function myPluginOnlyFeature() {
// implementation
}
export const pluginOnlyFeature = globalThis.IS_GUTENBERG_PLUGIN
? myPluginOnlyFeature
: undefined;
```
In the above example, the `pluginOnlyFeature` export will be `undefined` in non-plugin environments such as WordPress core.
### Importing features
If you’re attempting to import and call a plugin-only feature, be sure to wrap the function call in an `if` statement to avoid an error:
```js
import { pluginOnlyFeature } from '@wordpress/foo';
if ( globalThis.IS_GUTENBERG_PLUGIN ) {
pluginOnlyFeature();
}
```
## How it works
During the webpack build, instances of `globalThis.IS_GUTENBERG_PLUGIN` will be replaced using webpack’s [define plugin](https://webpack.js.org/plugins/define-plugin/).
For example, in the following code –
```js
if ( globalThis.IS_GUTENBERG_PLUGIN ) {
pluginOnlyFeature();
}
```
– the variable `globalThis.IS_GUTENBERG_PLUGIN` will be replaced with the boolean `true` during the plugin-only build:
```js
if ( true ) {
// Webpack has replaced `globalThis.IS_GUTENBERG_PLUGIN` with `true`
pluginOnlyFeature();
}
```
This ensures that code within the body of the `if` statement will always be executed.
In WordPress core, the `globalThis.IS_GUTENBERG_PLUGIN` variable is replaced with `undefined`. The built code looks like this:
```js
if ( undefined ) {
// Webpack has replaced `globalThis.IS_GUTENBERG_PLUGIN` with `undefined`
pluginOnlyFeature();
}
```
`undefined` evaluates to `false` so the plugin-only feature will not be executed.
### Dead code elimination
For production builds, webpack [‘minifies’](https://en.wikipedia.org/wiki/Minification_(programming)) the code, removing as much unnecessary JavaScript as it can.
One of the steps involves something known as ‘dead code elimination’. For example, when the following code is encountered, webpack determines that the surrounding `if` statement is unnecessary:
```js
if ( true ) {
pluginOnlyFeature();
}
```
The condition will always evaluate to `true`, so webpack removes it, leaving behind the code that was in the body:
```js
pluginOnlyFeature(); // The `if` condition block has been removed. Only the body remains.
```
Similarly, when building for WordPress core, the condition in the following `if` statement always resolves to false:
```js
if ( undefined ) {
pluginOnlyFeature();
}
```
In this case, the minification process will remove the entire `if` statement including the body, ensuring plugin-only code is not included in WordPress core build.
## Frequently asked questions
### Why shouldn’t I assign the result of an expression involving `IS_GUTENBERG_PLUGIN` to a variable, e.g. `const isMyFeatureActive = ! Object.is( undefined, globalThis.IS_GUTENBERG_PLUGIN )`?
Introducing complexity may prevent webpack’s minifier from identifying and therefore eliminating dead code. Therefore it is recommended to use the examples in this document to ensure your feature flag functions as intended. For further details, see the [Dead Code Elimination](#dead-code-elimination) section.
---
# Development Platform
Source: https://developer.wordpress.org/block-editor/how-to-guides/platform/
The Gutenberg Project is not only building a better editor for WordPress, but also creating a platform to build upon. This platform consists of a set of JavaScript packages and tools that you can use in your web application. [View the list of packages available on npm](https://www.npmjs.com/org/wordpress).
## UI components
The [WordPress Components package](https://developer.wordpress.org/block-editor/reference-guide/components/) contains a set of UI components you can use in your project. See the [WordPress Storybook site](https://wordpress.github.io/gutenberg/) for an interactive guide to the available components and settings.
Here is a quick example, how to use components in your project.
Install the dependency:
```bash
npm install --save @wordpress/components
```
Usage in React:
```jsx
import { Button } from '@wordpress/components';
function MyApp() {
return ;
}
```
Many components include CSS to add style, you will need to include for the components to appear correctly. The component stylesheet can be found in `node_modules/@wordpress/components/build-style/style.css`, you can link directly or copy and include it in your project.
## Development scripts
The [`@wordpress/scripts` package](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-scripts/) is a collection of reusable scripts for JavaScript development — includes scripts for building, linting, and testing — all with no additional configuration files.
Here is a quick example, on how to use `wp-scripts` tool in your project.
Install the dependency:
```bash
npm install --save-dev @wordpress/scripts
```
You can then add a scripts section to your package.json file, for example:
```json
"scripts": {
"build": "wp-scripts build",
"format": "wp-scripts format",
"lint:js": "wp-scripts lint-js",
"start": "wp-scripts start"
}
```
You can then use `npm run build` to build your project with all the default webpack settings already configured, likewise for formatting and linting. The `start` command is used for development mode. See the [`@wordpress/scripts` package](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-scripts/) for full documentation.
For more info, see the [Getting Started with JavaScript tutorial](https://developer.wordpress.org/block-editor/how-to-guides/javascript/js-build-setup/) in the Block Editor Handbook.
## Block Editor
The [`@wordpress/block-editor` package](https://developer.wordpress.org/block-editor/packages/packages-block-editor/) allows you to create and use standalone block editors.
You can learn more by reading the [tutorial “Building a custom block editor”](https://developer.wordpress.org/block-editor/how-to-guides/platform/custom-block-editor/).
---
# Building a custom block editor
Source: https://developer.wordpress.org/block-editor/how-to-guides/platform/custom-block-editor/
The WordPress block editor is a powerful tool that allows you to create and format content in various ways. It is powered, in part, by the [`@wordpress/block-editor`](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-block-editor/) package, which is a JavaScript library that provides the core functionality of the editor.
This package can also be used to create custom block editors for virtually any other web application. This means that you can use the same blocks and block editing experience outside of WordPress.

This flexibility and interoperability makes blocks a powerful tool for building and managing content across multiple applications. It also makes it simpler for developers to create content editors that work best for their users.
This guide covers the basics of creating your first custom block editor.
## Introduction
With its many packages and components, the Gutenberg codebase can be daunting at first. But at its core, it’s all about managing and editing blocks. So if you want to work on the editor, it’s essential to understand how block editing works at a fundamental level.
This guide will walk you through building a fully functioning, custom block editor “instance” within WordPress. Along the way, we’ll introduce you to the key packages and components, so you can see how the block editor works under the hood.
By the end of this article, you will have a solid understanding of the block editor’s inner workings and be well on your way to creating your own block editor instances.
The code used throughout this guide is available for download in the [accompanying WordPress plugin](https://github.com/getdave/standalone-block-editor). The demo code in this plugin as an essential resource.
## Code syntax
The code snippets in this guide use JSX syntax. However, you could use plain JavaScript if you prefer. However, once familiar with JSX, many developers find it easier to read and write, so all code examples in the Block Editor Handbook use this syntax.
## What you’re going to be building
Throughout this guide, you will create an (almost) fully functioning block editor instance. The result will look something like this:

While it looks similar, this editor will not be the same *Block Editor* you are familiar with when creating posts and pages in WordPress. Instead, it will be an entirely custom instance that will live within a custom WordPress admin page called “Block Editor.”
The editor will have the following features:
- Ability to add and edit all Core blocks.
- Familiar visual styles and main/sidebar layout.
- *Basic* block persistence between page reloads.
## Plugin setup and organization
The custom editor is going to be built as a WordPress plugin. To keep things simple, the plugin will be named `Standalone Block Editor Demo` because that is what it does.
The plugin file structure will look like this:

Here is a brief summary of what’s going on:
- `plugin.php` – Standard plugin “entry” file with comment meta data, which requires `init.php`.
- `init.php` – Handles the initialization of the main plugin logic.
- `src/` (directory) – This is where the JavaScript and CSS source files will live. These files are *not* directly enqueued by the plugin.
- `webpack.config.js` – A custom Webpack config extending the defaults provided by the [`@wordpress/scripts`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/) npm package to allow for custom CSS styles (via Sass).
The only item not shown above is the `build/` directory, which is where the *compiled* JS and CSS files are outputted by `@wordpress/scripts`. These files are enqueued by the plugin separately.
Throughout this guide, filename references will be placed in a comment at the top of each code snippet so you can follow along.
With the basic file structure in place, let’s look at what packages will be needed.
## The “Core” of the editor
While the WordPress Editor is comprised of many moving parts, at its core is the [`@wordpress/block-editor`](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-block-editor/) package, which is best summarized by its own `README` file:
> This module allows you to create and use standalone block editors.
Perfect, this is the main package you will use to create the custom block editor instance. But first, you need to create a home for the editor.
## Creating the custom “Block Editor” page
Let’s begin by creating a custom page within WordPress admin that will house the custom block editor instance.
If you’re already comfortable with the process of creating custom admin pages in WordPress, you might want to [skip ahead](#registering-and-rendering-our-custom-block-editor).
### Registering the page
To do this, you need to [register a custom admin page](https://developer.wordpress.org/reference/functions/add_menu_page/) using the standard WordPress [`add_menu_page()`](https://developer.wordpress.org/reference/functions/add_menu_page/) helper:
```php
// File: init.php
add_menu_page(
'Standalone Block Editor', // Visible page name
'Block Editor', // Menu label
'edit_posts', // Required capability
'getdavesbe', // Hook/slug of page
'getdave_sbe_render_block_editor', // Function to render the page
'dashicons-welcome-widgets-menus' // Custom icon
);
```
The `getdave_sbe_render_block_editor` function will be used to render the contents of the admin page. As a reminder, the source code for each step is available in the [accompanying plugin](https://github.com/getdave/standalone-block-editor).
### Adding the target HTML
Since the block editor is a React-powered application, you need to output some HTML into the custom page where JavaScript can render the block editor.
Let’s use the `getdave_sbe_render_block_editor` function referenced in the step above.
```php
// File: init.php
function getdave_sbe_render_block_editor() {
?>
Loading Editor...
` component into the waiting `
` on the custom admin page.
```jsx
domReady( function () {
const root = createRoot( document.getElementById( 'getdave-sbe-block-editor' ) );
const settings = window.getdaveSbeSettings || {};
registerCoreBlocks();
root.render(
);
} );
```
It is possible to render the editor from PHP without creating an unnecessary JS global. Check out the [Edit Site](https://href.li/?https://github.com/WordPress/gutenberg/blob/c6821d7e64a54eb322583a35daedc6c192ece850/lib/edit-site-page.php#L135) package in the Gutenberg plugin for an example of this.
## Reviewing the `` component
Let’s take a closer look at the `` component that was used in the code above and lives in `src/editor.js` of the [companion plugin](https://github.com/getdave/standalone-block-editor).
Despite its name, this is not the actual core of the block editor. Rather, it is a *wrapper* component that will contain the components that form the custom editor’s main body.
### Dependencies
The first thing to do inside `` is to pull in some dependencies.
```jsx
// File: src/editor.js
import Notices from 'components/notices';
import Header from 'components/header';
import Sidebar from 'components/sidebar';
import BlockEditor from 'components/block-editor';
```
The most important of these are the internal components `BlockEditor` and `Sidebar`, which will be covered shortly.
The remaining components consist mostly of static elements that form the editor’s layout and surrounding user interface (UI). These elements include the header and notice areas, among others.
### Editor render
With these components available, you can define the `` component.
```jsx
// File: src/editor.js
function Editor( { settings } ) {
return (
);
}
```
In this process, the core of the editor’s layout is being scaffolded, along with a few specialized [context providers](https://react.dev/reference/react/createContext#provider) that make specific functionality available throughout the component hierarchy.
Let’s examine these in more detail:
- `` – Enables the use of [dropzones for drag and drop functionality](https://github.com/WordPress/gutenberg/tree/e38dbe958c04d8089695eb686d4f5caff2707505/packages/components/src/drop-zone)
- `` – Provides a “snack bar” Notice that will be rendered if any messages are dispatched to the `core/notices` store
- `` – Renders the static title “Standalone Block Editor” at the top of the editor UI
- `` – The custom block editor component
### Keyboard navigation
With this basic component structure in place, the only remaining thing left to do
is wrap everything in the [`navigateRegions` HOC](https://github.com/WordPress/gutenberg/tree/e38dbe958c04d8089695eb686d4f5caff2707505/packages/components/src/higher-order/navigate-regions) to provide keyboard navigation between the different “regions” in the layout.
```jsx
// File: src/editor.js
export default navigateRegions( Editor );
```
## The custom ``
Now the core layouts and components are in place. It’s time to explore the custom implementation of the block editor itself.
The component for this is called ``, and this is where the magic happens.
Opening `src/components/block-editor/index.js` reveals that it’s the most complex component encountered thus far. A lot going on, so start by focusing on what is being rendered by the `` component:
```js
// File: src/components/block-editor/index.js
return (
);
```
The key components are `` and ``. Let’s examine these.
### Understanding the `` component
[``](https://github.com/WordPress/gutenberg/tree/e38dbe958c04d8089695eb686d4f5caff2707505/packages/block-editor/src/components/provider) is one of the most important components in the hierarchy. It establishes a new block editing context for a new block editor.
As a result, it is *fundamental* to the entire goal of this project.
The children of `` comprise the UI for the block editor. These components then have access to data (via `Context`), enabling them to *render* and *manage* the blocks and their behaviors within the editor.
```jsx
// File: src/components/block-editor/index.js
```
#### `BlockEditor` props
You can see that `` accepts an array of (parsed) block objects as its `value` prop and, when there’s a change detected within the editor, calls the `onChange` and/or `onInput` handler prop (passing the new Blocks as an argument).
Internally it does this by subscribing to the provided `registry` (via the [`withRegistryProvider` HOC](https://github.com/WordPress/gutenberg/blob/e38dbe958c04d8089695eb686d4f5caff2707505/packages/block-editor/src/components/provider/index.js#L158)), listening to block change events, determining whether the block changing was persistent, and then calling the appropriate `onChange|Input` handler accordingly.
For the purposes of this simple project, these features allow you to:
- Store the array of current blocks in state as `blocks`.
- Update the `blocks` state in memory on `onInput` by calling the hook setter
`updateBlocks(blocks)`.
- Handle basic persistence of blocks into `localStorage` using `onChange`. This is [fired when block updates are considered “committed”](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-editor/src/components/provider#onchange).
It’s also worth recalling that the component accepts a `settings` property. This is where you will add the editor settings inlined earlier as JSON within `init.php`. You can use these settings to configure features such as custom colors, available image sizes, and [much more](https://github.com/WordPress/gutenberg/tree/4c472c3443513d070a50ba1e96f3a476861447b3/packages/block-editor#SETTINGS_DEFAULTS).
### Understanding the `` component
Alongside `` the next most interesting component is [``](https://github.com/WordPress/gutenberg/blob/e38dbe958c04d8089695eb686d4f5caff2707505/packages/block-editor/src/components/block-list/index.js).
This is one of the most important components as it’s role is to **render a list of blocks into the editor**.
It does this in part thanks to being placed as a child of ``, which affords it full access to all information about the state of the current blocks in the editor.
#### How does `BlockList` work?
Under the hood, `` relies on several other lower-level components in order to render the list of blocks.
The hierarchy of these components can be *approximated* as follows:
```jsx
// Pseudo code for example purposes only.
/* renders a list of blocks from the rootClientId. */
/* renders a single block from the BlockList. */
/* renders the standard editable area of a block. */
/* renders the block UI as defined by its `edit()` implementation.
*/
```
Here is roughly how this works together to render the list of blocks:
- `` loops over all the block `clientIds` and
renders each via [``](https://github.com/WordPress/gutenberg/blob/e38dbe958c04d8089695eb686d4f5caff2707505/packages/block-editor/src/components/block-list/block.js).
- ``, in turn, renders the individual block
using its own subcomponent [``](https://github.com/WordPress/gutenberg/blob/def076809d25e2ad680beda8b9205ab9dea45a0f/packages/block-editor/src/components/block-edit/index.js).
- Finally, the [block itself](https://github.com/WordPress/gutenberg/blob/def076809d25e2ad680beda8b9205ab9dea45a0f/packages/block-editor/src/components/block-edit/edit.js) is rendered using the `Component` placeholder component.
The `@wordpress/block-editor` package components are among the most complex and involved. Understanding them is crucial if you want to grasp how the editor functions at a fundamental level. Studying these components is strongly advised.
## Reviewing the sidebar
Also within the render of the ``, is the `` component.
```jsx
// File: src/components/block-editor/index.js
return (
/* <-- SIDEBAR */
);
```
This is used, in part, to display advanced block settings via the `` component.
```jsx
```
However, the keen-eyed readers amongst you will have already noted the presence of a `` component within the `` (`src/editor.js`) component’s
layout:
```jsx
// File: src/editor.js
// <-- What's this?
```
Opening the `src/components/sidebar/index.js` file, you can see that this is, in fact, the component rendered within `` above. However, the implementation utilises
Slot/Fill to expose a `Fill` (``), which is subsequently imported and rendered inside of the `` component (see above).
With this in place, you then can render `` as a child of the `Sidebar.InspectorFill`. This has the result of allowing you to keep `` within the React context of `` whilst allowing it to be rendered into the DOM in a separate location (i.e. in the ``).
This might seem overly complex, but it is required in order for `` to have access to information about the current block. Without Slot/Fill, this setup would be extremely difficult to achieve.
And with that you have covered the render of you custom ``.
[``](https://github.com/WordPress/gutenberg/blob/def076809d25e2ad680beda8b9205ab9dea45a0f/packages/block-editor/src/components/block-inspector/index.js)
itself actually renders a `Slot` for [``](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-editor/src/components/inspector-controls). This is what allows you [render](https://github.com/WordPress/gutenberg/blob/def076809d25e2ad680beda8b9205ab9dea45a0f/packages/block-library/src/paragraph/edit.js#L127) a `>` component inside
the `edit()` definition for your block and have
it display within the editor’s sidebar. Exploring this component in more detail is recommended.
## Block Persistence
You have come a long way on your journey to create a custom block editor. But there is one major area left to touch upon – block persistence. In other words, having your
blocks saved and available *between* page refreshes.

As this is only an *experiment*, this guide has opted to utilize the browser’s `localStorage` API to handle saving block data. In a real-world scenario, you would likely choose a more reliable and robust system (e.g. a database).
That said, let’s take a closer look at how to handle save blocks.
### Storing blocks in state
Looking at the `src/components/block-editor/index.js` file, you will notice that some state has been created to store the blocks as an array:
```jsx
// File: src/components/block-editor/index.js
const [ blocks, updateBlocks ] = useState( [] );
```
As mentioned earlier, `blocks` is passed to the “controlled” component `` as its `value` prop. This “hydrates” it with an initial set of blocks. Similarly, the `updateBlocks` setter is hooked up to the `onInput` callback on ``, which ensures that the block state is kept in sync with changes made to blocks within the editor.
### Saving block data
If you now turn your attention to the `onChange` handler, you will notice it is hooked up to a function `persistBlocks()` which is defined as follows:
```js
// File: src/components/block-editor/index.js
function persistBlocks( newBlocks ) {
updateBlocks( newBlocks );
window.localStorage.setItem( 'getdavesbeBlocks', serialize( newBlocks ) );
}
```
This function accepts an array of “committed” block changes and calls the state setter `updateBlocks`. It also stores the blocks within LocalStorage under the key `getdavesbeBlocks`. In order to achieve this, the block data is serialized into [Gutenberg “Block Grammar”](https://developer.wordpress.org/block-editor/principles/key-concepts/#blocks) format, meaning it can be safely stored as a string.
If you open DeveloperTools and inspect the LocalStorage you will see serialized block data stored and updated as changes occur within the editor. Below is an example of the format:
```
An experiment with a standalone Block Editor in the WordPress admin
This is an experiment to discover how easy (or otherwise) it is to create a standalone instance of the Block Editor in the WordPress admin.
```
### Retrieving previous block data
Having persistence in place is all well and good, but it’s only useful if that data is retrieved and *restored* within the editor upon each full page reload.
Accessing data is a side effect, so you must use the `useEffect` hook to handle this.
```jsx
// File: src/components/block-editor/index.js
useEffect( () => {
const storedBlocks = window.localStorage.getItem( 'getdavesbeBlocks' );
if ( storedBlocks && storedBlocks.length ) {
updateBlocks( () => parse( storedBlocks ) );
createInfoNotice( 'Blocks loaded', {
type: 'snackbar',
isDismissible: true,
} );
}
}, [] );
```
This handler:
- Grabs the serialized block data from local storage.
- Converts the serialized blocks back to JavaScript objects using the `parse()` utility.
- Calls the state setter `updateBlocks` causing the `blocks` value to be updated in state to reflect the blocks retrieved from LocalStorage.
As a result of these operations, the controlled `` component is updated with the blocks restored from LocalStorage, causing the editor to show these blocks.
Finally, you will want to generate a notice – which will display in the `` component as a “snackbar” notice – to indicate that the blocks have been restored.
## Wrapping up
Congratulations for completing this guide. You should now have a better understanding of how the block editor works under the hood.
The full code for the custom block editor you have just built is [available on GitHub](https://github.com/getdave/standalone-block-editor). Download and try it out for yourself. Experiment, then and take things even further.
---
# User Interface
Source: https://developer.wordpress.org/block-editor/explanations/user-interface/
## The Block Editor
The block editor’s general layout uses a bar at the top, with content below.

The **Toolbar** contains document-level actions: Editor/Select modes, save status, global actions for undo/redo/insert, the settings toggle, and publish options.
The **Content Area** contains the document itself.
The **Settings Sidebar** contains additional settings for the document (tags, categories, schedule etc.) and for blocks in the “Block” tab. A cog button in the toolbar hides the Settings Sidebar, allowing the user to enjoy a more immersive writing experience. On small screens, the sidebar is hidden by default.
## The Block
The block itself is the most basic unit of the editor. Generally speaking, everything is a block. Users build posts and pages using blocks, mimicking the vertical flow of the underlying HTML markup.
By surfacing each section of the document as a manipulatable block, we surface block-specific features contextually. This is inspired by desktop app conventions, and allows for a breadth of advanced features without weighing down the UI.
A selected block shows a number of contextual actions:

The block interface has basic actions. The block editor aims for good, common defaults, so users should be able to create a complete document without actually needing the advanced actions in the Settings Sidebar.
**The Block Toolbar** highlights commonly-used actions. The **Block Icon** lives in the block toolbar, and contains high-level controls for the selected block. It primarily allows users to transform a block into another type of compatible block. Some blocks also use the block icon for users to choose from a set of alternate block styles.
The **Block Formatting** options let users adjust block-level settings, and the **Inline Formatting** options allow adjustments to elements inside the block. When a block is long, the block toolbar pins itself to the top of the screen as the user scrolls down the page.
Blocks can be moved up and down via the **Block Mover** icons. Additional block actions are available via an ellipsis menu: deleting and duplicating blocks, as well as **advanced actions** like “Edit as HTML” and “Convert to Reusable Block.”
An unselected block does not show the block toolbar or any other contextual controls. In effect, an unselected block is a preview of the content itself:

Please note that selection and focus can be different. An image block can be selected while the focus is on the caption field.
## Settings Sidebar

The sidebar has two tabs, Document and Block:
- The **Document Tab** shows metadata and settings for the post or page being edited.
- The **Block Tab** shows metadata and settings for the currently selected block.
Each tab has sets of editable fields (**Sidebar Sections**) that users can toggle open or closed.
If a block requires advanced configuration, those settings should live in the Settings Sidebar. Don’t put anything in the sidebar block tab that is necessary for the basic operation of your block; your user might dismiss the sidebar for an immersive writing experience. Pick good defaults, and make important actions available in the block toolbar.
Actions that could go in the block tab of the sidebar could be:
- Drop cap, for text
- Number of columns for galleries
- Number of posts, or category, in the “Latest Posts” block
- Any configuration that you don’t need access to in order to perform basic tasks
## Block Library

The **Block Library** appears when someone inserts a block, whether via the toolbar, or contextually within the content area. Inside, blocks are organized into expandable sections. The block library’s search bar auto-filters the list of blocks as the user types. Users can choose a block by selecting the **Block Button** or the **Block Name**.
---
# Accessibility
Source: https://developer.wordpress.org/block-editor/how-to-guides/accessibility/
Accessibility documentation for developers working on the Gutenberg Project.
For more information on accessibility and WordPress see the [Make WordPress Accessibility Handbook](https://make.wordpress.org/accessibility/handbook/) and the [Accessibility Team section](https://make.wordpress.org/accessibility/).
## Landmark regions
It is a best practice to include ALL content on the page in landmarks, so that screen reader users who rely on them to navigate from section to section do not lose track of content.
For setting up navigation between different regions, see the [navigateRegions package](https://developer.wordpress.org/block-editor/reference-guide/components/higher-order/navigate-regions/) for additional documentation.
Read more regarding landmark design from W3C:
- [General Principles of Landmark Design](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/#x4-2-general-principles-of-landmark-design)
- [ARIA Landmarks Examples](https://www.w3.org/WAI/ARIA/apg/example-index/landmarks/)
- [HTML5 elements that by default define ARIA landmarks](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/#x4-1-html-sectioning-elements)
---
# Internationalization
Source: https://developer.wordpress.org/block-editor/how-to-guides/internationalization/
## What is internationalization?
Internationalization is the process to provide multiple language support to software, in this case WordPress. Internationalization is often abbreviated as **i18n**, where 18 stands for the number of letters between the first *i* and the last *n*.
Providing i18n support to your plugin and theme allows it to reach the largest possible audience, even without requiring you to provide the additional language translations. When you upload your software to WordPress.org, all JS and PHP files will automatically be parsed. Any detected translation strings are added to [translate.wordpress.org](https://translate.wordpress.org/) to allow the community to translate, ensuring WordPress plugins and themes are available in as many languages as possible.
For PHP, WordPress has a long established process, see [How to Internationalize Your Plugin](https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/). The release of WordPress 5.0 brings a similar process for translation to JavaScript code.
## How to use i18n in JavaScript
WordPress 5.0 introduced the wp-i18n JavaScript package that provides the functions needed to add translatable strings as you would in PHP.
First, add **wp-i18n** as a dependency when registering your script:
```php
3,
'editor_script' => 'myguten-script',
) );
}
add_action( 'init', 'myguten_block_init' );
```
In your code, you can include the i18n functions. The most common function is **\_\_** (a double underscore) which provides translation of a simple string. Here is a basic block example:
```js
import { __ } from '@wordpress/i18n';
import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'myguten/simple', {
apiVersion: 3,
title: __( 'Simple Block', 'myguten' ),
category: 'widgets',
edit: () => {
const blockProps = useBlockProps( { style: { color: 'red' } } );
return
;
},
} );
```
In the above example, the function will use the first argument for the string to be translated. The second argument is the text domain which must match the text domain slug specified by your plugin.
Common functions available, these mirror their PHP counterparts are:
- `__( 'Hello World', 'my-text-domain' )` – Translate a certain string.
- `_n( '%s Comment', '%s Comments', numberOfComments, 'my-text-domain' )` – Translate and retrieve the singular or plural form based on the supplied number.
- `_x( 'Default', 'block style', 'my-text-domain' )` – Translate a certain string with some additional context.
**Note:** Every string displayed to the user should be wrapped in an i18n function.
After all strings in your code is wrapped, the final step is to tell WordPress your JavaScript contains translations, using the [wp\_set\_script\_translations()](https://developer.wordpress.org/reference/functions/wp_set_script_translations/) function.
```php
\n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2019-03-08T11:26:56-08:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.1.0\n"
"X-Domain: myguten\n"
#. Plugin Name of the plugin
msgid "Scratch Plugin"
msgstr ""
#: block.js:6
msgid "Simple Block"
msgstr ""
#: block.js:13
#: block.js:21
msgid "Hello World"
msgstr ""
```
Here, `msgid` is the string to be translated, and `msgstr` is the actual translation. In the POT file, `msgstr` will always be empty.
This POT file can then be used as the template for new translations. You should **copy the file** using the language code you are going to translate, this example will use the Esperanto (eo) language:
```
cp myguten.pot myguten-eo.po
```
For this simple example, you can simply edit the `.po` file in your editor and add the translation to all the `msgstr` sets. For a larger, more complex set of translation, the [GlotPress](https://glotpress.blog/) and [Poedit](https://poedit.net/) tools exist to help.
You need also to add the `Language: eo` parameter. Here is full `myguten-eo.po` translated file
```
# Copyright (C) 2019
# This file is distributed under the same license as the Scratch Plugin plugin.
msgid ""
msgstr ""
"Project-Id-Version: Scratch Plugin\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/scratch\n"
"Last-Translator: Marcus Kazmierczak \n"
"Language-Team: Esperanto \n"
"Language: eo\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2019-02-18T07:20:46-08:00\n"
"PO-Revision-Date: 2019-02-18 08:16-0800\n"
"X-Generator: Poedit 2.2.1\n"
"X-Domain: myguten\n"
#. Plugin Name of the plugin
msgid "Scratch Plugin"
msgstr "Scratch kromprogrameto"
#: block.js:6
msgid "Simple Block"
msgstr "Simpla bloko"
#: block.js:13 block.js:21
msgid "Hello World"
msgstr "Saltuon mundo"
```
The last step to create the translation file is to convert the `myguten-eo.po` to the JSON format needed. For this, you can use WP-CLI’s [`wp i18n make-json` command](https://developer.wordpress.org/cli/commands/i18n/make-json/), which requires WP-CLI v2.2.0 and later.
```
wp i18n make-json myguten-eo.po --no-purge
```
This will generate the JSON file `myguten-eo-[md5].json` with the contents:
```json
{
"translation-revision-date": "2019-04-26T13:30:11-07:00",
"generator": "WP-CLI/2.2.0",
"source": "block.js",
"domain": "messages",
"locale_data": {
"messages": {
"": {
"domain": "messages",
"lang": "eo",
"plural-forms": "nplurals=2; plural=(n != 1);"
},
"Simple Block": [ "Simpla Bloko" ],
"Hello World": [ "Salunton mondo" ]
}
}
}
```
### Load the translation file
The final part is to tell WordPress where it can look to find the translation file. The `wp_set_script_translations` function accepts an optional third argument that is the path it will first check for translations. For example:
```php
{
const blockProps = useBlockProps();
return
Your block.
;
},
};
```
### Block wrapper props
The first thing to notice here is the use of the `useBlockProps` React hook on the block wrapper element. In the example above, the block wrapper renders a “div” in the editor, but in order for the Gutenberg editor to know how to manipulate the block, add any extra classNames that are needed for the block… the block wrapper element should apply props retrieved from the `useBlockProps` react hook call. The block wrapper element should be a native DOM element, like `
` and `
`, or a React component that forwards any additional props to native DOM elements. Using a `` or `` component, for instance, would be invalid.
If the element wrapper needs any extra custom HTML attributes, these need to be passed as an argument to the `useBlockProps` hook. For example to add a `my-random-classname` className to the wrapper, you can use the following code:
```jsx
import { useBlockProps } from '@wordpress/block-editor';
// ...
const blockSettings = {
apiVersion: 3,
// ...
edit: () => {
const blockProps = useBlockProps( {
className: 'my-random-classname',
} );
return
Your block.
;
},
};
```
### attributes
The `edit` function also receives a number of properties through an object argument. You can use these properties to adapt the behavior of your block.
The `attributes` property surfaces all the available attributes and their corresponding values, as described by the `attributes` property when the block type was registered. See [attributes documentation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/) for how to specify attribute sources.
In this case, assuming we had defined an attribute of `content` during block registration, we would receive and use that value in our edit function:
```js
edit: ( { attributes } ) => {
const blockProps = useBlockProps();
return
{ attributes.content }
;
};
```
The value of `attributes.content` will be displayed inside the `div` when inserting the block in the editor.
### isSelected
The isSelected property is a boolean that communicates whether the block is currently selected.
```jsx
edit: ( { attributes, isSelected } ) => {
const blockProps = useBlockProps();
return (
Your block.
{ isSelected && (
Shows only when the block is selected.
) }
);
};
```
### setAttributes
This function allows the block to update individual attributes based on user interactions.
```jsx
edit: ( { attributes, setAttributes, isSelected } ) => {
const blockProps = useBlockProps();
// Simplify access to attributes
const { content, mySetting } = attributes;
// Toggle a setting when the user clicks the button
const toggleSetting = () => setAttributes( { mySetting: ! mySetting } );
return (
{ content }
{ isSelected && (
) }
);
};
```
When using attributes that are objects or arrays it’s a good idea to copy or clone the attribute prior to updating it:
```js
// Good - a new array is created from the old list attribute and a new list item:
const { list } = attributes;
const addListItem = ( newListItem ) =>
setAttributes( { list: [ ...list, newListItem ] } );
// Bad - the list from the existing attribute is modified directly to add the new list item:
const { list } = attributes;
const addListItem = ( newListItem ) => {
list.push( newListItem );
setAttributes( { list } );
};
```
Why do this? In JavaScript, arrays and objects are passed by reference, so this practice ensures changes won’t affect other code that might hold references to the same data. Furthermore, the Gutenberg project follows the philosophy of the Redux library that [state should be immutable](https://redux.js.org/faq/immutable-data#what-are-the-benefits-of-immutability)—data should not be changed directly, but instead a new version of the data created containing the changes.
The `setAttribute` also supports an updater function as an argument. It must be a pure function, which takes current attributes as its only argument and returns updated attributes. This method is helpful when you want to update an value based on a previous state or when working with objects and arrays.
***Note:** Since WordPress 6.9.*
```js
// Toggle a setting when the user clicks the button.
const toggleSetting = () =>
setAttributes( ( currentAttr ) => ( {
mySetting: ! currentAttr.mySetting,
} ) );
// Add item to the list.
const addListItem = ( newListItem ) =>
setAttributes( ( currentAttr ) => ( {
list: [ ...currentAttr.list, newListItem ],
} ) );
```
## Save
The `save` function defines the way in which the different attributes should be combined into the final markup, which is then serialized into `post_content`.
```jsx
save: () => {
const blockProps = useBlockProps.save();
return
Your block.
;
};
```
For most blocks, the return value of `save` should be an [instance of WordPress Element](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-element/) representing how the block is to appear on the front of the site.
*Note:* While it is possible to return a string value from `save`, it *will be escaped*. If the string includes HTML markup, the markup will be shown on the front of the site verbatim, not as the equivalent HTML node content. If you must return raw HTML from `save`, use `wp.element.RawHTML`. As the name implies, this is prone to [cross-site scripting](https://en.wikipedia.org/wiki/Cross-site_scripting) and therefore is discouraged in favor of a WordPress Element hierarchy whenever possible.
*Note:* The save function should be a pure function that depends only on the attributes used to invoke it.
It can not have any side effect or retrieve information from another source, e.g. it is not possible to use the data module inside it `select( store ).selector( ... )`.
This is because if the external information changes, the block may be flagged as invalid when the post is later edited ([read more about Validation](#validation)).
If there is a need to have other information as part of the save, developers can consider one of these two alternatives:
- Use [dynamic blocks](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/creating-dynamic-blocks/) and dynamically retrieve the required information on the server.
- Store the external value as an attribute which is dynamically updated in the block’s `edit` function as changes occur.
For [dynamic blocks](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/creating-dynamic-blocks/), the return value of `save` could represent a cached copy of the block’s content to be shown only in case the plugin implementing the block is ever disabled.
If left unspecified, the default implementation will save no markup in post content for the dynamic block, instead deferring this to always be calculated when the block is shown on the front of the site.
### block wrapper props
Like the `edit` function, when rendering static blocks, it’s important to add the block props returned by `useBlockProps.save()` to the wrapper element of your block. This ensures that the block class name is rendered properly in addition to any HTML attribute injected by the block supports API.
### attributes
As with `edit`, the `save` function also receives an object argument including attributes which can be inserted into the markup.
```jsx
save: ( { attributes } ) => {
const blockProps = useBlockProps.save();
return
{ attributes.content }
;
};
```
When saving your block, you want to save the attributes in the same format specified by the attribute source definition. If no attribute source is specified, the attribute will be saved to the block’s comment delimiter. See the [Block Attributes documentation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/) for more details.
### innerBlocks
There is a second property in the props passed to the `save` function, `innerBlocks`. This property is typically used for internal operations, and there are very few scenarios where you would need to use it.
`innerBlocks`, when initialized, is an array containing object representations of nested blocks. In those rare cases where you might use this property,
it can help you adjust how a block is rendered. For example, you could render a block differently based on the number of nested blocks or if a specific block type is present..
```jsx
save: ( { attributes, innerBlocks } ) => {
const { className, ...rest } = useBlockProps.save();
// innerBlocks could also be an object - react element during initialization
const numberOfInnerBlocks = innerBlocks?.length;
if ( numberOfInnerBlocks > 1 ) {
className = className + ( className ? ' ' : '' ) + 'more-than-one';
};
const blockProps = { ...rest, className };
return
{ attributes.content }
;
};
```
Here, an additional class is added to the block if number of inner blocks is greater than one, allowing for different styling of the block.
## Examples
Here are a couple examples of using attributes, edit, and save all together.
### Saving Attributes to Child Elements
```jsx
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'div'
}
},
edit: ( { attributes, setAttributes } ) => {
const blockProps = useBlockProps();
const updateFieldValue = ( val ) => {
setAttributes( { content: val } );
}
return (
;
},
```
### Saving Attributes via Serialization
Ideally, the attributes saved should be included in the markup. However, there are times when this is not practical, so if no attribute source is specified the attribute is serialized and saved to the block’s comment delimiter.
This example could be for a dynamic block, such as the [Latest Posts block](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-library/src/latest-posts/index.js), which renders the markup server-side. The save function is still required, however in this case it simply returns null since the block is not saving content from the editor.
```jsx
attributes: {
postsToShow: {
type: 'number',
}
},
edit: ( { attributes, setAttributes } ) => {
const blockProps = useBlockProps();
return (
);
},
save: () => {
return null;
}
```
## Validation
When the editor loads, all blocks within post content are validated to determine their accuracy in order to protect against content loss. This is closely related to the saving implementation of a block, as a user may unintentionally remove or modify their content if the editor is unable to restore a block correctly. During editor initialization, the saved markup for each block is regenerated using the attributes that were parsed from the post’s content. If the newly-generated markup does not match what was already stored in post content, the block is marked as invalid. This is because we assume that unless the user makes edits, the markup should remain identical to the saved content.
If a block is detected to be invalid, the user will be prompted to choose how to handle the invalidation:

Clicking the **Attempt Block Recovery** button will attempt a recovery action as much as possible.
Clicking the “3-dot” menu on the side of the block displays three options:
- **Resolve**: Open Resolve Block dialog box with two buttons:
- **Convert to HTML**: Protects the original markup from the saved post content and converts the block from its original type to the HTML block type, enabling the user to modify the HTML markup directly.
- **Convert to Blocks**: Protects the original markup from the saved post content and converts the block from its original type to the validated block type.
- **Convert to HTML**: Protects the original markup from the saved post content and converts the block from its original type to the HTML block type, enabling the user to modify the HTML markup directly.
- **Convert to Classic Block**: Protects the original markup from the saved post content as correct. Since the block will be converted from its original type to the Classic block type, it will no longer be possible to edit the content using controls available for the original block type.
### Validation FAQ
**How do blocks become invalid?**
The two most common sources of block invalidations are:
1. A flaw in a block’s code would result in unintended content modifications. See the question below on how to debug block invalidation as a plugin author.
2. You or an external editor changed the HTML markup of the block in such a way that it is no longer considered correct.
**I’m a plugin author. What should I do to debug why my blocks are being marked as invalid?**
Before starting to debug, be sure to familiarize yourself with the validation step described above documenting the process for detecting whether a block is invalid. A block is invalid if its regenerated markup does not match what is saved in post content, so often this can be caused by the attributes of a block being parsed incorrectly from the saved content.
If you’re using [attribute sources](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/), be sure that attributes sourced from markup are saved exactly as you expect, and in the correct type (usually a `'string'` or `'number'`).
When a block is detected as invalid, a warning will be logged into your browser’s developer tools console. The warning will include specific details about the exact point at which a difference in markup occurred. Be sure to look closely at any differences in the expected and actual markups to see where problems are occurring.
**I’ve changed my block’s `save` behavior and old content now includes invalid blocks. How can I fix this?**
Refer to the guide on [Deprecated Blocks](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-deprecation/) to learn more about how to accommodate legacy content in intentional markup changes.
---
# Attributes
Source: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/
Block attributes provide information about the data stored by a block. For example, rich content, a list of image URLs, a background color, or a button title.
A block can contain any number of attributes, and these are specified by the `attributes` field – an object where each key is the name of the attribute, and the value is the attribute definition.
The attribute definition will contain, at a minimum, either a `type` or an `enum`. There may be additional fields.
*Example*: Attributes object defining three attributes – `url`, `title`, and `size`.
```js
{
url: {
type: 'string',
source: 'attribute',
selector: 'img',
attribute: 'src',
},
title: {
type: 'string',
},
size: {
enum: [ 'large', 'small' ],
},
}
```
When a block is parsed this definition will be used to extract data from the block content. Anything that matches will be available to your block through the `attributes` prop.
This parsing process can be summarized as:
1. Extract value from the `source`.
2. Check value matches the `type`, or is one of the `enum` values.
*Example*: Attributes available in the `edit` and function, using the above attributes definition.
```js
function YourBlockEdit( { attributes } ) {
return (
URL is { attributes.url }, title is { attributes.title }, and size is { attributes.size }.
)
}
```
The block is responsible for using the `save` function to ensure that all attributes with a `source` field are saved according to the attributes definition. This is not automatic.
Attributes without a `source` will be automatically saved in the block [comment delimiter](https://developer.wordpress.org/block-editor/explanations/architecture/key-concepts/#data-attributes).
For example, using the above attributes definition you would need to ensure that your `save` function has a corresponding img tag for the `url` attribute. The `title` and `size` attributes will be saved in the comment delimiter.
*Example*: Example `save` function that contains the `url` attribute
```js
function YourBlockSave( { attributes } ) {
return (
)
}
```
The saved HTML will contain the `title` and `size` in the comment delimiter, and the `url` in the `img` node.
```html
```
If an attribute changes over time then a [block deprecation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-deprecation/) can help migrate from an older attribute, or remove it entirely.
## Type validation
The `type` indicates the type of data that is stored by the attribute. It does not indicate where the data is stored, which is defined by the `source` field.
A `type` is required, unless an `enum` is provided. A `type` can be used with an `enum`.
The `type` field MUST be one of the following:
- `null`
- `boolean`
- `object`
- `array`
- `string`
- `integer`
- `number` (same as `integer`)
Note that the validity of an `object` is determined by your `source`. For an example, see the `query` details below.
## Enum validation
An attribute can be defined as one of a fixed set of values. This is specified by an `enum`, which contains an array of allowed values:
*Example*: Example `enum`.
```js
{
size: {
enum: [ 'large', 'small', 'tiny' ]
}
}
```
## Value source
Attribute sources are used to define how the attribute values are extracted from saved post content. They provide a mechanism to map from the saved markup to a JavaScript representation of a block.
The available `source` values are:
– `(no value)` – when no `source` is specified then data is stored in the block’s [comment delimiter](https://developer.wordpress.org/block-editor/explanations/architecture/key-concepts/#data-attributes).
– `attribute` – data is stored in an HTML element attribute.
– `text` – data is stored in HTML text.
– `html` – data is stored in HTML. This is typically used by `RichText`.
– `query` – data is stored as an array of objects.
– `meta` – data is stored in post meta (deprecated).
The `source` field is usually combined with a `selector` field. If no selector argument is specified, the source definition runs against the block’s root node. If a selector argument is specified, it will run against the matching element(s) within the block.
The `selector` can be an HTML tag, or anything queryable with [querySelector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector), such as a class or id attribute. Examples are given below.
For example, a `selector` of `img` will match an `img` element, and `img.class` will match an `img` element that has a class of `class`.
Under the hood, attribute sources are a superset of the functionality provided by [hpq](https://github.com/aduth/hpq), a small library used to parse and query HTML markup into an object shape.
To summarize, the `source` determines where data is stored in your content, and the `type` determines what that data is. To reduce the amount of data stored it is usually better to store as much data as possible within HTML rather than as attributes within the comment delimiter.
### `attribute` source
Use an `attribute` source to extract the value from an attribute in the markup. The attribute is specified by the `attribute` field, which must be supplied.
*Example*: Extract the `src` attribute from an image found in the block’s markup.
Saved content:
```html
Block Content
```
Attribute definition:
```js
{
url: {
type: 'string',
source: 'attribute',
selector: 'img',
attribute: 'src',
}
}
```
Attribute available in the block:
```js
{ "url": "https://lorempixel.com/1200/800/" }
```
Most attributes from markup will be of type `string`. Numeric attributes in HTML are still stored as strings, and are not converted automatically.
*Example*: Extract the `width` attribute from an image found in the block’s markup.
Saved content:
```html
Block Content
```
Attribute definition:
```js
{
width: {
type: 'string',
source: 'attribute',
selector: 'img',
attribute: 'width',
}
}
```
Attribute available in the block:
```js
{ "width": "50" }
```
The only exception is when checking for the existence of an attribute (for example, the `disabled` attribute on a `button`). In that case type `boolean` can be used and the stored value will be a boolean.
*Example*: Extract the `disabled` attribute from a button found in the block’s markup.
Saved content:
```html
Block Content
```
Attribute definition:
```js
{
disabled: {
type: 'boolean',
source: 'attribute',
selector: 'button',
attribute: 'disabled',
}
}
```
Attribute available in the block:
```js
{ "disabled": true }
```
### `text` source
Use `text` to extract the inner text from markup. Note that HTML is returned according to the rules of [`textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent).
*Example*: Extract the `content` attribute from a figcaption element found in the block’s markup.
Saved content:
```html
The inner text of the figcaption element
```
Attribute definition:
```js
{
content: {
type: 'string',
source: 'text',
selector: 'figcaption',
}
}
```
Attribute available in the block:
```js
{ "content": "The inner text of the figcaption element" }
```
Another example, using `text` as the source, and using `.my-content` class as the selector to extract text:
*Example*: Extract the `content` attribute from an element with `.my-content` class found in the block’s markup.
Saved content:
```html
The inner text of .my-content class
```
Attribute definition:
```js
{
content: {
type: 'string',
source: 'text',
selector: '.my-content',
}
}
```
Attribute available in the block:
```js
{ "content": "The inner text of .my-content class" }
```
### `html` source
Use `html` to extract the inner HTML from markup. Note that text is returned according to the rules of [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML).
*Example*: Extract the `content` attribute from a figcaption element found in the block’s markup.
Saved content:
```html
The inner text of the figcaption element
```
Attribute definition:
```js
{
content: {
type: 'string',
source: 'html',
selector: 'figcaption',
}
}
```
Attribute available in the block:
```js
{ "content": "The inner text of the figcaption element" }
```
### `query` source
Use `query` to extract an array of values from markup. Entries of the array are determined by the `selector` argument, where each matched element within the block will have an entry structured corresponding to the second argument, an object of attribute sources.
The `query` field is effectively a nested block attributes definition. It is possible (although not necessarily recommended) to nest further.
*Example*: Extract `src` and `alt` from each image element in the block’s markup.
Saved content:
```html
```
Attribute definition:
```js
{
images: {
type: 'array',
source: 'query',
selector: 'img',
query: {
url: {
type: 'string',
source: 'attribute',
attribute: 'src',
},
alt: {
type: 'string',
source: 'attribute',
attribute: 'alt',
},
}
}
}
```
Attribute available in the block:
```js
{
"images": [
{ "url": "https://lorempixel.com/1200/800/", "alt": "large image" },
{ "url": "https://lorempixel.com/50/50/", "alt": "small image" }
]
}
```
### Meta source (deprecated)
Although attributes may be obtained from a post’s meta, meta attribute sources are considered deprecated; [EntityProvider and related hook APIs](https://github.com/WordPress/gutenberg/blob/c367c4e2765f9e6b890d1565db770147efca5d66/packages/core-data/src/entity-provider.js) should be used instead, as shown in the [Create Meta Block how-to](https://developer.wordpress.org/block-editor/how-to-guides/metabox/#step-2-add-meta-block).
Attributes may be obtained from a post’s meta rather than from the block’s representation in saved post content. For this, an attribute is required to specify its corresponding meta key under the `meta` key.
Attribute definition:
```js
{
author: {
type: 'string',
source: 'meta',
meta: 'author'
},
},
```
From here, meta attributes can be read and written by a block using the same interface as any attribute:
```js
edit( { attributes, setAttributes } ) {
function onChange( event ) {
setAttributes( { author: event.target.value } );
}
return ;
},
```
#### Considerations
By default, a meta field will be excluded from a post object’s meta. This can be circumvented by explicitly making the field visible:
```php
function gutenberg_my_block_init() {
register_post_meta( 'post', 'author', array(
'show_in_rest' => true,
) );
}
add_action( 'init', 'gutenberg_my_block_init' );
```
Furthermore, be aware that WordPress defaults to:
- not treating a meta datum as being unique, instead returning an array of values;
- treating that datum as a string.
If either behavior is not desired, the same `register_post_meta` call can be complemented with the `single` and/or `type` parameters as follows:
```php
function gutenberg_my_block_init() {
register_post_meta( 'post', 'author_count', array(
'show_in_rest' => true,
'single' => true,
'type' => 'integer',
) );
}
add_action( 'init', 'gutenberg_my_block_init' );
```
If you’d like to use an object or an array in an attribute, you can register a `string` attribute type and use JSON as the intermediary. Serialize the structured data to JSON prior to saving, and then deserialize the JSON string on the server. Keep in mind that you’re responsible for the integrity of the data; make sure to properly sanitize, accommodate missing data, etc.
Lastly, make sure that you respect the data’s type when setting attributes, as the framework does not automatically perform type casting of meta. Incorrect typing in block attributes will result in a post remaining dirty even after saving (*cf.* `isEditedPostDirty`, `hasEditedAttributes`). For instance, if `authorCount` is an integer, remember that event handlers may pass a different kind of data, thus the value should be cast explicitly:
```js
function onChange( event ) {
props.setAttributes( { authorCount: Number( event.target.value ) } );
}
```
## Default value
A block attribute can contain a default value, which will be used if the `type` and `source` do not match anything within the block content.
The value is provided by the `default` field, and the value should match the expected format of the attribute.
*Example*: Example `default` values.
```js
{
type: 'string',
default: 'hello world'
}
```
```js
{
type: 'array',
default: [
{ "url": "https://lorempixel.com/1200/800/", "alt": "large image" },
{ "url": "https://lorempixel.com/50/50/", "alt": "small image" }
]
}
```
```js
{
type: 'object',
default: {
width: 100,
title: 'title'
}
}
```
---
# Templates
Source: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-templates/
A block template is defined as a list of block items. Such blocks can have predefined attributes, placeholder content, and be static or dynamic. Block templates allow specifying a default initial state for an editor session.
The scope of templates include:
- Setting a default state dynamically on the client. (like `defaultBlock`)
- Registered as a default for a given post type.
Planned additions:
- Saved and assigned to pages as “page templates”.
- Defined in a `template.php` file or pulled from a custom post type (`wp_templates`) that is site specific.
- As the equivalent of the theme hierarchy.
## API
Templates can be declared in JS or in PHP as an array of blockTypes (block name and optional attributes).
The first example in PHP creates a template for posts that includes an image block to start, you can add as many or as few blocks to your template as needed.
PHP example:
```php
template = array(
array( 'core/image' ),
);
}
add_action( 'init', 'myplugin_register_template' );
```
The following example in JavaScript creates a new block using [InnerBlocks](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inner-blocks/README.md) and templates, when inserted creates a set of blocks based off the template.
```js
const el = React.createElement;
const { registerBlockType } = wp.blocks;
const { InnerBlocks } = wp.blockEditor;
const BLOCKS_TEMPLATE = [
[ 'core/image', {} ],
[ 'core/paragraph', { placeholder: 'Image Details' } ],
];
registerBlockType( 'myplugin/template', {
title: 'My Template Block',
category: 'widgets',
edit: ( props ) => {
return el( InnerBlocks, {
template: BLOCKS_TEMPLATE,
templateLock: false,
} );
},
save: ( props ) => {
return el( InnerBlocks.Content, {} );
},
} );
```
See the [Meta Block Tutorial](https://developer.wordpress.org/block-editor/how-to-guides/metabox/#step-4-finishing-touches) for a full example of a template in use.
## Block attributes
To find a comprehensive list of all block attributes that you can define in a template, consult the block’s `block.json` file, and look at the `attributes` and `supports` values.
For example, [packages/block-library/src/heading/block.json](https://github.com/WordPress/gutenberg/blob/c62ccd80c7c6abb85740cf8745439029bf0f4d35/packages/block-library/src/heading/block.json#L5-L25) shows that the block has a `level` attribute, and supports the `anchor` parameter.
If you don’t have the Gutenberg plugin installed, you can find `block.json` files inside `wp-includes/blocks/heading/block.json`.
## Custom post types
A custom post type can register its own template during registration:
```php
function myplugin_register_book_post_type() {
$args = array(
'public' => true,
'label' => 'Books',
'show_in_rest' => true,
'template' => array(
array( 'core/image', array(
'align' => 'left',
) ),
array( 'core/heading', array(
'placeholder' => 'Add Author...',
) ),
array( 'core/paragraph', array(
'placeholder' => 'Add Description...',
) ),
),
);
register_post_type( 'book', $args );
}
add_action( 'init', 'myplugin_register_book_post_type' );
```
## Locking
Sometimes the intention might be to lock the template on the UI so that the blocks presented cannot be manipulated. This is achieved with a `template_lock` property.
```php
function myplugin_register_template() {
$post_type_object = get_post_type_object( 'post' );
$post_type_object->template = array(
array( 'core/paragraph', array(
'placeholder' => 'Add Description...',
) ),
);
$post_type_object->template_lock = 'all';
}
add_action( 'init', 'myplugin_register_template' );
```
*Options:*
- `contentOnly` — prevents all operations. Additionally, the block types that don’t have content are hidden from the list view and can’t gain focus within the block list. Unlike the other lock types, this is not overridable by children.
- `all` — prevents all operations. It is not possible to insert new blocks, move existing blocks, or delete blocks.
- `insert` — prevents inserting or removing blocks, but allows moving existing blocks.
Lock settings can be inherited by InnerBlocks. If `templateLock` is not set in an InnerBlocks area, the locking of the parent InnerBlocks area is used. If the block is a top level block, the locking configuration of the current post type is used.
## Individual block locking
Alongside template level locking, you can lock individual blocks; you can do this using a `lock` attribute on the attributes level. Block-level lock takes priority over the `templateLock` feature. Currently, you can lock moving and removing blocks.
```js
attributes: {
// Prevent a block from being moved or removed.
lock: {
remove: true,
move: true,
}
}
```
*Options:*
- `remove` — Locks the ability of a block from being removed.
- `move` — Locks the ability of a block from being moved.
You can use this with `templateLock` to lock all blocks except a single block by using `false` in `remove` or `move`.
```php
$template = array(
array( 'core/image', array(
'align' => 'left',
) ),
array( 'core/heading', array(
'placeholder' => 'Add Author...',
) ),
// Allow a Paragraph block to be moved or removed.
array( 'core/paragraph', array(
'placeholder' => 'Add Description...',
'lock' => array(
'move' => false,
'remove' => false,
),
) ),
);
```
## Nested templates
Container blocks like the columns blocks also support templates. This is achieved by assigning a nested template to the block.
```php
$template = array(
array( 'core/paragraph', array(
'placeholder' => 'Add a root-level paragraph',
) ),
array( 'core/columns', array(), array(
array( 'core/column', array(), array(
array( 'core/image', array() ),
) ),
array( 'core/column', array(), array(
array( 'core/paragraph', array(
'placeholder' => 'Add a inner paragraph'
) ),
) ),
) )
);
```
---
# Annotations
Source: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-annotations/
**Note:** This API is experimental, that means it is subject to non-backward compatible changes or removal in any future version.
Annotations are a way to highlight a specific piece in a post created with the block editor. Examples of this include commenting on a piece of text and spellchecking. Both can use the annotations API to mark a piece of text.
## API
To see the API for yourself the easiest way is to have a block that is at least 200 characters long without formatting and putting the following in the console:
```js
wp.data.dispatch( 'core/annotations' ).addAnnotation( {
source: 'my-annotations-plugin',
blockClientId: wp.data.select( 'core/block-editor' ).getBlockOrder()[ 0 ],
richTextIdentifier: 'content',
range: {
start: 50,
end: 100,
},
} );
```
The start and the end of the range should be calculated based only on the text of the relevant `RichText`. For example, in the following HTML position 0 will refer to the position before the capital S:
```html
Strong text
```
To help with determining the correct positions, the `wp.richText.create` method can be used. This will split a piece of HTML into text and formats.
All available properties can be found in the API documentation of the `addAnnotation` action.
The property `richTextIdentifier` is the identifier of the RichText instance the annotation applies to. This is necessary because blocks may have multiple rich text instances that are used to manage data for different attributes, so you need to pass this in order to highlight text within the correct one.
For example the Paragraph block only has a single RichText instance, with the identifier `content`. The quote block type has 2 RichText instances, so if you wish to highlight text in the citation, you need to pass `citation` as the `richTextIdentifier` when adding an annotation. To target the quote content, you need to use the identifier `value`. Refer to the source code of the block type to find the correct identifier.
## Block annotation
It is also possible to annotate a block completely. In that case just provide the `selector` property and set it to `block`. The default `selector` is `range`, which can be used for text annotation.
```js
wp.data.dispatch( 'core/annotations' ).addAnnotation( {
source: 'my-annotations-plugin',
blockClientId: wp.data.select( 'core/block-editor' ).getBlockOrder()[ 0 ],
selector: 'block',
} );
```
This doesn’t provide any styling out of the box, so you have to provide some CSS to make sure your annotation is shown:
```css
.is-annotated-by-my-annotations-plugin {
outline: 1px solid black;
}
```
## Text annotation
The text annotation is controlled by the `start` and `end` properties. Simple `start` and `end` properties don’t work for HTML, so these properties are assumed to be offsets within the `rich-text` internal structure. For simplicity you can think about this as if all HTML would be stripped out and then you calculate the `start` and the `end` of the annotation.
---
# Hooks Reference
Source: https://developer.wordpress.org/block-editor/reference-guides/filters/
[Hooks](https://developer.wordpress.org/plugins/hooks/) are a way for one piece of code to interact/modify another piece of code. They provide one way for plugins and themes to interact with the editor, but they’re also used extensively by WordPress Core itself.
There are two types of hooks: [Actions](https://developer.wordpress.org/plugins/hooks/actions/) and [Filters](https://developer.wordpress.org/plugins/hooks/filters/). In addition to PHP actions and filters, WordPress also provides a mechanism for registering and executing hooks in JavaScript. This functionality is also available on npm as the [@wordpress/hooks](https://www.npmjs.com/package/@wordpress/hooks) package, for general purpose use.
You can also learn more about both APIs: [PHP](https://developer.wordpress.org/reference/) and [JavaScript](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-hooks/).
---
# Block Filters
Source: https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/
WordPress exposes several APIs that allow you to modify the behavior of existing blocks.
## Registration
Blocks in WordPress are typically registered on both the server and client side using `block.json“ metadata. You can use the following filters to modify or extend block settings during their registration on the server with PHP and on the client with JavaScript. To learn more, refer to the [block registration](https://developer.wordpress.org/block-editor/getting-started/fundamentals/registration-of-a-block/) guide.
### `block_type_metadata`
Filters the raw metadata loaded from the `block.json` file when registering a block type on the server with PHP. It allows modifications to be applied before the metadata gets processed.
The callback function for this filter receives one parameter:
- `$metadata` (`array`): Metadata loaded from `block.json` for registering a block type.
The following example sets the `apiVersion` of all blocks to `2`.
```php
function example_filter_metadata_registration( $metadata ) {
$metadata['apiVersion'] = 2;
return $metadata;
};
add_filter( 'block_type_metadata', 'example_filter_metadata_registration' );
```
Here’s a more robust example that disables background color and gradient support for Heading blocks. The `block_type_metadata` filter is excellent for [curating the Editor experience](https://developer.wordpress.org/block-editor/how-to-guides/curating-the-editor-experience/).
```php
function example_disable_heading_background_color_and_gradients( $metadata ) {
// Only apply the filter to Heading blocks.
if ( ! isset( $metadata['name'] ) || 'core/heading' !== $metadata['name'] ) {
return $metadata;
}
// Check if 'supports' key exists.
if ( isset( $metadata['supports'] ) && isset( $metadata['supports']['color'] ) ) {
// Remove Background color and Gradients support.
$metadata['supports']['color']['background'] = false;
$metadata['supports']['color']['gradients'] = false;
}
return $metadata;
}
add_filter( 'block_type_metadata', 'example_disable_heading_background_color_and_gradients' );
```
### `block_type_metadata_settings`
Filters the settings determined from the processed block type metadata. It makes it possible to apply custom modifications using the block metadata that isn’t handled by default.
The callback function for this filter receives two parameters:
- `$settings` (`array`): Array of determined settings for registering a block type.
- `$metadata` (`array`): Metadata loaded from the `block.json` file.
The following example increases the `apiVersion` for all blocks by `1`.
```php
function example_filter_metadata_registration( $settings, $metadata ) {
$settings['api_version'] = $metadata['apiVersion'] + 1;
return $settings;
};
add_filter( 'block_type_metadata_settings', 'example_filter_metadata_registration', 10, 2 );
```
### `register_block_type_args`
Filters a block’s arguments array (`$args`) right before the block type is officially registered on the server.
The callback function for this filter receives two parameters:
- `$args` (`array`): Array of arguments for registering a block type.
- `$block_type` (`string`): Block type name including namespace.
`register_block_type_args` is the most low-level PHP filter available, and it will work for every block registered on the server. All settings defined on the server are propagated to the client with higher priority than those set in the client.
The following code will disable the color controls for Paragraph, Heading, List, and List Item blocks.
```php
function example_disable_color_for_specific_blocks( $args, $block_type ) {
// List of block types to modify.
$block_types_to_modify = [
'core/paragraph',
'core/heading',
'core/list',
'core/list-item'
];
// Check if the current block type is in the list.
if ( in_array( $block_type, $block_types_to_modify, true ) ) {
// Disable color controls.
$args['supports']['color'] = array(
'text' => false,
'background' => false,
'link' => false,
);
}
return $args;
}
add_filter( 'register_block_type_args', 'example_disable_color_for_specific_blocks', 10, 2 );
```
### `blocks.registerBlockType`
Used to filter the block settings when registering the block on the client with JavaScript. It receives the block settings, the name of the registered block, and either null or the deprecated block settings (when applied to a registered deprecation) as arguments. This filter is also applied to each of a block’s deprecated settings.
The following example ensures that List blocks are saved with the canonical generated class name (`wp-block-list`):
```js
function addListBlockClassName( settings, name ) {
if ( name !== 'core/list' ) {
return settings;
}
return {
...settings,
supports: {
...settings.supports,
className: true,
},
};
}
wp.hooks.addFilter(
'blocks.registerBlockType',
'my-plugin/class-names/list-block',
addListBlockClassName
);
```
## Front end
The following PHP filters are available to change the output of a block on the front end.
### `render_block`
Filters the front-end content of any block. This filter has no impact on the behavior of blocks in the Editor.
The callback function for this filter receives three parameters:
- `$block_content` (`string`): The block content.
- `$block` (`array`): The full block, including name and attributes.
- `$instance` (`WP_Block`): The block instance.
In the following example, the class `example-class` is added to all Paragraph blocks on the front end. Here the [HTML API](https://make.wordpress.org/core/2023/03/07/introducing-the-html-api-in-wordpress-6-2/) is used to easily add the class instead of relying on regex.
```php
function example_add_custom_class_to_paragraph_block( $block_content, $block ) {
// Check if the block is a Paragraph block.
if ( 'core/paragraph' === $block['blockName'] ) {
// Add the custom class to the block content using the HTML API.
$processor = new WP_HTML_Tag_Processor( $block_content );
if ( $processor->next_tag( 'p' ) ) {
$processor->add_class( 'example-class' );
}
return $processor->get_updated_html();
}
return $block_content;
}
add_filter( 'render_block', 'example_add_custom_class_to_paragraph_block', 10, 2 );
```
### `render_block_{namespace/block}`
Filters the front-end content of the defined block. This is just a simpler form of `render_block` when you only need to modify a specific block type.
The callback function for this filter receives three parameters:
- `$block_content` (`string`): The block content.
- `$block` (`array`): The full block, including name and attributes.
- `$instance` (`WP_Block`): The block instance.
In the following example, the class `example-class` is added to all Paragraph blocks on the front end. Notice that compared to the `render_block` example above, you no longer need to check the block type before modifying the content. Again, the [HTML API](https://make.wordpress.org/core/2023/03/07/introducing-the-html-api-in-wordpress-6-2/) is used instead of regex.
```php
function example_add_custom_class_to_paragraph_block( $block_content, $block ) {
// Add the custom class to the block content using the HTML API.
$processor = new WP_HTML_Tag_Processor( $block_content );
if ( $processor->next_tag( 'p' ) ) {
$processor->add_class( 'example-class' );
}
return $processor->get_updated_html();
}
add_filter( 'render_block_core/paragraph', 'example_add_custom_class_to_paragraph_block', 10, 2 );
```
## Editor
The following JavaScript filters are available to change the behavior of blocks while editing in the Editor.
### `blocks.getSaveElement`
A filter that applies to the result of a block’s `save` function. This filter is used to replace or extend the element, for example using `React.cloneElement` to modify the element’s props, replace its children, or return an entirely new element.
The callback function for this filter receives three parameters:
- `element` (`Object`): The element to be modified and returned.
- `blockType` (`Object`): A block-type definition object.
- `attributes` (`Object`): The block’s attributes.
The following example wraps a Cover block in an outer container `div`.
```js
function wrapCoverBlockInContainer( element, blockType, attributes ) {
// Skip if element is undefined.
if ( ! element ) {
return;
}
// Only apply to Cover blocks.
if ( blockType.name !== 'core/cover' ) {
return element;
}
// Return the element wrapped in a div.
return
{ element }
;
}
wp.hooks.addFilter(
'blocks.getSaveElement',
'my-plugin/wrap-cover-block-in-container',
wrapCoverBlockInContainer
);
```
### `blocks.getSaveContent.extraProps`
A filter that applies to all blocks returning a WP Element in the `save` function. This filter is used to add extra props to the root element of the `save` function. For example, you could add a className, an id, or any valid prop for this element.
The callback function for this filter receives three parameters:
- `props` (`Object`): The current `save` element’s props to be modified and returned.
- `blockType` (`Object`): A block-type definition object.
- `attributes` (`Object`): The block’s attributes.
The following example adds a red background by default to all blocks.
```js
function addBackgroundColorStyle( props ) {
return {
...props,
style: { backgroundColor: 'red' },
};
}
wp.hooks.addFilter(
'blocks.getSaveContent.extraProps',
'my-plugin/add-background-color-style',
addBackgroundColorStyle
);
```
*Note:* A [block validation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#validation) error will occur if this filter modifies existing content the next time the post is edited. The Editor verifies that the content stored in the post matches the content output by the `save()` function.
To avoid this validation error, use `render_block` server-side to modify existing post content instead of this filter. See [render\_block documentation](https://developer.wordpress.org/reference/hooks/render_block/).
### `blocks.getBlockDefaultClassName`
Generated HTML classes for blocks follow the `wp-block-{name}` nomenclature. This filter allows to provide an alternative class name.
```js
// Our filter function.
function setBlockCustomClassName( className, blockName ) {
return blockName === 'core/code' ? 'my-plugin-code' : className;
}
// Adding the filter.
wp.hooks.addFilter(
'blocks.getBlockDefaultClassName',
'my-plugin/set-block-custom-class-name',
setBlockCustomClassName
);
```
### `blocks.switchToBlockType.transformedBlock`
Used to filter an individual transform result from block transformation. All of the original blocks are passed since transformations are many-to-many, not one-to-one.
### `blocks.getBlockAttributes`
Called immediately after the default parsing of a block’s attributes and before validation to allow a plugin to manipulate attribute values in time for validation and/or the initial values rendering of the block in the editor.
The callback function for this filter accepts 4 parameters:
– `blockAttributes` (`Object`): All block attributes.
– `blockType` (`Object`): The block type.
– `innerHTML` (`string`): Raw block content.
– `attributes` (`object`): Known block attributes (from delimiters).
In the example below, we use the `blocks.getBlockAttributes` filter to lock the position of all paragraph blocks on a page.
```js
// Our filter function
function lockParagraphs( blockAttributes, blockType, innerHTML, attributes ) {
if('core/paragraph' === blockType.name) {
blockAttributes['lock'] = {move: true}
}
return blockAttributes;
}
// Add the filter
wp.hooks.addFilter(
'blocks.getBlockAttributes',
'my-plugin/lock-paragraphs',
lockParagraphs
);
```
### `editor.BlockEdit`
Used to modify the block’s `edit` component. It receives the original block `BlockEdit` component and returns a new wrapped component.
The following example adds a new Inspector panel for all blocks.
```js
const { createHigherOrderComponent } = wp.compose;
const { InspectorControls } = wp.blockEditor;
const { PanelBody } = wp.components;
const withMyPluginControls = createHigherOrderComponent( ( BlockEdit ) => {
return ( props ) => {
return (
<>
My custom control
>
);
};
}, 'withMyPluginControls' );
wp.hooks.addFilter(
'editor.BlockEdit',
'my-plugin/with-inspector-controls',
withMyPluginControls
);
```
Note that as this hook is run for *all blocks*, consuming it has the potential for performance regressions, particularly around block selection metrics.
To mitigate this, consider whether any work you perform can be altered to run only under certain conditions.
For example, suppose you are adding components that only need to render when the block is *selected*. In that case, you can use the block’s “selected” state (`props.isSelected`) to conditionalize your rendering.
The following example adds a new Inspector panel for all blocks, but only when a block is selected.
```js
const withMyPluginControls = createHigherOrderComponent( ( BlockEdit ) => {
return ( props ) => {
return (
<>
{ props.isSelected && (
My custom control
) }
>
);
};
}, 'withMyPluginControls' );
```
### `editor.BlockListBlock`
Used to modify the block’s wrapper component containing the block’s `edit` component and all toolbars. It receives the original `BlockListBlock` component and returns a new wrapped component.
The following example adds a unique class name to all blocks.
```js
const { createHigherOrderComponent } = wp.compose;
const withClientIdClassName = createHigherOrderComponent(
( BlockListBlock ) => {
return ( props ) => {
return (
);
};
},
'withClientIdClassName'
);
wp.hooks.addFilter(
'editor.BlockListBlock',
'my-plugin/with-client-id-class-name',
withClientIdClassName
);
```
You can add new properties to the block’s wrapper component using the `wrapperProps` property of the returned component as shown in the following example.
```js
const { createHigherOrderComponent } = wp.compose;
const withMyWrapperProp = createHigherOrderComponent( ( BlockListBlock ) => {
return ( props ) => {
const wrapperProps = {
...props.wrapperProps,
'data-my-property': 'the-value',
};
return ;
};
}, 'withMyWrapperProp' );
wp.hooks.addFilter(
'editor.BlockListBlock',
'my-plugin/with-my-wrapper-prop',
withMyWrapperProp
);
```
### `editor.postContentBlockTypes`
Used to modify the list of blocks that should be enabled even when used inside a locked template. Any block that saves data to a post should be added here. An example of this is the Post Featured Image block. Often used in templates, this block should still allow selecting the image even when the template is locked.
The following example enables the fictitious block `namespace/example`.
```js
const addExampleBlockToPostContentBlockTypes = ( blockTypes ) => {
return [ ...blockTypes, 'namespace/example' ];
};
wp.hooks.addFilter(
'editor.postContentBlockTypes',
'my-plugin/post-content-block-types',
addExampleBlockToPostContentBlockTypes
);
```
## Removing Blocks
### Using a deny list
Adding blocks is easy enough, and removing them is as easy. Plugin or theme authors can “unregister” blocks using a deny list in JavaScript.
Place the following code in a `my-plugin.js` file.
```js
// my-plugin.js
import { unregisterBlockType } from '@wordpress/blocks';
import domReady from '@wordpress/dom-ready';
domReady( function () {
unregisterBlockType( 'core/verse' );
} );
```
Then, load this script in the Editor using the following function.
```php
post ) ) {
return array( 'core/paragraph', 'core/heading' );
}
return $allowed_block_types;
}
add_filter( 'allowed_block_types_all', 'example_filter_allowed_block_types_when_post_provided', 10, 2 );
```
## Managing block categories
### `block_categories_all`
Before WordPress 5.8, this hook was known as `block_categories`, which is now deprecated. If you need to support older versions of WordPress, you might need a way to detect which filter should be used. You can check if `block_categories` is safe to use by seeing if the `WP_Block_Editor_Context` class exists, which was introduced in 5.8.
It is possible to filter the list of default block categories using the `block_categories_all` filter. You can do it on the server by implementing a function which returns a list of categories. It is going to be used during block registration and to group blocks in the inserter. You can also use the second provided parameter `$editor_context` to filter the based on its content.
```php
// my-plugin.php
function example_filter_block_categories_when_post_provided( $block_categories, $editor_context ) {
if ( ! empty( $editor_context->post ) ) {
array_push(
$block_categories,
array(
'slug' => 'custom-category',
'title' => __( 'Custom Category', 'custom-plugin' ),
'icon' => null,
)
);
}
return $block_categories;
}
add_filter( 'block_categories_all', 'example_filter_block_categories_when_post_provided', 10, 2 );
```
### `wp.blocks.updateCategory`
You can also display an icon with your block category by setting an `icon` attribute. The value can be the slug of a [WordPress Dashicon](https://developer.wordpress.org/resource/dashicons/).
You can also set a custom icon in SVG format. To do so, the icon should be rendered and set on the frontend, so it can make use of WordPress SVG, allowing mobile compatibility and making the icon more accessible.
To set an SVG icon for the category shown in the previous example, add the following example JavaScript code to the Editor calling `wp.blocks.updateCategory` e.g:
```js
( function () {
var el = React.createElement;
var SVG = wp.primitives.SVG;
var circle = el( 'circle', {
cx: 10,
cy: 10,
r: 10,
fill: 'red',
stroke: 'blue',
strokeWidth: '10',
} );
var svgIcon = el(
SVG,
{ width: 20, height: 20, viewBox: '0 0 20 20' },
circle
);
wp.blocks.updateCategory( 'my-category', { icon: svgIcon } );
} )();
```
---
# Editor Hooks
Source: https://developer.wordpress.org/block-editor/reference-guides/filters/editor-filters/
WordPress exposes several APIs that allow you to modify the editor experience.
## Editor settings
One of the most common ways to modify the Editor is through the [`block_editor_settings_all`](https://developer.wordpress.org/reference/hooks/block_editor_settings_all/) PHP filter, which is applied before settings are sent to the initialized Editor. This filter allows plugin and theme authors extensive control over how the Editor behaves.
Before WordPress 5.8, this hook was known as `block_editor_settings`, which is now deprecated. If you need to support older versions of WordPress, you might need a way to detect which filter should be used. You can check if `block_editor_settings` is safe to use by seeing if the `WP_Block_Editor_Context` class exists, which was introduced in 5.8.
The `block_editor_settings_all` hook passes two parameters to the callback function:
- `$settings` – An array of configurable settings for the Editor.
- `$context` – An instance of [`WP_Block_Editor_Context`](https://developer.wordpress.org/reference/classes/wp_block_editor_context/), an object that contains information about the current Editor.
The following example modifies the maximum upload file size. Add this to a plugin or your theme’s `functions.php` file to test it.
```php
add_filter( 'block_editor_settings_all', 'example_filter_block_editor_settings_when_post_provided', 10, 2 );
function example_filter_block_editor_settings_when_post_provided( $editor_settings, $editor_context ) {
if ( ! empty( $editor_context->post ) ) {
$editor_settings['maxUploadFileSize'] = 12345;
}
return $editor_settings;
}
```
There are dozens of editor settings, too many to list in this documentation article, but here are a few examples of what you can do with the `block_editor_settings_all` filter.
To view all available settings, open the Editor and then open the console in your browser’s [Developer Tools](https://developer.wordpress.org/advanced-administration/debug/debug-javascript/#open-the-developer-tools). Enter the command `wp.data.select( 'core/block-editor' ).getSettings()` to display the current values for all Editor settings.
### Restrict code editor access
The `codeEditingEnabled`, which defaults to `true`, controls whether the user can access the code editor **in addition** to the visual editor. There may be instances where you don’t want certain users to be able to access this view.
If this setting is set to `false`, the user will not be able to switch between visual and code editor. The option in the settings menu will not be available, and the keyboard shortcut for switching editor types will not fire. Here’s an example:
```php
add_filter( 'block_editor_settings_all', 'example_restrict_code_editor' );
function example_restrict_code_editor( $settings ) {
$can_active_plugins = current_user_can( 'activate_plugins' );
// Disable the Code Editor for users that cannot activate plugins (Administrators).
if ( ! $can_active_plugins ) {
$settings[ 'codeEditingEnabled' ] = false;
}
return $settings;
}
```
### Restrict visual editor access
Similar to the `codeEditingEnabled` setting, `richEditingEnabled` allows you to control who can access the visual editor. If `true`, the user can edit the content using the visual editor.
The setting defaults to the returned value of the [`user_can_richedit`](https://developer.wordpress.org/reference/functions/user_can_richedit/) function. It checks whether the user can access the visual editor and whether the user’s browser supports it.
### Set a default image size
Images are set to the `large` image size by default in the Editor. You can modify this using the `imageDefaultSize` setting, which is especially useful if you have configured your own custom image sizes. The following example changes the default image size to `medium`.
```php
add_filter( 'block_editor_settings_all', 'example_set_default_image_size' );
function example_set_default_image_size( $settings ) {
$settings['imageDefaultSize'] = 'medium';
return $settings;
}
```
### Disable Openverse
The [Openverse](https://openverse.org/) integration is enabled for all WordPress sites by default and is controlled by the `enableOpenverseMediaCategory` setting. To disable Openverse, apply the following filter:
```php
add_filter( 'block_editor_settings_all', 'example_disable_openverse' );
function example_disable_openverse( $settings ) {
$settings['enableOpenverseMediaCategory'] = false;
return $settings;
}
```
### Disable the Font Library
The Font Library allows users to install new fonts on their site, which is enabled by default and is controlled by the `fontLibraryEnabled` setting. To disable the Font Library, apply the following filter:
```php
add_filter( 'block_editor_settings_all', 'example_disable_font_library' );
function example_disable_font_library( $settings ) {
$settings['fontLibraryEnabled'] = false;
return $settings;
}
```
### Disable block inspector tabs
Most blocks display [two tabs](https://make.wordpress.org/core/2023/03/07/introduction-of-block-inspector-tabs/) in the Inspector, one for Settings and another for Styles. You can disable these tabs using the `blockInspectorTabs` setting.
```php
add_filter( 'block_editor_settings_all', 'example_disable_inspector_tabs_by_default' );
function example_disable_inspector_tabs_by_default( $settings ) {
$settings['blockInspectorTabs'] = array( 'default' => false );
return $settings;
}
```
You can also modify which blocks have inspector tabs. Here’s an example that disables tabs for a specific block.
```php
add_filter( 'block_editor_settings_all', 'example_disable_tabs_for_my_custom_block' );
function example_disable_tabs_for_my_custom_block( $settings ) {
$current_tab_settings = _wp_array_get( $settings, array( 'blockInspectorTabs' ), array() );
$settings['blockInspectorTabs'] = array_merge(
$current_tab_settings,
array( 'my-plugin/my-custom-block' => false )
);
return $settings;
}
```
## Block Directory
The Block Directory allows users to install new block plugins directly in the Editor from the WordPress.org [Plugin Directory](https://wordpress.org/plugins/browse/block/). You can disable this functionality by removing the action that enqueues it, which is `wp_enqueue_editor_block_directory_assets`. To do so, use [`remove_action`](https://developer.wordpress.org/reference/functions/remove_action/) like this:
```php
remove_action( 'enqueue_block_editor_assets', 'wp_enqueue_editor_block_directory_assets' );
```
## Block patterns
Remote patterns, such as those from the WordPress.org [Pattern Directory](https://wordpress.org/patterns/), are available to users by default in the Editor. This functionality is controlled by `should_load_remote_block_patterns`, which defaults to `true`. You can disable remote patterns by setting the filter to false (`__return_false`).
```php
add_filter( 'should_load_remote_block_patterns', '__return_false' );
```
## Editor features
The following filters are available to extend features in the Editor.
### `editor.PostFeaturedImage.imageSize`
You can use this filter to modify the image size displayed in the Post Featured Image component. It defaults to `'post-thumbnail'` and will fail back to the `full` image size when the specified image size doesn’t exist in the media object. It’s modeled after the `admin_post_thumbnail_size` filter in the Classic Editor.
```js
import { addFilter } from '@wordpress/hooks';
const withImageSize = function ( size, mediaId, postId ) {
return 'large';
};
addFilter(
'editor.PostFeaturedImage.imageSize',
'my-plugin/with-image-size',
withImageSize
);
```
### `editor.PostPreview.interstitialMarkup`
You can also filter the interstitial message shown when generating previews. Here’s an example:
```js
import { addFilter } from '@wordpress/hooks';
const customPreviewMessage = function () {
return 'Post preview is being generated!';
};
addFilter(
'editor.PostPreview.interstitialMarkup',
'my-plugin/custom-preview-message',
customPreviewMessage
);
```
### `media.crossOrigin`
This filter is used to set or modify the `crossOrigin` attribute for foreign-origin media elements (i.e., `