Make WordPress Core

Opened 16 months ago

Last modified 14 months ago

#38797 new enhancement

api.previewer.refresh() could return a deferred.promise() with custom server data

Reported by: nikeo Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version:
Component: Customize Keywords: needs-patch
Focuses: javascript Cc:


Following a discussion (https://core.trac.wordpress.org/ticket/38728#comment:8) with @westonruter, I'd like to propose an enhancement for the api.previewer.refresh() method.

There might be cases when a developer needs to fire a previewer refresh after a specific customizer change, and execute other actions when this refresh has been done.

From a general standpoint, I think that the asynchronous nature of the refresh makes it a good candidate for returning a deferred promise.

An example of use case could be that a developer has several predefined settings configuration available for a given theme. Each time a configuration is switched to, the settings have to be changed to a set of predefined values set in the api. Those predefined values are stored server side in say a custom post type ( like the changeset for ex. ).
A way to do that would be to fire an api.previewer.refresh() when switching to a given predefined configuration, that would be followed on api.previewer.refresh().done( ... ) by an update of the api values, if some conditions are met.

With the current api, we can add callbacks to the 'synced' previewer event, but it will be fired on all api.previewer.refresh() calls, with no possibility to target a specific refresh situation that should be followed by a custom action.

This problem could be solved by making the refresh return a deferred promise. This $.Deferred() would be resolve() in the onceSynced() callback function (of the current refreh method), taking a sent_preview_data object as param.

While this deferred would be implemented in the api.previewer.refresh() method of customize-control.js, another minor addition in customize-preview.js could allow developers to easily pass custom server data on refresh to the panel this way, and then use those data once the refresh is done.

This way, it would be possible to use the following kind of syntax to fire an action on demand after a specific refresh().

api.previewer.refresh().done( function( sent_preview_data ) { 
 // fire actions after a specific refresh, when the preview is ready and synced
 // the sent_preview_data, could be an object sent when the api.preview.send( 'synced', preview_data() ),
 // providing customizable server informations that we may need after a refresh.
} );

On the preview side, in order to pass a server data object to the resolve refresh, the idea would be to introduce a new api.Value() that could be populated before the synced event occurence.

The current code in [customize-preview.js]https://core.trac.wordpress.org/browser/trunk/src/wp-includes/js/customize-preview.js#L679 :

api.preview.send( 'synced');

could be replaced by :

api.server_data = api.server_data || new api.Value( {} );
api.trigger('before_synced', api.server_data() );//<= developers can alter the api.server_data() here, before it gets sent
api.preview.send( 'synced', api.server_data() );

This way, a developer could pass custom data to the panel when api.previewer.refresh().done(), using the synced event, with this type of code :

add_action('wp_footer', function() {
  if ( ! is_customize_preview() )
  <script type="text/javascript">
    jQuery( function( $ ) {
        wp.customize.bind( 'before_synced', function( value ) {
            //the developer sets the server_data here, before it is sent to the preview
            wp.customize.server_data( { custom_data : <?php echo get_custom_data(); ?> } );
        } );
    } );

Attachments (3)

38797.patch (3.6 KB) - added by nikeo 14 months ago.
38797.2.patch (3.6 KB) - added by nikeo 14 months ago.
38797.3.patch (4.2 KB) - added by nikeo 14 months ago.

Download all attachments as: .zip

Change History (6)

#1 @celloexpressions
14 months ago

  • Keywords needs-patch added
  • Milestone changed from Awaiting Review to Future Release

This sounds good to me. Can you create a patch with your proposed changes @nikeo?

#2 @nikeo
14 months ago

@celloexpressions sure.
I'll work on it in the coming days

14 months ago

14 months ago

14 months ago

#3 @nikeo
14 months ago

@celloexpressions this is a proposition of implementation for the refresh promise.
I've also created a small plugin to test it with TwentySeventeen : https://gist.github.com/Nikeo/86eeff438fb6e23b1da0a74a89dd8199

Changes in wp-admin/customize-control.js :
I had to adapt the original debounced refresh because _.debounce won't work properly with a promise object. The proposed code should normally do the same job with setTimeout. The originaRefresh.call( previewer ) is now replaced by api.Previewer.prototype.refresh.call( previewer )

The onceSynced event now takes the server_data as params and resolves the $.Deferred object with it.

Changes in wp-includes/customize-preview.js :
The idea is to allow developer to hook on the synced event, and send for example contextual informations to the panel.
I have introduced a new api.Value to store those data : api.server_data() and a before_synced event to set it.

The gist example illustrates a possible use of this code to send the post informations to the panel in a is_singular context.

Note: See TracTickets for help on using tickets.