Miscellaneous Block Editor Changes in WordPress 6.7

In this post, you will find dev notesdev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase. for smaller changes to the editor in WordPress 6.7.


Table of contents


Stabilized Role Property for blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. Attributes

As of WordPress 6.7 the __experimentalRole block attribute property has been stablised as role.

This property is part of the block.json specification and can be applied to any attribute of a block to designate it as being of a particular conceptual type.

Depending on the chosen type, the attribute may then be handled differently at both an APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. level and/or within the Editor’s user interface.

The available types are:

Changes to Selectors and API functions

As part of this effort some selectors and API functions have received changes:

  • __experimentalHasContentRoleAttribute selector from the @wordpress/block-editor package has been deprecated and made private.
  • __experimentalGetBlockAttributesNamesByRole API function from the @wordpress/blocks package has been stablized as getBlockAttributesNamesByRole.

Props to @get_dave for writing the dev notedev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase..


Heading level curation

In WordPress 6.7, coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. blocks with a heading level dropdown now support the new levelOptions attribute, which includes the Heading, Site Title, Site Tagline, Query Title, Post Title, and Comments Title blocks. The levelOptions attribute accepts an array of numbers corresponding to heading levels, where 1 represents H1, 2 represents H2, and so on.

This attribute allows developers to specify which heading levels should appear in the dropdown UIUI User interface, providing a lightweight curation method that does not require block deprecations. Any existing heading levels are preserved in the markup, while levelOptions only affects the UI display.

You can apply this attribute directly in the block markup, a technique that will be commonly used in block templates, template parts, and patterns. For example, the following markup disables H1, H2, and H6 in the Heading block by setting "levelOptions":[3,4,5].

<!-- wp:heading {"level":3,"levelOptions":[3,4,5],"className":"wp-block-heading"} -->
<h3 class="wp-block-heading">Markup example</h3>
<!-- /wp:heading -->

You can also use block filters to set the default value of this attribute globally or for specific blocks. The example below disables H1, H2, and H6 for all Heading blocks. You can further customize this by restricting certain heading levels based on conditions like user capabilities.

function example_modify_heading_levels_globally( $args, $block_type ) {
	
	if ( 'core/heading' !== $block_type ) {
		return $args;
	}

	// Remove H1, H2, and H6.
	$args['attributes']['levelOptions']['default'] = [ 3, 4, 5 ];
	
	return $args;
}
add_filter( 'register_block_type_args', 'example_modify_heading_levels_globally', 10, 2 );

When either of the two examples above are applied, the Heading block UI in the Editor will look like this.

Props to @ndiego for writing the dev note.


Blocks with “contentOnly” locking are no longer transformable

In 6.7, the block transformation menu and block variations selector are not available for blocks with “contentOnly” content locking.

For example, a Group Block that has “contentOnly” locking cannot be transformed to a Columns Block, or switched to a Group variation such as Grid, Row or Stack. Transforming to other blocks or block variations has the potential to mutate the entire block structure, including its internal content.

The purpose of “contentOnly” is to allow editing of a block’s content, for example, its internal headings, text or images.

Props to @ramonopoly for writing the dev note.


Top level contentOnly locked blocks now surface block styles in the blocks inspector

Block’s style variations are now surfaced for contentOnly locked groups. This way styles can still be applied cohesively across the group of blocks.

Props to @ntsekouras for writing the dev note.


Support for async actions and filters in @wordpress/hooks

The @wordpress/hooks package has a couple of new functions for running async actions and filters, allowing pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party authors to conveniently register async (promise-based) handlers and make sure that they are run in series, one after another, waiting until the previous async handler finishes.

You can register an async function as an action or a filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. handler:

import { addAction, addFilter } from '@wordpress/hooks';

addAction( 'action', 'handler', async () => {
  await doSomethingAsync();
} );

addFilter( 'filter', 'handler', async ( value ) => {
  return await modifyValueAsync( value );
} );

In the filter handler, the value is always a synchronous value (not a promise) and the handler function returns a promise that resolves to an updated value.

Then you can run the filter with a newly introduced applyFiltersAsync function:

import { applyFiltersAsync } from '@wordpress/hooks';

const filteredValue = await applyFiltersAsync( 'filter', initialValue );

and similarly you can also run an action with the new doActionAsync function:

import { doActionAsync } from '@wordpress/hooks';

await doActionAsync( 'action' );

The runner functions make sure that handlers are run after each other, in a series. And that when a handler throws an error (or returns a rejected promise), the whole run is aborted and further handlers are not called. The error is propagated and becomes the result of the entire applyFiltersAsync/doActionAsync call.

Props to @jsnajdr for writing the dev note.


New filters to customize and extend behavior of post save

There are two new hooksHooks In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same. (one filter and one action) that allow plugin authors to customize and extend what happens when a post is being saved.

First, there is the (async) editor.preSavePost filter that receives two arguments:

  • edits is an object that contains the id of the saved post and the modified attributes. The filter can modify the edits and it will be this modified object that will be sent to the server as the payload of the save POST request. The filter can also abort the save, e.g., when some custom validation fails, by throwing an error or returning a rejected promise.
  • options is a read-only second argument that contains an isAutosave (boolean) field that lets the filter distinguish between regular saves and autosaves, and also an isPreview field that indicated whether the saved post is a draft intended to be previewed.

The handler can be async, as the filter is being applied using the new applyFiltersAsync function:

addFilter( 'editor.preSavePost', 'handler', async ( edits, options ) => {
  if ( ! await customValidation( edits ) ) {
    throw new Error( 'validation failed' );
  }
  return edits;
} );

The second new hook is the (async) editor.savePost action which is run after the post is saved and lets you perform additional work after the save. For example, the GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ post editor itself uses this action to save legacy metaboxes for the post. This action receives one argument, the options object, the same one as the editor.preSavePost action also receives.

Props to @jsnajdr for writing the dev note.


New ReactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org/. Hooks

New useEvent utility in @wordpress/compose

The new useEvent utility creates a stable callback that has access to the latest state (as opposed to a useCallback call with an empty dependency array). This is useful to “untrack” dependencies in a callback that is called within event handlers or effects. It cannot be called at render time.

This is a common pattern in React, and it’s even being considered as a core React feature (see the RFC). More context can be found in this popular issue in the React repository.

Here’s an example:

 function Component( props ) {
   const onClick = useEvent( props.onClick );
   useEffect( () => {
     onClick();
     // Won't trigger the effect again when `props.onClick` is updated.
   }, [ onClick ] );
   // Won't re-render `Button` when `props.onClick` is updated (if `Button` is
   // wrapped in `React.memo`).
   return <Button onClick={ onClick } />;
 }

Props to @daniguardiola for writing the dev note.


New useResizeObserver hook in @wordpress/compose

The new API and behavior of useResizeObserver is meant as a thin wrapper for the browser-native ResizeObserver API, which enables more use cases and better composition. The previous API is still supported, though it is considered legacy and deprecated.

Now, you must pass a callback as the first argument to the hook which is forwarded to the ResizeObserver constructor. The hook returns a setter that must be passed as a callback ref to the target element, or called in an effect in advanced use-cases. Additional options for the internal ResizeObserver.observe call can be passed as the second argument.

Here’s an example:

const setElement = useResizeObserver(
  ( resizeObserverEntries ) => console.log( resizeObserverEntries ),
  { box: 'border-box' }
);
<div ref={ setElement } />;

// The setter can be used in other ways, for example:
useLayoutEffect( () => {
  setElement( document.querySelector( `data-element-id="${ elementId }"` ) );
}, [ elementId ] );

Props to @daniguardiola for writing the dev note.


New useStyleOverride hook in @wordpress/block-editor

wp.blockEditor.useStyleOverride is a new editor API that can be used to add content styling (renders inside the content iframeiframe iFrame is an acronym for an inline frame. An iFrame is used inside a webpage to load another HTML document and render it. This HTML document may also contain JavaScript and/or CSS which is loaded at the time when iframe tag is parsed by the user’s browser.).

import { useStyleOverride } from '@wordpress/block-editor';

function SomeComponent() {
    useStyleOverride( { css: 'p{color:red}' } );

    return (...);
}

Props to @ellatrix for writing the dev note.


General Editor UI/UXUX User experience improvements

Updates to the Query LoopLoop The Loop is PHP code used by WordPress to display posts. Using The Loop, WordPress processes each post to be displayed on the current page, and formats it according to how it matches specified criteria within The Loop tags. Any HTML or PHP code in the Loop will be processed on each post. https://codex.wordpress.org/The_Loop. block

WordPress 6.7 brings a number of improvements and changes to the Query Loop block.

The controls to set how many items to display, the offset and max number of pages, have been moved from the block toolbar to the Inspector Sidebar. This change standardizes the location of all of the query controls in the UI, making it much easier to find them.

Query Loop blocks that are inserted into single page, post, or custom post typeCustom Post Type WordPress can hold and display many different types of content. A single item of such a content is generally called a post, although post is also a specific post type. Custom Post Types gives your site the ability to have templated posts, to simplify the concept. now no longer display the Query Type control and defaults to querying posts. When using the block on templates, the Posts per page setting is now inherited by the block.
A new filter was added to allow filtering by Post Formats and the Posts List variation was removed due to some inconsistencies in how the block would receive defaults.

Props to @welcher for writing the dev note.


New Font Size Presets UI

A new UI feature has been introduced in the Global Styles section of the editor, allowing users to add, edit, and remove font size presets.

A font size preset is a predefined font size that can be reused throughout the site via the font size picker. This enhancementenhancement Enhancements are simple improvements to WordPress, such as the addition of a hook, a new feature, or an improvement to an existing feature. provides a more user-friendly way to manage font size options, which were previously only accessible via the manual edition of theme.jsonJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. file. Users can now modify preset names, base sizes, enable or disable the default fluid behavior, and customize the minimum and maximum values for fluid font size presets directly from the UI.

To access this interface, navigate to the Styles sidebarSidebar A sidebar in WordPress is referred to a widget-ready area used by WordPress themes to display information that is not a part of the main content. It is not always a vertical column on the side. It can be a horizontal rectangle below or above the content area, footer, header, or any where in the theme., then go to Typography → Font Sizes.

Props to @mmaattiiaass for writing the dev note.


New ‘human-diff’ Date Format Option

A new date format option has been introduced for the Post Date and Comment Date blocks, allowing users to display dates in a human-readable, relative format.

The human-diff format presents dates in a more intuitive way, such as 12 hours ago2 days ago, or a month ago. This enhancement provides a more user-friendly way to display date information, which can improve readability and engagement for readers.

To use this new format, users can select the option that displays an example of the relative time format (e.g., “2 years ago”) from the Choose a format dropdown in the block settings panel for both the Post Date and Comment Date blocks. The feature utilizes WordPress’s built-in human_time_diff() function to calculate and display the relative time difference.

To access this option:

  1. Insert a Post Date or Comment Date block in your post or page.
  2. In the block’s settings panel, locate the Choose a format option.
  3. Click on the dropdown to reveal various date format options.
  4. Select the option that shows an example of the relative time format (e.g., “2 years ago”).

Props to @amitraj2203 for writing the dev note.


New preference to disable the “Choose a pattern” modal when adding pages

A pattern selector modal appears when creating pages. The modal will reappear so long as the the page content is empty.

In 6.7, this feature can be toggled on and off through a new “Show starter patterns” toggle switch, located in the “Interface” section of editor preferences.

Props to @ramonopoly for writing the dev note.


New style engine util for compiling CSSCSS Cascading Style Sheets. custom vars

WordPress 6.7 introduces a new public utility, getCSSValueFromRawStyle(), exported from the style engine package. This function is useful for processing or manipulating Global Styles data, handling both standard CSS and preset string values.

Example usage:

// Example 1: Standard CSS remains unchanged.
getCSSValueFromRawStyle('min(40%, 400px)');
// Returns: 'min(40%, 400px)'


// Example 2: CSS variable for preset color.
getCSSValueFromRawStyle('var:preset|color|wordpress-blue');
// Returns: 'var(--wp--preset--color--wordpress-blue)'

Props to @aaronrobertshaw for writing the dev note.


Read access to Global Styles data

In WordPress 6.7, users with the edit_posts capability will gain permission to access raw Global Styles data. This change supports recent improvements to block style variations and upcoming UI enhancements in displaying style inheritance.

Props to @aaronrobertshaw for writing the dev note.


Other Updates

Media & Text block now always uses img tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.) instead of background image

As of #64981, the Media & Text block now uses an img element instead of using CSS background-image when the “Crop image to fill” option is enabled, removing the last usage of background-image in this block. This means that, when rendering the post, all the usual performance benefits of using image elements will now be applied, such as having the image load lazily when appropriate, and letting the browser choose the most appropriate image size from the list of generated sizes.

Props to @sergiomdgomes for writing the dev note.


block.json: variations field can now be set to name of PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher file that generates block variations

Previously, the variations field in a block.json file could be used to provide a static list of the block’s variations (i.e., an array). Alternatively, the block’s variation_callback could be set during server-side block registration to point to a PHP function to generate those variations.
As of WordPress 6.7, it is also possible to set the variations field to a string, which will then be interpreted as the filename of a PHP file that generates the variations (akin to how the render field works):

{ "variations": "file:./variations.php" }

Refer to the docs for more information.

Props to @bernhard-reiter for writing the dev note.


Decreased spacing between Block Inspector controls

(This dev note was added on October 24th.)

The standard spacing between controls in the Block Inspector has been reduced to 16px (was previously 24px).

Extenders will likely see the majority of their controls adhereing automatically to the new spacing, due to a Block Inspector style setting bottom margins on all components built with BaseControl. However, if you have a control that is not built with BaseControl, or have overridden the bottom margin styles for whatever reason, you may want to adjust your custom spacing so it is consistent with the new 16px spacing.

Props to @0mirka00 for writing the dev note.


Props to @fabiankaegy for review.

#6-7, #dev-notes, #dev-notes-6-7