Getting ready for PHP 8.4: some code changes landing in 6.7

Earlier in the 6.7 cycle, @hellofromtonya and @jrf made a number of commits to get the codebase ready for PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher 8.4.

Here are a few of the most notable, starting with PR #7376:

Fix trigger_error() with E_USER_ERROR deprecation in wp_trigger_error().

PHP 8.4 deprecates the use of trigger_errror() with E_USER_ERROR as the error level, because this way of creating a Fatal Error brings its own set of pitfalls (finally blocks not executing, destructors not executing). instead, the recommendation is to use an exception or do a hard exit.

WP has its own wp_trigger_error() function, which under the hood calls trigger_error(). If the WP version of the function passes E_USER_ERROR as the $error_level, it too will hit the PHP 8.4 deprecation.

Now, there were basically three options:

  • Silence the deprecation until PHP 9.0 and solve this properly then. But that wouldn’t even really buy time, let alone solve the problem. That’s because before PHP 8.0, error silencing goes too far, applying to all errors. And starting with PHP 8.0, silencing doesn’t apply to fatal errors.
  • Use exit($status) when wp_trigger_error() is called with E_USER_ERROR. But that would make the code untestable. It would also disable handling of these errors with custom error handlers. Neither of those are acceptable outcomes.
  • Throw an exception when wp_trigger_error() is called with E_USER_ERROR. This is a fairly elegant solution, and it carries the least BC-breaking impact. There is some chance the error gets caught in a try-catch, but that’s not actually a bad thing. It’s likely to only happen for errors that can be worked around—and that’s actually an unexpected bonus.

This commit implements the third option, which:

  • Introduces a new WP_Exception class.
  • Starts using WP_Exception in the wp_trigger_error() function when the $error_level is set to E_USER_ERROR.

This change is covered by pre-existing tests, which have been updated to expect the exception instead of a PHP error.

Why not use WP_Error?

Well, for one, this would lead to completely different behavior (BC).

WP_Error doesn’t extend Exception. So the program would not stop. Instead, it would keep running, which is a much bigger breaking change and carries security risks. WP_Error also doesn’t natively trigger displaying/logging of the error message, so it would still need an exit with the error message, bringing us back to point 2 above.

Introducing WP_Exception delivers (essentially) the same behavior. It retains the fatal error and error message displaying/logging behaviors. Plus it introduces a base Exception class, which future exception classes can extend over time.

References:

Follow-up to [56530].

Several other commits, from #62061, also help get the codebase ready for 8.4. You can find them after an exhaustive introduction to the changes coming to the new PHP.

Here’s the list, by GH pull request:

PR #7369 WP_HTML_Processor: fix implicitly nullable parameter [1] in the WP_HTML_Processor class.

PR #7370 fixes the deprecation of  xml_set_object() for the TestXMLParser helper utility.

PR #7371 fixes the same deprecation for the IXR_Message::parse() method.

PR #7372  fixes the deprecation for the AtomParser::parse() method.

PR #7373 fixes it for the  MagpieRSS::__construct() method.

PR #7374 replaces the call to the deprecated mysqli_ping() with the DO 1 query.

PR #7375 adds a simple test for the Text_Diff::_check() method—and fixes the bugbug A bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority. that test finds!

PR #7377 adds testing for PR #7376.

PR #7379 Build/Test Tools: Enable running all the tests on PHP 8.4 once there’s a stable release of Xdebug 3.4.0.

Props @hellofromtonya for the commit message that formed the basis of this 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. and to @peterwilsoncc for review and collaboration.

#6-7, #dev-notes, #field-guide

Internationalization improvements in 6.7

Various internationalization (i18n) improvements are in WordPress 6.7, and this developers note focuses on these.

Determining whether a translationtranslation The process (or result) of changing text, words, and display formatting to support another language. Also see localization, internationalization. exists

Sometimes it can be useful to know whether a translation already exists for in memory without having to first load the translation for the given text domain. The new has_translation() function allows for exactly that.

See #52696 / [59029] for more details.

Sending emails in the adminadmin (and super admin)’s localeLocale A locale is a combination of language and regional dialect. Usually locales correspond to countries, as is the case with Portuguese (Portugal) and Portuguese (Brazil). Other examples of locales include Canadian English and U.S. English.

Back in version 4.7, WordPress added the ability for users to set their preferred locale. When sending emails to a user, they are always sent in that locale, and everyone else receives the email in the site’s locale.

Now, WordPress 6.7 is going a step further: every time an email is sent to the administrator email address (admin_email), WordPress checks if a user with the same email address exists. If so, the email is sent in that user’s locale.

See #61518 / [59128] for more details.

Warnings if translations are loaded too early

WordPress now warns developers if they are loading translations too early in a 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 or theme, before the current user is known. Existing functions like load_plugin_textdomain() and load_theme_textdomain() were updated to defer the actual loading to the existing just-in-time translation logic in coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress.. This reduces the likelihood of triggering the warning, and even improves performance in some situations by avoiding loading translations if they are not needed on a given page.

Reminder: if your plugin or theme is hosted on WordPress.orgWordPress.org The community site where WordPress code is created and shared by the users. This is where you can download the source code for WordPress core, plugins and themes as well as the central location for community conversations and organization. https://wordpress.org/ and is still using load_*_textdomain(), you can remove this call. Since WordPress 4.6, plugins and themes no longer need load_plugin_textdomain() or load_theme_textdomain(). WordPress automatically loads the translations for you when needed. If you still support older WordPress versions or do not host your plugin/theme on WordPress.org, move the function call to a later hook such as init.

When attempting to load translations before after_setup_theme or init, WordPress tries to load the current user earlier than usual, without giving other plugins a chance to potentially hook into the process. It also prevents any plugins from filtering translation calls, e.g. for switching the locale or file location. Hence the addition of this warning to call out this unexpected behavior.

See #44937, [59127], and [59157] for more details.

Your plugin might be _doing_it_wrong() if you for example directly call get_plugin_data() (which attempts to load translations by default) or __() without waiting for the init hook. Here is a common example that was found in an actual plugin that was fixed:

/**
 * Plugin Name: Awesome Plugin
 */

function myplugin_get_version() {
	require_once ABSPATH . 'wp-admin/includes/plugin.php';
	// Prevent early translation call by setting $translate to false.
	$plugin_data = get_plugin_data( __FILE__, false, /* $translate */ false );
	return $plugin_data['Version'];
}

define( 'MYPLUGIN_VERSION', myplugin_get_version() );

If you do not explicitly set $translate set to false when calling get_plugin_data(), the function translates the plugin metadata by default. Since this plugin just needs the version number, there is no need for translating any of the other fields.

Another example:

/**
 * Plugin Name: Awesome Plugin
 */

class My_Awesome_Plugin {
	public $name;
	public function __construct() {
		// This triggers just-in-time translation loading
		$this->name = __( 'My Awesome Plugin', 'my-awesome-plugin' );

		// ... do something
	}
}

// This immediately instantiates the class, way before `init`.
$myplugin = new My_Awesome_Plugin();

Here, a class is immediately instantiated in the main plugin file, and code within the class constructor uses a translation function. This can be avoided by deferring the class instantiation until after init, or deferring the translation call until later when it is actually needed.

If your plugin is affected by this warning, you can use code like follows to find out the code path that triggers it:

add_action(
	'doing_it_wrong_run',
	static function ( $function_name ) {
		if ( '_load_textdomain_just_in_time' === $function_name ) {
			debug_print_backtrace();
		}
	}
);

Developer tools such as Query Monitor are also helpful in situations like this.


Props to @ocean90, @fabiankaegy for review.

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

Block Bindings: Improvements to the Editor Experience in 6.7

WordPress 6.7 introduces various improvements to the 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. Bindings 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. and the built-in post metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. source, including a default UIUI User interface and the beginnings of a public editor API.

For an introduction to Block Bindings, first introduced in WordPress 6.5, see the prior dev note.

New Block Bindings UI

Compatible blocks — which currently include Heading, Paragraph, Image, and Button — have received a new default UI for viewing bindings.

Called Attributes, you can find the new tool panel in block settings whenever a compatible block is selected in either the post or site editor.

The panel shows active bindings on the current block. If there are any post meta available, the panel is also interactive, allowing you to bind attributes to those custom fields via the built-in post meta block bindings source.

Currently, there are two limitations to the panel:

  1. It will not allow users to bind attributes to custom sources just yet. 

    Bindings to custom sources, which can be added via the code editor or other programmatic means, will still display in the panel — they just can’t be connected via the UI for the moment in WordPress 6.7.

    A flexible API for connecting custom sources to the Attributes panel is currently under development and is planned for public release in the future.

    For now, the rollout of that API has started with the built-in post meta source to allow time for gathering feedback.
  2. For each attribute, the panel will only show custom fields that match its data type. For example, an attribute of type string or rich-text can only be connected to a custom fieldCustom Field Custom Field, also referred to as post meta, is a feature in WordPress. It allows users to add additional information when writing a post, eg contributors’ names, auth. WordPress stores this information as metadata. Users can display this meta data by using template tags in their WordPress themes. of type string, and an attribute of number can only be connected to another number.

New Post Meta Label Attribute

To improve how custom fields appear in the editor UI, a new label attribute has been created for post meta, which can be defined during registration:

If specified, the label will render in place of the meta key in the Attributes panel — in this example, the label would replace movie_director. The label will also render under certain circumstances in other parts of the editor, including as a placeholder for Rich Text if a block is bound to the post meta source and a default value is undefined.

Usage In Custom Post Templates

One of the primary use cases for Block Bindings is to assist in creating templates for custom post types. Given a 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. called movie, for example, one can define how custom fields for that post type will render, such as via connected images, headings, paragraphs, and buttons.

Here is an example of how one could use connected blocks to create a layout:

One can override the content in connected blocks for each instance of the custom post type, a much simpler and more flexible way of creating layouts than in the past — all without needing to create custom blocks.

Default Permissions

Accompanying this UI is a new canUpdateBlockBindings editor setting, used to determine whether the UI is interactive for users or not.

By default, this editor setting is set to a new edit_block_binding capability, which maps to a user’s ability to either:

  1. Edit the post type (in the post editor), or
  2. Edit the theme options (in the site editor)

This means that the setting is by default set to true for administrators, and false for other users.

This default setting can be overridden using the block_editor_settings_all 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. and modifying $editor_settings['canUpdateBlockBindings'] as follows:

function my_plugin_override_can_update_block_bindings( $settings ) {
    $settings['canUpdateBlockBindings'] = true;
    return $settings;
}
add_action( 'block_editor_settings_all', 'my_plugin_override_can_update_block_bindings' );

New Public Editor APIs

Several functions have been exposed to enable the use of block bindings in the editor.

Registration API

Source Bootstrapping 

As part of the new editor API, Block Bindings will automatically register custom sources defined on the server with bootstrapped values in the editor. This will allow existing sources registered using just the server APIs to render in the UI.

This means that any sources already registered using the server APIs, available since 6.5, will appear in the UI, at least minimally, without any action required.

For example, given the following server registration and block markup…

Server Registration
function my_plugin_register_block_bindings_post_attributes() {
    register_block_bindings_source(
        'my-plugin/post-attributes',
        array(
            'label'              => _x( 'Post Attributes', 'block bindings source', 'my-plugin' ),
            'get_value_callback' => 'my_plugin_block_bindings_post_attributes_get_value',
            'uses_context'       => array( 'postId' ),
        )
    );
}
add_action( 'init', 'my_plugin_register_block_bindings_post_attributes' );

function my_plugin_block_bindings_post_attributes_get_value( array $source_args, $block_instance ) {
    $allowed_fields = array( 'title', 'excerpt' );
    if ( ! in_array( $source_args['key'], $allowed_fields ) ) {
        return null;
    }
    $post = get_post( $block_instance->context['postId'] );
    return $post->{'post_' . $source_args['key']};
}
Block Markup
<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"my-plugin/post-attributes","args":{"key":"title"}}}}} -->
<p></p>
<!-- /wp:paragraph -->

…the source will get registered in the editor with the source’s name my-plugin/post-attributes, label, and uses_context values. This is enough for the UI to render as follows:

In this case, however, the bound paragraph in the block canvas will simply show the source label and will not be dynamic. Further customization of the editor experience requires using the new editor registration functions, detailed in the next section.

Editor Registration

The following functions have been exposed to allow customization of the editor experience:

  • registerBlockBindingsSource: Registers a source on the client (using this function will override the bootstrapped registration).
  • unregisterBlockBindingsSource: Unregisters an existing source.
  • getBlockBindingsSource: Gets a specific registered source and its properties.
  • getBlockBindingsSources: Gets all the registered sources in the client.

These are based on other registration APIs like block types, block variations, or block collections.

Source Properties

Registered sources in the client can include the following properties:

  • name: The unique and machine-readable name.
  • label: Human-readable label. Will overwrite preexisting label if it has already been registered on the server.
  • usesContext: Array of context needed by the source only in the editor. Will be merged with existing uses_context if it has already been registered on the server.
  • getValues: Function to get the values from the source. It receives select, clientId, context, and the block bindings created for that specific source. It must return an object with attribute: value. Similar to getBlockAttributes.
  • setValues: Function to update multiple values connected to the source. It receives select, clientId, dispatch, context, and the block bindings created for that specific source, including the new value. Similar to updateBlockAttributes.
  • canUserEditValue: Function to let the editor know if the block attribute connected should be editable or not. It receives select, context, and the source arguments.
Example Usages 
Register a Block Bindings Source

Building on the example server registration, use the following JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/. to register in the editor by enqueuing on the enqueue_block_editor_assets hook:

import { registerBlockBindingsSource } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { store as coreEditorStore } from '@wordpress/editor';

const allowedAttributes = [ 'title', 'excerpt' ];

registerBlockBindingsSource( {
    name: 'my-plugin/post-attributes',
    usesContext: [ 'postType' ],	
    getValues( { select, bindings } ) {
        const values = {};
        for ( const [ attributeName, source ] of Object.entries( bindings ) ) {
            if ( allowedAttributes.includes( source.args.key ) ) {
                values[ attributeName ] = select( coreEditorStore ).getEditedPostAttribute( source.args.key );
            }
        }
        return values;
    },
    setValues( { dispatch, bindings } ) {
        const newValues = {};
        for ( const [ attributeName, source ] of Object.entries( bindings ) ) {
            if ( allowedAttributes.includes( source.args.key ) ) {
                newValues[ source.args.key ] = source.newValue;
            }
        }
        if ( Object.keys( newValues ).length > 0 ) {
            dispatch( coreEditorStore ).editPost( newValues );
        }
    },
    canUserEditValue( { context, args } ) {
        return allowedAttributes.includes( args.key ) && 'post' === context.postType;
    },
} );

To connect example blocks to the source, go to the post editor, open the code editor, and use the following markup:

<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"my-plugin/post-attributes","args":{"key":"title"}}}}} -->
<p></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"my-plugin/post-attributes","args":{"key":"excerpt"}}}}} -->
<p></p>
<!-- /wp:paragraph -->

For a more in-depth example of how these properties can be defined in a real-world scenario, see the registration for the built-in post meta source.

Unregister a Block Bindings Source
import { unregisterBlockBindingsSource } from '@wordpress/blocks';

unregisterBlockBindingsSource( 'plugin/my-custom-source' );
Get All Block Bindings Sources
import { getBlockBindingsSources } from '@wordpress/blocks';

const registeredSources = getBlockBindingsSources();
Get a Block Bindings Source
import { getBlockBindingsSource } from '@wordpress/blocks';

const blockBindingsSource = getBlockBindingsSource( 'plugin/my-custom-source' );

Note: If desired, sources may be registered only on the client and not on the server at all. This could be useful for creating forms in the adminadmin (and super admin), or otherwise using bindings to interact with other parts of WordPress, or other dynamic data.

Block Bindings Utils

The useBlockBindingsUtils hook returns helper functions to modify the metadata.bindings attribute. The hook accepts an optional clientId argument. If the clientId is not specified, the helper functions will execute in the current block edit context.

Right now, the helpers include:

  • updateBlockBindings: This works similarly to updateBlockAttributes. It can be used to create, update, or remove specific connections.
  • removeAllBlockBindings: This is used to remove all existing connections in a block.

Example usage

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

const { updateBlockBindings, removeAllBlockBindings } = useBlockBindingsUtils();

// Updates bindings for url and alt attributes.
updateBlockBindings( {
    url: {
        source: 'core/post-meta',
        args: {
            key: 'url_custom_field',
        },
    },
    alt: {
        source: 'core/post-meta',
        args: {
            key: 'alt_custom_field',
        },
    },
} );

// Removes all bindings set for the block.
removeAllBlockBindings();

Used internally by the default UI for the post meta source and pattern overrides, these utils can be useful in building custom UI for other sources.

For more examples of how these functions are used in practice by the built-in UI, see the calls to updateBlockBindings and removeAllBlockBindings.

New Server Filter

A block_bindings_source_value filter has been introduced to allow for overriding of the value returned by a source in a bound block. It takes the following arguments:

  • value: Value returned by the source.
  • name: Name of the source.
  • source_args: Arguments passed to the source.
  • block_instance: The bound block.
  • attribute_name: The connected attribute in the bound block.
function modify_block_bindings_source_value( $value, $name, $source_args, $block_instance, $attribute_name ) {
    if ( 'core/post-meta' === $name && 'movie_runtime' === $source_args['key'] ) {
        return $value . ' minutes';
    }
    return $value;
}
add_filter( 'block_bindings_source_value', 'modify_block_bindings_source_value', 10, 5 );

Conclusion

The developers behind Block Bindings are always happy to hear feedback. Please feel free to share bugs, feature requests, or other thoughts by creating issues on GithubGitHub GitHub is a website that offers online implementation of git repositories that can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged be the repository owner. https://github.com/ or leaving a comment on this post.

Anyone can also follow and comment on Block Bindings development via the latest iteration, which is posted in the Block Bindings tracking issue at the beginning of each release cycle. Be sure to subscribe to the tracking issue for updates!

Lastly, if you’d like to help shape the roadmap for Block Bindings by sharing your use cases, feel free to post in Block Bindings discussions.

Props to @santosguillamot @gziolo @cbravobernal @greenshady @fabiankaegy and @welcher for their help compiling this post.

#6-7, #block-bindings, #dev-notes, #dev-notes-6-7

Developer Notes for Zoom Out in WordPress 6.7

Zoom Out in WordPress 6.7, introduces a new way to easily create and edit content using Patterns rather than lower-level, individual blocks.

Accessible via a toggle in the editor toolbar, when activated the canvas will “zoom out” providing users with a high level view of the content currently being edited. The inserter also automatically enables this new feature when the patterns tab is activated, allowing users to quickly and easily build and/or edit their Page or Template using pre-configured Patterns.

Note that whilst in this mode, blocks outside the “main content” of the current post will be non-editable. This allows users to focus on easily dealing with larger areas of content.

Theme Compatibility

To facilitate this feature, the Editor will attempt to detect the 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. which is acting as the “main content” of the current post type. This is achieved via a simple algorithm which optimises for detecting the Post Content (core/post-content) block, falling back to a Group with a tagName of main (i.e. the <main> HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. element).

 function getSectionRootBlock() { 
 	if ( renderingMode === 'template-locked' ) { 
 		return getBlocksByName( 'core/post-content' )?.[ 0 ] ?? ''; 
 	} 
  
 	return ( 
 		getBlocksByName( 'core/group' ).find( 
 			( clientId ) => 
 				getBlockAttributes( clientId )?.tagName === 'main' 
 		) ?? '' 
 	); 
 }

To maximise compatibility with this mode, Theme authors should update their templates to ensure their “main content” is wrapped with a Group block whose tagName attribute is configured as main. This can be found in the block’s 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. controls under Advanced. We recommend using a core/group as it is the most generic and flexible “sectioning element” in the editor.

Decoupling of Zoom Out mode from “zooming” the canvas

As part of this effort, contributors have also elected to decouple the scaling of the Editor canvas from the “Zoom Out” editor mode. This is largely in anticipation of future efforts around simplifying the editing experience. As a result, invoking zoom-out editor mode will not longer automatically scale the Editor canvas.

Further reading:

Props to @onemaggie, @andraganescu and @fabiankaegy for reviews.

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

New Plugin Template Registration API in WordPress 6.7

Since the introduction of 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. themes, theme authors have been able to create custom block templates. However, this possibility was limited to themes, leaving plugins without a straightforward way to register their own templates. To achieve similar functionality, plugins had to resort to complex methods, including hooking into multiple PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher filters, manually creating WP_Block_Template objects, and replicating internal WordPress logic.

WordPress 6.7 introduces a new 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. that will significantly simplify the process for plugins to register their own block templates. To enable this, two new functions have been introduced: register_block_template() for registering a block template and unregister_block_template() for unregistering it.

register_block_template( string $template_name, $args = array() ) accepts two parameters, that define how the template is registered:

  • $template_name: The name of the template in the form of plugin_uri//template_name (note that this requires a double //).
  • $args: An array of arguments for defining the template:
    • title: An internationalized title for the template.
    • description: An internationalized description of the template.
    • content: The default content (block markup) for the template when rendered in the editor or on the front end.
    • post_types: An array of post type slugs to make available to users as per-post custom templates.

For example, a 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 can register a template with the following snippet:


register_block_template( 'devblog-plugin-templates//my-template', [
	'title'   	=> __( 'Example', 'devblog-plugin-templates' ),
	'description' => __( 'An example block template from a plugin.', 'devblog-plugin-templates' ),
	'content' 	=> '
    	<!-- wp:template-part {"slug":"header","area":"header","tagName":"header"} /-->
    	<!-- wp:group {"tagName":"main"} -->
    	<main class="wp-block-group">
        	<!-- wp:group {"layout":{"type":"constrained"}} -->
        	<div class="wp-block-group">
            	<!-- wp:paragraph -->
            	<p>This is a plugin-registered template.</p>
            	<!-- /wp:paragraph -->
        	</div>
        	<!-- /wp:group -->
    	</main>
    	<!-- /wp:group -->
    	<!-- wp:template-part {"slug":"footer","area":"footer","tagName":"footer"} /-->'
] );

Once registered, the template will appear alongside all other templates in the Site Editor:

And, if needed, could later unregister it with:

unregister_block_template( 'devblog-plugin-templates//my-template' )

Plugins can also override templates from the WordPress template hierarchy, such as the archive page of a 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. or a specific author page.

Theme templates take priority over plugin-registered templates, allowing themes to override specific plugin templates just as they can with WordPress templates.

Currently, this API is limited to block templates and does not allow the registration of block template parts.

You can read more about this new feature in the following links:

Props to @aljullu for writing this 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.. And thanks to @fabiankaegy for reviewing

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

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

Auto Sizes for Lazy Loaded Images in WordPress 6.7

WordPress 6.7 adds sizes=”auto” for lazy-loaded images. This feature, which was recently added to the HTML specification, allows the  browser to use the rendered layout width of the image when selecting a source from the srcset list, since lazy loaded images don’t load until after the layout is known.

Background

Responsive image attributes, srcset and sizes were added in WordPress 4.4. Quoting 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. from that time:

To help browsers select the best image from the source set list, we also include a default sizes attribute that is equivalent to (max-width: {{image-width}}px) 100vw, {{image-width}}px. While this default will work out of the box for a majority of sites, themes should customize the default sizes attribute as needed using the wp_calculate_image_sizes 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..

Setting a default sizes value is important when choosing the right file to fetch from srcset, because it tells the browser what the intended layout of an image will be before the layout is known. Without any value, browsers will use the default 100vw value and assume the image is meant to fill the entire width of the viewport, resulting in many wasted bytes. The default value that has shipped with WordPress for many years ensures that the image layout is constrained by its width attribute. This helps, but in many cases is still not correct, since an image is likely layout constrained by the content width, or any blocks that they are nested within. 

Even though it is encouraged for themes to supply a more accurate sizes attribute value using the wp_calculate_image_sizes filter, doing so is challenging. Now that browsers are able to automatically apply the rendered layout to sizes for lazy-loaded images, the sizes value will be 100% correct, resulting in many fewer wasted bytes.

Implementation details

The HTML specification allows for lazy loaded images to omit sizes, explicitly set sizes=”auto”, or set sizes to a string that starts with "auto," followed by a valid source size list. In order to implement this as a progressive enhancementenhancement Enhancements are simple improvements to WordPress, such as the addition of a hook, a new feature, or an improvement to an existing feature. for browsers already supporting this feature, WordPress will prepend auto to the sizes attribute of content images during wp_filter_content_tags() and any image markup generated by wp_get_attachment_image(). This will cause browsers that don’t support the new auto value to fall back to the previous sizes list.

WordPress will only add auto to the sizes value if the image includes loading=”lazy”. Otherwise, browsers that support sizes=auto will fail to validate the sizes value and apply the default value of 100vw, which will cause larger than needed images to be selected from the srcset attribute. Any custom implementations that change the loading value of images after WordPress generates the markup should use the new wp_img_tag_add_auto_sizes() function to correct the sizes attribute.

Functions added

  • wp_img_tag_add_auto_sizes – adds auto sizes to an HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. img string.
  • wp_sizes_attribute_includes_valid_auto – tests whether auto already exists on an image to ensure it’s not added more than once.

Props to @flixos90 and  @fabiankaegy for feedback and editing.

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

Post Editor iframing with meta boxes in WordPress 6.7

After an effort to iframe the post editor, the presence of metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. boxes was a holdout condition that kept the editor content from loading in an 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. and made these benefits of the iframe unavailable:

  • Isolation of 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. and theme CSSCSS Cascading Style Sheets. from the editor UIUI User interface
  • Accuracy of media queries and viewport relative CSS units

Those benefits are important to support CSS reuse across the editor and front-end and generally ease block and theme development. It’s been an ongoing effort to bring them to the Post editor even when meta boxes are present yet it has taken a few attempts to determine how to adapt the interface to separate the meta boxes from the post content.

Now a split view is implemented that supports both editor content and meta boxes being visible together. This change ensures consistent WYSIWYGWhat You See Is What You Get What You See Is What You Get. Most commonly used in relation to editors, where changes made in edit mode reflect exactly as they will translate to the published page. experience between the Editor and front-end views. Additionally, it makes the meta boxes are more readily available than before and allows visually referencing any part of the post content while working with any meta box or vice versa.

Remaining exception to the iframe

For now, the last condition which prevents the iframe from always being used is whether any blocks are registered with their apiVersion less than 3. Yet even this condition may be removed in a future release and it already has an exception if your site uses 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/ 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 and a block based theme is active.

Edge cases and compatibility

Developers of plugins that add meta boxes should be wary of two things. One, the meta box container now clips overflowing elements so some popover-like UI such as dropdown menus will be cut off if they extend upward from the meta box container. However, if they’re rendered into a part of the DOM outside the container this won’t be an issue. Two, if your plugin also adds any rich text formats with editing UI that’s anchored to the text selection then their implementation has to be compatible with the iframe. This isn’t a new requirement but may have been overlooked for plugins only extending the Post editor.

Overflow clipping

To ensure this isn’t an issue any popover-like UI can be made to open downward in the meta box or by rendering the popover into a part of the DOM that is not within the meta box container. The latter, for instance, is how the Popover, Dropdown and DropDownMenu components from @wordpress/components work by default and using them will ensure there is no clipping even if the UI extends beyond the top of the meta box container.

Rich Text Format UI anchoring

This is may only be of concern if your plugin implemented custom code to anchor or position the UI. If your plugin is already using the recommended useAnchor hook available from @wordpress/rich-text everything should just work. In case it’s not, you can reference Gutenberg’s own link editing UI component for a canonical example of its usage.

Props @fabiankaegy and @faguni22 for review and proofreading.

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

Extending the Preview Dropdown Menu in WordPress 6.7

WordPress 6.7 introduces a new 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. that allows developers to extend the Preview dropdown menu in the post/page editor. 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 flexibility for 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 developers to integrate custom preview options seamlessly into the editor.

Background

Previously, the Preview dropdown was limited to default options. Plugins that wanted to add custom preview functionality had to implement complex workarounds or create separate UIUI User interface elements, leading to a fragmented user experience.

New API: PluginPreviewMenuItem

WordPress 6.7 introduces a new component, PluginPreviewMenuItem, which allows plugins to add custom items to the Preview dropdown menu.

How to Use

  1. Import the component:
import { PluginPreviewMenuItem } from '@wordpress/editor';
  1. Implement a custom menu item:
const CustomPreviewMenuItem = () => (
  <PluginPreviewMenuItem
    onClick={ () => {
      // Your custom preview logic
    } }
  >
    Custom Preview
  </PluginPreviewMenuItem>
);
  1. Register your plugin with the custom menu item:
import { registerPlugin } from '@wordpress/plugins';

registerPlugin( 'my-custom-preview', {
    render: CustomPreviewMenuItem,
} );

Key Features

  • Allows plugins to add menu items with custom titles and click handlers
  • Maintains the existing Preview dropdown structure while allowing for extensibility
  • Utilizes the existing ActionItem component from wordpress/interface
  • Implements a slot/fill pattern to inject custom menu items into the Preview dropdown

Use Cases

This API enables various publishing flows and tools, such as:

  • Custom format previews (e.g., AMP, social media shares)
  • Previewing content with different access restrictions or user roles
  • Specialized preview modes (e.g., dark mode, email format)

Considerations for Developers

  • The PluginPreviewMenuItem component is available in post, page, and site editors.
  • Custom preview items should be relevant to the content being edited.
  • Ensure that custom preview actions are performant and do not negatively impact the editor experience.

Future Enhancements

While this API provides immediate value, future enhancements may include:

  • Grouping of custom preview options
  • Support for custom preview canvas or sizes
  • Add support for item selection within custom groups

Take a look at this issue #65005 where these ideas are being discussed.

Feedback

We welcome your feedback on this new API. Please report any issues or suggestions in the Gutenberg repository. For more information, refer to the original pull request #64644.

Props @gziolo @youknowriad @simison, @fabiankaegy and @faguni22 for review and proofreading.

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

Updates to user-interface components in WordPress 6.7

This post lists notable changes to the @wordpress/components package for the WordPress 6.7 release

Table of Contents

  1. CustomSelectControl rewritten to Ariakit
  2. Reducing experimental APIs
    1. Stabilized Composite
    2. Stabilized Navigator
    3. Stabilized AlignmentMatrixControl
    4. Stabilized BoxControl
    5. Stabilized Button’s __experimentalIsFocusable prop
  3. Deprecated DimensionControl
  4. TimePicker: Time input can be used in isolation
  5. Stricter type checking in SelectControl
  6. Bottom margin styles are deprecated
  7. Modal: Buttons in headerActions should use “small” size

CustomSelectControl rewritten to Ariakit

The CustomSelectControl component has been completely rewritten using ariakit. Notably, this refactor enables the removal of the downshift library as a dependency of 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/ repository, causing a ~7.75 kB decrease for the @wordpress/components package bundle size.

While there are no breaking changes to the component public APIs, the refactor also allowed us to make a few improvements to the component:

  • the trigger button has the combobox role instead of button, in line with the WAI-ARIA specs;
  • the __experimentalShowSelectedHint and options[]. __experimentalHint props have been unprefixed and stabilized;
  • the select popover has a new entrance animation when opened, in line with other components;
  • while the select popover’s max-height hasn’t changed, the popover’s height adapts to the available space, without causing extra overflow on the page;
  • item hints can now wrap to a separate row from the item’s content when there isn’t sufficient space to render on the same line;
  • item internal padding now matches the trigger button padding for better visual consistency.

For more information visit #63258, and #63248(top)

Support disabled ToggleGroupControl options

The ToggleGroupControlOption and ToggleGroupControlOptionIcon components can now be marked as disabled via the newly added disabled prop. While disabled, an option cannot be selected by the end user.

For more information visit #63450(top)

Reducing experimental APIs

A few components have been stabilized or deprecated as part of an ongoing effort to progressively reduce the number of experimental APIs exported from the @wordpress/components package.

Stabilized Composite

Following the rewrite of the __unstableComposite (& related) components from ariakit to reakit in the WordPress 6.5 release, the 6.7 release introduces a new, stable version for the Composite component.

The new Composite component offers a more complete and versatile way to implement low-level composite widgets, and its APIs are more consistent with the rest of the @wordpress/components package.

import { Composite } from '@wordpress/components';

//...

<Composite>
  <Composite.Item>Item one</Composite.Item>
  <Composite.Item>Item two</Composite.Item>
  <Composite.Item>Item three</Composite.Item>
</Composite>

For more information on the component’s APIs and other usage examples, please refer to the Storybook page.

Finally, the __unstableComposite (& related) components have been marked as deprecated.

For more information visit #63569(top)

Stabilized Navigator

The legacy set of __experimentalNavigator* APIs is deprecated and should instead be imported as Navigator. All of the sub-components are also available via the Navigator namespace.

Moreover, the __experimentalNavigatorToParentButton component and the goToParent() method available via the __experimentalUseNavigator hook are deprecated, and they now behave identically to the __experimentalNavigatorBackButton and the goBack() method.

To recap:

  • __experimentalNavigatorProvider => Navigator
  • __experimentalNavigatorScreen => Navigator.Screen
  • __experimentalNavigatorButton => Navigator.Button
  • __experimentalNavigatorBackButton => Navigator.BackButton
  • __experimentalNavigatorToParentButton => Navigator.BackButton
  • __experimentalUseNavigator => useNavigator

For more information visit #64613(top)

Stabilized AlignmentMatrixControl

The __experimentalAlignmentMatrixControl component can now be imported as AlignmentMatrixControl.

The legacy __experimentalAlignmentMatrixControl export is marked as deprecated.

For more information visit #60913(top)

Stabilized BoxControl

The __experimentalBoxControl component can now be imported as BoxControl.

The legacy __experimentalBoxControl export is marked as deprecated.

For more information visit #65469(top)

Stabilized Button‘s __experimentalIsFocusable prop

The Button component had a __experimentalIsFocusable prop to keep the button focusable when disabled. This prop is now stabilized and renamed to accessibleWhenDisabled. (Existing usages of __experimentalIsFocusable will continue to work indefinitely.)

In most cases, it is recommended to set this to true. Disabling a control without maintaining focusability can cause accessibilityAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both “direct access” (i.e. unassisted) and “indirect access” meaning compatibility with a person’s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility) issues, by hiding their presence from screen reader users, or by preventing focus from returning to a trigger element.

Learn more about the focusability of disabled controls in the WAI-ARIA Authoring Practices Guide.

For more information visit #62282(top)

Deprecated DimensionControl

The DimensionControl component is now marked as deprecated and scheduled for removal in the WordPress 7.0 release.

Usages of DimensionControl can be replaced with SelectControl and CustomSelectControl, passing an array of dimension options to the components.

For more information visit #64951(top)

TimePicker: Time input can be used in isolation

The time input of the TimePicker component can now be used in isolation as <TimePicker.TimeInput />. In this case, the value will be passed as an object in a 24-hour format ({ hours: number, minutes: number }).

For more information visit #60613(top)

Stricter type checking in SelectControl

In TypeScript codebases, SelectControl will now be able to type-check whether the value type matches in the value, options, and onChange props. See detailed examples in the full dev note.

For more information visit #64069(top)

Bottom margin styles are deprecated

A number of UIUI User interface components currently ship with styles that give them bottom margins. This can make it hard to reuse them in arbitrary layouts, where you want different amounts of gap or margin between components.

To better suit modern layout needs, we have gradually been deprecating these margins. A deprecation begins with an opt-in period where you can choose to apply the new margin-free styles on a given component instance. Eventually in a future version, the margins will be completely removed.

Continuing the effort started in previous releases, for the WordPress 6.7 release we will start logging deprecation warnings for the following components if they are not yet opting into the new margin-free styles:

  • BaseControl
  • CheckboxControl
  • ComboboxControl
  • DimensionControl
  • FocalPointPicker
  • FormTokenField
  • RangeControl
  • SearchControl
  • SelectControl
  • TextControl
  • TextareaControl
  • ToggleControl
  • ToggleGroupControl
  • TreeSelect

To start opting into the new margin-free styles, set the __nextHasNoMarginBottom prop to true.

<SelectControl
  options={ selectOptions }
  value={ selectValue }
  label={ __( 'Label' ) }
  onChange={ onSelectChange }
  __nextHasNoMarginBottom={ true }
/>

For more information visit #39358(top)

The close button in the Modal component is now using the “small” Button size (currently 24px), down from the 36px default size in the old sizing scheme.

If you are using the headerActions prop to inject buttons beside the close button, we recommend you also use the “small” Button size variant to match.

<Modal
  headerActions={ <Button icon={ fullscreen } label="Fullscreen mode" size="small" /> }
/>

For more information visit #65131(top)

Props to @mirka for the help in writing these 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..

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