WordPress 5.3: Site Admin Email Verification Screen

In WordPress 5.3, a new screen has been introduced to help ensure the site’s administration email remains accurate and up to date. The site’s admin email (as defined when installing WordPress, and found on the Settings > General page) is a critical part of every WordPress site. This new screen will help site owners remain in full control of their site, even as years go by.

How does this work?

By default, administrators will see a screen after logging in that lists the site’s admin email address once every 6 months.

They are presented with 4 actions:

  1. The site’s email is verified as correct: After clicking “The email is correct” button, the user is taken to the Dashboard with an admin notice saying “Thank you for verifying”. The screen will be hidden for 6 months from all administrators.
  2. The site’s email needs to be changed: After clicking the “Update” button, the user is taken to the Settings > General page where they can update the site’s email address. Administrators will be presented with the verification screen the next time they log in.
  3. The user clicks “Remind me later”: the user is taken to the Dashboard. Administators will see the screen again after 3 days have passed.
  4. Back to “Site Name”: When this link is clicked, the user will be taken to the site’s home page. Administrators will be presented with the verification screen the next time they log in.

Available Actions and Filters


There are a few action hooks on the verification page that developers can use to customize the screen.

  • admin_email_confirm – Fires before the admin email confirm form.
  • admin_email_confirm_form – Fires inside the admin-email-confirm-form form tag, but before any other output.

A new action hook after the form was not introduced. Instead, use the login_footer action, which is called just after the closing </form> tag. The if ( 'confirm_admin_email' === $_GET['action'] ) conditional can be used to check that the email verification screen is being shown.


One new filter, admin_email_check_interval, has also been introduced. This filter can be used to change the frequency that administrators should see the verification screen.

The following example changes the interval from the default of 6 months to 2 months:

function myplugin_admin_email_check_interval( $interval ) {
	return 2 * MONTH_IN_SECONDS;
add_filter( 'admin_email_check_interval', 'myplugin_admin_email_check_interval' );

Note: The returned value should always be in seconds.

This filter can also be used to disable the feature by returning a “falsey” value, such as 0, or false.

The following example will disable the admin email verification check:

add_filter( 'admin_email_check_interval', '__return_false' );

For more information about these changes, check out #46349 in Trac.

Props to @desrosj for peer review.

#5-3, #admin, #dev-notes

The REST API in WordPress 5.3

WordPress 5.3 contains a number of REST API improvements designed to make it easier and faster to work with API data from the block editor or other client applications.

Register Array & Object Metadata

As covered previously in this developer note on array & object metadata, it is now possible to use register_post_meta & register_term_meta (as well as the underlying method register_meta) to interact with complex meta values as schema-validated JSON arrays or objects using the REST API. See the linked post for more details.

Nested response filtering with _fields query parameter

This developer note on the changes to the REST API’s _fields= query parameter shows how you may now filter your REST API response objects to include only specific nested properties within the response body.

Ticket #42094

Set drafts back to “floating date” status

Once a date has been set for a draft, it was previously impossible to set the post back to showing “publish immediately” (also referred to as a “floating date,” where the post will be dated whenever it is published). As of 5.3, passing null for a date value will unset the draft date and restore this floating state.

Ticket #39953

Faster Responses

We have introduced a caching wrapper around the generation of REST resource schema objects, which initial testing has shown to yield up to a 30-40% performance increase in large API responses. If you work with expensive or large REST API queries, things should be quite a bit faster now. (Ticket #47871)

The REST API has also been improved to avoid unnecessary controller object instantiation (#45677) and to skip generation of sample permalinks when that data is not requested (#45605).

Please Note: if your team has existing performance benchmarking tooling for the REST API, please contact the component maintainers in the #core-restapi Slack channel; we very much desire to expand our metrics in this area.

Additional Changes of Note

In addition to these key enhancements, there are a number of smaller improvements to the REST API which may be of interest to developers.

  • It is no longer possible to DELETE a Revision resource using the REST API, as this behavior could break a post’s audit trail. Ticket #43709
  • The /search endpoint will now correctly embed the full original body of each matched resource when passing the _embed query parameter. Ticket #47684
  • rest_do_request and rest_ensure_request now accept a string API path, so it is possible to instantiate a request in PHP using nothing more than the desired endpoint string, e.g.
    rest_do_request( '/wp/v2/posts' );
    Ticket #40614
  • Creating or updating a Terms resource via the REST API now returns the updated object using the “edit” context. Ticket #41411
  • It is now possible to edit a posted comment through the REST API when authenticating the request as a user with the moderate_comments capability. Previously a full editor- or admin-level role was needed. Ticket #47024
  • rest_get_avatar_urls now receives the entire User or Comment object, not just the object’s email address. Ticket #40030

Welcoming Timothy Jacobs as a REST API component maintainer

Last but not least, many of you have no doubt seen @timothyblynjacobs active in trac, slack, and community events. Timothy has driven much of the momentum that resulted in the above improvements, and I’m excited to (belatedly) announce that he has joined the REST API team as an official component maintainer. Thank you very much for your energy and dedication!

Thank you also to every other person who contributed to API changes this cycle; it’s the best version of the REST API yet, and we couldn’t have done it without the dozens of contributors who helped create, review and land these patches.

We’ve got some ambitious ideas about how we can make the REST API even better in 5.4. Interested in helping out, with code, docs, or triage? Join us for weekly office hours, every week on Thursdays at 1800 UTC!

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

Dev Chat Agenda for October 16 2019 (5.3 week 9)

Here is the agenda for the weekly meeting happening later today: Wednesday, October 16, 2019, 20:00 PM UTC. Please share any items you’d like to include in the comments below!

  • Announcements and highlighted posts
  • Upcoming Release Discussions
  • Calls from component maintainers
  • Open Floor

If you have anything to propose for the agenda or specific items related to those listed above, please leave a comment below.

This meeting is held in the #core channel. To join the meeting, you’ll need an account on the Making WordPress Slack.

#5-3, #agenda, #dev-chat

Report: WP 5.3 Admin CSS changes tested against top 20 plugins

In September 2019, the WordPress Accessibility team tested WP 5.3 Admin CSS changes against the Top 20 plugins on WordPress.org, to evaluate possible breakage on plugins admin screens and to iterate on the related changes.

This week, those tests were reproduced against 5.3-beta3-46471. This post is a report illustrated with screenshots of relevant admin screens for each plugin.

The idea was to test Admin CSS changes against various use cases to see what could happen and to fix as many found bugs as possible. Of course, not every use cases are covered in 20 plugins, but the Accessibility team assumes it will provide a general view on the robustness of the changes coming in WP 5.3.

A dev note will quickly follow this post, to communicate on all the CSS changes coming in WP 5.3 admin screens to plugin authors and WordPress developers.

To sum up, some plugins which use custom CSS that override WordPress Admin default CSS rules on form controls may have few minor visual glitches. Most notably: the input fields can be taller than before WP 5.3. There’s no breakage as the input fields are fully operable, but plugin authors and WordPress developers are encouraged to:

  • remove any fixed heights: flexible heights are the WordPress recommended standard (and one of the main goals of the Admin CSS changes)
  • remove any custom top and bottom padding values
  • remove any custom line-height values

For each plugin, screenshot are provided. You can click them to see the full media file.

Contact Form 7

This plugin uses default core admin styles. No breakage found.


This plugin uses both custom styles and default core admin styles. No breakage found. One input and one button are too close to each other in the search appearance page. Looks to be due to incorrect use of margins.


This plugin uses both custom styles and default core admin styles. No breakage found.

Classic Editor

This plugin uses default core admin styles. No breakage found.


This plugin uses custom styles. No change found on the screens audited. Further exploration could be needed on specific admin screens. Edit: Jetpack team is already working on some small CSS changes in a dedicated pull request. Worth a read to see how plugins could handle Admin CSS changes.


This plugin uses both custom and default admin styles. Two misaligned labels were found in the installation screen. Some inputs have large vertical paddings/heights. No breakage found.

Note: WooCommerce team already worked on Admin CSS changes in a dedicated pull request. An interesting read to see how plugins could handle Admin CSS changes.

WordPress Importer

This plugin uses default admin styles. No breakage found.

Really Simple SSL

This plugin uses both custom and default admin styles. No breakage found.

Elementor Page Builder

This plugin uses both custom and default admin styles. Small misalignment in one (screenshot 6) of the dozen pages of settings, due to fixed margins. Pretty minor though. No breakage found.

Wordfence Security

This plugin uses both custom and default admin styles. No breakage found.

Duplicate Post

This plugin uses default admin styles. No breakage found.

TinyMCE Advanced

This plugin uses both custom and default admin styles. No breakage found.

All in One SEO Pack

This plugin uses both custom and default admin styles. No breakage found.

WP Forms

This plugin uses both custom and default admin styles. No breakage found.

Google XML Sitemaps

This plugin uses default admin styles. No breakage found.

Google Analytics Dashboard Plugin for WordPress

This plugin uses custom admin styles. No breakage found but the test couldn’t handle each screen of the plugin due to the some issues with plugin’s configuration on local installs.

All-in-One WP Migration

This plugin uses both custom and default admin styles. No breakage found.

UpdraftPlus Backup

This plugin uses both custom and default admin styles. No breakage found.

WP Super Cache

This plugin uses default admin styles. No breakage found.

Google Analytics Dashboard for WP

This plugin mixes custom and default admin styles. No breakage found.

Please note this report is only including Top 20 plugins from WordPress.org, but the changes were also tested on various others plugins, such as WP-Rocket, Advanced Custom Fields, Polylang… and dozens of plugins with less active installations.

#5-3, #accessibility, #testing

PHP Native JSON Extension Now Required

The PHP native JSON extension has been bundled and compiled with PHP by default since 5.2.0 (2006). However, a significant number of PHP installs did not include it. In order to ensure a consistent experience for JSON related functionality in all supported versions of PHP, WordPress Core has historically included a large number of workarounds, functions, and polyfills.

In 2011 (WordPress 3.2), an attempt was made to remove JSON related compatibility code. However, it was discovered that a fair number of distributions were still missing the PHP JSON extension by default, and the removed code was restored to ensure compatibility.

In WordPress 5.2, the minimum version of PHP supported was raised from 5.2.6 to 5.6.20. In the 8 year period since the last attempt was made to encourage use of the PHP native JSON extension, the number of distributions with this extension disabled has significantly decreased.

Because of this, the PHP native JSON extension is now required to run WordPress 5.3 and higher.

To prevent compatibility issues, a site that does not have the PHP native JSON extension enabled will see an error message when attempting to upgrade to WordPress 5.3. The update will be cancelled and the site will remain on the current version (see [46455]). This is to prevent potential compatibility issues on servers running custom PHP configurations.

Here’s a summary of what has changed.


The following functions and classes will remain in the code base, but will trigger a deprecated warning when used (see [46205]):

  • The Services_JSON and Services_JSON_Error classes and all methods
  • The wp-includes/class-json.php file
  • The (private) _wp_json_prepare_data() function


The following functions, and classes have been removed entirely from the code base (see the [46208] changeset):

  • json_encode() function polyfill
  • json_decode() function polyfill
  • _json_decode_object_helper() function polyfill
  • json_last_error_msg() polyfill
  • JsonSerializable interface polyfill
  • $wp_json global variable
  • JSON_PRETTY_PRINT constant polyfill
  • JSON_ERROR_NONE constant polyfill


The wp_json_encode() function will remain with no intention to deprecate it at this time. This function includes an extra sanity check for JSON encoding data and should still be used as the preferred way to encode data into JSON.

For more information about these changes, check out #47699 on Trac and the relevant changesets ([46205], [46206], [46208], [46377], and [46455]).

Props @jrf & @jorbin for peer review.

#5-3, #dev-notes, #php

Enhancements to the Network Sites Screen in WordPress 5.3

Changes to the database

The introduction of Site metadata in WordPress 5.1 has opened up a lot of new possibilities for multisite.

Save database version and date updated in multisite site meta

In [46193], the database version and the updated dates are now stored in the blogmeta table.

If your setup of multisite requires the database version to be accessed from a global context, instead of looping around every site with an expensive switch_to_blog call to get_option( 'db_version' ), you maybe want to try a function like the following.

function get_site_versions() {
	global $wpdb;
	$query = $wpdb->prepare( "SELECT blog_id, meta_value FROM $wpdb->blogmeta WHERE meta_key = 'db_version' ORDER BY blog_id DESC");
	return $wpdb->get_results( $query );

Remove blog_versions table

Currently, there is a table in multisite called blog_versions. This table stores the database version as a number and the updated date. It was introduced in #11644 and has never been used in Core since then.

With the database version and updated date now stored in theblogmeta table, blog_versionstable becomes redundant. In [46194], this table is removed from Core.

Changes to WP_MS_Sites_List_Table

WordPress 5.3 adds several enhancements to the WP_MS_Sites_List_Table class that allows plugin authors to take advantage of Site metadata to provide a richer experience for multisite administrators on the Network Admin Sites screen.

These enhancements will be very familiar to those who have used and/or customized the All Posts screen.

Site Status Views

The Network Sites screen now displays a list of links with the counts of Sites by status (e.g., Public, Spam, etc.), similar to the post status links on the All Posts screen.

Network Sites screen showing site status views.

The status links can also be filtered with the new views_sites-network filter, introduced in Trac ticket #37392.

For example, imagine there is a multisite where the main site acts as a directory of local restaurants and each separate site is for an individual restaurant, and restaurant owners can purchase a “subscription” that would allow them to display more information about their restaurant listing: a basic subscription would allow them to add photographs of their restaurant and an advanced subscription would additionally allow them to include their menu.

The subscription level could then be stored in the blogmeta table and “status” links can be added for the different subscription levels as follows:

add_filter( 'views_sites-network', 'myplugin_add_site_status_views' );
function myplugin_add_site_status_views( $view_links ) {
	$statuses = array(
		'free'      => _n_noop(
			'Free <span class="count">(%s)</span>',
			'Free <span class="count">(%s)</span>',
		'basic'   => _n_noop(
			'Basic <span class="count">(%s)</span>',
			'Basic <span class="count">(%s)</span>',
		'advanced'   => _n_noop(
			'Advanced <span class="count">(%s)</span>',
			'Advanced <span class="count">(%s)</span>',

	// get the count of sites with each of our custom statuses.
	$args = array(
		'meta_query' => array(
				'key'     => 'myplugin-status',
				'compare' => '=',
		'count' => true,
	$counts = array();
	foreach ( array_keys( $statuses ) as $status ) {
		$args['meta_query'][0]['value'] = $status;
		$counts[ $status ] = get_sites( $args );

	$requested_status = isset( $_GET['status'] ) ? wp_unslash( trim( $_GET['status'] ) ) : '';

	foreach ( $statuses as $status => $label_count ) {
		$current_link_attributes = $requested_status === $status ?
			' class="current" aria-current="page"' :
		if ( (int) $counts[ $status ] > 0 ) {
			$label = sprintf( translate_nooped_plural( $label_count, $counts[ $status ] ), number_format_i18n( $counts[ $status ] ) );

			$view_links[ $status ] = sprintf(
				'<a href="%1$s"%2$s>%3$s</a>',
				esc_url( add_query_arg( 'status', $status, 'sites.php' ) ),

	return $view_links;

When a user clicks on one of the custom status links, the rows in the list table can be limited to those sites with that specific custom Status using the existing ms_sites_list_table_query_args as follows:

add_filter( 'ms_sites_list_table_query_args', 'myplugin_sites_with_custom_status' );
function myplugin_sites_with_custom_status( $args ) {
	$status = ! empty( $_GET['status' ] ) ? wp_unslash( $_GET['status' ] ) : '';

	if ( empty( $status ) || ! in_array( $_GET['status'], array( 'free', 'basic', 'advanced' ) ) ) {
		return $args;

	$meta_query = array(
		'key'   => 'myplugin-status',
		'value' => $status,

	if ( isset( $args['meta_query'] ) ) {
		// add our meta query to the existing one(s).
		$args['meta_query'] = array(
			'relation' => 'AND',
			array( $args['meta_query'] ),
	else {
		// add our meta query.
		$args['meta_query'] = array(

	return $args;

Extra Tablenav

The posts displayed on the All Posts screen can be filtered by date and category. Plugins can also add custom filter criteria with the restrict_manage_posts filter.

To continue with the above restaurant guide example, imagine the food served by each restaurant is also stored in the blogmeta table. We could then allow Network administrators to filter the Sites by the type of food by adding a dropdown of the various cuisines:

Network Sites screen that includes a dropdown added with the "restrict_manage_sites" action.

Dropdowns like this can now be added on the Network Sites screen with the new restrict_manage_sites action ( introduced in Trac ticket #45954), as follows:

add_action( 'restrict_manage_sites', 'myplugin_add_cuisines_dropdown' );
function myplugin_add_cuisines_dropdown( $which ) {
	if ( 'top' !== $which ) {

	echo '<select name="cuisine">';
	printf( '<option value="">%s</option>', __( 'All cuisines', 'myplugin' ) );

	$cuisines = array(
		'French'  => __( 'French', 'myplugin' ),
		'Indian'  => __( 'Indian', 'myplugin' ),
		'Mexican' => __( 'Mexican', 'myplugin' ),
	$requested_cuisine = isset( $_GET['cuisine'] ) ? wp_unslash( $_GET['cuisine'] ) : '';
	foreach ( $cuisines as $cuisine => $label ) {
		$selected = selected( $cuisine, $requested_cuisine, false );
		printf( '<option%s>%s</option>', $selected, $label );

	echo '</select>';


When a user selects a food type and clicks the Filter button, the rows in the list table can be limited to just those Sites that serve that cuisine using the existing ms_sites_list_table_query_args filter, as follows:

add_filter( 'ms_sites_list_table_query_args', 'myplugin_sites_with_cuisine' );
function myplugin_sites_with_cuisine( $args ) {
	if ( empty( $_GET['cuisine' ] ) ) {
		return $args;

	$meta_query = array(
		'key'   => 'myplugin-cuisine',
		'value' => wp_unslash( $_GET['cuisine' ] ),

	if ( isset( $args['meta_query'] ) ) {
		// add our meta query to the existing one(s).
		$args['meta_query'] = array(
			'relation' => 'AND',
			array( $args['meta_query'] ),
	else {
		// add our meta query.
		$args['meta_query'] = array(

	return $args;

Site Display States

As with other list tables, each row in the Sites list table can now have display states. By default, all Site statuses (other than Public) of each Site are included as display states. Additionally, the main Site for the Network also has the “Main” display state.

Network Sites screen showing display states added with the "display_site_states" filter.

When a specific Site status view has been selected by the user, that status will not be among the display states (this is just like the All Posts screen).

Plugins can also modify the display states with the new display_site_states filter, introduced in Trac ticket #37684.

To further continue our restaurant guide example, we can add our custom statuses and the cuisine served at each restaurant as display states. This can be achieved as follows:

add_filter( 'display_site_states', 'site_display_states', 10, 2 );
function site_display_states( $display_states, $site ) {
	$status = get_site_meta( $site->blog_id, 'myplugin-status', true );
	$requested_status = isset( $_GET['status'] ) ? wp_unslash( trim( $_GET['status'] ) ) : '';

	if ( $status !== $requested_status ) {
		switch ( $status ) {
			case 'free':
				$display_states['free']     = __( 'Free', 'myplugin' );
			case 'basic':
				$display_states['basic']    = __( 'Basic', 'myplugin' );
			case 'advanced':
				$display_states['advanced'] = __( 'Advanced', 'myplugin' );

	$cuisine = get_site_meta( $site->blog_id, 'myplugin-cuisine', true );
	$requested_cuisine = isset( $_GET['cuisine'] ) ? wp_unslash( trim( $_GET['cuisine'] ) ) : '';

	if ( $cuisine !== $requested_cuisine ) {
		$display_states[ $cuisine ] = $cuisine;

	return $display_states;

Misc changes

Return for short circuits for multisite classes.

Fixing a bug created in the [44983] original patch, introduced pre query filters in multisite classes. This bug made short circuit act differently from other short circuits and as it still continues to execute. Now after the filter networks_pre_query and sites_pre_query run, the code will exit straight away. This allows developers to completely hot-wire the network and site query, to load from another source, such as a different cache or Elastic search.

Improved performance for site and network lookups by ID

In earlier versions of WordPress when running the code get_site( 12345 ) was run and no ID with that site exists, the result is not being cached. That means every subsequent lookup will still cause a DB query to be fired, which is unnecessary. In [45910] non-existent sites data is stored as -1 instead of false to save further database lookups.

#5-3, #dev-notes, #multisite, #networks-sites

Expanded meta key comparison operators in 5.3

WordPress 5.1 introduced the compare_key parameter for WP_Meta_Query, allowing developers to perform LIKE queries against postmeta keys. (See #42409 and the related dev note.) WordPress 5.3 expands the options available to compare_key, so that developers have access to meta-key comparison operators similar to those available for meta values. See #43446 and [46188].

After this change, compare_key accepts the following operators: =, LIKE, !=, IN,NOT IN,NOT LIKE,RLIKE,REGEXP,NOT REGEXP,EXISTS, andNOT EXISTS. Usage notes:

  • For parity with value operators, we’ve added support for EXISTS and NOT EXISTS. In the case of compare_key, these map to = and !=, respectively.
  • MySQL regular expression comparison operators (RLIKE, REGEXP, NOT REGEXP) are case-insensitive by default. To perform case-sensitive regular expression matches, it’s necessary to cast to BINARY. To support this, WP_Meta_Query now accepts a type_key parameter; pass 'BINARY' to force case-sensitive comparisons. (This directly parallels the use of type when using regular expressions to match meta value.)
  • As is the case with other WP_Meta_Query-related parameters, the parameters discussed here are available to WP_Query using the meta_ prefix: meta_compare_key and meta_type_key.

#5-3, #dev-notes, #query

Use aria-label to ensure Posts and Comments navigation has proper context in WordPress 5.3

Many themes (including bundled themes) use previous/next navigation in single post and pagination links in the posts/comments archives.

The markup output is under the responsibility of core private function _navigation_markup, which prints out an unlabelled <nav> element:

<nav class="navigation post-navigation" role="navigation">

This <nav> element defines an ARIA landmark by default: landmarks help assistive technology users to perceive the page main sections and jump through them. However, when a landmark is used more than once in a page, it needs to be distinguished from the other ones to let users understand what the landmark is about.

For reference, see ARIA Landmarks Example on W3.org.

To distinguish each context WordPress 5.3 will programmatically add specific aria-label parameter for each navigation menu. That parameter is being added to navigation menus generated by the following functions:

  • _navigation_markup()
  • get_the_post_navigation()
  • get_the_posts_navigation()
  • get_the_posts_pagination()
  • get_the_comments_navigation()
  • get_the_comments_pagination()

The following functions are also impacted as they are used to echo the result of the functions listed above:

  • the_post_navigation()
  • the_posts_navigation()
  • the_posts_pagination()
  • the_comments_navigation()
  • the_comments_pagination()

All these functions now implement aria_label parameter which can be used to pass custom value for the related HTML attribute.

For example:

the_post_navigation( array(
    'prev_text'          => __( 'previous: %title', 'text-domain' ),
    'next_text'          => __( 'next: %title', 'text-domain' ),
    'taxonomy'           => 'chapters',
    'aria_label'         => __( 'Chapters', 'text-domain' ),
) );

For reference, see the related Trac ticket: #47123

#5-3, #accessibility, #dev-notes

Changes to wp_die() HTML output in WordPress 5.3

By default and before WordPress 5.3, the handler for wp_die() wraps error messages with a paragraph tag.

For a number of wp_die() calls in WordPress, a plain text string is passed and the HTML displayed is valid: 

wp_die( 'This is an error message.' );

Currently returns:

<p>This is an error message.</p>.

However, for a number of other wp_die() calls, the HTML displayed is invalid because paragraphs doesn’t allow every nesting possibilities.

For example:

wp_die( '<h1>You need a higher level of permission.</h1><p>Sorry, you are not allowed to manage terms in this taxonomy.</p>' );

Currently returns:

<p><h1>You need a higher level of permission.</h1><p>Sorry, you are not allowed to manage terms in this taxonomy.</p></p>

With WordPress 5.3, error messages are wrapped in a <div> rather than a <p>, to better support string calls in wp_die(), without
outputting invalid HTML.

These changes also add .wp-die-message CSS class for styling.

For example:

wp_die( '<h1>You need a higher level of permission.</h1><p>Sorry, you are not allowed to manage terms in this taxonomy.</p>' );

Will now return:

<div class="wp-die-message">
    <h1>You need a higher level of permission.</h1>
    <p>Sorry, you are not allowed to manage terms in this taxonomy.</p>

Plugin authors are encouraged to check their use of wp_die() and update their PHP calls to the function or their CSS styles if needed.

For reference, see Trac ticket #47580.

#5-3, #dev-notes

Miscellaneous Developer Focused Changes in 5.3

Oct. 14: Edited to include relevant ticket numbers for each External Library update.
Oct. 15: Corrected the jQueryColor updated from version and added a bullet point about the changes to the random_password filter.

In WordPress 5.3, a large handful of small developer-focused changes were made that deserve to be called out. Let’s take a look!

Passing Arrays to Supports Argument When Registering Post Types

When registering post type support for a feature using add_post_type_support(), it’s possible to pass “extra” arguments to provide more details for how that post type should support the feature.

		'custom_feature' => array(
			'setting-1' => 'value',
			'setting-2' => 'value',

However, passing multidimensional arrays with advanced configuration details to the supports argument in register_post_type() results in the extra arguments getting stripped before being added to the post type.

This has been fixed in WordPress 5.3 and multidimensional arrays can now be passed to supports in register_post_type().


		'supports' => array(
			'custom_feature' => array(
				'setting-1' => 'value',
				'setting-2' => 'value',

For more information on this change, see #40413 on Trac.

HTML5 Supports Argument for Script and Style Tags

In HTML5, the type attribute is not required for the <script> and <style> tags. Including the attribute on these tags (type="text/javascript", for example) will trigger a validation warning in HTML validation tools.

In WordPress 5.3, two new arguments are now supported for the html5 theme feature, script and style. When these arguments are passed, the type attribute will not be output for those tags.


function mytheme_register_support() {
	add_theme_support( 'html5', array( 'script', 'style' ) );
add_action( 'after_setup_theme', 'mytheme_register_support' );

For more information on this change, see #42804 on Trac.

Recording Additional Information For Saved Queries.

When the SAVEQUERIES constant is set to true, an array of data for every query to the database is logged for debugging purposes. This data includes:

  • The query itself
  • The total time spent on the query
  • A comma separated list of the calling functions
  • The Unix timestamp of the time at the start of the query.

A new filter, log_query_custom_data, has been added to allow custom debugging information to be added to this array of data. A good example where this would be useful is a plugin that runs a custom search implementation (such as Elasticsearch). “This query was served by Elasticsearch” could be added to the debug data to help trace where queries are being served.


function myplugin_log_query_custom_data( $query_data, $query, $query_time, $query_callstack, $query_start ) {
	$query_data['myplugin'] = 'Custom debug information';
	return $query_data;
add_filter( 'log_query_custom_data', 'myplugin_log_query_custom_data', 10, 5 );

For more information, see #42151.

Unit-less CSS line-height Values

Line height should also be unit-less, unless necessary to be defined as a specific pixel value.

The WordPress Core CSS Coding Standards

This standard was not followed consistently in the WordPress Core CSS files. All 346 line-height style definitions in Core have been individually examined and adjusted to now adhere to this coding standard.

This change will not cause any issues with Core admin CSS or custom styling, but sites with custom admin styling should be double checked just to be sure.

For more details, see #44643 on Trac, or any of the related sub-tickets (#46488, #46489, #46492, #46493, #46494, #46495, #46509, #46510, #46511, #46512, #46513, #46514, #46515, #46516, #46517, #46518, #46519, #46520, #46521, #46522, #46523, #46524, #46525, #46526, #46528, #46529, #46530, #46531).

Additional Developer Goodies

  • add_settings_error() now supports the warning and info message types in addition to the error and updated/success styles. error and updated types will also now output the .notice-error and .notice-success instead of the legacy .error and .updated classes (see #44941).
  • A typo in the Walker_Nav_Menu_Checklist class has been fixed for the hidden title attribute input field’s class. Previously, the class was .menu-item-attr_title. However, the other fields use a hyphen, which the admin JavaScript also expects. For that reason, the class has been changed to .menu-item-attr-title. This field is used to auto-populate the Title Attribute input field for menu items when adding a menu item. Plugins and themes that extend or that have copied the Walker_Nav_Menu_Checklist class into their code base should also fix this typo (see #47838).
  • An index has been added to wp_options.autoload. While most sites will be completely unaffected by this, sites with a large number of rows in wp_options and a small number of autoload set will see a significant performance improvement (see #24044).
  • The Media Library type filter has been expanded to include document, spreadsheet, and archive filters (see #38195).
  • Autocomplete support has been added for PHP mode in the CodeMirror code editor used when using the plugin and theme editors (see #47769).
  • Support for flex, grid, and column layout techniques have been added to the list of CSS attributes that KSES considers safe for inline CSS (see #37248).
  • The charset used when wp_die() is called is no longer hard coded as utf-8. Instead, utf-8 will be used as a default and a different charset argument can be passed in the third $args parameter for wp_die() (see #46666).
  • The sms protocol has been added to wp_allowed_protocols() (see #39415).
  • Support for a custom WP_PLUGIN_URL has been added to load_script_textdomain(). Plugins may not be on the same host/path as the rest of the content. This ensures translations are loaded correctly in this scenario (see #46336).
  • Three additional parameters ($length, $special_chars, and $extra_special_chars) are now passed to the random_password filter in wp_generate_password(). Previously, code using this filter had no knowledge of the requirements a generated password needed to meet. Now, custom password generators can better utilize the filter instead of overriding the entire pluggable function. (see #47092).

Build/Test Tools

  • A new job on TravisCI test builds has been added to scan for potential PHP compatibility issues (see #46152).
  • Composer scripts will now use the version of PHPCS/PHPCBF installed through Composer, removing the requirement to have them installed globally. The @php prefix has also been added to ensure each script runs on the PHP version that Composer used to install dependencies (see #47853).
  • Installing Grunt globally is no longer required to run build related scripts because Core now uses the local Grunt binary installed by NPM. For example, npm run build can now be used instead. (see #47380).

External Libraries

A number of external libraries and dependencies have been updated. Including Twemoji, which now includes the Transgender symbol and flag!

⚧️ 💖 🏳️‍⚧️

The following external libraries have been updated:

Props @earnjam for peer review.

#5-3, #dev-notes