Cover Block Refactor Dev Note

Prior to the WordPress 5.9 release, the Cover 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. was refactored in ways that changed the block HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. structure, and these changes were merged into coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. and released in 5.9. These changes were not noted 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. at the time, or in the 5.9 release notes, so theme and pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party authors were not alerted to this change.

This is a retrospective Dev Note to outline the reasons for, and the nature of these changes, and also to highlight two regressions that this change introduced. Patches for these regressions will be included in the 5.9.1 release.

The changes

Background opacity

In order to allow the opacity of the Cover block to be set when only a background color was set, the background color style had to be moved from the main block wrapper to the same nested <span> element that is used to set the background image. This means that a Cover block with a background color set changed from:

<!-- wp:cover {"overlayColor":"vivid-cyan-blue"} -->
<div class="wp-block-cover has-vivid-cyan-blue-background-color has-background-dim">
<div class="wp-block-cover__inner-container">
    <!-- wp:paragraph {"align":"center","placeholder":"Write title…","fontSize":"large"} -->
        <p class="has-text-align-center has-large-font-size">Cover with no background color opacity
        </p>
    <!-- /wp:paragraph -->
    </div>
</div>
<!-- /wp:cover -->

to:

<!-- wp:cover {"dimRatio":70,"overlayColor":"vivid-cyan-blue","isDark":false} -->
<div class="wp-block-cover is-light">
    <span aria-hidden="true" class="has-vivid-cyan-blue-background-color has-background-dim-70 wp-block-cover__gradient-background has-background-dim"></span>
    <div class="wp-block-cover__inner-container">
        <!-- wp:paragraph {"align":"center","placeholder":"Write title…","fontSize":"large"} -->
            <p class="has-text-align-center has-large-font-size">Cover with background color opacity</p>
        <!-- /wp:paragraph -->
    </div>
</div>
<!-- /wp:cover -->

Regressions introduced by the change

  1. When Cover blocks are edited they are automatically migrated to this new structure, but all existing blocks in post content need to have the old version of the CSSCSS Cascading Style Sheets. in place in order to be correctly supported in the site frontend. Some of these deprecated styles where inadvertently removed which meant that those blocks with a custom opacity set defaulted back to an opacity of 0.5. This regressionregression A software bug that breaks or degrades something that previously worked. Regressions are often treated as critical bugs or blockers. Recent regressions may be given higher priorities. A "3.6 regression" would be a bug in 3.6 that worked as intended in 3.5. has been fixed with this GitHub pull request and will be included in the 5.9.1 release. In the meantime the addition of this custom CSS to a 5.9 site will also fix this issue.
  2. Currently the background gradient class is also being applied in cases where the gradient is not set. This issue is fixed with this GitHub pull request, and will be included in the 5.9.1 release. If you created/edited a theme/plugin in the last 3 months that is now relying on the wp-block-cover__gradient-background always being in place you will need to review this change. The alternative class .wp-block-cover__background has been added in 5.9.1 to enable selection of the background span in all contexts.

Default background color

Previously when adding a Cover block with a white background the paragraph text was invisible as it was also set to white. The Cover block was updated to only set the text to white if the background was dark. This required the addition of an additional is-light class on the blocks outer wrapper.

When a background image is used, a ‘best guess’ approach is taken to determine if light or dark text should be used based on the ‘average’ color of the image. This can lead to imperfect results if an image is largely ‘light’, but the text is placed over a dark patchpatch A special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing., as outlined in this GitHub issue. In these instances the text can be manually updated to a more suitable color. This was considered to be less of a UXUX User experience issue than white text being invisible by default over a white background.

#5-9, #dev-notes

Menus endpoints in WordPress 5.9

WordPress 5.9 adds three new 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/. endpoints to manage menus and menu locations. These menus endpoints are used the in new navigation block.

Before discussing menu endpoints, it’s worth noting how menus are currently stored. Navigation menus are stored using the nav_menu 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. and the nav_menu_item post type. A menu is stored as a term and acts like a container for a number of menu items. Menu items are stored as posts. Menus and menu items also have custom fields stored in 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. and in various options.

Accessible via /wp/v2/menus, the menus endpoint allows for performing CRUDCRUD Create, read, update and delete, the four basic functions of storing data. (More on Wikipedia.) operations on menu data. This endpoint extends the WP_REST_Terms_Controller class, mapping fields to the menus and adding functionality like auto_add, that automatically adds new pages to menus when created. A GET request includes the list of menus, but does not contain the list of menu items. To get this data, the menu items endpoint can be used.

Example output from request:

{
    "auto_add": false
    "description": "",
    "id": 36,
    "locations": ['wporg_header_subsite_nav', 'primary'],
    "meta": [],
    "name": "Navigation",
    "slug": "navigation",
}

Accessible via /wp/v2/menu-items, the menu items endpoint allows for performing CRUD operations on menu items and assigning them to menus. This endpoint extends the WP_REST_Posts_Controller class, mapping fields and adding custom functionality. Menu items can only be assigned to one menu at a time unlike other taxonomies.

Many menu items have an associated object that the menu item links to. For instance, a link to a page will have the object set to page and the object_id set to the WordPress Post ID of that page. When using this endpoint, it may be useful to get information about that linked object. For example the page’s title. This information is not included in the response by default, but the REST API has a feature to embed this information by using the _embed query parameter. For example, making a GET request to /wp/v2/menu-item/8874?_embed=true will result in the following response:

{
     "attr_title": "",
     "classes": [''],
     "description": "",
     "id": 8874,
     "invalid": false,
     "menu_order": 1,
     "menus": 363,
     "meta": {},
     "object": "page",
     "object_id": 8823,
     "parent": 0,
     "status": "publish",
     "target": "",
     "title": {rendered: 'Tickets'},
     "type": "post_type",
     "type_label": "Page",
     "url": "https://make.wordpress.org/core/reports/",
     "xfn": [""],
     "_embedded": {
              wp:menu-item-object: [
                   {
                      "author": 5286302,
                      "date": "2014-01-29T19:49:26",
                      "featured_media": 0,
                      "id": 8823,
                      "link": "https://make.wordpress.org/core/reports/",
                      "slug": "reports",
                      "title": { "rendered": "Bug Reports"},
                      "type": "page",
                   }
              ],
              wp:term: [
                    {
                       "id": 363,
                       "name": "Navigation",
                       "slug": "navigation"
                    }
              ]
    },
}

Accessible via /wp/v2/menu-locations, the menu locations endpoint returns a list of menu locations registered with the register_nav_menus function. To assign a menu to a particular location, use the menus endpoint, by passing an array of menu location keys.

Example output from request:

{
     "description": "Desktop Horizontal Menu"
     "menu": 90
     "name": "primary"
}

Batching requests

Both the menu and menu item endpoints, both support the batching of requests, introduced in WordPress 5.6. This means that more than one menu / menu item can be updates / created in a simple request to the 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..

Access Control

To access data from any of the menus endpoints, requests must be made by a logged in user with the edit_theme_options capability. By default, only users with the Administrator role have this capability. This means that menu data is not publically exposed via the REST API. Ticketticket Created for both bug reports and feature development on the bug tracker. #54304 provides a means for developers to opt-in to exposing this data publicly. The REST API team hopes to implement this feature in a near future release of WordPress.

These endpoints were first developed as a feature pluginFeature Plugin A plugin that was created with the intention of eventually being proposed for inclusion in WordPress Core. See Features as Plugins. on GitHub. For those using this 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, after upgrading to WordPress 5.9, the plugin can be deactivated and removed as all of it’s functionality is now included in WordPress CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress..

Props to @timothyblynjacobs for peer review.

#5-9, #dev-notes, #rest-api

WordPress 5.9 and PHP 8.0-8.1

PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher 8.1 was released on 25 November 2021. PHP 8.1 contains new features, performance improvements, deprecations, and backward compatibility breaks. For more information, see the PHP 8.1 release page, changelog, and migration guide.

WordPress is not fully compatible with PHP 8.0 or 8.1. All remaining known PHP 8.1 issues are deprecation notices.

Please note, a deprecation notice is not an error, but rather an indicator of where additional work is needed for compatibility before PHP 9 (i.e. when the notices become fatal errors). With a deprecation notice, the PHP code will continue to work and nothing is broken.

The following is a breakdown of changes in WordPress CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. that 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 theme developers need to be aware of and accommodate in their code.

PHP 8.1 Remaining known deprecation notices

Deprecation notices remain in WordPress 5.9 and work will continue in the 6.0 cycle.

What is required to resolve each?

  • Resolution requires a more structural and all-encompassing solution for input validation (i.e. validating the data type and, in some cases, value passed to a function/method) to be architected and implemented to properly fix the underlying 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. rather than introducing buggy unexpected behavior by haphazardly silencing the deprecation notice.
  • Each notice needs investigation to determine the impact of such changes.
  • Each change requires thorough testing including full coverage happy and unhappy unit/integration tests.

The remaining known deprecation notices include:

  • Functions in the wp-includes/formatting.php file.
  • parse_url() or wp_parse_url() passed directly to a non-nullable in PHP native function without validating a string type is returned (i.e. both will return null when the requested component doesn’t exist within the given URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org (see the PHP manual)).
  • wp_xmlrpc_server::mw_newPost(): changing content structure default values from null to an empty string. This change requires a review from XMLRPC domain expert and more testing.
  • Upgrade to Requests 2.0.0: Originally planned for WordPress 5.9, but reverted due to issues with WordPress Core’s updater. Currently planned for 6.0 (TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. #54504).

To follow or contribute to this ongoing work, see Trac #53465, #53635, #54183, and #54730.

WordPress Core Changes

PHP 8.0 polyfills introduced

The following PHP 8 polyfills are available in WordPress 5.9:

Each polyfill loads into memory when the site is run on PHP versions less than PHP 8.0.

PHP 8.0 named parameters: match parent to child class method signatures

As noted last year in the PHP 8.0 dev note, WordPress Core is not compatible nor supports named parameters:

Using named parameters when calling WordPress functions and class methods is explicitly not supported and highly discouraged until this audit can be completed, as during the audit, parameter names are subject to change without notice. When this audit has been completed, it will be announced in a future developer note.

In 5.9, WordPress Core’s parent and child class method signatures were changed. The parameter names match in the parent and child methods.

If you extend Core classes and choose to support named parameters, you’ll need to audit and change each method being overloaded to ensure the method signatures match the Core class being extended.

To follow or contribute to this review, see Trac #51553, and #50531.

PHP 8.1 readonly() renamed to wp_readonly()

Though originally planned as a reserved keyword, PHP 8.1 changed readonly keyword to a (limited) contextual keyword with potential future plans to deprecate.

WordPress 5.9 renames the readonly() function to wp_readonly(). For PHP 8.0 or earlier, the original readonly() function is loaded into memory but deprecated.

Reference:

PHP 8.1 return type enforcement and new #[ReturnTypeWillChange] attribute

PHP 8.1 introduces a new #[ReturnTypeWillChange] attribute to silence the deprecation notice for each PHP native interface method where the overloaded method’s return type is incompatible. WordPress Core adds the attribute to each of its instances.

When overloading a PHP native interface method, you should either have the return type declared (in a covariant compatible manner with the PHP native interface method declaration), or add the #[ReturnTypeWillChange] attribute to silence the deprecation notice.

For example, when implementing the ArrayAccess interface, ensure the required methods are compatible or add the attribute as follows:

/**
 * @param mixed $offset The offset to check for.
 *
 * @return bool True on success or false on failure.
 */
#[ReturnTypeWillChange]
public function offsetExists( $offset ) {
	// the code
}

/**
 * @param mixed $offset The offset to retrieve.
 *
 * @return mixed The offset’s value.
 */
#[ReturnTypeWillChange]
public function offsetGet( $offset ) {
	// the code
}

/**
 * @param mixed $offset The offset to assign the value to.
 * @param mixed $value  The value to set.
 */
#[ReturnTypeWillChange]
public function offsetSet( $offset, $value ) {
	// the code
}

/**
 * @param mixed $offset The offset to unset.
 */
#[ReturnTypeWillChange]
public function offsetUnset( $offset ) {
	// the code
}

See the PHP RFC: Add return type declarations for internal methods.

PHP 8.1 MySQLi default error mode changed

PHP 8.1 changed the default mysqli error mode from silent to fatal error.

Prior to PHP 8.1, the default error handling mode of MySQLi was silent (i.e. MYSQLI_REPORT_OFF). An error in the extension, database, query, or the database connection returned false and emitted a PHP warning.

PHP 8.1 changed the default error mode to MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT. An error in the extension, database, query, or the database connection throws a fatal error exception.

WordPress Core has its own error reporting and gracefully handles the database errors by inspecting the error codes. In 5.9, Core sets MySQLi error reporting to off to avoid fatal errors due to uncaught exceptions and maintains the current behavior (see Trac #52825).

If you are using wpdb, 5.9 takes care of this for you. However, if you are not using wpdb, you will need to make changes in your theme or plugins. It is recommended to switch to wpdb.

References:

PHP 8.1 deprecation: passing null to non-nullable PHP native functions parameters

A deprecation notice is thrown when passing a null value to a PHP native function’s parameter that is not declared nullable. The value will continue to be coerced, meaning the PHP behavior has not (yet) changed. However, in PHP 9, a TypeError will be thrown.

For example, passing null to strlen() (which expects a string type) will throw the following notice:

Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated in .. on line ..

The deprecation notice identifies where an underlying bug exists in the code base. Rather than merely silencing the deprecation, the approach taken in WordPress Core is to fix each underlying bug notice through input validation (i.e. validating what is passed to the function) or targeted guarding to skip processing for type mismatches.

As noted previously, deprecation notices remain in WordPress Core. These remaining deprecation notices will require a more structural and all-encompassing architectural solution and tests to avoid haphazardly silencing the deprecation notice while potentially introducing buggy, unexpected behavior.

To follow or contribute to this effort, see Trac #54730.

What do you need to do?

Analyze each deprecation notice in your theme or plugin and craft a solution that resolves the bug.

For example, skip the trim() operation when the value to trimmed is not scalar:

if ( is_scalar( $value ) ) {
	$value = trim( $value );
}

Check that a string type is returned from the following function before passing the returned value to a PHP native function:

  • parse_url() or wp_parse_url() will return null when the requested component doesn’t exist within the given URL (see the PHP manual).
  • filter_input() will return null if the var_name to get is not set or if using FILTER_NULL_ON_FAILURE flag but the 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. fails.

For example:

$url_path     = parse_url( $url, PHP_URL_PATH );
$url_filename = '';
if ( is_string( $url_path ) && '' !== $url_path ) {
	$url_filename = basename( $url_path );
}

References:

PHP 8.1 deprecation: autovivification on false

Autovivification is the automatic creation of an array. When a variable is defined as a boolean false and then used as an array as shown,

$arr   = false;
$arr[] = 2;

PHP 8.1 throws a deprecation notice:

Deprecated: Automatic conversion of false to array is deprecated in .. on line ..

In PHP 8.1, this code will continue to work; however, in PHP 9.0, it will result in a fatal error.

There are multiple ways to fix your code to not only resolve the deprecation notice but to also avoid a fatal error in the future when PHP 9 is released. Some of ways include:

  • Declare an array before using it, i.e. $arr = array();.
  • Check the returned value to ensure it is an array or at minimum not false before using.
  • When getting an option with get_option(), if an array type is expected, set the default to an empty array.
$options = get_option( ‘some_option’, array() );

For more information, see the PHP RFC: Deprecate autovivification on false.

PHP 8.1 deprecation: implicit incompatible float to int conversion

The implicit conversion of float to int which leads to precision loss will throw a deprecation notice.

$arr = array();
$arr[15.5]; // will throw the deprecation notice because 0.5 is lost

References:

PHP 8.1 other notable deprecations and changes

The following functions are deprecated:

  • Date functions: date_sunrise(), date_sunset(), gmstrftime(), strftime(), strptime().
  • Hash functions:  mhash(), mhash_keygen_s2k(), mhash_count(), mhash_get_block_size(), and mhash_get_hash_name() .
  • Calling key(), current(), next(), prev(), reset(), or end() on objects is deprecated.

The following functions changed:

  • The default of ENT_COMPAT changed to ENT_QUOTES | ENT_SUBSTITUTE in these functions htmlspecialchars(), htmlentities(), htmlspecialchars_decode(), html_entity_decode(), and get_html_translation_table() (Trac #53465).
  • Undocumented operation abbreviations can no longer be passed to version_compare().

See the Migrating from PHP 8.0.x to PHP 8.1.x for a complete list of deprecations and changes.

External Libraries

WordPress 5.9 includes the following updated external libraries:

  • GetID3 1.9.21 which includes preliminary PHP 8.1 support (Trac #54162).
  • SimplePie 1.5.7 which includes significant PHP 8.0 and 8.1 compatibility improvements ( Trac #54659).
  • PHPMailer 6.5.1 which includes preliminary PHP 8.1 support (Trac #53953).

The Requests 2.0.0 library was originally planned for WordPress 5.9. However, due to issues with WordPress Core’s upgrader, it was reverted and planned for 6.0 (Trac #54504).

Test Suites and Tooling

Changes to the WordPress Core PHP Test Suite

What about static tooling? Can it identify incompatibilities?

PHPCompatibility can only find a limited amount of these issues. PHPStan/Psalm/Exakat may find more, but are prone to false positives for non-typed code bases.

A Good Test Suite is the first line of defense

Most of the incompatibilities can be found through a good test suite, which includes full test coverage of both happy and unhappy paths.

Theme and plugin developers are encouraged to extend your test suites.

WordPress Core’s test coverage is currently less than 10%. You are invited and encouraged to contribute tests to grow test coverage in WordPress.

PHPUnit deprecation notices

In PHPUnit < 9.5.10/8.5.21, if a PHP native deprecation notice was encountered, PHPUnit would:

  1. Show a test which causes a deprecation notice to be thrown as “errored”;
  2. Show the first deprecation notice it encountered;
  3. Exit with a non-0 exit code (2), which will fail a CI build.

As of PHPUnit 9.5.10/8.5.21, if a PHP native deprecation notice is encountered, PHPUnit will:

  1. Show a test which causes a PHP deprecation notice to be thrown as “risky”;
  2. Show all deprecation notices it encountered;
  3. Exit with a 0 exit code, which will pass a CI build.

To follow or contribute to this review, see Trac #54183.

Why is this a problem?

These deprecations will become errors in the next PHP major and they will still need to be fixed. As CI builds pass, the deprecations go unnoticed. This means more deprecations remaining in WordPress Core, and would lead to more reports of deprecation notices from end-users.

What’s changing in WordPress Core?

The single site and 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 PHPUnit configuration files for WordPress Core now include the following attributes:

convertErrorsToExceptions="true"
convertWarningsToExceptions="true"
convertNoticesToExceptions="true"
convertDeprecationsToExceptions="true"

How does this solve the problem?

This will cause CI builds to fail when a native PHP deprecation notice is encountered, meaning that deprecation notices can not go unnoticed.

Are there any negatives?

Only the first deprecation notice will be shown for a test, and there may be more issues hiding behind a deprecation.

What’s coming in PHP 8.2

A significant change is coming in PHP 8.2 which could impact your themes and plugins. The  RFC to deprecate dynamic properties was approved. See the RFC for more information.


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

#5-9, #dev-notes

Updates for Settings, Styles, and theme.json

Changes in v2 of theme.jsonJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML.

WordPress 5.9 is evolving the theme.json v1 introduced in WordPress 5.8 to a v2. The existing v1 theme.json files will still work as expected, and they’ll be transformed at runtime to the v2 format by WordPress.

Please, refer to the live specification document for a detailed description of the theme.json file capabilities.

Changes per section

Version

It’s now 2 instead of 1.

You don’t need to update the v1 file for it to work, as it’ll be transformed into v2 at runtime for you. However, if you want to update a v1 file, keep in mind that you have to update the version value and potentially change the names of some keys. See below for a full set of changes.

For example, one of the changes from v1 to v2 is that the customLineHeight key has been renamed to lineHeight. Besides changing from version 1 to 2, you also need to rename the old customLineHeight name, as it’s an 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. key for the v2 file and will be ignored.

Settings

The following section documents the changes done to settings in v2:

  • appearanceTools: new key; see section below for a detailed description.
  • border:
    • customRadius has been renamed to radius.
    • colorstyle, and width keys have been added; they control the visibility of the corresponding UIUI User interface controls. false by default.
  • color:
    • text and background keys have been added. They control the visibility of the corresponding controls. true by default.
    • defaultGradients and defaultPalette keys have been added to control whether the color palette UI control should show the default colors (gradients and solids, respectively) in addition to the theme colors. true by default.
  • spacing:
    • customMargin and customPadding have been renamed to margin and padding, respectively.
    • blockGap is a new key, see section below for a detailed description.
  • typography:
    • customLineHeight has been renamed to lineHeight.
    • fontStylefontWeightletterSpacingtextDecoration, and textTransform keys have been added. They control the visibility of the corresponding UI controls. true by default.
    • fontFamilies preset has been added. Themes can now provide a list of fonts to be displayed to the user in the blocks that support the font family style. WordPress doesn’t provide any font family by default.
    • The fontSizes preset has been updated. The Normal and Huge sizes (with normal and huge slugs) have been removed from the list, and Extra Large (x-large slug) has been added. While the UI controls will no longer show the Normal and Huge values, their CSSCSS Cascading Style Sheets. classes and CSS Custom Properties are still enqueued to make sure content that uses them still works as expected.

Styles

The following section documents the changes done to styles in v2:

  • bordercolorstyle, and width styles are now allowed.
  • filter: new section to allow themes to attach filters to styles. So far, it only includes the duotone 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..
  • spacing: added a new style property, blockGap; see section below for a detailed description.
  • typographyfontFamilyfontStylefontWeightletterSpacingtextDecoration, and textTransform styles are now allowed.

Custom templates

The customTemplates field has been introduced in version 2. It allows themes to declare their custom templates that should be present in the templates folder.

For example, for a custom template named my-custom-template.html, the theme.json can declare what post types can use it and what’s the title to show the user:

  • name: mandatory.
  • title: mandatory, translatable.
  • postTypes: optional, only applies to the page by default.

Example (theme.json):

{
  "version": 2,
  "customTemplates": [
    {
      "name": "my-custom-template",
      "title": "The template title",
      "postTypes": [
        "page",
        "post",
        "my-cpt"
      ]
    }
  ]
}

Template parts

The templateParts field has been introduced in version 2. It allows themes to list the template parts present in the partsfolder.

For example, for a template part named my-template-part.html, the theme.json can declare the area term for the template part entity responsible for rendering the corresponding 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. variation (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. block, Footer block, etc.) in the editor. Defining this area term in the theme.json will allow the setting to persist across all uses of that template part entity instead of a block attribute that would only affect one block. Defining area as a block attribute is not recommended as this is only used ‘behind the scenes’ to bridge the gap between placeholder flows and entity creation.

Currently, block variations exist for “header” and “footer” values of the area term. Any other values and template parts not defined in the json will default to the general template part block. Variations will be denoted by specific icons within the editor’s interface, will default to the corresponding semantic HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. element for the wrapper (this can also be overridden by the tagName attribute set on the template part block), and will contextualize the template part allowing more custom flows in future editor improvements.

  • name: mandatory.
  • title: optional, translatable.
  • area: optional, will be set to uncategorized by default and trigger no block variation.

Example (theme.json):

{
  "version": 2,
  "templateParts": [
    {
      "name": "my-template-part",
      "title": "Header",
      "area": "header"
    }
  ]
}

Appearance tools

The new setting appearanceTools serves to opt-in a number of other settings that are disabled by default, serving themes to quickly enable every setting available.

In v2, setting appearanceTools true opts-in to the following settings that are false by default:

  • border: color, radius, style, width
  • color: link
  • spacing: blockGap, margin, padding
  • typography: lineHeight

BlockGap

The blockGap adjusts the vertical margin, or gap, between blocks. It is also used for the gap between inner blocks in rows, buttons, and social icons. In the editor, the control for the blockGap is called Block spacing, located in the Dimensions panel.

By default the block gap support is disabled for all themes, but you can enable it in your theme.json with two different ways:

  • Set its value to false to enable the block gap styles support but keep the per block control hidden in the inspector controls of blocks.
  • Set its value to true to enable the block gap styles support and allow users to tweak the block gap per block (buttons, rows groups, social icons).

Example (theme.json):

{
	"version": 2,
	"settings": {
		"spacing": {
			"blockGap": true,
		}
	},
	"styles": {
		"spacing": {
			"blockGap": "1.5rem"
		}
	}
}

Changes to the global stylesheet

Default font sizes, colors, and gradients

The CSS for some of the presets defined by WordPress (font sizes, colors, and gradients) was loaded twice for most themes: in the block-library stylesheet plus in the global stylesheet. Additionally, there were slight differences in the CSS in both places.

We’ve consolidated the CSS of presets into the global stylesheet, that is now loaded for all themes. Each preset value generates a single CSS Custom Property and a class, as in:

/* CSS Custom Properties for the preset values */
body {
  --wp--preset--<PRESET_TYPE>--<PRESET_SLUG>: <DEFAULT_VALUE>;
  --wp--preset--color--pale-pink: #f78da7;
  --wp--preset--font-size--large: 36px;
  /* etc. */
}

/* CSS classes for the preset values */
.has-<PRESET_SLUG>-<PRESET_TYPE> { ... }
.has-pale-pink-color { color: var(--wp--preset--color--pale-pink) !important; } 
.has-large-font-size { font-size: var(--wp--preset--font-size--large) !important; }

For themes to override the default values they can use the theme.json and provide the same slug. Themes that do not use a theme.json can still override the default values by enqueuing some CSS that sets the corresponding CSS Custom Property.

Example (sets a new value for the default large font size):

body {
 --wp--preset--font-size--large: <NEW_VALUE>;
}

In v1, when a user selected a link color for a specific block we attached a class to that block in the form of .wp-element-<ID> and then enqueued the following style:

.wp-element-<ID> a { color: <USER_COLOR_VALUE> !important; }

While this preserved user preferences at all times, the specificity was too strong and conflicted with some blocks with legit uses of an HTML element that shouldn’t be considered links. To address this issue, we removed the !important and updated the corresponding blocks to style the a elements with a specificity higher than the user link color, which now is:

.wp-element-<ID> a { color: <USER_COLOR_VALUE>; }

As a result of this change, it’s now the block author and theme author’s responsibility to make sure the user choices are respected at all times and that the link color provided by the user (specificity 011) is not overridden.

Fix for CSS Custom Property names that contain numbers

In 5.9 we fixed a bug by which the frontend and the editors would render different CSS Custom Properties. Take this example:

{
    "settings": {
        "color": {
            "palette": [
                {
                    "slug": "white2black",
                    "color": "value",
                    "name": "White to Black"
                }
            ]
        },
        "custom": {
            "white2black": "value"
        }
    }
}

The expected result is that the engine generates the following properties (note how white2black is converted into white-2-black):

body {
  --wp--preset--color--white-2-black: "value";
  --wp--custom--white-2-black: "value";
}

In 5.8 the code generated for the frontend had 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. by which it wouldn’t explode the numbers.


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

Changelog:

  • March 10th, 2022: Fix for CSS Custom Property names that contain numbers section added and the example for a default large font size was updated to use body instead of root.

#5-9, #dev-notes

Locking Blocks in WordPress 5.9

To facilitate creating better patterns and templates, WordPress 5.9 comes with a 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. level locking mechanism that works alongside templateLock.

Instead of applying a lock to all inner blocks, you can apply it selectively to individual blocks via the lock attribute. The block level locking would supersede the inherited templateLock value. You can choose to lock moving or removing a 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. definition

You can lock a block by default by adding locking to its definition, for example:

"attributes": {
    "lock": {
        "type": "object",
        "default": {
            "move": true,
            "remove": true
        }
    }
}

You can also lock a specific block in a pattern. In this example, the heading block is now locked and can’t be removed:

<!-- wp:media-text {"align":"full","mediaType":"image","verticalAlignment":"center"} -->
<div class="wp-block-media-text alignfull is-stacked-on-mobile is-vertically-aligned-center">
    <figure class="wp-block-media-text__media"><img src="https://s.w.org/images/core/5.8/architecture-04.jpg" alt="Close-up, abstract view of architecture." /></figure>
    <div class="wp-block-media-text__content">
        <!-- wp:heading {"textAlign":"center","level":3,"style":{"color":{"text":"#000000"}},"lock":{"remove": true}} -->
        <h3 class="has-text-align-center has-text-color" id="open-spaces-1" style="color: #000000;"><strong>Open Spaces</strong></h3>
        <!-- /wp:heading -->

        <!-- wp:paragraph {"align":"center","fontSize":"extra-small"} -->
        <p class="has-text-align-center has-extra-small-font-size"><a href="#">See case study ↗</a></p>
        <!-- /wp:paragraph -->
    </div>
</div>
<!-- /wp:media-text -->

Working alongside templateLock

Block locking supersedes template locking, see block template documentation, this allows it to override or undo on the specified block:

For removing:

lock.remove\templateLock"all""insert"false
truecan’t Removecan’t Removecan’t Remove
falsecan Removecan Removecan Remove
undefinedcan’t Removecan’t Removecan Remove

For moving:

lock.move\templateLock"all""insert"false
truecan’t Movecan’t Movecan’t Move
falsecan Movecan Movecan Move
undefinedcan’t Movecan Movecan Move

Unlike templateLock, block locking is not inheritable. If a block is locked from being removed, its children can still be removed. If you want to apply locking on children as well, add templateLock to the inner block component, or templateLock attribute to supporting blocks.


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

#5-9, #dev-notes

Theme-focused changes and filters in WordPress 5.9

A few theme-related notes are already published in the Miscellaneous Core Changes developer note, including:

  1. The comment text field is now marked as required, and some themes that have special styling for the asterisk or that create a custom logged_in_as or comment_notes_before message may have a reason to update.
  2. The role="navigation" attribute is removed from <nav> elements.

The following changes are especially relevant to theme authors as well.

A CSSCSS Cascading Style Sheets. custom property to offset the adminadmin (and super admin) toolbar height

This new custom property, --wp-admin--admin-bar--height, reflects the admin bar’s height and adjusts responsively on smaller screens. Offsetting content can prevent the admin bar from overlapping it, without needing to copy the media query.

Adjusting for fixed 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. navigation

When clicking “Continue reading” or “Skip to content” links, a header fixed to the top of the page can cover where that content starts.

With the --wp-admin--admin-bar--height CSS variable and scroll padding, modern browsers can compensate for the admin toolbar (when it shows). The toolbar offset of 32 or 46 pixels—depending on screen width—is available on the front end without editing the theme:

html {
	scroll-padding-top: var(--wp-admin--admin-bar--height);
}

Themes that have a fixed header element can add to that. For example, Twenty Seventeen has a fixed header 72 pixels tall, so the scroll padding for the theme includes that measurement:

html {
	scroll-padding-top: calc( var(--wp-admin--admin-bar--height, 0px) + 72px );
}

Twenty Sixteen does not have a fixed header, but the border styling requires a little more scroll padding because it uses a pseudo-element on the body:

html {
	scroll-padding-top: calc( var(--wp-admin--admin-bar--height, 0px) + 21px );
}

For more information, see TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. tickets #52623 (CSS variable) and #46371 (scroll padding for anchor links).

Custom header image attributes

Alternative text is customizable (and the alt attribute is empty by default)

Custom header image markup now applies the alternative text assigned to the image (in the Media Library). The alternative text was always the site title, which is not relevant in most use cases. The header image is often decorative only, so the attribute is empty when the text is not supplied.

This affects the following functions:

  • get_header_image_tag()
  • the_header_image_tag()
  • get_custom_header_markup()
  • the_custom_header_markup()

If a theme allows linking the header image (for example, with the get_header_image_tag 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.), restoring the site title as backup alt text could prevent “empty link” 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) errors.

function linked_header_image_markup( $html, $header, $attr ) {
    // This variable might be a theme option instead.
    $header_image_link_option = home_url( '/' );

    $output = '';
    if ( ! empty( $header_image_link_option ) ) {
        $output .= '<a href="' . esc_url( $header_image_link_option ) . '">';
        // Replace empty alt text with site title when image is linked.
        $output .= str_replace( 'alt=""', 'alt="' . esc_attr( get_bloginfo( 'name' ) ) . '"', $html );
        $output .= '</a>';
    } else {
        $output .= $html;
    }

    return $output;
}
add_filter( 'get_header_image_tag', 'linked_header_image_markup', 99, 3 );

New attributes filter

The get_header_image_tag_attributes hook allows developers to filter the attributes of the header image 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.) before they are escaped, concatenated, and returned in the get_header_image_tag() function.

Filtering with this hook externally and preemptively intercepts the array of attributes, in a manner similar to the wp_get_attachment_image_attributes hook.

Adding classes is one possibility:

function header_image_add_class( $attr ) {
    if ( isset( $attr['class'] ) ) {
        $attr['class'] .= ' special classes';
    } else {
        $attr['class'] = 'special classes';
    }
    return $attr;
}
add_filter( 'get_header_image_tag_attributes', 'header_image_add_class', 10, 1 );

If an attribute should change due to part of the $header object, the filter has a second argument:

function header_add_data_thumbnail_url( $attr, $header ) {
    if ( ! empty( $header->thumbnail_url ) ) {
        $attr['data-thumbnail'] = $header->thumbnail_url;
    }
    return $attr;
}
add_filter( 'get_header_image_tag_attributes', 'header_add_data_thumbnail_url', 10, 2 );

For more information, see Trac tickets #46124 (alt attribute) and #38942 (filter).

Note that this pertains to the Classic RSS widget; 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.-based RSS widget does not include the icon.

With the new rss_widget_feed_link filter, some people may remove or replace the markup for the icon link instead of hiding it with CSS. This can prevent accessibility errors such as empty links, or it can simply remove undesired markup.

If the image is hidden but not the link, that can result in an empty link. A theme that hides .rss-widget-icon in the styles can update the stylesheet with an additional .rss-widget-feed selector.

.widget_rss a.rsswidget .rss-widget-feed,
.widget_rss a.rsswidget .rss-widget-icon {
    display: none;
}

If the theme uses :first-child or :first-of-type to target the feed link, including :not(.rss-widget-title) can support people using the filter as well as people still using older versions of WordPress.

For example, Twenty Seventeen floats the link to the side:

.widget_rss .widget-title .rsswidget:first-child:not(.rss-widget-title) {
    float: right;
}

Twenty Twenty hides the link, when it is in the markup:

.widget_rss .widget-title a.rsswidget:first-of-type:not(.rss-widget-title) {
    display: none;
}

Themes and plugins can remove the icon link with the rss_widget_feed_link hook:

add_filter( 'rss_widget_feed_link', '__return_false' );

For Twenty Twenty-One, the after_setup_theme action contains the filter.

For theme authors who want a custom image or some other change, the filter also allows new content.

function remove_link_from_rss_widget_image( $feed_link ) {
    $feed_icon = includes_url( 'images/rss.png' );
    $feed_link = sprintf(
        '<img class="rss-widget-icon" style="border:0" width="14" height="14" src="%1$s" alt="%2$s"%3$s /> ',
        esc_url( $feed_icon ),
        esc_attr__( 'RSS' ),
        ( wp_lazy_loading_enabled( 'img', 'rss_widget_feed_icon' ) ? ' loading="lazy"' : '' )
    );

    // Output is the image without the link, but this replaces both the link and the image.
    return $feed_link;
}
add_filter( 'rss_widget_feed_link', 'remove_link_from_rss_widget_image', 10, 1 );

Additional 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. to the default output

  1. Themes can style the feed link with the rss-widget-feed class and/or the title link with rss-widget-title, as long as they require at least 5.9.
  1. The image includes the lazy loading attribute when support is declared, either in all situations or specifically in the rss_widget_feed_icon context. 
function disable_rss_widget_image_lazy_loading( $default, $tag_name, $context ) {
    if ( 'img' === $tag_name && 'rss_widget_feed_icon' === $context ) {
        return false;
    }
    return $default;
}
add_filter( 'wp_lazy_loading_enabled', 'disable_rss_widget_image_lazy_loading', 10, 3 );

For more information, see Trac ticketticket Created for both bug reports and feature development on the bug tracker. #52224.


Thanks @ryelle for help with the toolbar section, and thanks to @joedolson and @ryokuhi for reviewing.

#5-9, #dev-notes, #themes

The new Navigation block

WordPress 5.9 sees the introduction of a Navigation block which allows users to create, manage, and reuse menus built with various blocks from page links to site logos and more.

For full information on using 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. please see the Navigation block support page.

This guide will dive deeper into some of the more technical aspects of the block’s functionality.

Reusing Navigation Menus and separation of concerns 

A key consideration when creating a block based navigation system has been to decouple the presentation of the Navigation block from its data (i.e. the menu items themselves). 

The primary aim of this effort has been to allow for the easy reuse of menus across different Themes, whilst allowing Theme authors to apply different stylistic treatments to their navigation areas. 

The wp_navigation Post

To facilitate this goal, the Navigation block has been designed to save its “items” (i.e. data) to a new wp_navigation custom post type which has been added to WordPress Core.

Changes made to the menu items within the Navigation block are automatically synchronised to an underlying Navigation Post.

In contrast, all presentational attributes remain local to the block instance itself and are not persisted to the Navigation Post.

By using a centralised data source, this “controlled” Navigation block affords reuse of Menus within the site and/or across Themes whilst still allowing for menus to be styled differently as required.

Reusing an existing Menu

To reuse an existing Menu the user may select a menu from the dropdown that appears when clicking on Select menu in the block interface. 

Selecting an existing menu from the Select menu dropdown.

Once selected the items from that menu will be added to the current Navigation block.

An association is also made between the block and the underlying data source via the ref attribute which references the ID of the Navigation Post.

<!-- wp:navigation {"ref":295} /-->

For more information on this feature please see the Navigation block support documentation on selecting an existing menu.

Facilitating Menu reuse across Themes

As a result of the above mechanic, Theme developers can add Navigation blocks to locations within their Theme and style them to suit the visual design. 

When a user activates the Theme they will then be presented with an option to choose from any existing Navigation Menus that they would like to use in those areas.

This affords simple reuse of menus across Themes.

Reusing and converting Classic Menus to block based Menus

Prior to WordPress 5.9, when using classic Themes, Menus were created using the Appearance Menus screen

In light of the advent of block-based Menus (and in line with similar previous nomenclature changes), we now refer to such menus as “Classic Menus”.

Thankfully, transitioning to creating a menu using the block editor doesn’t mean recreating existing Classic Menus from scratch. 

Instead the Navigation block affords the ability to copy these menus and transform them into block based equivalents from within the block interface.

To reuse an existing Classic Menu, the user should first insert a new Navigation block. By choosing the Select menu option from the block placeholder they will reveal a dropdown displaying both existing block based and Classic menus. 

Selecting a Classic menu will copy the Menu’s data, convert it to a block based form and then insert that menu data into the Navigation block.

Note that the original Classic Menu is not modified – there is no link between the original data and the new block based representation. Therefore should the user wish to switch back to a classic Theme, their original Classic Menu data will be preserved

Handling highly customised Classic Menu items

Plugins (and some Themes) may create customised Menu items for specialised usage. One such example are dynamic menu items which when added to a Classic Menu render multiple menu items on the front of the website.

The need for PluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party developers to hook into the conversion process has been recognised and an API is being worked on for a future WordPress release. 

User Permissions

In Classic Menus, only users with the edit_theme_options capability (by default only users with the Admin role) could access the Appearance Menus screen to edit menus.

Similarly when creating menus using the Navigation block, only users with the edit_theme_options capability can create or update Menus.

This is currently achieved by displaying a warning notice to the user within the editor interface if they have insufficient permissions to perform the desired (inter)action.

Note that currently it is still possible for the user to interact with the Navigation block itself. However, any changes to the underlying 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. data will not be persisted

In future versions of the block, features may be added to make the block interface fully read only based on user permissions.

Backwards compatibility with 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/ Plugin

Users of the Gutenberg Plugin may be aware that the Navigation block has existed for some time within the Plugin in a “BetaBeta A pre-release of software that is given out to a large group of users to trial under real conditions. Beta versions have gone through alpha testing in-house and are generally fairly close in look, feel and function to the final product; however, design changes often occur as part of the process.” form.

For early adopters who have been making use of previous iterations of the block there are two key considerations.

Handling legacy “uncontrolled” blocks

Users should note that previous implementations of the Navigation block saved the “items” to the block itself. This can be described as an “uncontrolled” version of the block, whereby the menu item data is local to the block (i.e. inner blocks) and thus persisted directly to the Post in which it is contained.

As a result of these changes, any Navigation block which contains “uncontrolled” blocks will be automatically converted to a “controlled” version where the menu item data is persisted to a new `wp_navigation` custom post.

No data will be lost in this process and it should be opaque to the user.

In the run up to WordPress 5.9 contributors began exploring the concept of Navigation Areas. Users should note that following consultation and testing this effort was abandoned and reverted.

Theme developers should avoid making use of this feature as Navigation Areas are formally deprecated.

An alternative method for automatically transferring menus between Theme locations will be explored as part of a future WordPress release.


Props to @annezazu, @isabel_brison, @bph, @bobbingwide, @javiarce and @spacedmonkey for contributions to this post.

#5-9, #dev-notes, #navigation-block

Bundled theme updates with WordPress 5.9

Besides creating the Twenty Twenty-Two theme, 30 tickets related to existing bundled themes have been closed as fixed during this 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. cycle. Below are some of the significant changes.

When a page is set as the site’s Privacy Policy, a link to it is now automatically added to the footer in both Twenty Twenty and Twenty Twenty-One.

Privacy Policy link displays below copyright on smaller screens
Twenty Twenty (600 pixels wide)
Privacy Policy link displays below site title on smaller screens
Twenty Twenty-One (600 pixels wide)

With Twenty Twenty, the “Powered by WordPress” link displays on screens 1,000 pixels or wider. This had shown at the 700-pixel breakpoint, but the change helps reduce the possibility that footer content wraps across two lines.

Privacy Policy link displays between copyright and powered-by link on larger screens in Twenty Twenty
Twenty Twenty (1200 pixels wide)
Privacy Policy link displays beside the powered-by link on larger screens in Twenty Twenty-One
Twenty Twenty-One (1200 pixels wide)

TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. tickets: #53446 (Twenty Twenty) and #53445 (Twenty Twenty-One)

These themes had used the WhatsApp icon for links in the social 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. that include the whatsapp.com domain. Now the icon also appears for links with the preferred wa.me domain.

WhatsApp icon in Twenty Seventeen social navigation
Twenty Seventeen
WhatsApp icon in Twenty Twenty social navigation
Twenty Twenty

Trac tickets: #51946 (Twenty Seventeen) and #50542 (Twenty Twenty)

Comment form required fields

When logged in, Twenty Nineteen and Twenty Twenty-One now have the default logged-in-as links and required fields message:

Logged in as [username]. Log out? Required fields are marked *

Comment form lacked required fields message in Twenty Nineteen
Twenty Nineteen
(before)
Required fields message will be included in Twenty Nineteen
Twenty Nineteen
(with links and message)
Comment form lacked required fields message in Twenty Twenty-One
Twenty Twenty-One
(before)
Required fields message will be included in Twenty Twenty-One
Twenty Twenty-One
(with links and message)

Improving required field indicator styling

In previous versions of Twenty Eleven, the star character to signify required comment form fields could overlap the text in some languages. In addition to removing the absolute positioning that caused the overlap, this revision makes the star’s styling more consistent between the input labels and the comment notes paragraph.

Comment field was not marked as required
Logged in, before
Comment field is required, with red indicator in Comment label and required fields message
Logged in, after
Comment field was not marked as required, but Name and Email fields had red indicator
Logged out, before
Comment field is marked as required, and all indicators are red
Logged out, after

Trac tickets: #54392 (Twenty Nineteen and Twenty Twenty-One) and #54408 (Twenty Eleven)

Additional updates for Twenty Seventeen

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. image alternative text

The header image’s alternative text is customizable with WordPress 5.9, and the default alt attribute is empty instead of the site title. If the image conveys meaning to people who do not see it, you can go to the Media Library—after uploading and assigning it as the header image—and compose the alternative text there. (Writing alt text within the upload dialog does not yet save to the new image.)

RSS WidgetWidget A WordPress Widget is a small block that performs a specific function. You can add these widgets in sidebars also known as widget-ready areas on your web page. WordPress widgets were originally created to provide a simple and easy-to-use way of giving design and structure control of the WordPress theme to the user. icon position

In right-to-left languages, the legacy RSS widget (with Classic Widgets) now positions the feed icon on the left side of the feed title. In other languages, the icon has floated to the right side, and this change mirrors that layout.

RSS feed icon floats to the left for right-to-left languages

Trac tickets: #46124 (header image) and #52224 (RSS widget)

Since the first version of Twenty Twenty-One, the feed icon beside the classic/legacy RSS widget title has been hidden, which resulted in an invisible link.

Using the rss_widget_feed_link 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. introduced in WordPress 5.9, the theme disables the output of the icon and its link. The visible text heading (the feed title) is still linked.

Trac ticketticket Created for both bug reports and feature development on the bug tracker.: #52880

Removing 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) landmark role attributes

With modern browsers, assistive technologyAssistive technology Assistive technology is an umbrella term that includes assistive, adaptive, and rehabilitative devices for people with disabilities and also includes the process used in selecting, locating, and using them. Assistive technology promotes greater independence by enabling people to perform tasks that they were formerly unable to accomplish, or had great difficulty accomplishing, by providing enhancements to, or changing methods of interacting with, the technology needed to accomplish such tasks. https://en.wikipedia.org/wiki/Assistive_technology does not require attributes such as role="navigation" to recognize several HTML5 elements’ native ARIA role. The role attribute is only necessary when an element does not have a native role.

These native roles have been removed from bundled themes:

  • role="banner" for <header> elements
  • role="navigation" for <nav> elements
  • role="main" for <main> elements
  • role="contentinfo" for most <footer> elements
  • role="complementary" for <aside> elements

Note: Twenty Twelve continues to include <footer role="contentinfo"> to maintain the styling, particularly if a child themeChild theme A Child Theme is a customized theme based upon a Parent Theme. It’s considered best practice to create a child theme if you want to modify the CSS of your theme. https://developer.wordpress.org/themes/advanced-topics/child-themes/. edits the markup but uses the original stylesheet’s selectors.

Trac tickets: #54054 (navigation) and #54079 (other roles)

When clicking “Continue reading” or “Skip to content” links, a header fixed to the top of the page can cover where that content starts. Likewise, the border for Twenty Sixteen needs a slight offset.

WordPress 5.9 includes a --wp-admin--admin-bar--height CSSCSS Cascading Style Sheets. variable and uses scroll padding to compensate for the adminadmin (and super admin) toolbar when it shows. Now, three bundled themes add the height of their headers to that offset value:

  • Twenty Fourteen (48 pixels)
  • Twenty Sixteen (21 pixels)
  • Twenty Seventeen (72 pixels)

Twenty Fourteen had a solution for the “Read more” links, which is now replaced by the more thorough option.

Trac tickets: #46371 (scroll padding for anchor links) and #52623 (CSS variable)


Thanks @audrasjb and @annezazu for reviewing.

#5-9, #bundled-theme, #dev-notes

New Capability Queries in WordPress 5.9

WordPress 5.9 adds support for capability queries in WP_User_Query. Similar to the existing role/role__in/role__not_in query arguments, this adds support for three new query arguments in WP_User_Query:

  • capability
  • capability__in
  • capability__not_in

These can be used to fetch users with (or without) a specific set of capabilities, for example to get all users with the capability to edit a certain post type.

A new capabilities parameter (mapping to capability__in in WP_User_Query) was added to 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/. users controller so you can also perform these queries via the REST API.

Under the hood, this will check all existing roles on the site and perform a LIKE query against the capabilities user 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. field to find:

  • all users with a role that has this capability
  • all users with the capability being assigned directly

Important note: In WordPress, not all capabilities are stored in the database. Capabilities can also be modified using filters like map_meta_cap. These new query arguments do not work for such capabilities.

The prime use case for capability queries is to get all “authors”, i.e. users with the capability to edit a certain post type. This is needed for the post author dropdown in the post editor, for instance.

Until now, 'who' => 'authors' was used for this, which relies on user levels. However, user levels were deprecated a long time ago and thus never added to custom roles. This led to constant frustration due to users with custom roles missing from author dropdowns.

Thanks to this new feature, any usage of 'who' => 'authors' in coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. was updated to use capability queries instead.

Subsequently, 'who' => 'authors' queries were deprecated in favor of these new query arguments. The same goes for ?who=authors queries for thewp/v2/users REST API endpoint.

In the same run, the twentyfourteen_list_authors() function in the Twenty Fourteen theme was updated to make use of this new functionality, adding a new twentyfourteen_list_authors_query_args 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. to make it easier to override this behavior.

Making use of capability queries while retaining compatibility for older WordPress versions, one could use code as follows to support both:

$args = array(
	'orderby'    => 'post_count',
	'order'      => 'DESC',
	'capability' => array( 'edit_posts' ),
);

// Capability queries were only introduced in WP 5.9.
if ( version_compare( $GLOBALS['wp_version'], '5.9-alpha', '<' ) ) {
	$args['who'] = 'authors';
	unset( $args['capability'] );
}

$authors = get_users( $args );

To learn more about this change and the 11-year-old 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. it fixed, check out #16841, [51943], and [52290]

#5-9, #dev-notes

Miscellaneous Core changes in WordPress 5.9

WordPress 5.9 brings a lot of smaller changes that developers should know about. Here’s a breakdown.

Comment text field now marked as required

With WP 5.9, a required asterisk is added to the comment text field. Historically, the name and email fields were marked as required, but the comment text field was not, though it was actually a required field.

Please note this change also adds a container to the comment required text sentence, with the required-field-message class.

If the theme (or 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) creates a custom logged_in_as or comment_notes_before message, this could result in having the asterisk character indicate the required Comment field without a “Required fields are marked *” explanation. For example, Twenty Nineteen and Twenty Twenty-One had removed the logged_in_as text by setting it to null, so the default text has been restored to display the required fields message (with the links).

Also, if a theme styles the indicator character specifically for the Name and Email field labels—as Twenty Eleven had done—those styles should apply to the Comment field label as well.

For more information, see 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. #16206 and related commits: [52029], [52149], [52200].

Two new oEmbed providers: Wolfram Notebook and Pinterest

All of the Wolfram services are tied together by the Wolfram Language: Notebooks are their hosted version of Wolfram Language based documents. Their oEmbed 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 based on the following URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org scheme: https://www.wolframcloud.com/oembed. There is also a secondary endpoint that returns the embed wrapped in an iframeiframe iFrame is an acronym for an inline frame. An iFrame is used inside a webpage to load another HTML document and render it. This HTML document may also contain JavaScript and/or CSS which is loaded at the time when iframe tag is parsed by the user’s browser.: https://www.wolframcloud.com/oembed/iframe/.

For more information, see Trac ticket #53326.

Pinterest provides a single oEmbed endpoint, which handles URLs of pins, boards, and profiles: https://www.pinterest.com/oembed.json.

For more information, see Trac ticket #53448.

KSES: Add options for restricting tags based upon their attributes

This change adds two now attribute-related config options to KSES:

  • An array of allowed values can be defined for attributes. If the attribute value doesn’t fall into the list, the attribute will be removed from the 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 can be marked as required. If a required attribute is not present, KSES will remove all attributes from the tag. As KSES doesn’t match opening and closing tags, it’s not possible to safely remove the tag itself, the safest fallback is to strip all attributes from the tag, instead.

Allow PDFs to be embedded as objects

Included with this change is an implementation of these options, allowing the <object> tag to be stored in posts, but only when it has a type attribute set to application/pdf.

This implementation also introduces the _wp_kses_allow_pdf_objects callback function, which is used to check if a PDF URL is safe.

For more information, see ticket #54261.

Remove role="navigation" from <nav> elements

According to HTML5 documentation, adding role="navigation" to a <nav> element is unnecessary. It should only be added to elements like <div> instead, when using the semantically correct <nav> is not possible.

Historically, role="navigation" was required for assistive technologyAssistive technology Assistive technology is an umbrella term that includes assistive, adaptive, and rehabilitative devices for people with disabilities and also includes the process used in selecting, locating, and using them. Assistive technology promotes greater independence by enabling people to perform tasks that they were formerly unable to accomplish, or had great difficulty accomplishing, by providing enhancements to, or changing methods of interacting with, the technology needed to accomplish such tasks. https://en.wikipedia.org/wiki/Assistive_technology to recognize HTML5 element’s native ARIA roles while HTML5 and ARIA were being introduced. With the deprecation of IE11, the role attribute is only required when mapping elements that don’t have native role.

This change removes the navigation role from the following items:

  • All the legacy navigation widgets
  • All the bundled themes from Twenty Eleven to Twenty Twenty-One
  • Functions such as the_posts_pagination(), which go through the _navigation_markup() function in the /wp-includes/link-template.php file.

For more information, see ticket #54054.

New hook in wp_http_validate_url to control which ports are allowed for remote requests

By default, WordPress only allows ports 80, 443, and 8080 to be used for (safe) remote requests. WordPress 5.9 adds a way to remove these hardcoded ports so it is possible to better control which ports are allowed or not.

The http_allowed_safe_ports can be used to control the list of ports considered safe in 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. API, with the following parameters:

  • $allowed_ports: Array of integers for valid ports.
  • $host: Host name of the requested URL.
  • $url: The requested URL.

Usage example:

function wporg_customize_http_allowed_safe_ports( $allowed_ports, $host, $url ) {
	$allowed_ports = array( 80, 81, 443, 444, 8080, 8081 );
	return $allowed_ports;
}
apply_filters( 'http_allowed_safe_ports', 'wporg_customize_http_allowed_safe_ports', 10, 3 );

For more information, see ticket #54331.

New wp_mail_succeeded hook for the wp_mail() function

WordPress 5.9 adds a new wp_mail_succeeded action in wp_mail() after the mail is sent. Please note that the hook’s firing does not necessarily mean the recipient received the mail, only that the mail was processed without any errors.

Usage example:

/*
 * Logs each successful mail operation related to a specific user. 
 */
function wporg_wp_mail_succeeded( $mail_data ) {
	$successful_mail_logs = get_site_option( 'successful_mail_logs', array() );
	if ( 'user@example.org' === $mail_data['to'] ) {
		$successful_mail_logs[] = current_time( 'mysql' );
		update_site_option( 'successful_mail_logs', $successful_mail_logs );
	}
}
add_action( 'wp_mail_succeeded', 'wporg_wp_mail_succeeded', 10, 1 );

For more information, see Trac ticket #53826.

Use global post as the default for wp_get_post_parent_id()

Starting with WordPress 5.9, the $post parameter of wp_get_post_parent_id() is now optional, defaulting to the current global post object when called within the 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..

For more information, see Trac ticket #48358.

Allow wp_register_script() to be called after wp_enqueue_script()

When a plugin registers styles/scripts on wp_enqueue_scripts (as plugin authors are encouraged to do), and conditionally enqueues their script/style on the_content 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., things “just work”. In 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, the_content is run prior to the 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. being processed, which results in the above scenario failing.

With WordPress 5.9, the following example will work:

wp_enqueue_script( 'example' );
wp_register_script( 'example' ); 

Before 5.9, the enqueue silently failed (no “doing it wrong” message) and the following register has no impact.

Now, scripts can therefore be enqueued and dequeued (by “handle”) before they are registered.

For more information, see Trac ticket #54529.

get_term() accepts a term ID, instance of WP_Term, or an object (i.e. stdClass as a result of a db query). Starting with WordPress 5.9, functions that use get_term() also now allow for the same data types. This adds consistency, and this change is also removing extra processing code in consuming functions, so it provides better performance.

The following functions were changed accordingly:

  • get_category_feed_link()
  • get_term_feed_link()
  • get_tag_feed_link()
  • get_edit_tag_link()
  • get_edit_term_link()
  • edit_term_link()

For each of consumer of these functions, it is now possible to pass the object instead of the term ID.

For more information, see Trac ticket #50225.


Thanks @sabernhardt for proofreading.

#5-9, #dev-notes