WordPress 4.5 Field Guide

WordPress 4.5 is the next major version of WordPress and with it come some bang bang changes. This guide will describe many of the developer-focused changes to help you test your themes, plugins, and sites. So grab a ☕️ ,🍷,🍵, or 🍺 and get ready for what’s coming soon.

JavaScript! and CSS!

Multiple external libraries have been updated with the two that require your attention being Backbone and Underscore. There were some‼️ breaking changes ‼️ with these two libraries, so make sure to test your code if you use either of these.  jQuery and jQuery Migrate have also been updated, please test with the unminified versions in order to ensure future compatibility with WordPress.

The script loader has been updated with three big changes. The build process no longer creates wp-admin.min.css, wp_add_inline_script() joins the family of functions, and better support for multigenerational dependencies is included.

Term Edit Page! –‼️ Backward Incompatible change‼️

The term edit screen has been separated out from the term list screen. This brings greater consistency to how the admin generates screens for terms and posts but at the cost of the need to change how you register scripts and how you detect that you are on a term edit screen.

Live Preview: Faster, Extensible, More Features!

Live Preview (also known as “The Customizer”) once again has received attention this release with the addition of new controls, some performance improvements that require your attention to implement, and a two new user-facing features.

Setting-less Controls, Device Previews, and Selective Refresh are the three biggest changes you’ll find. Setting-less controls make it easier for you to implement complex interfaces. Device Preview is a user facing feature that allows users to adjust the preview to match the screens on various devices.  This feature includes filters to change the devices users can choose. Selective Refresh allows for changes to appear quicker inside the preview, and you can do so with less code than before. Theme authors need to make changes to take advantage of selective refresh. Luckily, the change will generally result in fewer lines of code needed overall ( more 🍎 than 🍏 ).

One area that selective refresh helps live preview function faster is with widgets.

‼️ If you offer sidebars or a widget in your theme or plugin, please update your code to implement selective refreshBoth themes and widgets need to indicate support, so please update your code accordingly.

The final change to Live Preview involves a control for a new theme feature, and that is Custom Theme Logos.

Custom Theme Logos!

Themes can now offer support for custom logos. Custom Logos add an additional way for users to customize their site and theme developers can customize how custom logos are displayed.

Image Performance!

Following up on the introduction of responsive images in WordPress 4.4, WordPress 4.5 is making changes to improve image performance including improved compression settings and smarter handling of image metadata.

Embed Templates! (and other iterations)

Iterating on embeds has led to the ability to better customize embeds by adding new templates to the template hierarchy for embeds. Embeds have also had some performance improvements for autodiscovery, the ability to embed the front page of a site, and changes to the iframe of embedded content.

Comments Component!

The comments component has a few user-facing changes to make comments easier to moderate. For developers, the most notable change is the ability to adjust field lengths for your custom database schema. Additionally, the rel=nofollow attribute and value pair will no longer be added to relative or same domain links within comment_content.

Multisite!

Multisite once again has seen changes with the addition of new filters around site and user creation, and a WP_Site object.

And more!

Overall, 372 bugs have been marked as fixed in WordPress 4.5 (so far). There are also dozens of new hooks and dozens of hooks that have received additional parameters. It’s entirely possible that one or more has caused a regression, so please make sure to test your code deeply and report any issues you find.

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

jQuery Updates in WordPress 4.5

jQuery was updated from version 1.11.3 to 1.12.2, see [36285], [36680], and [37070].
At the same time jQuery Migrate – the plugin to detect and restore APIs or features that have been deprecated in jQuery – was updated from 1.2.1 to 1.4.0 ([36285] and [37072]).

The non-minified version of jQuery Migrate throws a few more warnings now. See some examples from core in [36286-36288].

🔬 Please test your plugins and themes with the non-minified version to make them compatible with future versions of jQuery.

Ticket: #35380

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

The Editor in WordPress 4.5

Inline Link Toolbar

From WordPress 4.5 you will be able to link text with an inline toolbar, which replaces the link modal. You will still be able to access the modal with the gear icon in the toolbar, if you’re using one of the advanced fields or are using a plugin that extends the modal. Eventually we will try to move all those fields inline, though still under an advanced toggle and not visible by default. For those interested, see #36312.

Inline link toolbar.

Text Patterns

We also added some more text patterns, or shortcuts if you like: `text` will change to <code>text</code> and --- (or more dashes) will change to <hr> while typing. We considered adding patterns for bold and italic, but there was no consensus yet and we’d like to test the inline text patterns first on an HTML tag mostly used by developers. See #33301.

#4-5, #dev-notes, #editor

Implementing Selective Refresh Support for Widgets

WordPress 4.5 includes a new Customizer framework called selective refresh. To recap, selective refresh is a hybrid preview mechanism that has the performance benefit of not having to refresh the entire preview window. This was previously available with JS-applied postMessage previews, but selective refresh also improves the accuracy of the previewed change while reducing the amount of code you have to write; it also just makes possible to do performant previews that would previously been practically impossible. For example, themes often include some variation of the following PHP and JavaScript to enable performant previewing of changes to the site title:

function mytheme_customize_register( WP_Customize_Manager $wp_customize ) {
	$wp_customize->get_option( 'blogname' )->transport = 'postMessage';
}
add_action( 'customize_register', 'mytheme_customize_register' );

function mytheme_customize_preview_js() {
	$handle = 'mytheme-customize-preview';
	$src = get_template_directory_uri() . '/js/customize-preview.js';
	$deps = array( 'customize-preview' );
	$ver = '0.1';
	$in_footer = true;
	wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer );
}
add_action( 'customize_preview_init', 'mytheme_customize_preview_js' );
( function( $, api ) {
	api( 'blogname', function( setting ) {
		setting.bind( function( value ) {
			$( '.site-title a' ).text( value );
		} );
	} );
} ( jQuery, wp.customize ) );

In 4.5, the core themes now utilize selective refresh for previewing the site title and tagline. This allows the above code to be replaced with the following PHP:

function mytheme_customize_register( WP_Customize_Manager $wp_customize ) {
	$wp_customize->selective_refresh->add_partial( 'blogname', array(
		'selector' => '.site-title a',
		'render_callback' => function() {
			bloginfo( 'name' );
		},
	) );
}
add_action( 'customize_register', 'mytheme_customize_register' );

So as you can see, not only is the amount of code more than cut in half (also eliminating the JS file altogether), it also ensures that when a site title change is previewed it will appear with all of the PHP filters applied from core and plugins: for example wptexturize will apply so that curly quotes and dashes will appear as expected. In REST API parlance, selective refresh enables the Customizer preview to show title.rendered instead of just title.raw. (For more on this change to previewing the site title and tagline, see #33738. The previous JS-based previewing is retained for an instant low-fidelity preview while the selective refresh request returns.) Selective refresh is also the mechanism used for previewing the new custom logo feature in 4.5, ensuring that the logo image is rendered re-using the image_downsize logic in PHP without having to re-implement it in JS (keeping the code DRY).

With that recap of selective refresh out of the way, let’s turn to the focus of this post: selective refresh for widgets. When widget management was added to the Customizer in 3.9, every change to a widget required a full page refresh to preview. This resulted in a poor user experience since a full refresh can take awhile, especially on weighty pages. So selective refresh of widgets is a key usability experience improvement for widget management in the Customizer in 4.5. However, as live postMessage updates to the site title and tagline have required supporting theme code (see above), so too will theme support be required for widgets, as noted in the Selective Refresh of Widgets section from the previous post on this topic:

Selective refresh for nav menus was enabled by default in 4.3. While some themes needed to add theme support for any dynamic aspects (such as the expanding submenus in Twenty Fifteen), generally nav menus seem to be fairly static and can be replaced in the document without needing any JS logic to be re-applied. Widgets, on the other hand, have much more variation in what they can display, since they can in fact display anything. For any widget that uses JavaScript to initialize some dynamic elements, such as a map or gallery slideshow, simply replacing the widget’s content with new content from the server will not work since the dynamic elements will not be re-initialized. Additionally, the sidebars (widget areas) in which the widgets are displayed may also have dynamic aspects associated with them, such as the Twenty Thirteen sidebar which displays widgets in a grid using Masonry. For this theme, whenever a widget is changed/added/removed/reordered, the sidebar needs to be reflowed.

In order to allow themes to reflow sidebars and widgets to reinitialize their contents after a refresh, the selective refresh framework introduces widget-updated and sidebar-updated events. Additionally, since re-ordering widgets in a sidebar is instant by just re-ordering the elements in the DOM, some widgets with dynamically-generated iframes (such as a Twitter widget) may need to also be rebuilt, and for this reason there is a partial-content-moved event.

For the above reasons, I believe it will be much more common for widgets (and sidebars) to need special support for selective refresh, and so I think that at least for 4.5 the selective refresh should be opt-in for widgets (and perhaps in themes for sidebars). See theme support for Twenty Thirteen and plugin support for a few widgets in Jetpack (which won’t be part of the merge). At last week’s Core dev meeting, it was suggested that we add the opt-in for widget selective refresh at RC.

So as noted, selective refresh for widgets will be opt-in as of 4.5 RC1 (see #35855).

What do themes and widgets need to do to opt-in for selective refresh support?

Selective refresh will be used for previewing a widget change when both the theme and the widget itself indicate support as follows:

Adding Theme Support

If your theme does not do anything fancy with its sidebars (such as using Masonry to lay out widgets), then all that you need to do is add the following to your theme:

add_theme_support( 'customize-selective-refresh-widgets' );

On the other hand, if the theme is rendering a sidebar in a unique way, then to add a bit of logic to handle the changes properly. For example, as noted previously the footer area in Twenty Thirteen consists of a sidebar that is laid out using Masonry. When a widget is added, removed, or updated, the Masonry logic needs to be re-run to update the positioning of the widgets in the sidebar. The following highlighted code is what handles this:

jQuery( function( $ ) {
	var widgetArea = $( '#secondary .widget-area' );
	widgetArea.masonry( {
		itemSelector: '.widget',
		columnWidth: columnWidth,
		gutterWidth: 20,
		isRTL: body.is( '.rtl' )
	} );
	
	if ( 'undefined' !== typeof wp && wp.customize && wp.customize.selectiveRefresh ) {
		wp.customize.selectiveRefresh.bind( 'sidebar-updated', function( sidebarPartial ) {
			if ( 'sidebar-1' === sidebarPartial.sidebarId ) {
				widgetArea.masonry( 'reloadItems' );
				widgetArea.masonry( 'layout' );
			}
		} );
	}
} );

Update 2016-07-17: Added the jQuery() DOM ready wrapper around this logic to ensure it runs after the DOM has been fully loaded, and thus ensuring the wp.customize.selectiveRefresh object exists if it is going to be loaded. See ​#37390 as this also turned out to be broken in Twenty Thirteen.

Note the if statement is there so the code will only run in the Customizer preview and if selective refresh is available (that is, if they are running 4.5 or later).

Adding Widget Support

If your widget lacks any dynamic functionality with JavaScript initialization, adding support just requires adding a customize_selective_refresh flag to the $widget_options param when constructing the WP_Widget subclass. If you are enqueueing any CSS for styling the widget, you’ll also want to enqueue this unconditionally in the Customizer preview (if is_customize_preview()) so that a widget can be added to the preview and be styled properly without doing a full page refresh. For example, note these highlighted lines in a sample widget:

class Example_Widget extends WP_Widget {

	public function __construct() {
		parent::__construct(
			'example',
			__( 'Example', 'my-plugin' ),
			array(
				'description' => __( 'Selective refreshable widget.', 'my-plugin' ),
				'customize_selective_refresh' => true,
			)
		);

		// Enqueue style if widget is active (appears in a sidebar) or if in Customizer preview.
		if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
		}
	}

	public function enqueue_scripts() {
		wp_enqueue_style( 'my-plugin-example-widget', plugins_url( 'example-widget.css', __FILE__ ), array(), '0.1' );
	}

	/* ... */
}

On the other hand, as with sidebars in a theme, if a widget uses JavaScript for initialization, you’ll need to add logic to make sure re-initialization happens when the widget is selectively refreshed. So in addition to the above example, you must:

  1. Enqueue any dependent JS logic if is_customize_preview() just as noted above for enqueueing any CSS stylesheet.
  2. Add a handler for partial-content-rendered selective refresh events to rebuild a widget’s dynamic elements when it is re-rendered.
  3. As needed, add a handler for partial-content-moved selective refresh events to refresh partials if any dynamic elements involve iframes that have dynamically-written documents (such as the Twitter Timeline widget). (Adding this event handler should normally not be required.)

The Twitter Timeline widget in the Jetpack plugin is a good example for how to write these event handlers:

jQuery( function() {
	// Short-circuit selective refresh events if not in customizer preview or pre-4.5.
	if ( 'undefined' === typeof wp || ! wp.customize || ! wp.customize.selectiveRefresh ) {
		return;
	}

	// Re-load Twitter widgets when a partial is rendered.
	wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) {
		if ( placement.container ) {
			twttr.widgets.load( placement.container[0] );
		}
	} );

	// Refresh a moved partial containing a Twitter timeline iframe, since it has to be re-built.
	wp.customize.selectiveRefresh.bind( 'partial-content-moved', function( placement ) {
		if ( placement.container && placement.container.find( 'iframe.twitter-timeline:not([src]):first' ).length ) {
			placement.partial.refresh();
		}
	} );
} );

(This is adapted from a pending PR for Jetpack.)

Conclusion

All core themes and core widgets will have support for selective refresh in 4.5. Now it’s up to theme and plugin authors to also add support to also start taking advantage of these drastic performance improvements for previewing widget changes.

#4-5, #customize, #dev-notes, #feature-selective-refresh

Performance improvements for images in WordPress 4.5

WordPress 4.5 includes a few performance enhancements for images.

Increased image compression for custom sizes

WordPress 4.5 increases the amount of compression applied to intermediate sizes by changing the default quality in WP_Image_Editor from 90 to 82. As noted in the proposal for this change, this results in a noticeable reduction in file sizes with little change in visual quality. Developers can override the default image quality value using the wp_editor_set_quality filter.

Improved resizing settings for ImageMagick

For sites making use of ImageMagick, we’ve reduced file sizes further by resizing images  more efficiently in WP_Image_Editor_Imagick and by stripping extraneous metadata using the new WP_Image_Editor_Imagick::strip_image() method.

For now, ‘icc’ and ‘icm’ color profiles are retained, along with ‘exif’, ‘xmp’, and ‘iptc’ profiles, which can contain copyright and orientation data. Those who want to retain additional metadata can disable profile stripping by adding a callback function to the image_strip_meta hook that returns false.

Note that the original full sized images uploaded to WordPress are unaffected by these changes.

Introduction of wp_get_upload_dir()

As Jeremy Felt mentioned in his post on Multisite changes, wp_upload_dir() received a major performance overhaul in this release. Those changes were pared with the addition of a new function, wp_get_upload_dir(), which can be used as a more performant way to display information about the uploads directory on the front end. This is particularly useful when building URLs for images in templates. (See #34359)

#4-5, #dev-notes, #images, #media, #optimization, #performance

Embeds Changes in WordPress 4.5

After the introduction of the embeds feature in WordPress 4.4 there have been a few significant changes in 4.5 to make embeds more robust and easier to customize. 🎉

Embed Code Adjustments

Tickets: #35804, #35894

There were two minor changes to the <iframe> embed code:

  1. The iframe’s title attribute has been adjusted to better describe its content for improved accessibility.
  2. The iframe is now hidden using a different technique to prevent images from not being displayed properly in Firefox, working around a known bug in that browser.

Discovery Improvements

Ticket: #35979

Since WordPress 4.4, oEmbed discovery has been turned on by default. Using auto discovery, WordPress tries to find embeddable content when a URL is pasted on a new line in the editor. [36880] prevents timeouts from happening when requesting the URL by limiting the response size to 150KB.

Embedding Static Front Pages

Ticket: #34971

Previously, embedding a static front page was not possible due to not having an /embed/ endpoint. Now embed is a reserved slug that can’t be used for new pages/posts. When https://example.com/foo/embed/ is an existing page, embeds fall back to https://example.com/foo/?embed=true.

Embed Template Changes

Displays select embed template and template part locations, as well as various areas of an example embed view. Covers embed.php, the_embed_site_title(), embed-content.php, the_excerpt_embed(), and print_embed_sharing_options().

Tickets: #35322, #35630, #34561

  • The site icon in the embed template used to fall back to an image located inside /wp-admin/. This was problematic when the directory is not accessible to the public. That image is now loaded from inside /wp-includes/.
  • Thanks to an adjusted click event handler, links inside the iframe now work even when they’re inserted dynamically after the page load.
  • By far the biggest changes affect the way the embed template is loaded 💪🏽. Most notably, the old wp-includes/embed-template.php file has been deprecated and split into five new template parts that can be individually overridden by themes:
    • embed.php
    • embed-404.php
    • embed-content.php
    • header-embed.php
    • footer-embed.php

The five new template parts live in /wp-includes/theme-compat/ and allow core to gracefully fall back should themes prefer not to override any or all of them.

Previously, the embed template could only be changed using the embed_template filter. This filter can now be leveraged directly within the template hierarchy via the already-existing {$type}_template filter (where $type equals “embed”).

See get_query_template() and locate_template() for more information.

See [36693] for the relevant changeset.

Embeds in the Template Hierarchy

Ticket: #34278

In addition to the new base embed.php template and related template parts, themes can now implement embed templates for specific post types and post formats within the confines of the template hierarchy. The embeds template cascade looks like this:

  • embed-{post-type}-{post_format}.php
  • embed-{post-type}.php
  • embed.php
  • wp-includes/theme-compat/embed.php

Note that this is the first time direct theme-compat inheritance has been integrated with the template hierarchy. This approach allows core to provide basic, yet standardized templates and template parts for handling post embeds.

To leverage the core embed template parts, simply use standard get_template_part() calls within your themes. The template hierarchy will do the rest.

For example:

  • If the theme is leveraging its own version of embed.php template, it would likely call template parts directly, e.g. get_template_part( 'embed', 'content' );
  • If the theme is relying on the core embed template parts – i.e. not providing its own embed-content.php file – the template hierarchy would fall back to using wp-includes/theme-compat/embed-content.php, and so on.

See [36876] for the relevant changeset.

Note:
For more information on extending embeds within the scope of the template hierarchy, check out the new Embeds section in the Template Hierarchy reference in the Theme Developer handbook.

#4-5, #dev-notes, #embeds

Customizer Improvements in 4.5

In addition to the ~35 defects that were fixed in this release, there were also ~17 features and enhancements that were made. What follows are some highlights, starting with some smaller enhancements and then listing out full posts that document the larger features.

Setting-less Controls (#35926)

Sometimes controls need to be added which don’t directly have associated settings. For example, there can be controls needed which manipulate some aspect of the Customizer interface or manage the behavior of other controls and their settings: consider a control for managing repeating controls, where the button only serves to create other controls and their settings. When nav menus were added in the Customizer in 4.3, the UI for creating a new menu involved two controls which had custom settings associated them (create_new_menu and new_menu_name) which served no purpose other than to make sure the control wouldn’t raise an error. The settings had custom types to prevent them from getting saved to the DB.

In 4.5, controls are no longer required to have associated settings. By default registering a control without an explicit settings argument will result in the control’s own id being supplied as the associated setting id. To explicitly register a control without any associated settings, pass an empty array as the settings:

$wp_customize->add_control( 'new-post', array(
	'section'  => 'title_tagline',
	'settings' => array(),
	'type' => 'button',
	'input_attrs'  => array(
		'value' => __( 'Add Post' ),
	),
	'capability' => 'edit_posts',
) );

Because controls no longer require settings, controls now accept a capability argument (as seen above) whereas previously a control’s capability would depend on the capabilities of its associated settings. A control will not be displayed if it has a defined capability which the user doesn’t have, or if the user doesn’t have the capability required for any of the associated settings. If you omit the capability for a setting-less control, it will be displayed to all users (who can customize).

Other Improvements

  • Shift-click on nav menu items in preview to open corresponding control in Customizer pane (#26005).
  • Shift-click on site title and tagline for Core themes and any that implement selective refresh partials for these settings. Focus on the control for any setting in the preview by sending a focus-control-for-setting message to the pane, passing the setting ID. This is used to focus on controls when a shift-click is done on a selective refresh partial.
  • Site title and tagline will be updated via selective refresh in core themes. (#33738)
  • WP_Customize_Manager::add_*() methods now return the added instance. (#34596)
  • WP_Customize_Manager::add_setting() now applies the relevant dynamic setting filters. (#34597)
  • There is a new customize_nav_menu_searched_items filter for nav menu item searches. (#34947)
  • The WP_Customize_Media_Control now allows its button_labels to be overridden. (#35542)
  • The setting models in the preview now have a id property and _dirty flag to correspond to the settings in the pane; dynamically created settings in the pane will be created in the preview. (#35616)
  • More config settings are exported to the preview to allow the preview to do more operations inline, including more nonces, the current theme, and the previewed URL. (#35617)

Dedicated Feature Posts

Device Preview (#31195)

https://make.wordpress.org/core/2016/01/28/previewing-site-responsiveness-in-the-customizer/

Selective Refresh (#27355)

https://make.wordpress.org/core/2016/02/16/selective-refresh-in-the-customizer/

Custom Logo (#33755)

https://make.wordpress.org/core/2016/03/10/custom-logo/

#4-5, #customize, #dev-notes

Comment Changes in WordPress 4.5

WordPress 4.5 includes several ancient bug fixes and a few enhancements in the Comments component. We have closed 25 tickets. Check out the full list of changes.

Moderate Comment Screen Refresh

This often neglected screen has received a UX update. Don’t know what the “Moderate Comment” screen is? This is where you land when clicking one of the moderation actions from a comment notification email message.

Changes of note:

  • Comment content is formatted for display, instead of one massive block of escaped text
  • Include navigation via a text link to the Edit Comment screen at the bottom of the comment
  • Updated message styles that match other screens
  • Only wrap the comment date in a link if the comment permalink exists to avoid confusion
  • Appended #wpbody-content to the comment email message links for accessibility

Before:
34133-before
After:
34133-after

See #34133

Max Lengths for Comment Form Fields

Be verbose without having to worry that your insightful words will be lost.

The comment form will now enforce the maximum length of each field’s respective database column with hardcoded maxlength attributes. The hardcoded maxlength attributes can be adjusted for custom database schemas by using the comment_form_default_fields filter.

The default length settings are as follows:

  • Comment: 65525 characters
  • Name : 245 characters
  • Email: 100 characters
  • Url: 200 characters

Comments will also have the input lengths checked by the new function wp_get_comment_fields_max_lengths(), and accompanying filter wp_get_comment_fields_max_lengths, upon submission returning a WP_Error object if any value is longer than its database column.

See #10377.

Comment Error Page Navigation

Previously, visitors who submitted a comment that was unable to be processed were shown an error message without a method to navigate back to their comment. Your potential commenter would have to use their browser’s back button to get back to their comment to resolve the error.

A simple back link has been added to the bottom of the error message page. See the screenshots below.

Before:
4332-before

After:
4332-after

See #4332.

Other Changes of Note

  • The rel=nofollow attribute and value pair will no longer be added to relative or same domain links within comment_content. See #11360.
  • WP_Comment_Query now supports the author_url parameter. See #36224.
  • The new pre_wp_update_comment_count_now filter allows you to bail out of updating the comment count for a given Post. See #35060

#4-5, #comments, #dev-notes

Multisite Focused Changes in 4.5

Howdy! The 4.5 release cycle was relatively quiet for multisite, though we still managed to knock out a few good things. The following is a brief rundown of each, full details can be found in the full list of multisite focused changes for 4.5. 💫

Introduce WP_Site

The global $current_blog has always been used as a way to store the properties in a stdClass object of the current site during bootstrap. With the introduction of WP_Site, we add some definition and have a more proper object to pass around. Sweet.

Take a look at ms-settings.php if you are using a custom sunrise.php to populate the $current_blog global. We now create a WP_Site object from the existing $current_blog if it has been populated elsewhere. This is a backward compatible change, though should be tested wherever your code interacts with $current_blog, especially if anything has been done to extend its structure.

This last paragraph may sound familiar to you because I copied it from the notes on the work we did in the 4.4 release to add WP_Network as an object. In future releases, we’ll continue to build these out with query classes as well.

See #32450 for all the details.

New Actions and Filters

  • network_user_new_form fires at the end of the network’s Add New User form. #15389
  • network_site_new_form fires at the end of the network’s Add New Site form. #34739
  • network_allowed_themes and site_allowed_themes allow for more granular filtering of the themes allowed for a site. The legacy allowed_themes will continue to do its job. #28436
  • pre_network_site_pre_created_user fires right before a new user is created during the Add New Site process if one does not already exist. #33631

Other interesting things

  • Use a usermeta key rather than a site option keyed to the user ID when a user changes their email address and confirmation is needed. #23358
  • In subdomain installations, if a user attempted to login to a site they did not have access to on the network, they would be shown an access denied message with a list of authorized sites. This differed from the behavior in subdirectory installs, where the user would be redirected to either their profile page or the dashboard of their primary site. In 4.5, the subdomain behavior now matches the subdirectory behavior. #30598
  • The performance of wp_upload_dir() has been improved, specifically via persistent cache. This isn’t necessarily multisite related, though you should probably be familiar with the change. #34359
  • Show the home URL rather than siteurl in site-info.php and use the text “Site Address (URL)” for consistency with the similar site in single site. #35632
  • Provide an “Edit user” link after adding a new user to a site or network. #35705 😻

And that’s about it. There may still be some bug fixing in the next week or so, but only if you get out there and test trunk against your plugins, themes, and crazy configurations. Have at it!

#4-5, #dev-notes, #multisite