New Feature: The Block Bindings API

WordPress 6.5 is introducing a new way of extending blocks that substantially reduces the custom code needed to integrate different kinds of data in 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. editor.

This can now be done through the new Block 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..

What is the Block Bindings API?

Given a coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. block, rather than displaying a user’s inline written content inside of it, imagine wanting to populate that block with data from a particular source instead. For example, the post metadata or custom PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher logic. What would be the process for doing that?

Screenshot showing a heading and paragraph in the Gutenberg editor, with a large red arrow pointing to the paragraph. The paragraph reads: "How would you replace this sentence with data from somewhere else?"

This is actually a trick question: In previous versions of WordPress, you were unable to do this with 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/’s core blocks — it would instead require creating a custom block with particular logic for reading from the source in question. But this is no longer the case.

With the Block Bindings API, you can now bind core blocks to read from different sources without needing to write custom block boilerplate — this means it is possible to bind a Paragraph to read from a post’s metadata, or a Heading to read from 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’s PHP logic, all without needing to deal with ReactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org/., block registration, and other particulars of writing custom blocks from scratch for each new source you want to read from.

This initial release of the Block Bindings API in WordPress 6.5 is a big step towards simplifying the process of extending the editor and expanding the capabilities of blocks. Under the hood, the API already powers a showcase feature being shipped in WordPress 6.5 alongside it: Connecting core blocks to custom fields in the post metadata.

Using the same functionality, as an advanced use case, it is also possible to define and have blocks read from custom sources — more on that briefly below.

Note: For a more detailed walkthrough on creating and using Block Bindings than can be related in this brief 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., see the Introducing Block Bindings tutorial from the WordPress Developer Blogblog (versus network, site).

How do block bindings work?

Overview

Before getting into the rich functionality Block Bindings can enable via custom sources, this section will first review how the API works in general, then detail how to bind core blocks to custom fields in the post metadata.

The following table shows the current compatible blocks and attributes that can be bound: 

Supported BlocksSupported Attributes
Imageurl, alt, title
Paragraphcontent
Headingcontent
Buttonurl, text, linkTarget, rel

While the list of compatibility is short for now, this already enables a wide range of use cases, and support for the rest of the core blocks, as well as custom blocks, is planned for the future.

To use Block Bindings, you would specify that these attributes should be read from particular registered sources using the block markup; the logic for those sources would then be executed when rendering on the frontend.

Upon being bound, editing of the attribute in question will be locked and indicators will appear in the editor to signal that the binding has been created.

Screenshot of the Gutenberg editor; a paragraph is selected and there are icons in the block toolbar, as well as a purple outline around the paragraph, declaring the block as bound.

Specifically, here is how to make use of this via the built-in custom fields support.

Custom fields

Importantly, in this first version of the Block Bindings API, there is no UIUI User interface for binding attributes to custom fields yet. Therefore, it is necessary to add the markup manually using the Code Editor in Gutenberg.

To bind a supported attribute 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. in the post metadata, you would use markup such as the following:

<!-- wp:paragraph {
"metadata":{
"bindings":{
"content":{
"source":"core/post-meta",
"args":{
"key":"book-genre"
}
}
}
}
} -->
<p></p>
<!-- /wp:paragraph -->

In order for this to work, you would need to make sure the field is registered to the post metadata by including code such as the following in the theme’s functions.php or a plugin.

register_meta(
'post',
'book-genre',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'default' => 'Default text field',
)
);

*Note that the show_in_rest property must be set to true for the time being due to security considerations, though there are plans to explore how to remove this requirement in the future.

Future sources

Support for post metadata is just a start, and the plan is to add more built-in sources, such as site, user, and taxonomyTaxonomy A taxonomy is a way to group things together. In WordPress, some common taxonomies are category, link, tag, or post format. https://codex.wordpress.org/Taxonomies#Default_Taxonomies. data, for WordPress 6.6.

That being said, the Block Bindings API already has the functionality to allow for registering of custom sources as well, which is the same functionality used internally to register the core/post-meta source above.

Registering a custom source

Overview

To register a Block Bindings source, one needs to use the register_block_bindings_source() function, which has the following signature:

register_block_bindings_source(
string $source_name,
array $source_properties
);

There are two available parameters:

  • $source_name: A unique name for the custom binding source in the form of namespace/slug. The namespace is required.
  • $source_properties: An array of properties to define the binding source:
    • label: An internationalized text string to represent the binding source. Note: this is not currently shown anywhere in the UI.
    • get_value_callback: A PHP callable (function, closure, etc.) that is called when a block’s bound attribute source matches the $source_name parameter.
    • uses_context: (Optional) Extends the block instance with an array of contexts if needed for the callback. For example, to use the current post ID, it should be set to [ 'postId' ].

When WordPress encounters the custom bindings source while parsing a block, it will run the get_value_callback function, whose signature should look like this:

projectslug_bindings_callback(
array $source_args,
WP_Block $block_instance,
string $attribute_name
);

It can accept up to three parameters, though you don’t need to include them unless your logic requires them:

  • $source_args: An array of arguments passed via the metadata.bindings.$attribute.args property from the block.
  • $block_instance: The current instance of the block the binding is connected to as a WP_Block object.
  • $attribute_name: The current attribute set via the metadata.bindings.$attribute property key on the block.

Using the Registration Mechanism

In practice, here is how you might use the above registration function to create a simple binding for copyright information:

add_action( 'init', 'projectslug_register_block_bindings' );

function projectslug_register_block_bindings() {
register_block_bindings_source( 'projectslug/copyright', array(
'label' => __( 'Copyright', 'projectslug' ),
'get_value_callback' => 'projectslug_copyright_binding'
) );
}

function projectslug_copyright_binding() {
return '&copy; ' . date( 'Y' );
}

And here is how you would bind a paragraph to the copyright source in the block markup, and how it would look on the frontend:

<!-- wp:paragraph {
"metadata":{
"bindings":{
"content":{
"source":"projectslug/copyright"
}
}
}
} -->
<p>Copyright Block</p>
<!-- /wp:paragraph -->
A screenshot of a post titled "Block Bindings Copyright Example"; in the content is a copyright symbol and the year 2024.

Of course, this is a simple example, and you could make use of the other parameters in the callback signature to create more extensive logic.

Additional API functions

Additionally, there are a few other functions currently part of the public API:

  • unregister_block_bindings_source( $string source_name ): Unregisters a source
  • get_all_registered_block_bindings_sources(): Gets all registered sources
  • get_block_bindings_source( $string source_name ): Retrieves a registered source

Also, please note that while the core sources use shared APIs in the editor UI, be aware that these editor APIs will remain private for the time being while discussion continues on how to standardize extensions to the UI around this feature.

This means that if you would like to implement a UI to handle your custom fields easily, for now, you will need to create that functionality yourself.

Further learning and next steps

For more inspiration on how to use Block Bindings in your own projects, see the registration logic in block-bindings.php and the built-in core/post-meta source, and take a look at the Introducing Block Bindings tutorial series.

With that in mind, Block Bindings are just getting started, and future plans include:

  • Add the possibility of editing the value of the 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. fields directly from the UI.
  • Add UI to allow users to add bindings through the Editor.
  • Create new built-in sources: Site data, post data, and taxonomy data.
  • Add support for more core blocks.
  • Add the ability for developers to extend the Editor UI.

As always, feedback is more than welcome, and we invite you to share your ideas and use cases on Github, this post, or WordPress SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/. to help shape the development of the Block Bindings API.

A big thanks to @greenshady for providing code snippets and the initial ideas for this post, as well as @santosguillamot, and @czapla for offering their feedback.

#6-5, #dev-notes, #dev-notes-6-5

Performance Chat Summary: 5 March 2024

Meeting agenda here and the full chat log is available beginning here on Slack.

Announcements

  • Welcome to our new members of #core-performance
  • WordCampWordCamp WordCamps are casual, locally-organized conferences covering everything related to WordPress. They're one of the places where the WordPress community comes together to teach one another what they’ve learned throughout the year and share the joy. Learn more. Asia is this week
  • Updated agenda format to match CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. dev chat as suggested in previous chats
  • Reminder on timezone difference for the next 3 weeks, this chat will remain at 16:00 UTC, then it will switch to 15:00 UTC from April 2

Priority Items

Structure:

  • WordPress performance TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. tickets discussion
  • Performance Lab 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 other performance plugins) discussion
  • Active priority projects
    • Plugin checker
    • Improve template loading
    • INP opportunities research

WordPress Performance Trac Tickets

  • For WordPress 6.5:
    • @joemcgill The only open ticketticket Created for both bug reports and feature development on the bug tracker. we still have in the milestone is #60127, which can happen at any time. @thelovekesh was planning on taking a pass at this soon.
      • The only other thing that I think we’ve been aware of is that this release is showing a slightly higher TTFB than 6.4, but we can discuss that in more detail later.
    • @thelovekesh tried to replicate the issue on 6.4 but facing some issues with local setup. Will try to set it up again.
  • For Future Releases:
    • We already have 15 items in the 6.6 milestone, but it’s a good time for folks to start thinking about what they are wanting to focus on for the next release.

Performance Lab Plugin (and other Performance Plugins)

  • @flixos90 There has been a lot of progress on the unbundling of Performance Lab (see overview issue)
  • https://github.com/WordPress/performance/pull/1011 and https://github.com/WordPress/performance/pull/1019 are close to being merged into trunk
  • While that would in principle set us up to ship the 3.0 release, there have been a few conversations on the UXUX User experience of the new screen that deserve more attention. There is a lot to unpack, but it falls into 2 categories at a high level:
    • The migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. from modules to plugins is a confusing user experience.
    • The PL screen itself, with the plugins and modules to activate, is a confusing user experience.
  • The first point affects a one-time functionality, as it was recently decided that the concept of modules will be permanently removed. In other words, this migration will never need to happen again. As it’s already released and users are already migrating, it is not worth investing time to improve it
  • For the screen itself though, there is things we can do.
    • Most importantly, it would be more intuitive to make the experience about the features, rather than the plugins. As in, each card should describe a feature, instead of focusing on the technicality that it’s a plugin. We shouldn’t pull down .org information, but instead provide more solution driven feature descriptions. Things like the star ratings and other things related to the underlying plugin don’t need to be shown.
      • Under the hood, enabling a feature will still install and activate the corresponding plugin. But that shouldn’t matter for the user, their focus should be on the actual features.
    • We need to think about a better onboarding experience, e.g. a step which allows enabling all recommended features at once. There used to be modules which are activated by default, which is no longer possible now that the features are in the form of standalone plugins. So we need a solution to make that intuitive, which goes hand in hand with a better onboarding experience.
  • @thelovekesh suggested Maybe showing some on-boarding wizard? Where user can select what they want to improve in terms of performance on their site?
    • @flixos90 Potentially. I usually think of multiple steps when I think “onboarding wizard”, so not sure that’s needed here. But at least it would need to be a dedicated screen, or a customized version of the regular
  • @joemcgill I’m definitely in favor of the first point above, and see the second as a “nice to have”. Do we already have a GH issue to track this discussion?
  • The most immediate course of action because of those additional points regarding the Performance Lab plugin unbundling: Because of the additional discussion and engineering required, I think we should postpone the 3.0 release. Hopefully only to April. We need to make sure the UX is good enough before we ship it, but at the same time we want to minimize the time we remain in this limbo where the 2.x branchbranch A directory in Subversion. WordPress uses branches to store the latest development code for each major release (3.9, 4.0, etc.). Branches are then updated with code for any minor releases of that branch. Sometimes, a major version of WordPress and its minor versions are collectively referred to as a "branch", such as "the 4.0 branch". and trunk are so diverged, as that complicates shipping potential fixes in the existing code.

Active Priority Projects

Plugin Checker

  • No updates this week

Improve template loading

INP research opportunities

  • No updates this week

Open Floor

Our next chat will be held on Tuesday, March 12, 2024 at 16:00 UTC in the #core-performance channel in Slack.

#core-performance, #performance, #performance-chat, #summary

New Feature: Font Library

Introduced in WordPress 6.5, the Font Library allows users to manage fonts directly in the editor. It comes with a set of APIs that allow developers to control, adapt, and disable its behavior.

Font Collections

A Font Collection is a list of font family definitions that can be installed by the user via the editor. The font family definition is a fontFamily item in theme.json format. By default, WordPress 6.5 allows users to opt-in to a collection listing for Google Fonts. To allow sites to remain GDPR compliant, installing a Google Font downloads the file to the WordPress server.

When a Font Collection is registered, it will appear in the Font Library UIUI User interface in the editor. From here, users can install and activate fonts from the collection.

Adding a Font Collection

A new Font Collection can be added using the wp_register_font_collection() function. This can be done by supplying a list of font families and their font faces in either PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher or 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. format as part of the Font Collection array.

Here is an example of adding a Font Collection in PHP:

$font_families = [
array(
'font_family_settings' => (
array (
'fontFamily' => 'Open Sans, sans-serif',
'slug' => 'open-sans',
'name' => 'Open Sans',
'fontFace' => array (
array (
'fontFamily' => 'Open Sans',
'fontStyle' => 'normal',
'fontWeight' => '300',
'src' => 'https://fonts.gstatic.com/s/opensans/v40/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0C4iY1M2xLER.woff2',
),
array (
'fontFamily' => 'Open Sans',
'fontStyle' => 'italic',
'fontWeight' => '400',
'src' => 'https://fonts.gstatic.com/s/opensans/v40/memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk8ZkaVIUwaERZjA.woff2'
),
),
)
),
'categories' => [ 'sans-serif' ],
),
array(
'font_family_settings' => (
array (
'fontFamily' => 'Monoton, system-ui',
'slug' => 'monoton',
'name' => 'Monoton',
'fontFace' => array (
array (
'fontFamily' => 'Monoton',
'fontStyle' => 'normal',
'fontWeight' => '400',
'src' => 'https://fonts.gstatic.com/s/monoton/v19/5h1aiZUrOngCibe4fkPBQ2S7FU8.woff2',
'preview' => 'https://s.w.org/images/fonts/17.7/previews/monoton/monoton-400-normal.svg'
),
),
)
),
'categories' => [ 'display' ],
),
array(
'font_family_settings' => (
array (
'fontFamily' => 'Arial, Helvetica, Tahoma, Geneva, sans-serif',
'slug' => 'arial',
'name' => 'Arial',
)
),
'categories' => [ 'sans-serif' ],
),
];

$categories = [
array(
'name' => _x( 'Display', 'Font category name' ),
'slug' => 'display',
),
array(
'name' => _x( 'Sans Serif', 'Font category name' ),
'slug' => 'sans-serif',
),
];

$config = array (
'name' => _x( 'My font collection', 'Font collection name' ),
'description' => _x( 'A collection of my favorite fonts.', 'Font collection description' ),
'font_families' => $font_families,
'categories' => $categories,
);

wp_register_font_collection ( 'my-font-collection', $config );

Please note that the name and description fields of the Font Collection array must be translatable, which can be achieved by wrapping the strings in the _x() function. Font Family names are not typically translated. For more information and background discussion, see #60509.

JSON format for the font_families field can be a local path or a remote URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org that points to the JSON file.

Removing a Font Collection

A Font Collection can be disabled by using the wp_unregister_font_collection() function. Here is an example which disables the default font collection:

add_action( 'init', function() {
wp_unregister_font_collection( 'default-font-collection' );
} );

For more information, see #57980.

Installing and Activating Fonts

Fonts definitions are based on the theme.json format for font settings. “Installing” a font to the site saves the theme.json formatted settings from the collection into the database, so the font can be activated for any theme.

When the font is “activated,” the Global Styles settings for the theme are updated so that the font is included, along with the fonts defined by the theme, and can be used in the typography settings for Global Styles and individual blocks.

When switching to a new theme, installed fonts need to be re-activated, to update the site’s Global Styles settings for that theme. If Global Styles for a theme are reset, this will deactivate all installed fonts, but they will remain installed on the site and can be reactivated as desired.

Additionally, the Font Library can be used to deactivate fonts included with the theme, if they aren’t needed, to improve the loading performance of the site.

Customizing the Fonts Upload Directory

Please note that some of the following details, such as function names, may change prior to the 6.5 release. For more information, see #60751 and 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/ issue #59699.

By default, fonts will be uploaded to the wp-content/fonts directory. However, this location can be customized as required using the font_dir 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.. For installations that don’t support modification of the wp-content directory, wp-content/uploads/fonts will be used as a fallback directory.

It is possible to return the location of the fonts upload directory by using wp_get_font_dir().

The example below changes the fonts directory to the WordPress “Uploads” directory (by default, this is wp-content/uploads):

function alter_wp_fonts_dir( $defaults ) {
$wp_upload_dir = wp_get_upload_dir();
$uploads_basedir = $wp_upload_dir['basedir'];
$uploads_baseurl = $wp_upload_dir['baseurl'];

$fonts_dir = $uploads_basedir . '/fonts';
// Generate the URL for the fonts directory from the font dir.
$fonts_url = str_replace( $uploads_basedir, $uploads_baseurl, $fonts_dir );

$defaults['path'] = $fonts_dir;
$defaults['url'] = $fonts_url;

return $defaults;
}
add_filter( 'font_dir', 'alter_wp_fonts_dir' );

When modifying the upload location, it is important to ensure that the chosen location exists and has appropriate read/write permissions set.

Like the wp-content/uploads directory, the fonts upload directory will not adhere to wp_is_file_mod_allowed / DISALLOW_FILE_MODS to prevent font uploads.

For further info, see #59417 and this post.

How to Disable the Font Library

The Font Library is accessible via the editor by default.

Disable the UI

The UI can be disabled using a filter to customize the editor settings:

function disable_font_library_ui( $editor_settings ) { 
$editor_settings['fontLibraryEnabled'] = false;
return $editor_settings;
}

add_filter( 'block_editor_settings_all', 'disable_font_library_ui' );

Disable the REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/.

The unregister_post_type() function can be used to remove the post types associated with the Font Library and by extension the REST API:

add_action( 'init', function() {
unregister_post_type( 'wp_font_family' );
unregister_post_type( 'wp_font_face' );
} );

This allows extenders to disable the Font Library, while retaining the UI for managing fonts provided by the active theme.

For more info, see #55275 and #57818.

New REST API

The Font Library feature introduces three new REST API endpoints:

For detailed documentation about each of the new endpoints, please refer to the REST API Handbook and #57616.

Props and a massive thank you to everyone who helped put 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. together: @mmaattiiaass, @grantmkin, @peterwilsoncc, @youknowriad, @get_dave, @stevenlinx, @leonnugraha.

#6-5, #dev-notes, #dev-notes-6-5

Interactivity API in 6.5

The Interactivity 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. provides a standard way for developers to add interactions to the frontend of their blocks.

This standard aims to make it easier for developers to create rich, interactive user experiences, from simple cases like counters or pop-ups to more complex features like instant page navigation, instant search, carts, or checkouts.

Blocks can share data, actions, and callbacks between them. This makes communication between blocks simpler and less error-prone. For example, clicking on an “add to cart” 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. can seamlessly update a separate “cart” block.

To understand better the reasoning behind it, you can take a look at the original proposal, where it is explained in more detail.

More information about it can be found in the merge announcement, the status update post, and the Trac ticket for the Interactivity API.

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. covers the APIs included in 6.5 and how to use the Interactivity API.

How to create interactions using the Interactivity API

It’s important to highlight that the block creation workflow doesn’t change.

Until now, WordPress has been intentionally unopinionated about the different solutions used on the frontend of blocks. The Interactivity API changes that. It adds a new standard way to easily add frontend interactivity to blocks while the APIs handling the Block Editor remain the same.

You need first to declare its compatibility with the API by adding the interactivity property inside  supports, in the block.json file:

"supports": {
    "interactivity": true
},

Refer to the Block Editor handbook to get a more detailed description of the interactivity support property.

The Interactivity API script requires using the new script modules coming in WordPress 6.5, so blocks should enqueue the 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/. by using viewScriptModule:

// block.json
{
   ...
   "viewScriptModule": "file:./view.js"
}

You can easily scaffold and test an interactive block following this quick start guide, which explains how to use a CLICLI Command Line Interface. Terminal (Bash) in Mac, Command Prompt in Windows, or WP-CLI for WordPress. command to speed up this process.

With that in mind, in order to add interactivity to blocks powered by the Interactivity API, developers would need to:

  1. Add directives to the markup to add specific interactions to the block.
  2. Create a store with the logic (state, actions, or callbacks) for interactivity.

Let’s use a simple example to explain it: a button that shows and hides some text. Let’s also send a message in the console whenever the button is hidden or revealed.

1. Add the directives

Directives are custom attributes that are added to the markup of your block to add interactions to its DOM elements. They are placed in the render.php file (for dynamic blocks).

The very first step is to add the data-wp-interactive directive. This is used to “activate” the Interactivity API in a DOM element and its children, and its value must be the unique namespace of your 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 block:

<div data-wp-interactive="myPlugin">
    <!-- Interactivity API zone -->
</div>

The rest of the directives can be added with the desired interactions.

// render.php

$context = array('isOpen' => false);

<div
  <?php echo get_block_wrapper_attributes(); ?>
  <?php echo wp_interactivity_data_wp_context($context) ?>
  data-wp-interactive='myPlugin'
  data-wp-watch="callbacks.logIsOpen"
>
  <button
      data-wp-on--click="actions.toggle"
      data-wp-bind--aria-expanded="context.isOpen"
  >
    Toggle
  </button>
  <p id="p-1" data-wp-bind--hidden="!context.isOpen">
    This element is now visible!
  </p>
</div>

Additionally, directives can also be injected dynamically using the HTML Tag Processor.

Don’t worry if you don’t understand how it works yet. So far, the important part is that the example above uses directives like wp-on and wp-bind to add interactivity to the HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers.. This is the list of directives available in WordPress 6.5:

You can find a deeper explanation of each directive and examples of how to use it in the relevant links.

  • wp-interactive: This attribute must be set to the unique identifier of your plugin or block in order for it to use the Interactivity API.
  • wp-context: It provides a local state available to a specific HTML node and its children. It accepts stringified 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. as a value. It’s recommended to use wp_interactivity_data_wp_context() to set it in PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher.
  • wp-bind: It allows HTML attributes to be set on elements based on a boolean or string value. It follows the syntax data-wp-bind--[attribute]. (like data-wp-bind--value)
  • wp-class: It adds or removes a class to an HTML element, depending on a boolean value. It follows the syntax data-wp-class--[classname].
  • wp-style: It adds or removes inline style to an HTML element, depending on its value. It follows the syntax data-wp-style--[css-property].
  • wp-text: It sets the inner text of an HTML element. It only accepts strings as the parameter.
  • wp-on: It runs code on dispatched DOM events like click or keyup. Its syntax is data-wp-on--[event] (like data-wp-on--click or data-wp-on--keyup).
  • wp-on-window: It allows to attach global window events like resize, copy, focus and then execute a defined callback when those happen. Its syntax is data-wp-on-window--[window-event] (like data-wp-on-window--resize or data-wp-on-window--languagechange).
  • wp-on-document: It allows to attach global document events like scroll, mousemove, keydown and then execute a defined callback when those happen. Its syntax is data-wp-on-document--[document-event] (like data-wp-on-document--keydown or data-wp-on-document--selectionchange).
  • wp-watch: It runs a callback when the node is created and runs it again when the state or context changes.
  • wp-init: It runs a callback only when the node is created.
  • wp-run: It runs the passed callback during node’s render execution.
  • wp-key: It assigns a unique key to an element to help the Interactivity API identify it when iterating through arrays of elements.
  • wp-each: It is intended to render a list of elements.
  • wp-each-child: Ensures hydration works as expected, is added automatically on the server processing of wp-each directive.

2. Create the store

The store is used to create the logic that will link the directives with the data used inside that logic.

All stores are referenced by a unique namespace, separating the logic and avoiding name collisions between different store properties and functions.

If there are multiple stores defined with the same namespace, they will be merged into a single store.

The store is usually created in the view.js file of each block, although the state can be initialized in the backend, for example, in the render file of the block.

The state is a global object, available to all HTML nodes of the page. It is defined by the store() function. If you need a local state for just a node and its children, check the context definition.

The object can accept any property, in order to keep consistency between projects, this convention is recommended.

  • State: Defines data available to the HTML nodes of the page. Properties inside the state will be available globally. If you need to edit them, the recommended way is by using getters.
    • Derived State. If you need a modified version of any state property, getters are the recommended approach (more on deriving state below).
  • Actions: Usually triggered by the data-wp-on directive (using event listeners).
  • Callbacks: Automatically reactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org/. to state changes. Usually triggered by data-wp-on-window, data-wp-on-document or data-wp-init directives.

Returning to our example, this could be a simple store in one block, a global state has been added for having a complete sample of how a store could look like.

// view.js
import { store, getContext } from "@wordpress/interactivity";

const { state } = store( 'myPlugin', {
 state: {
  likes: 0,
  getDoubleLikes() {
    return 2 * state.likes;
  }
 },
  actions: {
    toggle: () => {
      const context = getContext();
      context.isOpen = !context.isOpen;
    },
  },
  callbacks: {
    logIsOpen: () => {
      const context = getContext();
      // Log the value of `isOpen` each time it changes.
      console.log(`Is open: ${context.isOpen}`);
    },
  },
});

There can be cases where only actions and callbacks are defined in the store.

DOM elements are connected to data stored in the state and context through directives. If data in the state or context change directives will react to those changes, updating the DOM accordingly (see diagram).

When creating the store, there are some important things to be aware of:

Using derived state

Derived state uses getters to return a computed version of the state. It can access both state and context.

// view.js
const { state } = store( "myPlugin", {
  state: {
    amount: 34,
    defaultCurrency: 'EUR',
    currencyExchange: {
      USD: 1.1,
      GBP: 0.85,
    },
    get amountInUSD() {
      return state.currencyExchange[ 'USD' ] * state.amount,
    },
    get amountInGBP() {
      return state.currencyExchange[ 'GBP' ] * state.amount,
    },
  },
} );

Accessing the store by destructuring

The store contains all the store properties, like state, actions, or callbacks. They are returned by the store() call, so you can access them by destructuring it:

const { state, actions, callbacks } = store( "myPlugin", {
  // ...
} );

Note that context is not part of the store and is accessed through the getContext function.

If you want to take a deeper view about how the store() function works, feel free to check the function documentation here.

Async actions

Async actions should use generator functions instead of async/await or promises. The Interactivity API needs to be able to track async behavior in order to restore the proper scope. Otherwise, getContext may return stale values if it was updated concurrently with the async operation. Instead of awaiting the promise, yield it from the generator function, and the Interactivity API will handle awaiting its completion.

So, instead of:

store("myPlugin", {
  state: {
    get isOpen() {
      return getContext().isOpen;
    },
  },
  actions: {
    someAction: async () => {
      state.isOpen; // This is the expected context.
      await longDelay();
      state.isOpen; // This may not get the proper context unless it's properly restored.
    },
  },
});

function longDelay() {
  return new Promise( ( resolve ) => {
    setTimeout( () => resolve(), 3_000 );
  } );
}

The store should be:

store("myPlugin", {
  state: {
    get isOpen() {
      return getContext().isOpen;
    },
  },
  actions: {
    someAction: function* () {
      state.isOpen; // This is the expected context.
      yield longDelay(); // With generators, the caller controls when to resume this function.
      state.isOpen; // This context is correct because the scope was restored before resuming after the yield.
    },
  },
});

If you want to take a deeper look at the example, check the api reference.


Working with other namespaces

Interactive blocks can share data between them, unless they are private stores.

Directives

In order to access the store of a different namespace in a directive, add the namespace before the directive value. For example:

<!-- This accesses the current store -->
<div data-wp-class--is-hidden="state.isHidden"></div>

<!-- This accesses the "otherPlugin" store -->
<button data-wp-on--click="otherPlugin::actions.addToCart>Button</button>

Context

Context from a different namespace can be accessed by providing the desired namespace as an argument to getContext( namespace ):

import { getContext } from "@wordpress/interactivity";

const otherPluginContext = getContext( "otherPlugin" );

Store

Like context, different stores can be accessed by passing the desired namespace as an argument: 

const { state: otherState, actions: otherActions } = store( "otherPlugin" );

Private stores

A store can be “locked” to prevent its content from being accessed from other namespaces. To do so, set the lock option to true in the store() call, like in the example below. When the lock is set, subsequent executions of store() with the same locked namespace will throw an error, meaning that the namespace can only be accessed where its reference was returned from the first store() call. This is especially useful for developers who want to hide part of their plugin stores so it doesn’t become accessible for extenders.

const { state } = store("myPlugin/private", {
  state: {
      messages: [ "private message" ]
    } 
  },
  { lock: true }
);

// The following call throws an Error!
store( "myPlugin/private", { /* store part */ } );

There is also a way to unlock private stores: instead of passing a boolean, you can use a string as the lock value. Such a string can then be used in subsequent store() calls to the same namespace to unlock its content. Only the code with the lock string will be able to access the protected store. This is useful for complex stores defined across multiple files.

const { state } = store("myPlugin/private", {
  state: {
      messages: [ "private message" ]
    }
  },
  { lock: PRIVATE_LOCK }
);

// The following call works as expected.
store( "myPlugin/private", { /* store part */ }, { lock: PRIVATE_LOCK } );

Interactivity API client methods

The following methods are for use in JavaScript and are provided by the wordpress/interactivity script module available in WordPress 6.5.

getContext()

The context defined with the data-wp-context attribute can be retrieved with the getContext function:

const { state } = store( "myPlugin", {
  actions: {
    someAction() {
      const context = getContext();
      const otherPluginContext = getContext( 'otherPlugin' );
      // ...
    }
  }
} );

Handbook description.

getElement()

Retrieves a representation of the element where a function from the store is being evaluated. This representation is read-only, and contains a reference to the DOM element and its attributes.

Handbook description.

getConfig()

Retrieves a configuration object that was previously defined in the server via wp_interactivity_config() function.

Configuration is immutable on the client, it cannot be modified. You can get an example later in this document.

store()

Creates the store used to link the data and actions with their respective directives. Check the main section for more information.

withScope()

Actions can depend on the scope when they are called, e.g., when you call getContext() or getElement().

When the Interactivity API runtime execute callbacks, the scope is set automatically. However, if you call an action from a callback that is not executed by the runtime, like in a setInterval() callback, you need to ensure that the scope is properly set. Use the withScope() function to ensure the scope is properly set in these cases.

An example, where actions.nextImage would trigger an undefined error without the wrapper:

store('mySliderPlugin', {
	callbacks: {
		initSlideShow: () => {
		    setInterval(
				withScope( () => {
					actions.nextImage();
				} ),
				3_000
			);
		}
	},
})

Interactivity API server functions

These are the PHP functions the Interactivity API includes:

wp_interactivity_state( $store_namespace, $state )

It is used to initialize the state on the server and ensure that the HTML sent by it, and the HTML after the client hydration are the same. And it also allows you to use any WordPress API like coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. translations.

// render.php

wp_interactivity_state( "movies", array(
      "1" => array(
        "id" => "123-abc",
        "movieName" => __("someMovieName", "textdomain")
      ),
) );

It receives two arguments, a string with the namespace that will be used as a reference and an associative array containing the values.

The state defined on this function gets merged with the stores defined in the view.js files.

wp_interactivity_data_wp_context( $context, $store_namespace )

Generates a data-wp-context attribute ready to be server side rendered. This function escapes the array to prevent external attacks, apart from any error that may appear when writing JSON strings manually.

$context is an array containing the keys and values of the context.

$store_namespace allows referencing different stores, and is empty by default.

<?php
 $context = array(
  'id' => $post_id,
  'show' => true,
 );
?>
<div <?php echo wp_interactivity_data_wp_context($context) ?> >
  My interactive div
</div>

Will return

<div data-wp-context="{ "id": 1, "show": "true" } ">
  My interactive div
</div>

wp_interactivity_config( $store_namespace, $config )

Sets or gets configuration for an interactivity store. An immutable copy of the configuration can be read by the client.

Consider config as a global setting that can affect the full site and won’t be updated on client interactions. For example, determining if a site can handle client-side navigation or not.

<?php
// Sets configuration for the  'myPlugin' namespace.
wp_interactivity_config( 'myPlugin', array( 'setting' => true ) );

// Gets the current configuration for the 'myPlugin' namespace.
$config = wp_interactivity_config( 'myPlugin' );

This config can be retrieved in the client:

// view.js

const { setting } = getConfig();
console.log( setting ); // Will log true.

wp_interactivity_process_directives( $html )

Processes directives within HTML content, updating the markup where necessary.

This is the core functionality of the Interactivity API. It’s public so that any HTML can be processed, not just blocks.

For blocks with supports.interactivity, directives are automatically processed. Developers do not need to call wp_interactivity_process_directives in this case.

<?php
$html_content = '<div data-wp-text="myPlugin::state.message"></div>';
wp_interactivity_state( 'myPlugin', array( 'message' => 'hello world!' ) );

// Process directives in HTML content.
$processed_html = wp_interactivity_process_directives( $html_content );
// output: <div data-wp-text="myPlugin::state.message">hello world!</div>

Relevant links

Props to @gziolo, @darerodz, @santosguillamot, @luisherranz and @jonsurrell for technical review.

Props to @leonnugraha for copy review.

#6-5, #dev-notes, #dev-notes-6-5

Introducing Plugin Dependencies in WordPress 6.5

Overview

#22316 introduces 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 Dependencies to WordPress.

Extensibility of WordPress through plugins and the 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. 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. is one of its most beneficial features. There are many plugins that act purely as extensions of others, building functionality on top. The Plugin Dependencies feature aims to make the process of installing and activating addons (dependents) and the plugins they rely on (dependencies) consistent and easy.

New Plugin HeaderHeader The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitor’s opinion about your content and you/ your organization’s brand. It may also look different on different screen sizes.

A new Requires Plugins header has been introduced.

This must contain a comma-separated list of 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/-formatted slugs for its dependencies, such as my-plugin (my-plugin/my-plugin.php is not supported). It does not support commas in plugin slugs.

How to use the new header

/**
* Plugin Name: Express Payment Gateway Checkout for Shop
* Requires Plugins: shop, payment-gateway
 */

Requirements

Dependent plugins

The following requirements are placed on dependent plugins:

  • Cannot be installed until its dependencies are installed.
  • Cannot be activated until its dependencies are activated.

Dependency plugins

The following requirements are placed on dependency plugins:

  • Cannot be deactivated while its dependents are activated.
  • Cannot be deleted while its dependents are installed.

What happens if a dependency is no longer met?

If a dependency plugin is deleted via FTPFTP FTP is an acronym for File Transfer Protocol which is a way of moving computer files from one computer to another via the Internet. You can use software, known as a FTP client, to upload files to a server for a WordPress website. https://codex.wordpress.org/FTP_Clients. or deployment, a notice will be displayed on the administration’s plugin screens, informing the user that there are missing dependencies to install and/or activate. Additionally, each dependent whose dependencies are no longer met will have an error notice in their plugin row.

What happens if a plugin update has a new dependency?

The update will be allowed for now, and the dependent will remain active. A notice will be displayed on the administration’s plugin screens, informing the user that there are missing dependencies to install and/or activate.

What happens if there are circular dependencies?

A circular dependency is when two or more plugins form a 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. in their requirements.

For example: Plugin A requires Plugin B requires Plugin C requires Plugin A

Plugin Dependencies includes circular dependency detection, and will display a notice to inform users of plugins whose requirements are invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid.. The plugins cannot be activated, and users should contact the plugin authors so that this circular reference can be broken where appropriate.

Is defensive coding still needed?

Yes. Plugin Dependencies makes it easier for the user to install and activate required plugins, and informs them when these are not met. This means plugin authors can safely remove checks and notices when their dependencies are not installed or activated.

However, at this time, Plugin Dependencies does not include minimum or maximum version support for dependencies, nor does it account for the loading order of plugins. Plugin authors should therefore continue to use function|class|interface_exists() and version checks where their plugin relies on specific functionality being available at a given time.

Does Plugin Dependencies affect WP-CLIWP-CLI WP-CLI is the Command Line Interface for WordPress, used to do administrative and development tasks in a programmatic way. The project page is http://wp-cli.org/ https://make.wordpress.org/cli/?

Plugin Dependencies does not prevent the installation of dependent plugins without their dependencies via WP-CLI, as it is assumed that those using WP-CLI are advanced users that are aware of their dependency stack. However, to avoid missing dependencies going unnoticed, dependent plugins cannot be activated using WP-CLI until their dependencies are activated.

This affects wp plugin activate --all, which may need to be run multiple times if a dependent appears alphabetically earlier than its dependencies. We plan to collaborate with WP-CLI maintainers on possible ways of easing this burden by exploring loading order in WordPress CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress., WP-CLI, or both, if appropriate.

Limitations

Plugins hosted on WordPress.org

Dependent plugins hosted on WordPress.org can only declare dependencies that are also hosted on WordPress.org. If your plugin hosted on WordPress.org requires plugins that are not hosted there, it is recommended that you do not use the Requires Plugins header in your plugin at this time.

Plugins not hosted on WordPress.org

Dependent plugins not hosted on WordPress.org can declare dependencies whether hosted on WordPress.org or elsewhere. However, the UIUI User interface will not provide an installation link for the third-party dependencies, and these must continue to be installed manually by the user.

Must-Use plugins as dependencies

Must-Use plugins as dependencies are not officially supported by WordPress Core at this time. Discussion will continue in #60504 and we will release further information when decisions about possible future support have been made.

Themes that require plugins

Themes that require plugins are not supported by Plugin Dependencies at this time, and theme authors should continue to use the checks and messaging that they have in place.

New 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.

The wp_plugin_dependencies_slug filter hook has been introduced to allow for alterations to dependency slugs. For example, if a dependent plugin declares my-plugin as a dependency, and a premium version of my-plugin exists, the premium version can filter the slug and convert it to my-plugin-pro so that it can be detected by Plugin Dependencies.

  • Parameters
    string $slug – The slug.

Example usage

add_filter( 'wp_plugin_dependencies_slug', 'convert_myplugin_to_myplugin_pro' );

function convert_myplugin_to_myplugin_pro( $slug ) {
if ( 'my-plugin' === $slug ) {
$slug = 'my-plugin-pro';
}
return $slug;
}

UI Changes

Plugins > Installed plugins

The following changes are made:

  • Dependent plugin rows now contain a list of their dependencies, linked to the respective plugin modal to install and activate the dependency.
  • Dependency plugin rows now contain a list of their dependents.
  • If a plugin has dependencies that are not installed and active, the Activate link is disabled.
  • If a plugin has dependents that are active, the Deactivate and Delete links are disabled.
  • Bulk Actions are disabled for dependency plugins.

Before

Three plugin rows, with one plugin requiring the other two. However, there is no indication or enforcement of the requirements.
No dependents or dependencies are listed.

After

Three plugin rows, with one plugin requiring the other two. The requirements are listed under "Requires" and "Required by" sections. The Bulk Actions checkbox is disabled, as well as the Activate, Deactivate, or Delete actions, depending on the status of the plugins.
Dependents and dependencies are listed, and actions are enabled/disabled based on the status of requirements.

Plugins > Add New

The following changes are made:

  • If a plugin has unmet dependencies, the Install Now and Activate buttons are disabled, both in their plugin card and their plugin information modal.
  • Dependent plugin cards now contain a notice listing their dependencies, with a More Details link to the dependency’s information modal which contains Install Now or Activate buttons based on their current installation status.
  • Plugin information modals are now persistent after button clicks, and modal-based plugin installation and activation are now performed through AJAX directly within the modal.

Before

Plugin card with no dependencies listed and an active Install Now button despite unmet dependencies.

After

Plugin card with dependencies listed with modal links to install and activate each dependency, and the Install Now button disabled while dependencies are unmet.

Onboarding experiences

Due to the unified AJAX approach now used on the Plugins > Add New screen, activation of a plugin will no longer automatically redirect to the Plugins > Installed plugins screen, or to onboarding experiences implemented by plugin authors. This allows users to install and activate multiple plugins without leaving their current context.

Plugins with onboarding experiences usually incorporate checks so that if, for example, their plugin is installed and activated using WP-CLI, the onboarding experience will be triggered when the user enters one of the plugin’s settings screens. Such implementations will be unaffected by Plugin Dependencies, as will activation from the Plugins > Installed plugins screen Activate link.

New WP_Plugin_Dependencies Class

A new WP_Plugin_Dependencies class has been introduced.

The following public API methods are available:

static ::initialize()
Initializes Plugin Dependencies by reading dependencies from the Requires Plugins header, and fetching Plugins API data for dependencies. This runs only once per execution.

static ::has_dependents( $plugin_file )
Determines whether the plugin has plugins that depend on it.

  • Parameters
    string $plugin_file – The plugin file, relative to the plugins directory.
  • Return value
    bool Whether the plugin has plugins that depend on it.

static ::has_dependencies( $plugin_file )
Determines whether the plugin has plugin dependencies.

  • Parameters
    string $plugin_file – The plugin file, relative to the plugins directory.
  • Return value
    bool Whether the plugin has plugin dependencies.

static ::has_active_dependents( $plugin_file )
Determines whether the plugin has active dependents.

  • Parameters
    string $plugin_file – The plugin file, relative to the plugins directory.
  • Return value
    bool Whether the plugin has active dependents.

static ::get_dependents( $slug )
Gets filepaths of plugins that require the dependency.

  • Parameters
    string $slug – The dependency’s slug.
  • Return value
    array An array of dependent plugin filepaths, relative to the plugins directory.

static ::get_dependencies( $plugin_file )
Gets the slugs of plugins that the dependent requires.

  • Parameters
    string $plugin_file – The dependent plugin’s filepath, relative to the plugins directory.
  • Return value
    array An array of dependency plugin slugs.

static ::get_dependent_filepath( $slug )
Gets a dependent plugin’s filepath.

  • Parameters
    string $slug – The dependent plugin’s slug.
  • Return value
    string|false The dependent plugin’s filepath, relative to the plugins directory, or false if the plugin has no dependencies.

static ::get_dependency_filepath( $slug )
Gets the filepath for a dependency, relative to the plugin’s directory.

  • Parameters
    string $slug – The dependency’s slug.
  • Return value
    string|false If installed, the dependency’s filepath relative to the plugins directory, otherwise false.

static ::has_unmet_dependencies( $plugin_file )
Determines whether the plugin has unmet dependencies.

  • Parameters
    string $plugin_file – The plugin’s filepath, relative to the plugins directory.
  • Return value
    bool Whether the plugin has unmet dependencies.

static ::has_circular_dependency( $plugin_file )
Determines whether the plugin has a circular dependency.

  • Parameters
    string $plugin_file – The plugin’s filepath, relative to the plugins directory.
  • Return value
    bool Whether the plugin has a circular dependency.

static ::get_dependent_names( $plugin_file )
Gets the names of plugins that require the plugin.

  • Parameters
    string $plugin_file – The plugin’s filepath, relative to the plugins directory.
  • Return value
    array An array of dependent names.

static ::get_dependency_names( $plugin_file )
Gets the names of plugins required by the plugin.

  • Parameters
    string $plugin_file – The dependent plugin’s filepath, relative to the plugins directory.
  • Return value
    array An array of dependency names.

static ::get_dependency_data( $slug )
Returns API data for the dependency.

  • Parameters
    string $slug – The dependency’s slug.
  • Return value
    array|false The dependency’s API data on success, otherwise false.

FAQs

Where can I stay updated on the future development of Plugin Dependencies?

The Plugin Dependencies feature plugin will no longer receive updates now that the Plugin Dependencies feature has been merged into WordPress Core. The feature will be primarily maintained by contributors to the Upgrade/Install and Plugins components. You can stay updated on Plugin Dependencies and other developments by subscribing to the blog.

How can I get involved in the future development of Plugin Dependencies?

You can join us in the #core-upgrade-install channel on Slack. Our weekly meetings are held every Wednesday at 18:00 UTC. Tickets will be opened on WordPress Core Trac.

How can I report an issue?

You can search for an existing ticket or create a new ticket with the type of defect (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.) on WordPress Core TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress..

How can I request an enhancementenhancement Enhancements are simple improvements to WordPress, such as the addition of a hook, a new feature, or an improvement to an existing feature.?

You can search for an existing ticket or create a new ticket with the type of enhancement on WordPress Core Trac.

Props to @afragen and @swissspidy for technical review, and @stevenlinx for copy review.

In memory of Alex Mills and Alex King.
WordPress Remembers.

#6-5, #dev-notes, #dev-notes-6-5

WordPress 6.5 adds AVIF support 

WordPress 6.5 supports AVIF, a modern image format that offers significant improvements in image quality and compression over previous formats like JPEG, PNG, and even WebP.  AVIF images can be up to 50% smaller than JPEGs while maintaining the same image quality. AVIF images also support a wide range of colors (including HDR) and produce sharper images than JPEGs, especially in areas with high detail.

From WordPress version 6.5 forward, you can upload and use AVIF images in WordPress just like you would a JPEG or PNG image today – as long as your hosting environment supports AVIF. Switching to the AVIF format for your images is likely to improve your site’s performance and your site visitor’s experience. 

How AVIF helps you

AVIF images are significantly smaller than their JPEG equivalents, so pages load more quickly and take less bandwidth to transmit. AVIF images still get all of the benefits of the responsive images, Fetch Priority, and lazy loading that WordPress supports by default. Finally, AVIFs are supported in all major browsers, so most sites can start using them today.

Creating AVIF images

Many image editing tools support exporting to AVIF. You can also use command line conversion tools or web based open sourceOpen Source Open Source denotes software for which the original source code is made freely available and may be redistributed and modified. Open Source **must be** delivered via a licensing model, see GPL. tools like Squoosh. Once you save your images as AVIF, upload them to WordPress and use them like you would any other image. WordPress can also create AVIFs for you automatically, for more details, see the FAQ item below.

Using AVIF images in WordPress

AVIF images work like any other image format in WordPress, with a few important notes:

AVIF in WordPress depends on support in your web server’s image processing library (WordPress has built-in support for both Imagick and LibGD for image processing). You can check for AVIF support in wp-adminadmin (and super admin) by visiting Tools -> Site Health, clicking the “Info” tab and expanding the “Media Handling” section, then finally looking for “AVIF” in the list of supported formats.

If your audience includes a significant number of users on an unsupported browser, either avoid using AVIF images, or enqueue a browser polyfill.

FAQ

Q: How do I adjust the compression level used for generated AVIF images?

The wp_editor_set_quality 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. can be used to set the quality setting. The passed mime type enables setting by type, for example:

// Use a quality setting of 75 for AVIF images.
function filter_avif_quality( $quality, $mime_type ) {
if ( 'image/avif' === $mime_type ) {
return 75;
}
return $quality;
}
add_filter( 'wp_editor_set_quality', 'filter_avif_quality', 10, 2 );

How can I output lossless AVIF images?

Using a compression level of 100 will set AVIF to its lossless mode.

Q: Can WordPress create AVIF images when I upload JPEGs?

Yes. Developers can use the image_editor_output_format filter to specify this type of transformation for uploads. Here is an example:

// Output AVIFs for uploaded JPEGs
function filter_image_editor_output_format( $formats ) {
$formats['image/jpeg'] = 'image/avif';
return $formats;
}
add_filter( 'image_editor_output_format', 'filter_image_editor_output_format' );

If I use WordPress multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site, will all my sites work with AVIF images?

No. Multisite stores the file types that users are allowed to upload when a site is created. We are still working on improving this in #53167. In the meantime, to ensure all existing sites on a networknetwork (versus site, blog) allow AVIF files, you can use the site_option filter in a network mu-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 to add avif to the allowed file types for all network sites:

// Ensure all network sites include AVIF support.
function filter_site_option_upload_filetypes( $filetypes ) {
$filetypes = explode( ' ', $filetypes );
if ( ! in_array( 'avif', $filetypes, true ) ) {
$filetypes[] = 'avif';
}
return implode( ' ', $filetypes );
}
add_filter( 'site_option_upload_filetypes', 'filter_site_option_upload_filetypes' );


Thanks to @stevenlinx and @westonruter for reviewing this post.

#6-5, #core-images, #dev-notes, #dev-notes-6-5, #images

Performance Chat Agenda: 12 March 2024

Here is the agenda for this week’s performance team meeting scheduled for Mar 12, 2024 at 16:00 UTC.

  • Announcements
    • Welcome to our new members of #core-performance
    • WordPress 6.5 Release Candidaterelease candidate One of the final stages in the version release cycle, this version signals the potential to be a final release to the public. Also see alpha (beta). 2 is today
    • Reminder on timezone difference for the next 3 weeks, this chat will remain at 16:00 UTC
  • Priority items
    • WordPress performance TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. tickets
    • Performance Lab 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 other performance plugins)
    • Active priority projects
      • Plugin checker
      • Improve template loading
      • INP opportunities research
  • Open floor

If you have any topics you’d like to add to this agenda, please add them in the comments below.


This meeting happens in the #core-performance channel. To join the meeting, you’ll need an account on the Make WordPress Slack.

#agenda, #meeting, #performance, #performance-chat

Unblocking WP6.5 – Font Library and Synced Pattern Overrides

A number of contributors have flagged a stalemate on a couple of different topics for WP6.5 this week. I want to first thank everyone who joined in the discussions 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/, SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/., and elsewhere. There were a lot of well-reasoned and important concerns raised and it was an excellent example of the way open sourceOpen Source Open Source denotes software for which the original source code is made freely available and may be redistributed and modified. Open Source **must be** delivered via a licensing model, see GPL. works in the open. Over the last few days, I’ve discussed the suggested approaches with several coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. and core-editor contributors, including pros, cons, and side effects. We’ve reached a consensus on a path forward on both the Font Library and the issue with Synced Pattern Overrides.

Font Library

Let’s ship the Font Library in WordPress 6.5 contingent on the following, which meet all the criteria and offers a good compromise:

  • The Font Library will use wp-content/fonts as the default storage folder. While locating fonts at the same level as themes and plugins gives fonts a lot of prominence, it’s worth noting 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 are heading toward composability, allowing users to change collections of fonts, patterns, templates, and color schemes without switching the full theme. Storing fonts at the same level as themes is the first step to breaking down themes in these composable pieces and establishing new first-class concepts and objects within our software.
  • For installations that don’t support modification of the wp-content directory, the Font Library will use wp-content/uploads/fonts as a fallback location, ensuring we stay true to our project philosophy of designing for the majority while still making the feature available to anyone out of the box without extra steps from the user. 
  • The wp_get_font_dir() (source) is available to return the location of the site’s fonts folder. Extenders should use this function as it will allow them to seamlessly integrate with the Font Library regardless of their installed version of WordPress. This allows WordPress to manage the preferred directory location and any factors related to migrating folder locations (e.g., consolidating any remaining installations using wp-content/uploads/fonts to use wp-content/fonts) in future versions without extenders also needing to make changes.
  • For very edge cases, a font_dir 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. (source) still allows overriding the font storage folder.
  • Like wp-content/uploads itself, the fonts directory will not adhere to wp_is_file_mod_allowed / DISALLOW_FILE_MODS to prevent font uploads.
  • 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. will reflect these changes upon publication.

The following is still to be explored after WP 6.5:

  • A means to move the canonical location of the fonts directory. Should the wp-content directory become writable for a site, a safe path forward should be offered for its owners.
  • Related checks will be added to Site Health.
  • A roadmap will be published outlining where the project components are headed in relation to establishing new first-class concepts outside of previously established paradigms within the software (like breaking down themes into fonts, patterns, templates, etc.). Why was this such an important and impactful decision? And how might it present itself again in the future?

Synced Pattern Overrides

During beta a change was merged that switches how blocks are named and marked as overridable patterns. This is proving to have unforeseen side effects that need further research and testing. Given that we need to focus on the solution outlined above for the Font Library, let’s revert this and try again in WP6.6.

Let’s do it!

While there may still be some disagreement about these decisions, I ask that we all support this fair and reasonable compromise to ensure the release is ready for all to enjoy the Font Library feature that many contributors have worked so hard on over the last few years. Sticking to our philosophies is important, but we must balance that with releasing early and often. We’re not perfect, and the only way to know how is to release features for all to use.

Props to @priethor, @desrosj, @swissspidy, @cbringmann, @dd32, @youknowriad

#6-5

Miscellaneous Editor changes in WordPress 6.5

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.5.


Table of contents

  1. New Block Supports
  2. Footnotes support for Custom Post Types
  3. DependencyExtractionWebpackPlugin: Drop webpack4 and node<18
  4. Enable Block Renaming support for (almost) all blocks
  5. Stabilization of the block editor’s RecursionProvider API
  6. Support for new allowedBlocks field in block.json
  7. Add new selectors to fetch entity revisions
  8. New useSettings hook for reading block instance settings
  9. Introduction of the PluginPostExcerpt Slot Component
  10. Changes to the underlying Composite component implementation
  11. Deprecated components
  12. Setting to disable custom content size controls

New 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. Supports

Background image block support additional features for size, repeat, and position

In WordPress 6.5, the background image block support receives new controls related to the size of the background image: size, repeat, and position.

For blocks that use the background image block support (currently, the Group block is the only coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. block to use this support), these optional controls can now be displayed. They are hidden by default behind the tools panel menu in the Background controls on the inspector 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..

How to add backgroundSize support to a theme

There are two ways to add support for backgroundSize and the related size, as well as repeat and position control to a block theme. The simplest one is to opt into the appearanceTools setting, which automatically enables a number of design tools (read more in the developer handbook).

For themes that wish to have more granular control over which UIUI User interface tools are enabled, the backgroundSize support can be opted into by setting settings.background.backgroundSize to true in theme.json. For example:

{
"settings": {
"background": {
"backgroundImage": true,
"backgroundSize": true

Note that as of WordPress 6.4 and WordPress 6.5, the backgroundImagebackgroundSize, and related supports are only available at the individual block level, not in global styles or at the site root. These features will be explored in subsequent releases, with progress tracked in this 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/ issue: #54336.

GitHub pull request: #57005

Props to @andrewserong 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..

Aspect ratio block support

A new aspect ratio block support has been added in WordPress 6.5, with the Cover block opted-in by default. For themes using the appearanceTools feature in theme.json, the control will be available in the inspector controls under Dimensions.

The feature allows users to set an aspect ratio for the Cover block, and is mutually exclusive with min-height rules. If an aspect ratio is set, then min-height is unset to ensure that height rules do not conflictconflict A conflict occurs when a patch changes code that was modified after the patch was created. These patches are considered stale, and will require a refresh of the changes before it can be applied, or the conflicts will need to be resolved. with the aspect ratio. The aspect ratio rules will be output at render-time for the block via an inline style applied to the block’s wrapper.

Note that themes or blocks that add width or height rules to a block will need to take care in testing compatibility with aspect-ratio if they are to opt-in to aspect ratio support. The aspect ratio tends to work most flexibly when width or height rules are not set.

How to add aspectRatio support to a theme

There are two ways to add support for aspectRatio to a block theme. The simplest is to opt into the appearanceTools setting, which automatically enables a number of design tools (read more in the developer handbook).

For themes that wish to have more granular control over which UI tools are enabled, the aspectRatio support can be opted into by setting settings.dimensions.aspectRatio to true in theme.json. For example:

{
"settings": {
"dimensions": {
"aspectRatio": true

GitHub pull request: #56897

Props to @andrewserong for writing the dev note.

Add block gap support to Quote block

The Quote block has blockGap support in WordPress 6.5. It also changes the default spacing between the quote and the citation in block themes that have blockGap enabled, to be consistent with all other blocks that use the layout support. The default spacing will now use the layout spacing rules defined by a theme’s styles.spacing.blockGap value in theme.json.

For themes that use blockGap but wish to use a different gap between the quote and the citation, they can set a spacing.blockGap value for the block directly.

GitHub pull request: #56054

Props to @andrewserong for writing the dev note.

Add padding and margin support to the Pullquote block

Pullquote block now supports padding and margin. At the same time, the browser default margin applied to the blockquote element inside the block has been reset to zero to ensure that padding values are applied accurately inside the block. Depending on themes, this effect may result in visual changes and the need to adjust padding or margin.

GitHub pull request: #45731

Props to @wildworks for writing the dev note.

Footnotes support for Custom Post Types

In WordPress version 6.5, footnotes are now supported on any 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. that fulfills certain requirements. To be eligible for footnotes, a custom post type must have capabilities like rest APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/., custom fields, revisionsRevisions The WordPress revisions system stores a record of each saved draft or published update. The revision system allows you to see what changes were made in each revision by dragging a slider (or using the Next/Previous buttons). The display indicates what has changed in each revision., and editor support. If a post type meets these requirements, footnotes should be available by default without requiring any changes from the developer.

However, if a developer wants to remove footnotes support in a specific condition, for example, in a particular post type, they can use the block 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. like any other block. The following code sample demonstrates how we can remove footnotes support from the “post” post type:


add_filter( 'allowed_block_types_all', 'footnotes_allowed_block_types', 10, 2 );

function footnotes_allowed_block_types( $allowed_blocks, $editor_context ) {
if( 'post' === $editor_context->post->post_type ) {
$allowed_blocks_array = array();
if ( is_array( $allowed_blocks )) {
$allowed_blocks_array = $allowed_blocks;
} else if( $allowed_blocks === false ) {
return false;
} else if ($allowed_blocks === true ) {
$block_types = WP_Block_Type_Registry::get_instance()->get_all_registered();
foreach( $block_types as $block_type) {
$allowed_blocks_array[] = $block_type->name;
}
}

$allowed_blocks = array_values( array_diff( $allowed_blocks_array, array(
'core/footnotes',
) ) );
}
return $allowed_blocks;
}

GitHub pull request: #57353

Props to @jorgefilipecosta for writing the dev note.

DependencyExtractionWebpackPlugin: Drop webpack4 and node<18

As webpack4 doesn’t support modules that blocks require to work, and that webpack5 was released more than three years ago, the support for webpack4 is dropped in WordPress 6.5.

In addition, the support for Node.js version 17 or older is dropped, as Node.js 18 is currently the oldest maintained version.

  • @wordpress/scripts version 17 has dropped official support for unmaintained Node.js versions. The oldest supported Node.js version is now Node.js 18.
  • @wordpress/dependency-extraction-webpack-plugin version 5 has dropped official support for unmaintained Node.js versions. The oldest supported Node.js version is now Node.js 18.
  • @wordpress/dependency-extraction-webpack-plugin version 5 has dropped support for webpack versions less than 5. Users should either upgrade to webpack v5 or continue to use v4 of the 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. Version 4 will not be maintained going forward.
    If you’re using @wordpress/dependency-extraction-webpack-plugin via @wordpress/scripts, the webpack change should not affect you.

GitHub pull request: #57303

Props to @jonsurrell for writing the dev note.

Enable Block Renaming support for (almost) all blocks

Building on the foundation introduced in WordPress 6.4all blocks (with some exceptions) can now be given custom names within the Editor.

The data for this continues to be stored under the name property of the block’s metadata attribute (e.g. attributes.metadata.name).

All blocks (including 3rd party blocks) will be “renameable” by default, with the only exceptions being the following blocks:

  • core/block
  • core/template-part
  • core/pattern
  • core/navigation
  • core/navigation-link

To disable the ability to rename a block, set the relevant support property to false in block.json:

// block.json
{
	"supports": {
		"renaming": false // disables ability to rename block via the Editor UI
	},
}

GitHub pull request: #54426

Props to @get_dave for writing the dev note.

Stabilization of the block editor’s RecursionProvider API

Context

Originally implemented as an experimental hook named __experimentalUseNoRecursiveRenders  in early 2021, then improved and repackaged in 2022 as the pair __experimentalRecursionProvider and __experimentalUseHasRecursion, the purpose of these APIs is to prevent certain advanced block types from accidentally triggering infinite rendering loops inside the block editor. For example, the Template block must guard against these loops:

  • If a user adds an instance of the Template block into the contents of that same template (linear recursion);
  • If Template A contains Template B, which then contains Template A (mutual recursion).

As of today, the following core block types use the RecursionProvider API: 

  • core/block
  • core/navigation
  • core/post-content
  • core/template-part.

Changes with WordPress 6.5

The API has been promoted to stable, thereby shedding the __experimental prefix. Consumers should now use the API by importing RecursionProvider and useHasRecursion from @wordpress/block-editor, or via the WP global as wp.blockEditor.RecursionProvider and wp.blockEditor.useHasRecursion.

For more details and a working example, see the component’s README.md document.

BeforeAfter
wp.blockEditor.__experimentalRecursionProviderwp.blockEditorRecursionProvider
wp.blockEditor.__experimentalUseHasRecursionwp.blockEditor.useHasRecursion

Backwards compatibility

The former identifiers — __experimentalRecursionProvider and __experimentalUseHasRecursion — are now deprecated. This means that they are still accessible, but their use will trigger a warning in the browser console.

GitHub pull request: #58120

Props to @mcsf for writing the dev note.

Support for new allowedBlocks field in block.json

WordPress 6.5 adds support for the new allowedBlocks field in the block.json file. It lets block developers specify which block types can be inserted as children of the given block. It’s a companion to the existing parent and ancestor fields that have a similar function, namely specifying allowed parent block types. Example of usage in a block.json file:

{
  "name": "core/list",
  "title": "List",
  "allowedBlocks": [ "core/list-item" ]
}

One of the main advantages of the block.json field is that it can be modified by plugins. For example, you can create a block that acts as a custom list item and extend the Core List block so that your custom block can be inserted as its child:

addFilter( 'blocks.registerBlockType', 'my-list-item', ( settings, name ) => {
  if ( name === 'core/list' ) {
    const { allowedBlocks = [] } = settings;
    return { ...settings, allowedBlocks: [ ...allowedBlocks, 'my/list-item' ] };
  }
  return settings;
} );

This new API replaces the allowedBlocks option that can be passed to the useInnerBlocksProps hook inside the block’s edit function. This option was previously used to implement the same check, but it wasn’t extensibleExtensible This is the ability to add additional functionality to the code. Plugins extend the WordPress core software.: the list of allowed blocks was hardcoded in the block’s edit function and couldn’t be modified.

The allowedBlocks option on the useInnerBlocksProps hook is still supported and is not deprecated, but you should use it only for specialized use cases. Like when the list of allowed blocks is dynamically calculated for each block: from its attributes, or from its surrounding environment (the parent block etc.).

GitHub pull request: #58262

Props to @jsnajdr for writing the dev note.

Introducing the block_core_navigation_listable_blocks 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.

WordPress 6.5 introduces a new filter, block_core_navigation_listable_blocks which is designed to provide control over the accessible rendering of child blocks used within the Navigation block.

Historically, the Navigation block has conditionally wrapped particular blocks in <li> tags to ensure accessible markup on the front of the site.

With the introduction of the new allowedBlocks API, which technically allows any block to be added as valid children of the Navigation block, developers require a means to indicate which blocks need to be wrapped.

The block_core_navigation_listable_blocks filter allows developers to determine whether a specific block should be wrapped in an <li> 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.), thereby aiding in adherence to 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) standards and the creation of valid markup.

The example below shows the mycustomblock/icon block opting into being wrapped in an <li> tag:

function add_icon_block_to_navigation_listable_blocks( $blocks ) {
$blocks[] = 'mycustomblock/icon';
return $blocks;
}
add_filter( 'block_core_navigation_listable_blocks', 'add_icon_block_to_navigation_listable_blocks' );

GitHub pull request: #55551

Props to @get_dave for writing the dev note.

Add new selectors to fetch entity revisions

Two new selectors have been introduced to Block Editor’s Core Data API to fetch revisions and single revisions for post types that support revisions, for example, posts and pages, templates, and global styles.

getRevisions( kind, name, recordKey, query ) – fetches a post’s revisions where recordKey is the id of the parent post.

getRevision(kind, name, recordKey, revisionKey, query) – fetches a single post revision, where revisionKey is the id of the individual revision.

The functions use similar arguments to existing core data entity functions, such as getEntityRecords with the addition of recordKey (post parent id) and revisionKey (single revision id).

Example usage:

// Returns a collection of revisions.
// `parentGlobalStylesId` is the id (int) of the parent post.
wp.data.select( 'core' ).getRevisions( 'root', 'globalStyles', parentGlobalStylesId, { per_page: -1 } );
 
// Paginated results.
// `parentId` is the id (int) of the parent post.
wp.data.select( 'core' ).getRevisions( 'postType', 'post', parentId, { per_page: 3, page: 2 } )
 
// Get a single revision object.
// `parentId` is the id (int) of the parent post.
// `revisionId` is the id (int) of the individual revision post.
wp.data.select( 'core' ).getRevision( 'postType', 'post', parentId, revisionId );
 
 
// Get a single revision with only the id, parent and date fields.
// `parentId` is the id (int) of the parent post.
// `revisionId` is the id (int) of the individual revision post.
wp.data.select( 'core' ).getRevision( 'postType', 'post', parentId, revisionId, { _fields: 'id,parent,date' } );

getRevisions and getRevision can also be used via useSelect in ReactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org/. components:

import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';

function MyComponent() {
    const pageRevisions = useSelect(
        ( select ) =>
            select( coreStore ).getRevisions( 'postType', 'page', pageId ),
        [ pageId ]
    );
    // Do something with pageRevisions...
}

In the background, these selectors’ corresponding resolvers call revisions REST API endpoints.

GitHub pull request: #54046

Props to @ramonopoly for writing the dev note.

New useSettings hook for reading block instance settings

When trying to improve the block editor’s performance for WordPress 6.5, one of the identified issues was related to the useSetting hook that is used by block instances to read various settings provided by the environment they are in: parent blocks, the theme, the block editor itself. It turns out that it’s inefficient to read multiple settings with separate useSetting calls:

const allowFixed = useSetting( 'position.fixed' );
const allowSticky = useSetting( 'position.sticky' );

The editor performance is improved when all the settings are read at once using a new hook called useSettings:

const [ allowFixed, allowSticky ] = useSettings( 'position.fixed', 'position.sticky' );

That’s why WordPress 6.5 introduces this new hook. The useSetting (singular) hook is now deprecated (using it will trigger a console warning), because reading even a single setting is very easy with the useSettings (plural) hook:

const [ allowFixed ] = useSettings( 'position.fixed' );

The only change is that the useSettings hook always returns an array, and the array needs to be destructured to read the single value. Supporting two APIs for performing the same task is therefore not justified.

GitHub pull request: #55337

Props to @jsnajdr for writing the dev note.

Introduction of the PluginPostExcerpt Slot Component

This update introduces a new PluginPostExcerpt slot component within 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/ 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. allows for the extension of the Post ExcerptExcerpt An excerpt is the description of the blog post or page that will by default show on the blog archive page, in search results (SERPs), and on social media. With an SEO plugin, the excerpt may also be in that plugin’s metabox. panel, allowing developers to customize this area for their needs.

What’s New?

The component enables the addition of custom content within the Post Excerpt panel. This is particularly useful for plugins looking to add extra functionality or information specific to their use case.

Usage

To utilize this new feature, developers can now insert their custom content into the Post Excerpt panel by creating a component that leverages the slot. This allows for a seamless integration of custom functionalities directly within the editor.

The following example shows adding custom content to the post excerpt panel.

import { PluginPostExcerpt } from '@wordpress/edit-post';
import { __ } from '@wordpress/i18n';

const MyPluginPostExcerpt = () => (
  <PluginPostExcerpt
    className="my-plugin-post-excerpt"
  >
    { __( 'Post excerpt custom content' ) }
  </PluginPostExcerpt>
);

GitHub pull request: #55200

Props to @retrofox for writing the dev note.

Changes to the underlying Composite component implementation

WordPress 6.5 no longer includes the Reakit package, as it does not support React beyond v16. The __unstable* Composite component was built on this library, so it has been internally refactored.

What does this mean for consumers?

The primary API has not changed, and can still be imported with no changes. For typical usage patterns, there should be no differences, and in most cases, no action is required from consumers of the package.

However, composite state props must now be generated by the useCompositeState hook; they can no longer be provided by independent state logic. Composite state arguments have not changed, though, and will continue to work as before.

import {
  __unstableComposite: Composite,
  __unstableCompositeGroup: CompositeGroup,
  __unstableCompositeItem: CompositeItem,
  __unstableUseCompositeState: useCompositeState
} from '@wordpress/components';

const state = useCompositeState({ ... });

// ✅ This will continue to work
...( <Composite { ...state } /> );

// ⛔️ This will no longer work
...( <Composite { ...state } currentId={ ... } /> );

Consumers can continue to either spread the state or pass as a single state prop.

// ✅ Used by spreading the state
...(
  <Composite { ...state }>
    <CompositeGroup { ...state }>
      <CompositeItem { ...state }>
        { ... }
      </CompositeItem>
    </CompositeGroup>
  </Composite>
);

// ✅ Or with a single `state` prop
...(
  <Composite state={ state }>
    <CompositeGroup state={ state }>
      <CompositeItem state={ state }>
        { ... }
      </CompositeItem>
    </CompositeGroup>
  </Composite>
);

Because the shape of the returned composite state has changed, consumers can also now no longer destructure specific state props from useCompositeState.

// ✅ This will continue to work
const state = useCompositeState({ ... });

// ⛔️ This will no longer work
const { groups, items } = useCompositeState({ ... });

What’s next?

We anticipate a new stable Composite component to be released in WordPress 6.6, along with the deprecation of this unstable version.

GitHub pull request: #58620

Props to @andrewhayward for writing the dev note.

Deprecated components

Deprecating isPressed in Button component

The isPressed prop on the Button component implicitly sets aria-pressed, with no way to override it. But sometimes Button is used for roles other than button, such as option and checkbox, where aria-pressed is not appropriate, and workarounds are required to add the correct semantics.

In an effort to move away from custom props that have native HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. equivalents, and to allow greater flexibility in component usage, aria-pressed is now supported as a first-class prop, taking precedence over isPressed.

GitHub pull request: #54740

Props to @andrewhayward for writing the dev note.

Outer Margins Deprecation

A number of UI components currently ship with styles that give them top and/or 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 are in the process of deprecating these outer margins

A few releases ago, we deprecated the outer margins on a number of components and introduced transitional props so consumers could opt into these new styles before they become the default:

  • AnglePickerControl__nextHasNoMarginBottom
  • CustomGradientPicker__nextHasNoMargin
  • FontSizePicker__nextHasNoMarginBottom
  • GradientPicker__nextHasNoMargin

In WordPress 6.5, these margin-free styles have become the default. Any use of these props can be safely removed.

GitHub pull request: #58699, #58700, #58701, #58702

Props to @mikachan for writing the dev note.

CustomSelectControl deprecation

CustomSelectControl used to have a hard-coded width, which was inconsistent with our other form components. In WordPress 6.1, we deprecated this unconstrained width, and introduced the transitional __nextUnconstrainedWidth prop so consumers could opt into these new styles before they become the default.

In WordPress 6.5, these unconstrained width styles have become the default. Any use of the __nextUnconstrainedWidth prop can be safely removed.

GitHub pull request: #58974

Props to @mikachan for writing the dev note.

Remove deprecation warnings for __next36pxDefaultSize

A few releases ago, we introduced a __next36pxDefaultSize prop on several components, meant to coordiate the transition to a new default sizing scheme (36px height). Due to some changes in our design direction, we eventually dropped this prop in favor of the __next40pxDefaultSize prop (40px height), making all existing opt-ins to the __next36pxDefaultSize prop act as an opt-in to the 40px one.

After receiving developer feedback about this ahead of WordPress 6.5, we will no longer throw a deprecation warning for usages of the __next36pxDefaultSize prop, informing consumers of this change. Do note, however, that it will trigger the new 40px size rather than the 36px size, despite the prop name.

GitHub pull request: #58703

Props to @mikachan for writing the dev note.

Remove unused buttonBehavior attribute from the Search block

The Search block had a buttonBehavior attribute, which was referenced internally to determine the display variations of the block. However, this attribute was removed because it could not be changed from the user interface, and the default value was always referenced.

With this change, this attribute will no longer be referenced even if it has been added manually.

GitHub pull request: #53467

Props to @wildworks for writing the dev note.

Setting to disable custom content size controls

Similar to the setting that allows disabling layout controls in WP 6.4, this allows only the content and wide size controls for a constrained layout to be disabled from the 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, globally or at a per-block level.

To disable the control globally for all blocks, add the following in theme.json under settings.layout:

"allowCustomContentAndWideSize": false

To disable at the block level, add the following in theme.json under settings.blocks:

"core/group": {
"layout": {
"allowCustomContentAndWideSize": false
}
}

Props to @isabel_brison for writing the dev note.


Props to @fabiankaegy and @bph for reviewing the post

#6-5, #dev-notes, #dev-notes-6-5

Updates to the HTML API in 6.5

WordPress 6.5 brings significant updates to the HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. 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.. Notably, the Tag Processor received a major overhaul allowing it to scan every token in an HTML document and unlocking a broad array of new functionality. The HTML Processor supports much more of the HTML specification than it did when it was minimally introduced in WordPress 6.4.

New functionality in the Tag Processor.

The Tag Processor was designed to scan every 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.) in an HTML document, skipping all of the non-tag tokens. In WordPress 6.5 it can scan everything. Tokens are the fundamental pieces that make up a document; in the case of HTML, they are the tags, comments, doctype definitions, and text nodes. This means that it’s now possible to read the text content of an HTML document, trivializing previously-complicated operations like stripping tags or truncating HTML.

Supporting this work is the introduction of a new concept called modifiable text. Modifiable text represents content within token boundaries, or content which can be changed without affecting the structure of the document as a whole. Different tokens contain different types of modifiable text:

  • The entire span of a text node is modifiable text.
  • The inside contents of an HTML comment is modifiable text.
  • The content between the opening and closing tags of special elements is modifiable content.

In this case, special elements refer to elements whose inner contents cannot contain other HTML tags. These include the contents of SCRIPT and STYLE elements as well as the contents of the TITLE and TEXTAREA elements. There are a few more representing deprecated or invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid. syntax: see the class documentation for a comprehensive list.

New Methods.

  • next_token() advances to the next token in the document, including closing tags. Unlike next_tag() there is no query for this method. It scans everything.
  • get_token_type() indicates what kind of token was found, e.g. a #tag or #text or #comment.
  • get_token_name() returns a value roughly corresponding to the DOM nodeName, e.g. SPAN or #text or html (for doctype declarations).
  • get_modifiable_text() returns the properly-decoded text content for a matched token.
  • get_comment_type() indicates why the token is a comment, since different kinds of invalid markup become HTML comments. For example, <​![CDA​TA[​text]​]> is an HTML comment of the type COMMENT_AS_CDATA_LOOKALIKE because it appears as though it was intended to be a CDATA section, which doesn’t exist within HTML content.
  • paused_at_incomplete_token() indicates if the Tag Processor reached the end of the document in the middle of a token. For example, it may have been truncated in the middle of a tag.

Example usage:

$title = null;
$text_content = '';
$processor = new WP_HTML_Tag_Processor( $html );
while ( $processor->next_token() ) {
    if ( '#text' === $processor->get_token_type() ) {
        $text_content .= $processor->get_modifiable_text();
    } elseif ( null === $title && 'TITLE' === $processor->get_token_name() ) {
        $title = $processor->get_modifiable_text();
    }
}

echo $title ? $title : '(untitled post)';
echo "\n\n";
echo $text_content;

Expanded support in the HTML Processor.

WordPress is now able to recognize and properly parse most HTML. There are only a few major exceptions.

  • The HTML Processor will bail any time it encounters a FORM, MATH, SVG, TABLE, or TEMPLATE tag. These elements introduce complicated parsing rules that require additional care, testing, and design work.
  • There are times when an HTML parser needs to implicitly create an element that wasn’t in the HTML itself, or when it needs to move a tag to an earlier place in the document. This requires further design work to properly communicate that the document has retroactively changed.
  • If the HTML Processor is fed full HTML documents or snippets that exist outside of a BODY element (e.g. a document HEAD), then it will abort, as it currently only supports parsing HTML inside a BODY context.

The last point highlights that the HTML Processor has been developed following the needs 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.-related code and focused on rules in the HTML specification relating to how tags ought to be interpreted inside a BODY element. Once this section is complete, the others will be added. Thankfully, this is the hardest section by a long shot, and parsing full documents should follow quickly after the primary work is done.

Notes for experimenters.

If you’ve been experimenting with the HTML API and building custom subclasses of the Tag Processor then it’s important to understand two changes: handling of incomplete documents, and special HTML tags with modifiable text.

Incomplete documents.

Previously, when the Tag Processor reached the end of a document and there was an incomplete token (for instance, “<div cl“), it would return false and finish parsing the document. Now that the Tag Processor can scan and visit every token in the document, however, it will indicate if it encountered such a situation. When it does, it will still return false, but it will back up to the beginning of the token and freeze. In a future release, it will be possible to extend the document and continue processing. For now, if paused_at_incomplete_token() returns true, then you can know that there might have been more to the original HTML that was sent into the processor than it received.

Special HTML tags with modifiable text.

The HTML Processor properly tracks document structure and is the appropriate method for determining when an element starts and ends. Many simpler approaches will often seem correct enough for practical use, but these will all break down in common situations. While the Tag Processor makes it easier to estimate structure than regex-based approaches, be cautioned whenever skipping the rules that the HTML Processor implements, as even normative HTML often breaks simple mental models for translating HTML text into DOM structure.

For those who are relying on the Tag Processor to estimate structure, there’s a change in behavior that might break your subclasses: the Tag Processor no longer visits the closing tag for the group of special elements. These are tags like SCRIPT, STYLE, and TITLE. The reason for this change is that these elements cannot contain other tags inside of them. It will often look like they do (for instance, with <title>an <img> is plain text</title>), but the inner content is parsed as text and not as HTML. This change prevents misinterpreting those inner contents as HTML tags.

When the Tag Processor encounters a SCRIPT tag or any of these special elements, it will continue parsing until it finds the associated closing tag and then the inner contents will be available as modifiable text. For algorithms tracking depth in a document, they will not only need to check if the tag is_void(), but also if it’s a special element since the closing tag will no longer be separately visited.

Note that it’s still possible to visit a closing tag for a special element, but only if they are unexpected and come without a corresponding opening tag.


Follow along in the CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/. channel #core-html-api or watch here for updated posts to be part of the conversation driving and developing this API.

Props to @stevenlinx for copy review on this post.

#dev-notes #dev-notes-6-5 #6-5