Requests library upgraded to 2.0.5 in WordPress 6.2

TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. ticketticket Created for both bug reports and feature development on the bug tracker. #54504 was created to upgrade the Requests library to 2.0.0. Requests 2.0.0 was a major releasemajor release A release, identified by the first two numbers (3.6), which is the focus of a full release cycle and feature development. WordPress uses decimaling count for major release versions, so 2.8, 2.9, 3.0, and 3.1 are sequential and comparable in scope. and contains breaking changes. Additional upgrades to 2.0.5 were completed during this process. View the upgrade guide.

Namespacing introduced

Requests 2.0.0 introduces namespacing (PSR-4) for all Requests code. A full backward compatibility layer is included and old PSR-0 class names are still supported. However, using the old PSR-0 class names will generate a deprecation notice.

If 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 theme uses the WordPress native wp_remote_*() functions, you won’t need to do anything.

If your plugin or theme uses Requests directly, and only supports the latest version of WordPress, you should update your code to use the namespaced names. For example, to perform a request with a try-catch using the namespaced names:

// Old: Perform a request with a try-catch in Requests 1.x.
try {
	$response = Requests::request( $url, $headers, $data, $type, $options );
} catch ( Requests_Exception $e ) {
	return new WP_Error( 'http_request_failed', $e->getMessage() );
}

// New: Perform a request with a try-catch in Requests 2.x.
try {
	$response = WpOrg\Requests\Requests::request( $url, $headers, $data, $type, $options );
} catch ( WpOrg\Requests\Exception $e ) {
	return new WP_Error( 'http_request_failed', $e->getMessage() );
}

If your plugin or theme uses Requests directly and supports a wider range of WordPress versions, you may need to conditionally declare the REQUESTS_SILENCE_PSR0_DEPRECATIONS constant as true to silence deprecation notices about the old PSR-0 class names. You should upgrade your code as soon as WordPress 6.2 becomes the minimum WordPress version for your plugin or theme.

if ( ! defined( 'REQUESTS_SILENCE_PSR0_DEPRECATIONS' ) ) {
    define( 'REQUESTS_SILENCE_PSR0_DEPRECATIONS', true );
}

Directory structure changes

wp-includes/class-requests.php and wp-includes/Requests/library/Requests.php have been deprecated in WordPress 6.2.

Class and interface files/directories have been moved.

  • Old location: wp-includes/Requests/.
  • New location: wp-includes/Requests/src/.

The Requests class file is now located at wp-includes/Requests/src/Requests.php.

New minimum PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher version

Requests 2.0.0 drops support for PHP 5.2 – 5.5, and the new minimum supported PHP version is now 5.6.

Support for HHVM has also been dropped formally now.

Many classes now marked final

A large number of classes have been marked as final. These changes were made after researching which classes were being extended by plugin and theme authors, and due diligence was applied before making these changes.

If this change causes a problem that wasn’t anticipated, please open an issue to report it.

Stricter input validation

All typical entry point methods in Requests will now, directly or indirectly, validate the received input parameters for being of the correct type.

When an incorrect parameter type is received, a catchable WpOrg\Requests\Exception\InvalidArgument exception will be thrown.

The input validation has been set up to be reasonably liberal, so if Requests was being used as per the documentation, this change should not affect you. If you still find the input validation to be too strict and you have a good use-case of why it should be loosened for a particular entry point, please open an issue to discuss this.

PHP 8.x compatibility

Requests 2.x is compatible with PHP 8.0, 8.1 and 8.2.

A note on bundled certificates

While the changelogs for Requests 2.0.0 – 2.0.5 mention updates for bundled certificates, WordPress uses its own bundled certificates, so these updates do not affect plugins or themes.

Full changelogs

Props to @jrf and @hellofromtonya for peer review, to @bph, @webcommsat, and @milana_cap for review.

#6-2, #dev-notes, #dev-notes-6-2

Patterns API expanded to include template_types property

The Patterns 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 a powerful feature in WordPress that allows developers to create pre-designed blocks of content that can be easily inserted into posts, pages, custom post types, and templates. With the introduction of WordPress 6.2, the Patterns API has been expanded to include a template types property. The property allows pattern developers to specify which templates their patterns fit in. For example, a pattern can declare its purpose is to be used on 404 templates or as author templates, etc. Any template in the WordPress hierarchy is supported.

This is a backend-only update. The work on the UXUX User experience parts is ongoing and will be available in future 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/ releases – it is expected to arrive at the Site Editor in WordPress 6.3. The API provides WordPress coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. information on the patterns and template relationships. This information could be used for multiple purposes. The first usage, in thinking for WordPress 6.3, is to show the user some patterns that make sense on a template when the user starts creating a template. Users can start from a pattern instead of “blank” or the fallback template.

Technical details

The Patterns API’s register_block_pattern() function was updated to include a new template_types parameter. This parameter is an array of strings containing the names of the templates the template is intended for, e.g., 404, author, etc. The parameter template_types is optional, and using it is not mandatory to register a pattern.

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/. was also extended to return the template types of a pattern in case there is one defined.

Testing

  1. Activate the Twenty Twenty-One theme.
  2. In the theme’s inc/block-patterns.php file, after the existing calls to register_block_pattern(), add the sample test pattern with the snippet below (Figure 1). Save the file.
  3. Open the post editor and then the browser’s Developer Tools (Chrome) or Web Developer Tools (Firefox) console.
  4. In the console, enter the following to retrieve the registered patterns: wp.apiFetch( { path: '/wp/v2/block-patterns/patterns' } ).then( console.log );
  5. Verify that the API response includes the pattern query/template-type-test, and template_types has 404 listed (Figure 2).

Figure 1: Twenty Twenty-One Test Code Snippet

register_block_pattern(
    'query/template-type-test',
    array(
        'title'      => __( 'Template type test', 'twentytwentyone' ),
        'templateTypes' => array( '404' ),
        'content'    => '<!-- wp:paragraph {"align":"center","fontSize":"x-large"} -->
                        <p class="has-text-align-center has-x-large-font-size">404</p>
                        <!-- /wp:paragraph -->',
    )
);

Figure 2: API response output in Developer Tools Console tab

Screenshot of the Developer Tools console output of the example code

Props to @ironprogrammer for writing these detailed instructions, @bph and @webcommsat for review

#6-2, #dev-notes, #dev-notes-6-2

Introduction of Block Inspector Tabs

The 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. Inspector tabs aim to help organize and delineate the design tools within the Block 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.. Before these tabs, the sidebar was becoming increasingly crowded and challenging to use. With the release of WordPress 6.2, you’ll find the inspector’s design tools categorized under three tabs;

  • Settings – Contains configuration settings for the block that are not appearance-related, e.g. Number of columns or whether the block links to another resource.
  • Appearance – Groups panels and controls related specifically to styling the appearance of the current block, e.g. typography and colors.
  • List View – Contains controls for managing a block’s children in a similar manner to the editor’s list view, e.g. editing submenus and links in the Navigation block.

Block Inspector Tabs Display

The Block Inspector will only render tabs when it makes sense to do so. As such, there are a few conditions around their display:

  • A tab is only rendered if it contains items for display.
  • If the Settings tab would only contain the Advanced panel, it will be consolidated into the Appearance tab.
  • If the Block Inspector only has a single tab to display, tabs will not be rendered. Instead, the design tools will be rendered directly into the sidebar as they would have been prior to WordPress 6.2.

It is possible that the Block Inspector tabs may not make sense for all blocks. Plugins might also aim to overhaul a block’s available tools. In these cases, it would be desirable to disable Block Inspector tabs. This can be achieved via a new editor setting, blockInspectorTabs. One approach to doing so might be via the block_editor_settings_all filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output., like the example below.

function my_plugin_disable_tabs_for_my_custom_block( $settings ) {
	$current_tab_settings = _wp_array_get( $settings, array( 'blockInspectorTabs' ), array() );
	$settings['blockInspectorTabs'] = array_merge(
		$current_tab_settings,
		array( 'my-plugin/my-custom-block' => false )
	);

	return $settings;
}

add_filter( 'block_editor_settings_all', 'my_plugin_disable_tabs_for_my_custom_block' );

If available, the Block Inspector tabs will be displayed in the following order; List View, Settings, and Appearance. The default selected tab will be the first available. For the majority of blocks, this will be the Settings tab.

Inspector Control Groups

The InspectorControls groups have become requirements for new default experiences and features, such as the Block Inspector tabs or the Navigation Block’s off-canvas editor. As a result, the __experimentalGroup property has been stabilized. You can now define which InspectorControls group to render controls into via the group prop.

In addition to stabilizing the __experimentalGroup property, a new styles group has been added, so styles-related controls that do not fit conceptually under the block support panels; border, color, dimensions, typography etc., can be included under the “Appearance” tab in the Block Inspector.

<InspectorControls group="styles">
  // Add your custom styles-related controls here.
</InspectorControls>

Block Inspector Tabs vs InspectorControl Groups

Each Block Inspector tab is responsible for displaying a subset of the available Inspector Controls groups.

  • Settings Tab – Includes any items rendered into the default, settings (alias for default), advanced, or position groups.
  • Appearance Tab – Renders block support groups such as; bordercolordimensions, and typography. It also now includes the new styles group, which offers a means of displaying items under the Appearance tab but outside of the block support panels.
  • List View Tab – Includes only the list group as this tab is only intended for blocks that need to manage their own children in a list.

Settings-only Blocks

During the experiment trialling Block Inspector tabs, it became clear that some blocks should be considered “settings-only”. A great example of this is the Query block. A user’s primary focus while interacting with this block is to configure it to display their desired posts. Attempts to apply styling e.g. colors, at such a high level leads to inconsistent results.

To ease that friction moving forward, the color block support was removed from the Query block, making it settings-only. A new deprecation has been added to migrate existing Query blocks with colour styles. These will have their inner blocks wrapped in a Group block with the original color styles applied.

For blocks considered settings-only, the recommended approach to styling moving forward is to wrap the inner blocks in a style-provider block, e.g. Group.

Screenshots

Settings and Styles

Default (with icons)
Text only labels

List View, Settings, and Styles

Default (with icons)
Text only labels

Props to @bph and @webcommsat for review

#6-2, #dev-notes, #dev-notes-6-2

Shadows in Global Styles with WordPress 6.2

Shadows are an important part of a design – they help to establish a hierarchy of content and help bring focus to particular areas of a site. With WordPress 6.2 it is now possible to add and modify shadows to some blocks using Global Styles and 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..

Use in theme.json

To apply a shadow using theme.json, you can add this to a 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.’s definition:

"styles": {
    "blocks": {
        "core/button": {
            "shadow": "2px 2px #000000"
        }
    }
}

Themes can also define preset shadows like this:

"settings": {
		"shadow": {
			"preset": [
				{
					"name": "Shadow Name",
					"slug": "slug",
					"shadow": "5px 5px 0px -2px #FFFFFF, 5px 5px #000000"
				}
			]
		}
}

If your theme provides a preset then the blocks can use it like this:

"styles": {
    "blocks": {
        "core/button": {
            "shadow": "var(--wp--preset--shadow--slug)"
        }
    }
}

Use in Global Styles

Users can also modify these styles using the Global Styles UIUI User interface.

Navigate to Styles > Blocks > Button and you’ll see a Shadow option:

When you select the “Shadow” option you will be able to select from a variety of different shadow presets:

Note: This is currently only available on the Button block. There are plans to make it available for more blocks.

Props to @bph and @webcommsat for review .

#6-2, #dev-notes, #dev-notes-6-2

Introducing the HTML API in WordPress 6.2

This post was co-authored by Adam Zielinski @zieladam and Dennis Snell @dmsnell

WordPress 6.2 introduces WP_HTML_Tag_Processor – a tool for blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. authors to adjust HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. 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.) attributes in block markup within PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher. It’s the first component in a new HTML processing 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..

Updating HTML in WordPress has always required using uncomfortable tools. Regular expressions are difficult and prone to all kinds of errors. DOMDocument is resource-heavy, fails to handle modern HTML correctly, and isn’t available on many hosting platforms.

WP_HTML_Tag_Processor takes the first step towards bridging this gap.

The Tag Processor can reliably update HTML attributes

The Tag Processor finds specific tags and can change its attributes. Here’s an example setting an alt attribute on the first img tag within a block of HTML.

$html = '<img src="/husky.jpg">';

$p = new WP_HTML_Tag_Processor( $html );

if ( $p->next_tag() ) {
    $p->set_attribute( 'alt', 'Husky in the snow' );
}

echo $p->get_updated_html();

// Output:
// <img alt="Husky in the snow" src="/husky.jpg">

The next_tag() method moves to the next available tag in the HTML, but also accepts a tag name, a CSSCSS Cascading Style Sheets. class, or both in order to find specific tags. According to the HTML specification, lookup of tag and attribute names aren’t case-sensitive, but CSS class names are.

if ( $p->next_tag( array( 'tag_name' => 'DIV', 'class_name' => 'block-GROUP' ) ) ) {
    $p->remove_class( 'block-group' );
    $p->add_class( 'wp-block-group' );
}

Operations are safe by default:

  • remove an attribute without first checking if it exists,
  • add a CSS class which might already be there,
  • set an attribute value without ensuring that it’s not duplicating an existing one.

You no longer need to be concerned that your code mistakes for a real tag the content inside a <textarea>, and attribute value, or even inside an HTML comment.

The Tag Processor conforms to the HTML5 specification, so you don’t have to. It automatically escapes and decodes values where necessary and knows how to handle malformed markup.

$ugly_html = <<<HTML
<textarea title='<div> elements are semantically void'>
    <div><!--<div attr-->="</div>"></div>">
</textarea>
<div></div>
HTML;

$p = new WP_HTML_Tag_Processor( $ugly_html );
if ( $p->next_tag( 'div' ) ) {
    $p->add_class( 'bold' );
}

echo $p->get_updated_html();
// Output:
// <textarea title='<div> elements are semantically void'>
//     <div><!--<div attr-->="</div>"></div>">
// </textarea>
// <div class="bold"></div>

The Tag Processor operates fast enough to run in critical hot code paths and incurs almost no memory overhead. In WordPress 6.2 it replaces 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.-prone code relying on regular expressions and string-searching to perform similar updates.

For more advanced use of the Tag Processor, read through the extensive in-class documentation and learn how to…

  • …set bookmarks to re-visit parts of the document which have already been scanned and modified.
  • …visit closing tags like </div> in addition to the opening tags.
  • …run advanced and stateful queries by visiting every tag in a document.

Further considerations

There are many things the Tag Processor doesn’t do: it doesn’t build a DOM document tree, find nested tags, or update a tag’s inner HTML or inner text. Work on new HTML-related APIs continues, and a future WordPress release will build upon this work to enable accessing all of a block’s attributes from within PHP (if the block supplies a block.json file), finding tags using a CSS selector, and modifying the HTML structure with new tags, removed tags, and updated inner markup.

You can keep up with further development via this overview issues on 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/ 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/ Repo.

#6-2, #dev-notes, #dev-notes-6-2

Miscellaneous Editor changes in WordPress 6.2

In 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., you will find a collection of smaller changes to existing features and deprecated APIs and components.


Table of Contents


Fluid typography minimum font size

Following on from the fluid typography settings that were introduced in WordPress 6.1, WordPress 6.1.1 introduced a hard-coded minimum for the fluid typography rules of 14px, to ensure that the generated typography rules would not result in font sizes that were too smaller for readability in narrower viewports.

In WordPress 6.2, themes can define their own minimum font size for fluid typography rules. Depending on the theme’s requirements, sometimes the desired minimum font size value might be greater or less than the provided default of 14px. When used, the minimum font size will result in any font-sizes used that are equal to or less than the minimum being output directly as that font size. For font sizes larger than the minimum font size, the minimum font size will be used as the floor of the fluid typography calculated rule.

How to use the minimum font size in your theme

Within 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., the property settings.typography.fluid now accepts an object in addition to the existing boolean value. Setting fluid to true will use the default minimum font size of 14px; however, themes can now provide an object with a minFontSize property instead:

{
  "settings": {
    "typography": {
      "fluid": {
        "minFontSize": "15px"
      }
    }
  }
}

With the minFontSize property set to 15px in the above example, the output of a paragraph 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. set to 15px font size will be as follows with no fluid rules applied:

<p style="font-size:15px">A paragraph at 15px</p>

The output for a paragraph block set to 16px will result in the fluid rules being applied, but with 15px as the minimum font-size:

<p style="font-size:clamp(15px, 0.938rem + ((1vw - 7.68px) * 0.12), 16px);">A paragraph at 16px</p>

Props to @andrewserong for dev note (top)

Sizing controls for flex layout children

A new Layout feature was added that allows the children of container blocks with Flex type layout to provide controls to change their relative size within their parent block. This feature can be added to the container block in its __experimentalLayout settings in block.json, like so:

"__experimentalLayout": {
             "allowSizingOnChildren": true,
             "default": {
               "type": "flex"
            }
}

The controls for the child blocks will then be displayed under the “Dimensions” panel in the block 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.. If the parent’s orientation is horizontal the control will appear as “Width”, and if it’s vertical it will be “Height”.

Three options are available in this control:

  • “Fit” is the default, and means the block will take up only as much space as its intrinsic dimensions;
  • “Fill” makes the block stretch to take up all remaining available space within its parent;
  • “Fixed” allows for setting a fixed width or height (depending on the parent’s orientation) in px, %, em, rem, vw or vh units.

(#45364)

Props to @isabel_brison for the dev note (top)

wp-block-heading CSSCSS Cascading Style Sheets. class added to every Heading block

In WordPress 6.2, the h1-h6 elements added via the heading block have a brand new wp-block-heading CSS class.

This change enables styling the heading block differently from the regular h1-h6 elements. For example, the following theme.json would add a blue background to all h1 elements and a pink background to only the h1 elements added via the cover block:

{
	"styles": {
		"elements": {
			"h1": {
				"color": {
					"background": "blue"
				}
			}
	        },
		"blocks": {
			"core/cover": {
				"elements": {
					"h1": {
						"color": {
							"background": "pink"
						}
					}
				}
			}
		}
	}
}

Work is underway to add a CSS class to every block in future WordPress releases. ( #42122)

Props to @zieladam for the Dev Note to @ajlende and @scruffian for review (top)

wp_theme_has_theme_json()

WordPress 6.2 introduces a new method called wp_theme_has_theme_json() that returns whether the active theme or its parent has a theme.json file. The goal is to provide 3rd parties with a public 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. they can use to query the active theme for this information. It deprecates the private API  WP_Theme_JSON_Resolver:theme_has_support(). Details are available in the PR #45168

Edit block style variations from theme.json

This new theme.json API allows existing coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. block style variations to be styled directly from the theme.json file. It does not currently allow adding new variations. Styles should be added as follows:

Each variation should be targeted by its name, which can be found in the block’s block.json file, under “styles”.

	"styles": {
		"blocks": {
			"core/image": {
				"variations": {
					"rounded": {
						"border": {
							"width": "10px",
							"color": "#cc3ee6"
						}	
					}
				}
			}
                }
       }

There is also a corresponding UIUI User interface in the block section of global styles, as you can see in the screenshot. (#46343)

Screenshot 2023-03-03 at 10 23 55 am
Graphic: Edit style variations for Image block

Props to @isabel_brison for the dev note (top)

Updated caching behavior for APIs to access global styles and settings.

WordPress 5.9 added New API to access global settings & styles. In 6.2 they received updates to their caching behavior:

  • wp_get_global_settings => the result is now cached per request (also known as non-persistent cache), so it’s faster.
  • wp_get_global_stylesheet => the result is now cache per request (aka non-persistent) while it was cached using 1-minute transient. This caused bugs (the changes in the site editor were not reflected in the front until 1 minute later) that are fixed now.
  • wp_get_global_styles_svg_filters => the result is now cached per request (aka non-persistent cache) while it was cached using 1-minute transient. While this did not cause any known bugs, it was updated for due diligence.

More details are available in this tracking issue #45171

Props to @oandregal for dev note (top)

Retaining navigation when switching themes

When users switch themes, the navigation on their site should stay the same, regardless of whether it is a block theme or a classic theme. To enable users to switch from classic themes to block themes, we have made some further refinements to the way that the navigation block imports menus from classic themes.

If a site has a classic menu, and has not yet created a navigation using the navigation block, then the navigation block will automatically import a classic menu to use. Many classic themes (for example TT1) use the primary name and slug as a convention for its main menu location. If a site has a classic menu defined at this location, then the navigation block will import this one. If not, then it will use the most recently created classic menu.

The conditions for deciding which classic menu to import are:

  1. If no wp_navigation menus exist
  2. If the theme has a menu defined at location called primary, use that otherwise
  3. Use the most recently created classic menu

If these conditions are met, the navigation block will display the classic menu, automatically converting it to navigation menuNavigation Menu A theme feature introduced with Version 3.0. WordPress includes an easy to use mechanism for giving various control options to get users to click from one place to another on a site.. More details via the PR (#45976)

Props to @scruffian and @jffng for content (top)

Disable Openverse categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging. in new Media tab

In addition to Blocks and Patterns, with WordPress 6.2 the Inserter shows a new Media tab, giving the user fast access to the images, videos, and audio files in the Media library. It enables users to browse and search the Openverse catalog for Creative Commons licensed images. The Openverse media category can be controlled with a new public block editor setting(enableOpenverseMediaCategory). The default is to show this category, but it can be turned off by updating this setting’s value. (#47404)

settings = wp.data.select('core/block-editor').getSettings();
wp.data.dispatch('core/block-editor').updateSettings({
	...settings,
	enableOpenverseMediaCategory: false
});
add_filter(
	'block_editor_settings_all',
	function( $settings ) {
		$settings['enableOpenverseMediaCategory'] = false;

		return $settings;
	},
	10
);

Other block editor settings are listed in the handbook.

Props to @ntsekouras for the dev note (top)

Fixed focus issue after block removal.

In WordPress 6.2 the behavior of removeBlock() changed. Until then, when a block was removed, the previous block was selected and gained focus in the user interface. Occasionally, if there wasn’t any previous block available, it resulted in focus loss, which is a particularly difficult experience when using a screen reader.

With this update, the behavior of the removeBlock() action was changed to select the first parent instead. For a developer writing Custom Blocks or otherwise depending on the result of the removeBlock action, this might require an update to their code, to account for the possibility that sometimes the parent is selected on block removal. There is a way to opt-out of this behavior by passing false as the second argument to removeBlock() function.

Example code from the core/list block.

const shouldSelectParent = false;
removeBlock( parentListId, shouldSelectParent );

Details in #48204
Documentation removeBlock()

Props to @andraganescu for first draft, and to @webcommsat for review (top)

Bug fix: Global Styles for adminadmin (and super admin) users on multi-site

In WordPress 6.1 the layout block support was refactored to output CSS values for block spacing, with additional layout controls within global styles being made available. This resulted in a 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. for admin users without the unfiltered_html capability (e.g. admin users within a 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 instance) where block spacing or layout content sizes were not saved when updated within the global styles interface. (#45520) The cause was that within the Theme JSON class, theme.json values are filtered for users without the unfiltered_html capability based on a lookup to a direct CSS property, e.g. margin or padding. For layout features, the styling rules are stored in indirect properties that don’t directly map to a real CSS property, e.g. blockGap and contentSize.

For WordPress 6.2 (and backported to WordPress 6.1.2) this issue is resolved by the Theme JSON class storing a list of indirect properties (INDIRECT_PROPERTIES_METADATA), with a mapping between a CSS property to use for validation, and the path to the indirect property as stored in theme.json. In this way, blockGap will be validated against the CSS gap property, and contentSize against the CSS max-width property, etc.

For themes using layout features, no changes are required, as the bug fix is an internal implementation detail of how Theme JSON styles are validated and output.

See #46388, #46712

Props to @andrewserong for the dev note (top)

Removal of deprecated APIs and Components

formatting prop in RichText component

The formatting prop have been deprecated in WordPress 5.4 release and is not available anymore starting from WordPress 6.2. If you want to define the available formats when using the RichText component, use the allowedFormats prop instead. (#46106)

Props to @youknowriad for dev note (top)

useAnchorRef hook not deleted in 6.3

The deprecated useAnchorRef hook from the @wordpress/rich-text package will not be deleted in WordPress 6.3, as initially planned. (#45302)

DateTimePicker deprecated prop removal postponed to 6.3

The removal of the __nextRemoveHelpButton and __nextRemoveResetButton props on the DateTimePicker component in @wordpress/components, initially scheduled for 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/ 14.6, has been postponed to the Gutenberg 15.8 release. (#46006)

Props to @mciampini for above dev note (top)

Deprecate non-string descriptions

In WordPress 6.2, non-strings as block descriptions have been deprecated.

Previously, we could register a block with a non-string description (like a ReactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org/. Node or any other 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/. object for example). Another way to achieve that was to use the blocks.registerBlockType filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. and change the description with a non-string there.

While there could be niche edge cases that found non-string descriptions useful, contributors discovered that this could cause unexpected bugs and thus have decided to deprecate it. This makes it clearer that the recommended type for block descriptions should be of type string only.

For context and more information, see #44455 and #44233. (top)

Removal of the Navigation Editor screen and associated package

The Navigation Editor screen was an experimental feature of the Gutenberg PluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party that contributors worked on as a potential replacement for the classic Menus screen using a block-based paradigm. The code for this feature existed within a dedicated @wordpress/edit-navigation package.

As the Navigation project has evolved, however, the requirement for a dedicated screen has become less pronounced, with features originally proposed for/included within the screen being incorporated into the Navigation block itself.

During the 6.1 cycle, due to lack of contributions, the experiment was informally deprecated in the Plugin by being removed from the Experiments screen in the Gutenberg Plugin settings page.

With the arrival of list view editing for the Navigation block in WordPress 6.2, menus can now be edited away from the editor canvas, and therefore it is finally time to formally remove the experiment from the codebase.

The @wordpress/edit-navigation package has now been removed from the Gutenberg repository and then associated package unpublished from npm. (#47055)

Props to @get_dave for content, @andraganescu and @talldanwp for review (top)


Props for review of the full post to @mciampini and @webcommsat

#6-2, #dev-notes, #dev-notes-6-2

Introducing move_dir() in WordPress 6.2

The problem

WordPress 2.5 introduced copy_dir() for copying a directory from one location to another. This function recursively creates the necessary subdirectories and copies files to their respective location in the new folder.

However, there was previously no function to move a directory that worked on all filesystems. This meant that CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress., and extenders, had to use copy_dir(), and then delete the original version. 

Moving a directory should not require so much memory, diskspace, time, or file operations. It should be quick, easy to call, and reliable.

The solution

WordPress 6.2 (#57375) introduces the move_dir() function, which has the following parameters:

  • from (string) – The current location of the directory.
  • to (string) – The new location of the directory.
  • overwrite (bool) – Whether to overwrite the destination. Default false.

The function will return true on success, or a WP_Error object on failure.

Failures include:

  • $from and $to are the same.
  • $overwrite is false and the destination exists.
  • $overwrite is true, and an existing destination could not be deleted.
  • If falling back to copy_dir() and the destination cannot be created.

How do you use it?

If your intent is to use move_dir(), and the destination hasn’t already been deleted, then it must be called with $overwrite as true.

$result = move_dir( $from, $to, $overwrite );

if ( is_wp_error( $result ) ) {
    return $result;
}

When can you start using it?

You can immediately begin replacing any combinations of copy_dir() and delete with move_dir() in anticipation of WordPress 6.2’s release.

As always, please perform sufficient testing to ensure your code continues to work as expected before publishing it to production/users. This includes testing in all WordPress 6.2 release candidates.

Where is it used in Core?

move_dir() has now been implemented within the WP_Upgrader::install_package() method in #57557. This affects all upgrade paths, reducing diskspace and memory usage, and improving speed to reduce timeouts on systems with lower resources when updating Plugins, Themes and Language Packs.

If an extender sets clear_working to false, or the destination exists and has contents, the upgrade will use copy_dir() instead.

This is not a replacement for the use of copy_dir() in Core updates, as there are several areas where specific subdirectories are not copied in the process.

Under The Hood

move_dir() uses the ::move() method for the WP_Filesystem_Direct, WP_Filesystem_FTPext, WP_Filesystem_ftpsockets, and WP_Filesystem_SSH2 filesystem abstractions.

Not only is this more intuitive for moving directories than a combination of copy_dir() and delete, but it’s also significantly faster, and uses less diskspace and memory on the server.

OPcache is invalidated for all of the moved files, using the newly introduced wp_opcache_invalidate_directory() function. Find out more about this function in the Miscellaneous 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 WordPress 6.2.

Should the move operation fail, move_dir() falls back to copy_dir(). If copy_dir() is successful, the source directory is deleted.

VirtualBox

While working on this function, Core developers encountered a well-known issue in VirtualBox, in which file existence and metadata may not be updated after a move. 

This produced a highly destructive result when a combination of Move A to C, Move B to A, Delete C was used via PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher’s rename() and unlink() functions.

move_dir() makes use of the calls to filesize() and filemtime() within the WP_Filesystem_*::dirlist() method called in wp_opcache_invalidate_directory() to resolve delayed metadata updates. File existence warnings are resolved with a 200ms delay after moving a directory, which gives the filesystem’s cache time to update.

This 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. was known exclusively to VirtualBox. Extensive testing in VirtualBox 6 and 7 has shown that move_dir() does not encounter this bug, and is safe to use.

Props to @milana_cap and @webcommsat for review.

#6-2, #dev-notes, #dev-notes-6-2

Miscellaneous developer changes in WordPress 6.2


Update on 8 March 2023: Add sections about oEmbed providers, search_columns argument, and privacy-policy attribute.


WordPress 6.2 brings more new hooksHooks In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same. and methods, as well as security updates.

Media

The Media component brings another 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., wp_get_attachment_link_attributes which allows developers to filter the link attributes when getting the attachment link. See #41574.

Besides the new filter, Media has a new method for setting Imagick time limit, WP_Image_Editor_Imagick::set_imagick_time_limit(). PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher timeout during the ImageMagick operation can cause multiple problems, such as temporary files not being cleaned by ImageMagick garbage collection. The cause of such a timeout is hard to pinpoint as no clear error is provided.

This method is expected to be run before heavy image routines. It is used in ::resize() and ::crop() and it aligns Imagick’s timeout with PHP’s timeout, assuming it is set, which will resolve the cleaning of temporary files issue. See #52569.

The wp_ajax_save_attachment action hook is renamed to wp_ajax_save_attachment_updated to avoid confusion with the similarly named wp_ajax_save-attachment action. See #23148.

Login and Registration

The new release of WordPress will disable spellcheck for password fields. However small this change might seem at first, spellcheck is considered a security and privacy concern by MDN. The specification does not regulate how spellchecking is done and the element’s content may be sent to a third party for spellchecking results. Thus, it is recommended to set spellcheck attribute to false for elements containing sensitive information, which is the case for password fields. See #56763.

Improvements in writing CSSCSS Cascading Style Sheets.

Position CSS properties (positiontoprightbottomleft, and z-index) are added in safe_style_css filter (#57504) to support sticky position 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. support. Read more about it in a 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.:

Another improvement in writing CSS happened in #57664, where the aspect-ratio is added as a valid property in kses.

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.

WordPress 6.2 introduces a new filter for wp_save_post_revision(), wp_save_post_revision_revisions_before_deletion. It allows extenders to exclude specific revisions from being considered for deletion. See #57320.

Example of using this filter to delete all but the oldest revision:

add_filter(
        'wp_save_post_revision_revisions_before_deletion',
        function( $revisions, $post_id ) {
                $original_revision = get_transient( 'original_revision_for_post_' . $post_id );
                if ( $original_revision ) {
                        // Always remove the oldest revision from the array of revisions to potentially delete.
                        unset( $revisions[ $original_revision ] );
                } else {
                        // Set the oldest revision in a transient, so we can verify that it is always ignored.
                        $original_revision = array_key_first( $revisions );
                        set_transient( 'original_revision_for_post_' . $post_id, $original_revision );
                }
                return $revisions;
        },
        10,
        2
);

Props to @audrasjb for the snippet.

HTTPHTTP HTTP is an acronym for Hyper Text Transfer Protocol. HTTP is the underlying protocol used by the World Wide Web and this protocol defines how messages are formatted and transmitted, and what actions Web servers and browsers should take in response to various commands. 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.

Changes in HTTP API modify WP_Http::make_absolute_url() to prevent it from dropping URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org fragments, which, in turn, fixes the same issue for links_add_base_url(). If you wish to maintain the legacy behaviour, include strip_fragment_from_url(). See #56231.

Changes in oEmbed providers

Mixcloud oEmbed URL was updated to their new domain. The old endpoint https://www.mixcloud.com/oembed was replaced with https://app.mixcloud.com/oembed. Old URLs will be automatically redirected by Mixcloud to the new endpoint.

See ticketticket Created for both bug reports and feature development on the bug tracker. #57376 for more information.

oEmbed Support was added for crowdsignal.net surveys. Crowdsignal has a block-editor powered survey/project editor. Surveys created using this editor appears on `*.crowdsignal.net` when published. WP 6.2 adds oEmbed support for these URLs to embed Crowdsignal surveys.

See ticket #57543 for more information.

Props to @audrasjb for the dev note.

Introducing the search_columns argument to control which fields are searched in a search query

Previously, the s argument of the WP_Query::parse_query() method searched the post_title, post_excerpt, and post_content fields, with no way of controlling this apart from using the posts_search filter and adjust the SQL manually.

WordPress 6.2 adds the ability to specify which fields are searched when performing a query, using the search_columns argument.

For now, only the default post_title, post_excerpt and post_content columns are allowed, but it may be extended on further releases of WordPress.

The default value of the  search_columns argument is: array( 'post_title', 'post_excerpt', 'post_content' ).

The example below will search for posts containing  foo in their 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. (post_excerp column), excluding post_title and post_content columns.

<?php
$my_query = new WP_Query(
	array(
		's'              => 'foo',
		'post_type'      => 'post',
		'search_columns' => array( 'post_excerpt' ),
	)
);

See ticket #43867 for more information.

Props to @audrasjb for the dev note.

Introducing the privacy-policy rel attribute on Privacy Policy links

WordPress 6.2 introduces a new rel="privacy-policy" attribute to user-facing links to the Privacy Policy of the website when a privacy policy page is set and available.

The rel attribute defines the relationship between a linked resource and the current document. While adding a  rel value for privacy policy links is still a RFC of the Link Types HTML specification, the WordPress CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. Team decided to implement it, to help make Privacy Policy links more discoverable for user agents and HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. parsers.

As of WP 6.2, all links generated via get_the_privacy_policy_link() will return the following markup:

<a class="privacy-policy-link" href="PRIVACY_PAGE_URL" rel="privacy-policy">PRIVACY_PAGE_TITLE</a>

For more information, see ticket #56345.

Props to @audrasjb for the dev note.

Props to @webcommsat, @bph for the peer review.

#6-2, #dev-notes

Sticky position block support

WordPress 6.2 adds a new position 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. support feature, beginning with support for sticky positioning, with the Group block opted-in by default. For themes using the appearanceTools feature in theme.json, the Group block will now be able to be set to “sticky”. The sticky positioning feature follows the CSS behavior for position: sticky which sets an element to stick to its immediate parent (in this case, the block’s immediate parent) when the user scrolls down the page.

Because it can be a potentially confusing feature to work with, for WordPress 6.2, the positioning controls will only be displayed for Group blocks at the root of the document. To create a sticky 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. in a site template, people building themes or sites can wrap a Header template part in a Group block and set that Group block to “sticky”.

This is just the beginning of the position block support feature, and there are ideas for future enhancements, including rolling out sticky to non-root blocks, and improving the UXUX User experience surrounding building sticky site headers. There is an open issue in 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/ repo to track progress beyond 6.2.

How to add sticky position support to a theme

There are two ways to add support for sticky position to a blocks theme. The simplest is to opt in to the appearanceTools setting, which automatically enables several 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 sticky position support can be opted into by setting settings.position.sticky to true in theme.json. For example:

{
	"settings": {
		"position": {
			"sticky": true

How does it work?

When a user sets a block to the sticky position via the drop-down list in the inspector controls, styling rules are output for position: sticky, a top position of 0px (with an offset to account for the logged in adminadmin (and super admin) bar), and a hard-coded z-index value of 10 to ensure that the sticky block sits above other content, while still working correctly in the admin UI. There is not yet support for controlling custom z-index values.

To support the output of these position properties, the safe_style_css 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. has been updated in core to support the positiontoprightbottomleft, and z-index properties.

The styling rules are output when the block is rendered, and a class name is-position-sticky is injected into the block markup. For themes wishing to add custom CSSCSS Cascading Style Sheets. that targets sticky positioned group blocks, this could be achieved by using a selector like .wp-block-group.is-position-sticky.

Why was support for non-root sticky blocks removed in Gutenberg?

While the feature was being developed in the Gutenberg pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party, sticky positioning was initially enabled in all hierarchies of blocks. However, in manual testing, feedback indicated that without additional UI or UX work, it could be confusing for users attempting to create sticky headers if they accidentally set a non-root block to sticky, or for example, a block within a header template part to sticky. The decision was to scale back the feature to just the root blocks for 6.2 to allow more time to explore a suitable solution for nested blocks. See the discussion in this Gutenberg issue for more context.

Why is positioning not available in global styles?

The position block support has been designed to be set within individual block attributes, as positioning is typically set for an individual block, rather than globally for a particular block type. Therefore, within theme.json the position setting can be used to opt in to using the position support, however a block’s position styles cannot be set within global styles. It should instead be set at the individual Group block level, either within a site template, or a page or post.

Further reading

Props to @bph and @webcommsat for review

#6-2, #dev-notes, #dev-notes-6-2

Upgrading to React 18 and common pitfalls of concurrent mode

WordPress 6.2 ships with version 18 of ReactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org/., 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/. library used to build 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 and all custom blocks. It comes with several new features, improvements, and 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. fixes, including a new rendering algorithm, called concurrent mode. (#45235)

In concurrent mode, React performs UIUI User interface updates faster, and keeps the web page responsive. When it works on a large and complex UI update, it can still process all user input (mouse events, scrolling, keyboard events) in real-time, concurrently with the work it’s already doing.

However, it also introduces some potential pitfalls that developers need to be aware of, and which may break some components that rely on the precise timing of events and state updates. These pitfalls affect only a small set of complex and specialized React code. Unless your code relies on the specific timing of state updates, it’s almost certain that your code will continue to work without any changes.

Batched state updates

Almost all concurrent mode pitfalls are related to a feature called “batched state updates”. What does that mean? Consider this React component:

function ShowX() {
  const [ x, setX ] = useState( 0 );

  console.log( 'rendering with state', x );

  useEffect( () => {
    const handle = setTimeout( () => {
      console.log( 'started setting state' );
      setX( 1 );
      setX( 2 );
      console.log( 'finished setting state' );
    }, 1000 );

    return () => clearTimeout( handle );
  }, [] );

  return <div>{ x }</div>;
}

This component will initially render with state 0, and after one second it will do two state updates after each other: first to 1 and then to 2. In React 17, without concurrent mode and automated batching, messages in the console would be logged in this order:

rendering with state 0
started setting state
rendering with state 1
rendering with state 2
finished setting state

Each of the setX calls will immediately and synchronously trigger a component render, and there will be two renders. By the time the script executes the line that logs finished setting state, both renders have already happened. The effects from the setX(1) update has been executed, too. Every so often there is code that relies on the fact that the render and/or effects are already performed at this moment. And exactly this kind of code is a typical source of concurrent mode bugs. Because in concurrent mode, in React 18, the order of the logged messages will be very different:

rendering with state 0
started setting state
finished setting state
rendering with state 2

First, by the time the finished setting state message is being logged, no render has happened yet. At that time it’s merely scheduled, not yet performed.

Second, both setX(1) and setX(2) updates have been batched together, and only one render was performed with the 2 final values, after performing both state updates in a batch. That’s another source of bugs. If your code relied on the render with the state 1 being performed, it will never happen. Effects are also running only with the 2 value, the 1 effects are skipped.

Batched updates and @wordpress/data

A special case of batched state updates, often present in WordPress code, are dispatch calls in @wordpress/data stores:

const counter = useDispatch( counterStore );
counter.increment();

Here, dispatching the increment action ultimately leads to a state update inside a component that selects from the counterStore. Occasionally, your code can rely on the fact that immediately after the counter.increment() call, all the updates and re-renders have been already synchronously executed. But, as described above, in React 18 concurrent mode that doesn’t happen immediately. The update is merely scheduled at that time.

New APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. for mounting a root

If 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 is mounting its own React UI into the page, instead of exporting React components to be rendered by the Block Editor, you should be aware of the new React 18 APIs for mounting a component root. The old, React 17 way, was the render function from react-dom or from @wordpress/element:

import { render } from '@wordpress/element';

const el = document.getElementById( 'root' );
render( <App />, el );

This still continues to work, and you can continue to use it. The only downsides are that you’ll be getting a console warning about using a React 17 legacy API, and that concurrent mode is disabled in React apps mounted this way.

The React 18 way is to use the new createRoot API:

import { createRoot } from '@wordpress/element';

const el = document.getElementById( 'root' );
const root = createRoot( el );
root.render( <App /> );

There is one extra step: from a DOM element, you create a root, and then you render a JSX element into that root. Apps mounted this way will use the new concurrent mode.

There is also a new API for unmounting a React root. The old one was unmountComponentAtNode( el ), the new one is to call a method on the root object: root.unmount()

Other new APIs in React 18

There are other new API functions in React 18, all of them also exported by the @wordpress/element package:

These are entirely new and don’t introduce any backwards-compatibility concerns. If you would like to learn about them or want to use them, please consult the React 18 Migration Guide and the React docs.

Props to @youknowriad, @tyxla, @bph, @milana_cap for review

#6-2, #dev-notes, #dev-notes-6-2