Global overloading in advanced-cache.php

As a part of the 4.6 release, a change is made to the order of loading files during the bootstrap process. This change included an attempt to protect sites from the overloading of the hook related globals in advanced-cache.php. This change was reverted with [38251]. This means that the 4.5 behavior where if an advanced-cache.php sets one of the globals to an empty array, previously entered records will not exist.

This is a general reminder to not directly touch the globals in WordPress and to always use API functions. The format that the globals are in is not guaranteed to stay consistent from version to version. If you need to interact with the Plugins API in advanced-cache.php, as of 4.6, you can use the Plugins API (add_action(), add_filter(), etc.).

How to know if you are using advanced-cache.php

advanced-cache.php is a drop-in. If you are using any drop-ins, you will see “Drop-ins” at the top of wp-admin/plugins.php as one of the filtering options. If advanced-cache.php is listed and no warning is displayed, your site is using it. This file lives in your wp-content directory as a peer to plugins and themes. Updates to it are not made like updates to plugins. You will never see a notice that there is an update pending. If you did not write this code yourself, you are encouraged to keep up to date with upstream updates.

#4-6, #bootstrap-load, #dev-notes

Editor changes in 4.6

In WordPress 4.6 TinyMCE is upgraded from version 4.3.10 to 4.4.1. There are numerous bug fixes and several new features, most notably a new inline theme (changelog).

The wpview editor plugin (that is responsible for showing gallery, video, audio, and oEmbed previews) was updated to use the TinyMCE API for non-editable elements. This brought some small changes and improvements in the UI, for example “views” are draggable now. On the back-end the wp-mce-view-unbind event was removed as it doesn’t exist in the API. It was intended for cleanup/unloading but was never very reliable. If a plugin needs to unload instance dependent scripts, it can use mutation observer to monitor when the view node is deleted. See #36434 for more information.

wpview remains an experimental API, though with each iteration it is getting closer to being finalized. As an experimental API, breaking changes are expected. As always, please test your plugin now if it modifies or depends on the editor, especially if you use experimental features like wpview.

#4-6, #dev-notes, #editor, #media, #tinymce

HTTP API in 4.6

For WordPress 4.6, the HTTP API (wp_remote_request() and family) have undergone a large internal change. Rather than using a WordPress-specific HTTP library, WordPress now uses the open-source independent Requests library, developed by yours truly.

Why Requests?

The WP_HTTP library in previous releases has been primarily maintained by myself and @dd32, with my support time split between the two libraries. Both libraries are very similar, and code has been shared between them (when licensing permitted) in the past. Requests follows the same development philosophies as WordPress: developing for the masses with broad PHP support, and maintaining backwards compatibility.

By switching to Requests, a library without any WordPress-specific dependencies, WordPress benefits from input from the wider PHP ecosystem and community

Requests also has a huge number of unit tests, with test coverage at 92% of the codebase and increasing. It’s also used by other projects via the Composer ecosystem, including wp-cli’s HTTP functionality.

What has changed?

From your perspective as a developer, nothing should have changed visibly. You can and should continue to use WP’s HTTP functions the way you always have.

(Note: For the 4.6 development cycle and beta 1, the HTTP functions returned an array-like object. Many plugins and themes in the real world are using direct is_array() checks, so it was decided to pull this functionality back a bit to be safe, see #37097.)

Some new functionality has been introduced. In particular, the array returned from wp_remote_request() now includes a new http_response value, which contains a WP_HTTP_Response object (technically, WP_HTTP_Requests_Response). This shares functionality with WP_REST_Response objects introduced in WordPress 4.4, allowing common functionality to be developed for both APIs. In future releases, WordPress may introduce new WP_HTTP_Request objects as well, allowing common middleware to be used across both APIs.

In addition, all of Requests’ features are now available in WordPress. This includes things like better HTTP standard support, case-insensitive headers, parallel HTTP requests, support for Internationalized Domain Names (like bö, and many other internal improvements.

Some new features are only available when using Requests::request() directly (such as parallel requests), however, these will be introduced into new WordPress-specific APIs in future releases (#37459). This release is focussing on switching internal implementation and remaining stable.

For more background on the change, see #33055.

#4-6, #dev-notes, #http-api

WordPress 4.6 Field Guide

Many of the changes in the forthcoming WordPress 4.6 are developer-focused changes that take place under the hood. Please remember to test your plugins, themes, and sites with WordPress 4.6 before the release. An hour of testing today can save you days of anguish later.

Enhanced Meta Registration

register_meta() is getting some updates to enable greater flexibility and features in the future (such as inclusion in the Rest API). Until now, register_meta() took four arguments. In WordPress 4.6, this will decrease to 3, with the third one being an array of arguments. When register_meta() is used with the old signature in WordPress 4.6, it will continue to function but will now return false. Please read the initial post outlining why register_meta() has been updated and the followup detailing further enhancements.

Persistent Comment Cache

Since WordPress 2.6, the comments API has purposefully not used a persistent cache. Over the past 20 releases, changes have been made to purge the problems from the comments API that caused this. If you have a plugin which modifies comment data directly please change them to make use of the various comment API functions or use clean_comment_cache(). You can hit this changes announcement for more info.

New Object: WP_Post_Type

Rather than a standard object, there is now a WP_Post_Type for each registered post type. Three functions and three actions have been changed to use this new object. WP_Post_Type provides methods to handle post type supports, rewrite rules, meta boxes, hooks, and taxonomies.

🛫 Open Sans, 🛬 Native Fonts

With the continued evolution of system fonts allowing for all devices to have a beautiful looking admin, WordPress 4.6 updates the font stack. To keep your custom admin pages looking consistent with the rest of the WordPress admin, you are encouraged to audit your CSS. The new font stack is:

font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;

When using this font stack, it must be called using the font-family property, and not the font shorthand. This works around an issue in Microsoft Edge. Additionally, the only font weights used in core now are 400 for general text and 600 for heavier text.

Shiny Updates

One of the user-facing features in 4.6 is an update to Shiny Updates, first introduced in 4.2. For developers, the change to pay attention to is that the JavaScript under the updates handle has been refactored and updated to support plugins and themes. If you are dependent on that handle, make sure to read about the shiny updates changes.

Resource Hints in 4.6

Resource Hints is a rather new W3C specification that “defines the dns-prefetch, preconnect, prefetch, and prerender relationships of the HTML Link Element (<link>)”. These can be used to assist the browser in the decision process of which origins it should connect to, and which resources it should fetch and preprocess to improve page performance.

In 4.6, WordPress adds an API to register and use resource hints. The relevant ticket is #34292.

Developers can use the wp_resource_hints filter to add custom domains and URLs for dns-prefetchpreconnect, prefetch or prerender. One needs to be careful to not add too many resource hints as they could quite easily negatively impact performance, especially on mobile.


WordPress 4.6 will introduce WP_Term_Query. This new class brings parity between taxonomy term queries and WP’s other content type queries: WP_Query, WP_Comment_Query, and WP_User_Query. And – as in the case of posts, comments, and users – the get_terms() function has been converted to a wrapper for the new WP_Term_Query.


Everyone should be able to use WordPress in the language they want. WordPress 4.6 makes a number of changes to assist with internationalization and localization. Some of the highlights include:

  • Just-in-time loading for translations. You do not have to call load_plugin_textdomain() or load_theme_textdomain() anymore (if you distribute your theme/plugin via
  • Community translations are now favored over translations which are included in your theme/plugin.
  • Localized jQuery UI datepicker.
  • Support for comment number declension in get_comments_number_text(). See #13651.
  • Fallback for TextDomain header field in get_plugin_data(). See #36706.
  • Updated list of continents and cities for the timezone selector. See #37554.
  • Support for the German (Switzerland) locale in remove_accents(). See #37076.
  • Improved support for month name declension. See #36790.

Pre-instantiated Widget Registration in 4.6

Since WP_Widget was introduced in 2.8 the register_widget() and unregister_widget() functions required the class name (string) of a WP_Widget subclass to be supplied. As of 4.6 these functions also accept a class instance (object) of a WP_Widget subclass as well. See #28216.

Two key benefits of allowing objects to be instantiated are:

  1. Widgets can now be instantiated and registered with constructor dependency injection.
  2. New widget types can now be added dynamically, such as adding a Recent Posts widget for each post type, per #35990.

New and Improved Customizer APIs

The customizer has four major changes in WordPress 4.6. The most prominent is a new collection of APIs for validation of setting values. Included in this new notifications API for the customizer.

Additional changes include some CSS cleanup. Custom controls that use part of the core UI and subclass WP_Customize_Media_Control no longer need to create their own CSS styles that duplicate core rules. Because the markup and styling have changed significantly, please test any custom controls, CSS, or JavaScript that is related to media controls in the customizer.

If your code uses the customizer, you are encouraged to review the changes.

Bootstrap/Load Updates in 4.6

Alert: A late change was made to <a href=””>remove protection for overloading Plugin API related global variables</a> in <code>advanced-cache.php</code>

Every time WordPress is loaded, it goes through the bootstrap or loading process. In WordPress 4.6, there will be a few changes to the process focused on making pieces available earlier. Many of these changes will have no effect whatsoever on the vast majority of WordPress sites. However, if you are the type that maintains your own advanced-cache.php drop-in, host/run large profile sites, or work on tools that bootstrap WordPress is odd ways, you need to know about the following changes:

  • Load plugin.php earlier in wp-settings.php
  • is_ssl() is now located in wp-includes/load.php
  • ABSPATH can now be safely defined before WordPress is loaded

Multisite Focused Changes

This release, work continues on multisite with a focus on improved APIs and performance. Some highlights include:

  • New WP_Site_Query and WP_Network_Query classes to query sites and networks in a standardized way.
  • Enhancements to WP_Site and WP_Network objects including lazy-loading for site details.
  • A new helper function get_current_network_id() to find the current network’s ID.
  • wp_get_sites() has been deprecated. get_site(), get_sites(), get_network(), and get_networks() are the future.

External Library Updates

  • Masonry was updated to version 3.3.2 from version 3.1.4.
  • imagesLoaded was updated to version 3.2.0 from version 3.1.4.
  • imagesLoaded can now be enqueued without Masonry being enqueued. For backward compatibility reasons, imagesLoaded remains a dependency for Masonry.
  • MediaElement.js was updated to version 2.22.0 from version 2.18.1.
  • TinyMCE was updated to version 4.4.1 from version 4.3.10.
  • Backbone.js was updated to version 1.3.3 from 1.2.3.

Summaries for each of these updates and links to full changelogs are available.

But Wait! There’s More!

Over 280 bugs, 125 enhancements, 7 feature requests, and 18 blessed tasks have been marked as fixed in WordPress 4.6. Some additional ones include:

Please, test your code. Fixing issues now, before the release, helps you and helps millions of WordPress sites.

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

Additional register_meta() changes in 4.6

In the last 2 weeks, the direction of register_meta() has changed significantly from the original write-up. There was a meeting to discuss some of the changes and a recap of that discussion. Some other discussion after that meeting led to a much more simplified version of register_meta() that is now shipping in 4.6.

Here’s what registering meta looked like in 4.5. This meta key has sanitization and authorization callbacks.

register_meta( 'post', 'my_meta_key', 'sanitize_my_meta_key', 'authorize_my_meta_key' );

The above code will continue to work in 4.6, though will not be considered completely registered. The callbacks will be registered, but the key will not be added to the global registry and register_meta() will return false.

Here’s what registering meta looks like in 4.6. This meta key will have sanitization and authorization callbacks, and be registered as public for the WordPress REST API.

$args = array(
    'sanitize_callback' => 'sanitize_my_meta_key',
    'auth_callback' => 'authorize_my_meta_key',
    'type' => 'string',
    'description' => 'My registered meta key',
    'single' => true,
    'show_in_rest' => true,
register_meta( 'post', 'my_meta_key', $args );

The above will register the meta key properly and return true.

There will no longer be a check for unique object types and subtypes for meta keys. There is no CURIE like syntax involved. Instead, be sure to uniquely prefix meta keys so that they do not conflict with others that may be registered with different arguments.

Additional helper functions get_registered_metadata(), get_registered_meta_keys(), unregister_meta(), and registered_meta_key_exists() have been added to make the innards of the global data more accessible.

The $wp_meta_keys variable should not be altered directly. It is possible that its structure will change in the future.

Any code currently using register_meta() and expecting pre-4.6 behavior will continue to work as is. Please report any breaks in compatibility that might be found.

For the full history, see #35658. 🙂



#4-6, #dev-notes, #options-meta

Comments in 4.6 can now be cached by a persistent object cache

The ‘comment’ cache group was made non-persistent in [7986], to address the difficulty of reliable cache invalidation. This meant the comment cache values were only held for the current page load, and lost on reload or navigation. The comment API has improved since WordPress 2.6, and cache is king.

In WordPress 4.6 the ‘comment’ cache group has been removed from the list of non-persistent cache groups, see [37613]. When comments are added, modified, or deleted we properly invalidate out of date cache values. You can now cache with confidence.

If you have a plugin which modifies comment data directly please change them to make use of the various comment API functions or use clean_comment_cache().

Don’t miss out on this change. For more background on the change, see #36906.

#4-6, #comments, #dev-notes

External library updates in 4.6

The following are external libraries that have been updated during the 4.6 release cycle.


Masonry was updated to version 3.3.2 from version 3.1.4 (#32802). Notable changes:

  • jQuery events are now triggered.
  • CommonJS is supported.
  • Percentages can now be used for horizontal positions.
  • Various browser compatibility issues are now resolved.

Full Changelog:


imagesLoaded was updated to version 3.2.0 from version 3.1.4 (#32802). Notable changes:

  • Background images are now supported.
  • setTimeout no longer triggers multiple events errantly.
  • Internal cache has been removed. Each image will now be checked.
  • Various browser compatibility issues are now resolved.

Full Changelog:

NOTE: imagesLoaded and Masonry are now in separate files. This means that imagesLoaded can be enqueued without Masonry being enqueued. For backward compatibility reasons, imagesLoaded remains a dependency for Masonry.


MediaElement.js was updated to version 2.22.0 from version 2.18.1 (#36759, #37363). Notable changes:

  • Several YouTube embed issues have been resolved.
  • More Vimeo API support added.
  • A few a11y and i18n issues have been fixed.
  • General stability enhancements.

Full Changelog:


TinyMCE was updated to version 4.4.1 from version 4.3.10 (#37225, #37327, #37476). Notable changes:

  • Various contentEditable bugs fixed.
  • Various browser compatibility bugs fixed.
  • General stability and performance enhancements.

Full Changelog:


Backbone.js was updated to version 1.3.3 from 1.2.3 (#37099). Notable changes:

  • 4 major regressions were fixed.
  • Added findIndex and findLastIndex Underscore methods to Collection.
  • Added options.changes to Collection “update” event which includes added, merged, and removed models.
  • Removed component package support.

Full Changelog:

#4-6, #dev-notes, #external-libraries

Introducing admin_print_footer_scripts-$hook_suffix in 4.6

The admin_print_footer_scripts action hook is the last chance to localize admin scripts; but it is a generic one. If you ever wanted to do something for specific admin pages only, you would either have to hook into another dynamic action, or hook into admin_print_footer_scripts and check the $hook_suffix (which is not even passed, but that’s not an issue) yourself. The problem with the former is that there might be happening a lot between the chosen action and when your script gets enqueued (admin_print_footer_scripts); and maybe you need to be aware of what has happened. The problem with the latter is that you would have to register possibly a lot of functions, maybe check the current admin page inside several of these, and eventually bail most of the times. That’s why WordPress 4.6 brings the dynamic footer action admin_print_footer_scripts-$hook_suffix. See [37279].

The following pre-4.6 code

add_action( 'admin_print_footer_scripts', function() {
    global $hook_suffix;

    if ( 'some_admin_page' !== $hook_suffix ) {

    // Whatever it is that you want to do...
} );

can now be simplified like this:

add_action( 'admin_print_footer_scripts-some_admin_page', function() {
    // Whatever it is that you want to do...
} );

This change brings more consistency between wp-admin/admin-footer.php and wp-admin/admin-header.php, which already fires the generic admin_print_scripts and the dynamic admin_print_scripts-$hook_suffix actions.

For more background on the change, see #34334.

#4-6, #dev-notes, #plugins, #script-loader

dbDelta() updates in 4.6

dbDelta() is a function which helps to modify the database based on specified SQL statements. In WordPress 4.6 this function has been updated to resolve some long standing bugs.

Normalized index definitions

Previously, dbDelta() compared the raw SQL data for index definitions with the output of SHOW INDEX FROM. This required a specific format so indices are not unnecessarily re-created. But this format wasn’t always ensured, until now. See [37583]:

  • dbDelta() now parses the raw index definition to extract the type, name and columns. With this data a normalized definition is build (#20263, #34873).
  • Core standardize now on uppercase types (#34871) and on ‘KEY’. ‘INDEX’ is only a synonym for ‘KEY’.
  • ASC and DESC definitions are currently unused by MySQL, dbDelta() ignores them now too (#34959).
  • Spaces in index definitions don’t create duplicate indices anymore (#34869).

Backtick all the things

Index names (#20263), index column names (#20263), names in index change queries (#20263) and other queries (#31679) are now escaped with backticks to improve compatibility with names which are reserved keywords.

Support for SPATIAL keys

dbDelta() already supported spatial fields (by virtue of not checking field types), so it’s nice to round that out with spatial key support, too. See #36948.


If you’re using dbDelta() in your plugin please test it with WordPress 4.6 and report any issues in the comments or on Trac.

There are still a few issues with dbDelta(), can you help us to fix them? 🔨

#4-6, #database, #dev-notes

WP_Post_Type in 4.6

WordPress 4.6 will introduce a new WP_Post_Type class. This changes the global $wp_post_types to an array of WP_Post_Type objects. WP_Post_Type provides methods to handle post type supports, rewrite rules, meta boxes, hooks, and taxonomies. These methods are used internally by register_post_type() and unregister_post_type(). Each post type argument is now a property of WP_Post_Type.

The following functions have been changed to return a WP_Post_Type object:

  • register_post_type()
  • get_post_type_object()

The following hook parameters are now a WP_Post_Type object:

  • The second parameter $post_type of xmlrpc_prepare_post_type.
  • The second parameter $post_type_object of registered_post_type.
  • The third parameter $post_type of nav_menu_items_{$post_type_name}.

The following function accepts a WP_Post_Type object now too:

  • is_post_type_viewable()

For more background on the change, see #36217.

Note that there are plans to introduce a WP_Taxonomy class as well, see #36224.

#4-6, #dev-notes, #posts