From 2a8973f117cc575bdb25d5b3cf3816d877c0e0fd Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 8 Jul 2015 21:29:53 +0000 Subject: [PATCH] Customizer: Remove additional wrapper element around `wp_nav_menu()` which broke some theme designs. Also includes these related changes: * Export `oldContainer` and `newContainer` among the `customize-preview-menu-refreshed` event params for themes to be able to more easily re-initialize the DOM elements. * Improve performance for partial refresh by only sending settings related to the menu being previewed. * Fix previewing of menu assigned to Custom Menu by exporting a menu `term_id` as opposed to an object, as the former is more stable for comparing in in args hashes. * Do full refresh of preview when nav menu unassigned so that the layout can be updated. * Harden conditions for when partial refresh is eligible for a `wp_nav_menu()` instance. Fixes #32841. git-svn-id: https://develop.svn.wordpress.org/trunk@33138 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-customize-nav-menus.php | 20 +++++++-- .../js/customize-preview-nav-menus.js | 42 ++++++++++++------- tests/phpunit/tests/customize/nav-menus.php | 9 ++-- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/wp-includes/class-wp-customize-nav-menus.php b/src/wp-includes/class-wp-customize-nav-menus.php index c13ed93ba7..f85ebfc0fb 100644 --- a/src/wp-includes/class-wp-customize-nav-menus.php +++ b/src/wp-includes/class-wp-customize-nav-menus.php @@ -768,6 +768,12 @@ final class WP_Customize_Nav_Menus { ( empty( $args['fallback_cb'] ) || is_string( $args['fallback_cb'] ) ) && ( empty( $args['walker'] ) || is_string( $args['walker'] ) ) + && + ( + ! empty( $args['theme_location'] ) + || + ( ! empty( $args['menu'] ) && ( is_numeric( $args['menu'] ) || is_object( $args['menu'] ) ) ) + ) ); $args['can_partial_refresh'] = $can_partial_refresh; @@ -778,6 +784,11 @@ final class WP_Customize_Nav_Menus { $hashed_args['walker'] = ''; } + // Replace object menu arg with a term_id menu arg, as this exports better to JS and is easier to compare hashes. + if ( ! empty( $hashed_args['menu'] ) && is_object( $hashed_args['menu'] ) ) { + $hashed_args['menu'] = $hashed_args['menu']->term_id; + } + ksort( $hashed_args ); $hashed_args['args_hash'] = $this->hash_nav_menu_args( $hashed_args ); @@ -798,10 +809,11 @@ final class WP_Customize_Nav_Menus { */ public function filter_wp_nav_menu( $nav_menu_content, $args ) { if ( ! empty( $args->can_partial_refresh ) && ! empty( $args->instance_number ) ) { - $nav_menu_content = sprintf( - '
%2$s
', - $args->instance_number, - $nav_menu_content + $nav_menu_content = preg_replace( + '/(?<=class=")/', + sprintf( 'partial-refreshable-nav-menu partial-refreshable-nav-menu-%1$d ', $args->instance_number ), + $nav_menu_content, + 1 // Only update the class on the first element found, the menu container. ); } return $nav_menu_content; diff --git a/src/wp-includes/js/customize-preview-nav-menus.js b/src/wp-includes/js/customize-preview-nav-menus.js index ce962d63f4..d1ce55892b 100644 --- a/src/wp-includes/js/customize-preview-nav-menus.js +++ b/src/wp-includes/js/customize-preview-nav-menus.js @@ -159,19 +159,27 @@ wp.customize.menusPreview = ( function( $, api ) { * @param {int} instanceNumber */ self.refreshMenuInstance = function( instanceNumber ) { - var self = this, data, customized, container, request, wpNavArgs, instance; + var self = this, data, menuId, customized, container, request, wpNavArgs, instance, containerInstanceClassName; if ( ! self.navMenuInstanceArgs[ instanceNumber ] ) { throw new Error( 'unknown_instance_number' ); } instance = self.navMenuInstanceArgs[ instanceNumber ]; - container = $( '#partial-refresh-menu-container-' + String( instanceNumber ) ); + containerInstanceClassName = 'partial-refreshable-nav-menu-' + String( instanceNumber ); + container = $( '.' + containerInstanceClassName ); - if ( ! instance.can_partial_refresh || 0 === container.length ) { + if ( _.isNumber( instance.menu ) ) { + menuId = instance.menu; + } else if ( instance.theme_location && api.has( 'nav_menu_locations[' + instance.theme_location + ']' ) ) { + menuId = api( 'nav_menu_locations[' + instance.theme_location + ']' ).get(); + } + + if ( ! menuId || ! instance.can_partial_refresh || 0 === container.length ) { api.preview.send( 'refresh' ); return; } + menuId = parseInt( menuId, 10 ); data = { nonce: self.previewCustomizeNonce, // for Customize Preview @@ -183,8 +191,8 @@ wp.customize.menusPreview = ( function( $, api ) { data[ self.renderQueryVar ] = '1'; customized = {}; api.each( function( setting, id ) { - // @todo We need to limit this to just the menu items that are associated with this menu/location. - if ( /^(nav_menu|nav_menu_locations)/.test( id ) ) { + // @todo Core should propagate the dirty state into the Preview as well so we can use that here. + if ( id === 'nav_menu[' + String( menuId ) + ']' || ( /^nav_menu_item\[/.test( id ) && setting() && menuId === setting().nav_menu_term_id ) ) { customized[ id ] = setting.get(); } } ); @@ -203,19 +211,25 @@ wp.customize.menusPreview = ( function( $, api ) { url: self.requestUri } ); request.done( function( data ) { - var eventParam; - container.empty().append( $( data ) ); + // If the menu is now not visible, refresh since the page layout may have changed. + if ( false === data ) { + api.preview.send( 'refresh' ); + return; + } + + var eventParam, previousContainer = container; + container = $( data ); + container.addClass( containerInstanceClassName ); + container.addClass( 'partial-refreshable-nav-menu customize-partial-refreshing' ); + previousContainer.replaceWith( container ); eventParam = { instanceNumber: instanceNumber, - wpNavArgs: wpNavArgs + wpNavArgs: wpNavArgs, + oldContainer: previousContainer, + newContainer: container }; - $( document ).trigger( 'customize-preview-menu-refreshed', [ eventParam ] ); - } ); - request.fail( function() { - // @todo provide some indication for why - } ); - request.always( function() { container.removeClass( 'customize-partial-refreshing' ); + $( document ).trigger( 'customize-preview-menu-refreshed', [ eventParam ] ); } ); }; diff --git a/tests/phpunit/tests/customize/nav-menus.php b/tests/phpunit/tests/customize/nav-menus.php index 616bf0b75c..7fa88e7d62 100644 --- a/tests/phpunit/tests/customize/nav-menus.php +++ b/tests/phpunit/tests/customize/nav-menus.php @@ -353,6 +353,7 @@ class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { 'echo' => true, 'fallback_cb' => 'wp_page_menu', 'walker' => '', + 'menu' => wp_create_nav_menu( 'Foo' ), ) ); $this->assertEquals( 1, $results['can_partial_refresh'] ); @@ -390,6 +391,7 @@ class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { $args = $menus->filter_wp_nav_menu_args( array( 'echo' => true, + 'menu' => wp_create_nav_menu( 'Foo' ), 'fallback_cb' => 'wp_page_menu', 'walker' => '', ) ); @@ -401,11 +403,10 @@ class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { $object_args = json_decode( json_encode( $args ), false ); $result = $menus->filter_wp_nav_menu( $nav_menu_content, $object_args ); $expected = sprintf( - '
%2$s
', - $args['instance_number'], - $nav_menu_content + '