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

Kicking off the oEmbed Feature Plugin

On Monday during the feature plugin chat we proposed a new plugin to explore making WordPress itself an oEmbed provider.

That means that instead of just embedding YouTube videos or tweets you would be able to paste the URL of a blog post and a short preview gets embedded right away.

There’s already a proof-of-concept plugin on GitHub, where development will happen. Luckily, @melchoyce made some mockups for embedded WordPress posts. Here’s an example with the Twenty Fifteen theme:

embed-test-1-noquote

 

We will be holding weekly chats in the #feature-oembed Slack channel on Mondays, 21:00 UTC. If you want to get involved with this feature plugin, you should definitely join us.

Time/Date: July 20 2015 9pm UTC

Agenda:

  1. Why we’re doing this — @swissspidy
  2. Exploring the mockups — @melchoyce
  3. The current state of the plugin — @swissspidy
  4. Open Floor – If you have something you’d like to discuss, leave a note in the comments

Regarding point no. 4, there are many things that we need to keep in mind, for example:

  • Embedded content should be easily customisable
  • oEmbed requires lots of trust. Security is very important, while still maintaining ease of use.
  • There are also alternatives to oEmbed, see #32955

I suggest you to read the initial discussion on #32522 to see where we’re at.

#embeds, #feature-plugins, #feature-oembed, #kickoff, #updates

Emoji Feature Plugin for 4.2

It’s time for a weekend fun feature! Now that #21212 is complete, WordPress kind of supports Emoji (for the 60% of WordPress sites using MySQL 5.5+, and the 30-40% (by usage) of browsers that natively display Emoji – including when Chrome for OS X adds support in the next month or so).

In order to complete this support, I’ve created a feature plugin called x1f4a9, which makes use of Twitter’s Open Source twemoji icon set, the same as WordPress.com recently added.

I’ve added a few tickets to the Github project, feel free to add any others you think of, and pull requests are always welcome! If you’d like to test the plugin, daily builds are available from the plugin repo.

(And if you’re using MySQL older than 5.5, please pay special attention to this ticket.)

#emoji, #feature-plugins, #kickoff, #updates, #x1f4a9

4.1 Kick-off Meeting, 2014/09/29

These are my rough highlights from yesterday’s kick-off meeting. They emphasize who is working on what.

https://irclogs.wordpress.org/chanlog.php?channel=wordpress-dev&day=2014-09-29&sort=asc#m929822

johnbillion:

Preliminary session management interface: https://i.imgur.com/sHz2oeV.png
There’s a repo: https://github.com/johnbillion/wp-session-manager/

Various tasteful and sensible people:
“We might end up calling this the Keep Ryan Happy release”
“the rboren happy release, for those who don’t know, is fixing and improving mobile stuff”
“ryan deserves happiness. Not just because I want mobile and media too :)”

johnbillion:
Also on the list is improvements to the UI when installing and updating plugins, themes, and core. I want to get rid of the ancient UI which has been in core since we first started doing updates inside core

markjaquith:
So, one of the things I originally wanted to do (and avryl had in early versions of the Focus plugin) was to do some fading of the rest of the UI when you are actively typing into a post. I think this would get us the rest of the way to DFW’s feature set.
So my goal for 4.1 would be to remove DFW completely.
We also could/should do the fancy scroll behavior for the menu like we do for post side metaboxes.

nacin:
1) the theme will be ready by October 25
2) if the theme is not on track for that, the default themes are matt’s pet project, and he will allocate appropriate design and development resources to make sure it will be ready by October 25

johnbillion:
One last feature that I forgot, I’d love to get the language chooser on the General Settings screen to be able to download and install new languages like we planned for 4.0 but had to get punted

helen:
mentioned this a couple weeks ago i believe, ericandrewlewis and i are experimenting with tackling some tickets as a plugin to start so we can move faster: https://github.com/helenhousandi/wp-19867-9864
currently working on a branch that uses select2 to help with scaling issues with the users dropdown – would look to bring this to pages, tags/nonhierachical taxonomies, and the multisite add user and add site forms.

DH-Shredder:
I’d like to do some work with markoheijnen on getting a few of the image manip API improvements in before image-flow

netweb and helen:
#22435 Export API <- Would be great to get this in, has-patch, needs-testing, adds export unit tests to core and that will help other export related tickets.
https://github.com/hlashbrooke/Export-Plus

boonebgorges:
I’ll be working on syntax and internal improvements for WP_Tax_Query, WP_Date_Query, WP_Meta_Query. Berzerk test coverage, support for multi-relational/nested queries, some other goodies. See eg #29738

jeremyfelt:
I want to get a bunch done around multisite unit testing and rewriting some old junk to clean things up a bit. This should help us start moving steadier with other improvements.

boonebgorges:
Also want to investigate moving WP_Meta_Query to subqueries rather than JOINs because of the massive crappiness of JOINing the meta tables. May not have time for 4.1, but will start doing some benchmarks. #24093
https://core.trac.wordpress.org/ticket/24093 Future Release, sc0ttkclark->(no owner), new, WP_Meta_Query is inefficient when referencing the same keys in “OR” query

boren:
I’ll be evangelizing flow and visual records. http://simp.ly/publish/rBkqyq

#4-1, #kickoff, #meeting