Legacy Theme Preview Removed in 4.3

This release we removed the old code for the Legacy Theme Preview, which hasn’t been maintained since the introduction of the customizer in WordPress 3.5. Recently, we noticed that the theme preview no longer works when using a static front page. We kept the old theme preview for no-JS and some browsers that were less capable. But since browsers are doing a better job today we don’t need to continue fixing/shipping this legacy code. It’s removed in [33492].

#4-3, #dev-notes, #themes

Fast previewing changes to Menus in the Customizer

The foundation of the Customizer is built on the concept of the “setting”, an abstract representation of anything in WordPress: options, theme mods, posts, terms, and so on. Settings are linked to controls which are responsible for manipulating them. When a setting is changed it gets pushed into the preview window so that the modification can be reviewed before being published live.

There are two ways (transports) for how a setting can be pushed into the preview: refresh and postMessage. The refresh transport does a full page refresh with the modified settings applied, and so it relies on PHP to apply the setting changes. The refresh transport is designed to be compatible with all themes, but for heavy sites refresh can be excruciating slow and taxing on the server. For this reason, the postMessage transport was introduced for previewing changes. This transport uses JavaScript to apply the changes instantly in the preview without any Ajax requests or PHP calls. This is great, but themes have to opt-in to postMessage transport for settings because they must also include JavaScript code which duplicates the logic which is already being executed on the server by PHP. The postMessage transport violates the DRY principle.

With that background out of the way…

Partial Refresh of Menus

In WordPress 4.3 menu management is being added to the Customizer, extending the types of objects that the Customizer can manipulate to include nav_menu taxonomy terms and nav_menu_item posts. We wanted this menu management experience to be fast so it had to avoid the slow full-page refresh transport. Nevertheless, the postMessage transport wasn’t possible to use either since we wouldn’t be able to duplicate all of the PHP menu walker logic and theme/plugin extensions for rendering menus purely in JavaScript. We also wanted to enable fast previewing of menu changes by default. So we implemented a postMessage/refresh hybrid approach which uses postMessage to sync the menus settings to the preview, and then the preview does an Ajax request to render just the contents of the menu container, and this Ajax response is then inserted into the DOM to replace the previous menu container. The technical name for this approach we have been calling “partial refresh”, but you can call it “fast preview”.

When the Customizer determines it can’t do a partial refresh, it falls back to performing a full page refresh. Conditions for why a menu change will get a full page refresh include:

  • if the menu was just assigned to a location for the first time or removed from being assigned to a location, since the theme may have some changes to the layout that it may need to perform;
  • or if wp_nav_menu() is called with with echo being false, since the theme may be doing some string replacement in this case which we can’t replicate in the partial-refresh Ajax request;
  • or if wp_nav_menu() is called with with a non-JSON serializable fallback_cb, such as a closure or a object method—this arg has to be empty or a string;
  • or if wp_nav_menu() is called with with a walker object instance, as opposed to a class name string;
  • or if wp_nav_menu() is called without a theme_location arg and the menu arg is not an term ID or a menu object;
  • or if the menu selected in a Custom Menu widget is changed, since partial refresh for widgets is not yet supported (however, see feature plugin)—subsequent changes to the menu will result in fast partial refreshes if the above conditions

When a menu is being updated via partial refresh, the menu container will receive a classname customize-partial-refreshing, which by default changes the opacity to 25%.

Theme Support

The fast preview for menu changes is being enabled by default so that theme authors don’t have to opt-in to the functionality like they do for instant preview (postMessage transport). In general this should be fine. However, if the theme includes some JavaScript which dynamically manipulates the rendered menu container, such as adding event handlers for expanding/collapsing submenus, then the theme would need to include some JS to re-apply the modifications once the menu is partial-refreshed, as the old DOM for the menu container gets replaced.

The Twenty Fifteen theme actually uses JS to expand/collapse submenu items, so it needed a patch in 4.3 to re-setup a partial-refreshed main nav menu. In addition to firing the menu container DOM setup logic once at jQuery.ready(), it now invokes the functionality whenever the menu is partial-refreshed. See the initMainNavigation() JS function.

So in general, if your theme needs to dynamically initialize menus with JavaScript, the pattern for the initialization code should be:

jQuery(function($) {
	function initMainNavigation( container ) {
		/* set up container... */
	}
	initMainNavigation( $( '.main-navigation' ) );

	$( document ).on( 'customize-preview-menu-refreshed', function( e, params ) {
		if ( 'primary' === params.wpNavMenuArgs.theme_location ) {
			initMainNavigation( params.newContainer );
			/* optionally sync a previous menu state from params.oldContainer... */
		}
	});
});

The params being passed to the event handler consists of the following properties:

  • newContainer: jQuery object containing the new menu container element retrieved from Ajax; this is what you would manipulate to initialize.
  • oldContainer: the previous jQuery object holding the element for the replaced menu container; this is useful if there is any state in the old menu that should persist in the new menu, such as which submenus are expanded (as in Twenty Fifteen).
  • wpNavMenuArgs: The array of arguments passed to wp_nav_menu() in the template, such as template_location.
  • instanceNumber: The index for which wp_nav_menu() call being updated.

The Future

Partial refresh is an “experimental transport” introduced here specifically for menus. In 4.4 we hope to generalize the framework so that any setting can be setup for fast preview, starting with widgets (see #27355). There is a Customize Partial Refresh feature plugin that implements widget partial refresh in a beta state. This partial refresh functionality I’ve also identified as being critical for Customizer Transactions.

#4-3, #customize, #dev-notes, #feature-plugins, #feature-selective-refresh, #kickoff, #menu-customizer, #menus, #partial-refresh, #proposal

Old Distraction Free Writing Code Removed in 4.3

This release we removed all old DFW code, which hasn’t been used in core since 4.1. We left it in core for two releases so plugin authors had the time to update. If it is essential to your plugin, the files in 4.2 can still be reused and improved. See [32677].

#4-3, #dev-notes, #editor

Dev Chat Agenda for July 29

Here’s the agenda for today’s Dev Chat in the #core channel on Slack.

We’re getting ready for RC1 so lets discuss blocker, RC guidelines, and everything else related to RC.

Time/Date: July 29 2015 20:00 UTC:

  1. RC Notes
  2. Feature Updates
  3. Component Updates
  4. Open Floor

#4-3, #agenda

Passwords in 4.3: Strong by Default

One of the development efforts in the WordPress 4.3 cycle was improving the way that passwords are chosen and changed. Before, people had to start from scratch when choosing a password. They were presented with an empty box, and had to use a really terrible tool for generating secure passwords: the human brain.

Here’s how things look now, as we approach 4.3’s release candidate…

Screen Shot

And when you click that button…

Screen Shot

You start out with a strong password. And if you like, you can just accept that. Most modern browsers will offer to remember it for you (as well as password managers like 1Password and LastPass). Or, you could go old school and write it on a sticky note. Hey: anything is better than choosing “letmein”!

You can, of course, click into the field and edit it. But now the password strength meter is better integrated with the field. Things start to look dire as you go your own way.

Screen Shot

That red seems to signal danger. And hey, look, below. This password is SO BAD that WordPress wants to make extra sure you know you’re doing something monstrously foolhardy.

If you’re in a public location, you can hide your password, to prevent people from peeking over your shoulder.

Screen Shot

This new interface is also integrated into the Add New User screen. By default, we won’t even reveal the password. We’ll just send the user a reset link.

Screen Shot

But if you’re in a non-email environment or would like to pass this password to the user in a secure method such as iMessage, Signal, or TextSecure, you can reveal it…

Screen Shot

The new interface can also be found on the password reset screen and the WordPress install screen. They all start you out with a long, random, unguessable password. Although WordPress isn’t stopping you from choosing terrible passwords, the default in 4.3 is that you get secure passwords, and making them less secure takes a bit of work.

In addition to this new UI, we have also stopped e-mailing passwords, so valid passwords aren’t going to sit in your e-mail inbox, waiting for some future e-mail hacker to gain access. Password reset links now expire in 24 hours by default. And when your password or e-mail changes, we send you an e-mail (in the case of e-mail, to your old address), so if someone hijacks your browser session and changes those critical items, at least you’ll be aware that it happened, and you can take action. You can disable these e-mails via the send_password_change_email and send_email_change_email filters (just have them return false).

Huge thanks to everyone who contributed code, testing, UI, and thoughtful feedback on this feature!

#4-3, #dev-notes, #passwords

Site Icon

WordPress 4.3 adds the ability for site owners to manage their site’s favicon on desktop and mobile. Site Icons work out of the box, are theme independent, and don’t require theme support. There are four sizes that WordPress supports by default:

  • 32x32px favicon.
  • 180x180px app icon for iOS up to the iPhone 6+.
  • 192x192px Android/Chrome app icon.
  • 270x270px medium-sized tile for Windows.

The public API is very simple:

  • wp_site_icon() displays all available favicons and app icons.
  • get_site_icon_url() returns the url to the current site’s icon, or the default passed to it.
  • site_icon_url() displays an escaped version of the url to the current site’s icon.
  • has_site_icon() returns whether the current site has an icon set up or not.

At this point we discourage theme authors from using site icons as logos in the front-end. It’s unexpected behavior for users since it doesn’t fit the API’s purpose.

Custom Site Icons

Plugin authors can add custom sizes to the site icon feature. To do this, filter the array of available sizes on the admin side and the array of meta tags on the front-end, like so:

<?php

function prefix_custom_site_icon_size( $sizes ) {
   $sizes[] = 64;

   return $sizes;
}
add_filter( 'site_icon_image_sizes', 'prefix_custom_site_icon_size' );

function prefix_custom_site_icon_tag( $meta_tags ) {
   $meta_tags[] = sprintf( '<link rel="icon" href="%s" sizes="64x64" />', esc_url( get_site_icon_url( null, 64 ) ) );

   return $meta_tags;
}
add_filter( 'site_icon_meta_tags', 'prefix_custom_site_icon_tag' );

Customizer Controls

Nick Halsey published an article about the new Customizer controls that were introduced for Site Icon. The new controls make it trivial for any theme or plugin author to add custom features that require cropped images. For example, a logo manager. 😉

#4-3, #customize, #dev-notes, #site-icons

Changes to Customizer Panels and Sections in 4.3

WordPress 4.3 contains some important changes to the Panels and Sections APIs. These won’t impact basic usage – add_section() and add_panel(), for example – but could potentially have compatibility issues for any custom panels or sections that override default methods. If you have themes or plugins that create custom sections or panels, please be sure to test with the latest 4.3 beta. Additionally, we’ve built out the API to support dynamically-added and more JS-driven panels and sections in 4.3. Details below.

Changes to the Default Panel & Section UI

Ticket #31336 introduced a new user experience for core Customizer sections, and made some adjustments to panels in the process. Sections in general now slide in sideways (like panels) rather than expanding open vertically in the “accordion” style. This change adds a heading within section containers that contains context for the user’s location within the Customizer hierarchy of sections/panels as well as the navigation back out of the panel.

If you have a custom section that overrides WP_Customize_Section::render(), you will probably need to add the new section header markup that has been added to the base section. Without at least the back button, users could potentially become stuck within an open section because of this core change. Additionally, the panel-back button has moved from a single button in the header (over the Customizer close button) to being contained within the panel header, similarly to the section header. If you’re overriding WP_Customize_Panel::render_content() in a custom panel, you’ll probably need to add the panel back button there. For panels and sections, if you’re overriding the onChangeExpanded method in JavaScript, you would need to implement the core changes there as well, although odds are your implementation is custom enough that the changes to the default objects won’t affect you. Because custom section and panel implementations will vary widely, your best bet is to look at the revised code in trunk and adjust your code accordingly (see wp-includes/class-wp-customize-section.php). However, for basic sections using a UI close to the default one, adding the following to your render_template() method within ul.accordion-section-content is likely to work (note this is a JS template; can be converted to a PHP template fairly easily):



<li class="customize-section-description-container">


	<div class="customize-section-title">
		<button class="customize-section-back" tabindex="-1">
			<span class="screen-reader-text"><?php _e( 'Back' ); ?></span>
		</button>


		<h3>
			<span class="customize-action">
				{{{ data.customizeAction }}}
			</span>
			{{ data.title }}
		</h3>


	</div>


	<# if ( data.description ) { #>


		<div class="description customize-section-description">
			{{{ data.description }}}
		</div>


	<# } #>
</li>


Note that custom sections and panels are generally designed to allow different UI implementations than the default behavior, so in many cases the changes to the default objects shouldn’t break your custom versions.

JavaScript-templated Panels and Sections

Building on the work done in 4.1 for controls, #30737 introduces JavaScript templates for panels and sections. The built-in core panel and section objects now use JS templates to render all instances by default. The PHP-rendered object API is still present and fully supported, but developers are recommended to strongly consider using JavaScript templates for control, section, and panel UI instead. These templates allow objects to be more easily created dynamically and improve performance by loading an object’s data (in JSON format) and a single template for the HTML structure rather than the complete fully-rendered HTML structure for repetitive (PHP-generated) UI.

Menus in the Customizer drove the completion of this API addition, and it facilitates the dynamic creation of Customizer sections and controls when creating new menus. Further plans in this area include using JS templates for the base WP_Customize_Control object by default ( #30738) and building out the API for dynamically-created controls by implementing container templates similar to what panels have ( #30741).

The remainder of this post will outline the various API additions that facilitate this, with code examples. Please review the initial post about JS templates and sections, as the new API for sections and panels is conceptually identical to what was introduced for controls in 4.1, taking a few more steps beyond it.

Registered Panel and Section Types

Similarly to the concept of registered control types introduced in 4.1, WP_Customize_Manager now supports registered section and panel types. For those that haven’t previously worked with custom sections or panels, they’re just like custom controls. You can override different pieces of the base object as needed to create custom UI. A great example in core is WP_Customize_New_Menu_Section, which is displayed as a button that toggles display of its controls inline, rather than a sliding panel.

Registering a section or panel type tells the Customizer to print one copy of the object’s JS template to the page, so that any object with this type can be rendered dynamically. Instances added in PHP will be automatically inserted into the DOM after being rendered from the JS template when ready, and the template can also be used when adding an instance dynamically in JS (for example, when adding a new section when a new menu is created).

Registering panel and section types works just like it does for controls:

add_action( 'customize_register', 'prefix_customize_register' );
function prefix_customize_register( $wp_customize ) {
  // Define a custom section class, WP_Customize_Custom_Section.
  // Register the class so that its JS template is available in the Customizer.
  $wp_customize->register_section_type( 'WP_Customize_Custom_Section' );
}

 

Sending PHP Data to JavaScript

Customizer panel and section data has been passed to the relevant JS models since 4.1, but you’re much more likely to need to send data down when working with JS templates. Anything that you would want access to in render_content() in PHP will need to be exported to JavaScript to be accessible in your section or panel template. Since JS templates are now used by default for sections and panels, most of the core class variables for these objects are passed already. To add custom ones, override WP_Customize_Panel::json()/WP_Customize_Section::json() in your custom subclass. In most cases, you’ll want to merge with the return value of the parent class’s json() method also, to ensure that all core variables are exported as well. Here’s an example from the core nav menu section class:

/**
 * Get section parameters for JS.
 *
 * @since 4.3.0
 * @access public
 * @return array Exported parameters.
 */
public function json() {
	$exported = parent::json();
	$exported['menu_id'] = intval( preg_replace( '/^nav_menu\[(\d+)\]/', '$1', $this->id ) );
	return $exported;
}

Using JS/Underscore Templates

Once you’ve registered your custom section or panel class as a section or panel type and exported any custom class variables, you can create the template that will render the section or panel UI. This works slightly differently for sections and panels, because panels have a distinct container and content that can be overridden separately as needed.

Sections

For sections, you’ll override WP_Customize_Section::render_template() instead of WP_Customize_Section::render(). The render function is now empty in the base core control, so there’s no need to override it if you’re using a custom template. If you are using the existing PHP API, the JS template will not be used if content exists after running the render() function. The default section’s template looks like this in 4.3:

/**
 * An Underscore (JS) template for rendering this section.
 *
 * Class variables for this section class are available in the `data` JS object;
 * export custom variables by overriding WP_Customize_Section::json().
 *
 * @since 4.3.0
 * @access protected
 *
 * @see WP_Customize_Section::print_template()
 */
protected function render_template() {


<li id="accordion-section-{{ data.id }}" class="accordion-section control-section control-section-{{ data.type }}">


	<h3 class="accordion-section-title" tabindex="0">
		{{ data.title }}
		<span class="screen-reader-text"><?php _e( 'Press return or enter to open' ); ?></span>
	</h3>




	<ul class="accordion-section-content">


		<li class="customize-section-description-container">


			<div class="customize-section-title">
				<button class="customize-section-back" tabindex="-1">
					<span class="screen-reader-text"><?php _e( 'Back' ); ?></span>
				</button>


				<h3>
					<span class="customize-action">
						{{{ data.customizeAction }}}
					</span>
					{{ data.title }}
				</h3>


			</div>


			<# if ( data.description ) { #>


				<div class="description customize-section-description">
					{{{ data.description }}}
				</div>


			<# } #>
		</li>


	</ul>


</li>


}

As you can see, Underscore-style templates are very similar to PHP. As more and more of WordPress core becomes JavaScript-driven, these templates are becoming increasingly more common. Besides the Customizer, sample template code in core can be found in media, revisions, the theme browser, and even in the Twenty Fifteen theme, where a JS template is used to both save the color scheme data and instantly preview color scheme changes in the Customizer. The best way to learn how these templates work is to study similar code in core.

Panels

Panels have two distinct pieces to their UI: the container, which is displayed in a list with other panels and sections at the top level of the Customizer UI, and the content, which is the context that the Customizer enters when the panel is opened. Note that this distinction is due to the philosophical design of Panels to be distinct contexts, rather than simply being a way to group related sections together. This is also based on the distinction between the container and the content in control objects. However, the distinction between panels and sections in terms of UI is less visually clear in WordPress 4.3.

Panel containers are rendered with the render_template() function, and the content template is inserted into the container in JS by looking for .accordion-sub-container. It will rarely be necessary to override the container template in a custom panel, as the custom UI will typically go in the content of the panel. The default panel template looks like this:

/**
 * An Underscore (JS) template for rendering this panel's container.
 *
 * Class variables for this panel class are available in the `data` JS object;
 * export custom variables by overriding WP_Customize_Panel::json().
 *
 * @see WP_Customize_Panel::print_template()
 *
 * @since 4.3.0
 * @access protected
 */
protected function render_template() {
	?>


	<li id="accordion-panel-{{ data.id }}" class="accordion-section control-section control-panel control-panel-{{ data.type }}">


		<h3 class="accordion-section-title" tabindex="0">
			{{ data.title }}
			<span class="screen-reader-text"><?php _e( 'Press return or enter to open this panel' ); ?></span>
		</h3>




		<ul class="accordion-sub-container control-panel-content"></ul>


	</li>


	<?php
}

Panel contents are rendered with the content_template() function, similarly to the way control templates work. In the future, this part of the API will be completed with the addition of container templates for controls, see #30741. The default panel content template in 4.3 looks like this:

/**
 * An Underscore (JS) template for this panel's content (but not its container).
 *
 * Class variables for this panel class are available in the `data` JS object;
 * export custom variables by overriding WP_Customize_Panel::json().
 *
 * @see WP_Customize_Panel::print_template()
 *
 * @since 4.3.0
 * @access protected
 */
protected function content_template() {
	?>


	<li class="panel-meta customize-info accordion-section <# if ( ! data.description ) { #> cannot-expand<# } #>">
		<button class="customize-panel-back" tabindex="-1"><span class="screen-reader-text"><?php _e( 'Back' ); ?></span></button>


		<div class="accordion-section-title">
			<span class="preview-notice"><?php
				/* translators: %s is the site/panel title in the Customizer */
				echo sprintf( __( 'You are customizing %s' ), '<strong class="panel-title">{{ data.title }}</strong>' );
			?></span>
			<button class="customize-help-toggle dashicons dashicons-editor-help" tabindex="0" aria-expanded="false"><span class="screen-reader-text"><?php _e( 'Help' ); ?></span></button>
		</div>


		<# if ( data.description ) { #>


			<div class="description customize-panel-description">
				{{{ data.description }}}
			</div>


		<# } #>
	</li>


	<?php
}

In core, the nav menus panel, which adds screen options for the panel, is a good example of a panel with a custom content template.

#4-3, #customize, #dev-notes

This week in 4.3: Jul 27 – Aug 2

This is the jump-start post for the twelfth week of the WordPress 4.3 release cycle.

We’re in the final stages of the release, by Wednesday we want to be able to present our Release Candidate to the community. A release candidate (RC) is a beta version with potential to be a final product, which is ready to release unless significant bugs emerge. In this stage all product features have been designed, coded, and tested through a few beta cycles with no known showstopper-class bug.

Priority Tickets this week:

Core Meetings this week:

#4-3, #jump-starts

Multisite Focused Changes in 4.3

Howdy! We’ve made quite a bit of progress in multisite as part of the 4.3 cycle and have a bunch slated to continue working on throughout the year. If you’d like to follow along, stop by our weekly office hours on Tuesdays at 20:00 UTC in #core-multisite.

Here’s what we have coming in 4.3…

Begin streamlining the interface for setting a site’s URL.

Editing a site’s address for what it is—a combination of domain and path—becomes more straightforward in 4.3. A full address with or without scheme can now be entered if multisite is configured as subdomain. Network administrators have been hacking at this anyway for years when the two fields were separate to provide arbitrary domain support. See #22383 for all the details.

In combination with this, the checkbox for “Update siteurl and home as well” has been removed when editing a site. Instead we can make an educated decision based on the current state. If the home and/or siteurl domain and path match the existing domain and path of the site, we assume that we can update all values with the new information. See #32503 for details.

And to better enforce URLs vs domain and path, we’ve improved the default columns displayed in MS Sites List Table. The full URL is now show instead of the domain or the path. We also now show a total user count for each site rather than the first 5 users. See #32434 for details.

Introduce get_main_network_id()

This likely isn’t too useful to many, though will come in handy for those working with custom multi-network configurations. It will always return 1 on single site or if the current network has an ID of 1. It will return PRIMARY_NETWORK_ID if defined. And if those conditions aren’t met, it will go to the database to determine which ID is the first in line.

It is possible to filter this value with the new get_main_network_id filter for those who have multiple networks and would like to avoid the incremental assumptions. See #30294 for the details.

Visual and interface enhancements:

  • Better responsive styling for my-sites.php, a screen that would love to have a complete overhaul one day but now looks much better on smaller devices. #31685
  • Also in my-sites.php, the Save Changes button is conditionally displayed only if the user is a member of more than one site OR if a plugin or theme has filtered the HTML on this screen and may be expecting a Save Changes button to exist. #32645
  • Achieve parity between single and multisite by removing the Upgrades subsection in the menu and moving Updates to Dashboard. #32431
  • Provide a link to the dashboard when editing a site in the network admin. Previously, only the URL would show in the title area of the site screens with no great way to access the dashboard. Now, the full site name is shown as the title and smaller text URLs are displayed underneath for Visit and Dashboard. #32525
  • Mobile display of the network admin has been improved in general. A few inputs have been adjusted on mobile to make them act as expected. #32643, #32644, #32646. A full sweep of “content overruns” was done to ensure admin screens don’t overflow the screen on small mobile devices. #32846, #32962.

Bugs of note fixed:

  • Don’t allow usernames over 60 characters long, a limit that was already in place via the database schema but was not enforced explicitly in code. #26784
  • Calculate the storage space used correctly for the main site. Previously, it was possible that the main site would reach it’s calculated space limit because the storage of all other sites was included in the total. #30202
  • get_blogs_of_user() now returns proper values for the archived, spam, and deleted properties. These were previously forced to 0 only when using this function. #32281
  • Deleting a super admin user via wpmu_delete_user() is no longer possible. This matches the expectation previously set by the UI. #32935

And because some are smaller and were left out of the above, here’s a full list of multisite focused changes made in 4.3.

#4-3, #dev-notes, #multisite

Word/character count updates in 4.3

Here are several adjustments we did:

  • Instead of updating on enter/return, it will now refresh when you stop typing.
  • For word count, it will exclude a lot more characters that shouldn’t be counted as words.
  • For character count, we no longer exclude any of these characters. This means that numbers and common western punctuation are no longer excluded compared to 4.2. Emoji and other astral characters are now counted as one character instead of two.
  • We added a new type all, in addition to words and characters, that will count characters including spaces. This seemed necessary for Japanese and maybe other languages. Edit: this is now character_including_spaces and character_excluding_spaces.
  • Shortcodes and HTML comments are now excluded.

See ticket #30966 for more information.

Please test the latest beta which includes these changes.

#4-3, #dev-notes, #editor