From 5a03cb2426ea63149d2727da16d53f275578d60b Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 3 Nov 2016 05:06:17 +0000 Subject: [PATCH] Customize: Prevent syncing unmodified settings from controls into preview to guard against triggering an infinite reload due to selective refresh fallback behavior. If a value is sanitized in PHP and differs from the JS value in the pane, a `change` event for the setting is triggered upon refresh. This should be avoided since the value just came from the server as being sanitized. This also fixes periodic issue where selective refresh happens immediately after a full refresh. Fixes #37032. git-svn-id: https://develop.svn.wordpress.org/trunk@39112 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/js/customize-controls.js | 12 +++++++++++- src/wp-includes/js/customize-preview.js | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js index 56c061f04a..b43c1df109 100644 --- a/src/wp-admin/js/customize-controls.js +++ b/src/wp-admin/js/customize-controls.js @@ -4299,6 +4299,7 @@ var previewer = this, synced = {}, constructs; synced.settings = api.get(); + synced['settings-modified-while-loading'] = previewer.settingsModifiedWhileLoading; if ( 'resolved' !== previewer.deferred.active.state() || previewer.loading ) { synced.scroll = previewer.scroll; } @@ -4421,7 +4422,7 @@ * Refresh the preview seamlessly. */ refresh: function() { - var previewer = this; + var previewer = this, onSettingChange; // Display loading indicator previewer.send( 'loading-initiated' ); @@ -4435,6 +4436,15 @@ container: previewer.container }); + previewer.settingsModifiedWhileLoading = {}; + onSettingChange = function( setting ) { + previewer.settingsModifiedWhileLoading[ setting.id ] = true; + }; + api.bind( 'change', onSettingChange ); + previewer.loading.always( function() { + api.unbind( 'change', onSettingChange ); + } ); + previewer.loading.done( function( readyData ) { var loadingFrame = this, previousPreview, onceSynced; diff --git a/src/wp-includes/js/customize-preview.js b/src/wp-includes/js/customize-preview.js index 484ccf4acc..be24e414bf 100644 --- a/src/wp-includes/js/customize-preview.js +++ b/src/wp-includes/js/customize-preview.js @@ -654,6 +654,25 @@ }); api.preview.bind( 'sync', function( events ) { + + /* + * Delete any settings that already exist locally which haven't been + * modified in the controls while the preview was loading. This prevents + * situations where the JS value being synced from the pane may differ + * from the PHP-sanitized JS value in the preview which causes the + * non-sanitized JS value to clobber the PHP-sanitized value. This + * is particularly important for selective refresh partials that + * have a fallback refresh behavior since infinite refreshing would + * result. + */ + if ( events.settings && events['settings-modified-while-loading'] ) { + _.each( _.keys( events.settings ), function( syncedSettingId ) { + if ( api.has( syncedSettingId ) && ! events['settings-modified-while-loading'][ syncedSettingId ] ) { + delete events.settings[ syncedSettingId ]; + } + } ); + } + $.each( events, function( event, args ) { api.preview.trigger( event, args ); });