Customizer: Export `nonce`, `theme`, and `url` app settings in preview as exported in pane.

* Introduce `WP_Customize_Manager::get_nonces()` to consolidate logic for retrieving nonces.
* Export nonces centrally in `wp.customize.settings.nonce` with each request and update nav menus preview to utilize.
* Send updated nonces to preview upon `nonce-refresh`.
* Request full preview refresh if Nav Menu selective refresh request fails (e.g. due to bad nonce).
* Update nav menus and widgets in Customizer to utilize `customize_refresh_nonces` for exporting nonces and keeping them up to date.

See #27355.
Fixes #35617.


git-svn-id: https://develop.svn.wordpress.org/trunk@36414 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Weston Ruter 2016-01-27 17:54:39 +00:00
parent fe7495efdf
commit 304ab7c0e4
10 changed files with 128 additions and 60 deletions

View File

@ -3375,6 +3375,7 @@
api.bind( 'nonce-refresh', function( nonce ) { api.bind( 'nonce-refresh', function( nonce ) {
$.extend( api.settings.nonce, nonce ); $.extend( api.settings.nonce, nonce );
$.extend( api.previewer.nonce, nonce ); $.extend( api.previewer.nonce, nonce );
api.previewer.send( 'nonce-refresh', nonce );
}); });
// Create Settings // Create Settings

View File

@ -323,7 +323,7 @@
availableMenuItemContainer.find( '.accordion-section-title' ).addClass( 'loading' ); availableMenuItemContainer.find( '.accordion-section-title' ).addClass( 'loading' );
self.loading = true; self.loading = true;
params = { params = {
'customize-menus-nonce': api.Menus.data.nonce, 'customize-menus-nonce': api.settings.nonce['customize-menus'],
'wp_customize': 'on', 'wp_customize': 'on',
'type': type, 'type': type,
'object': object, 'object': object,

View File

@ -1107,7 +1107,7 @@
params = {}; params = {};
params.action = 'update-widget'; params.action = 'update-widget';
params.wp_customize = 'on'; params.wp_customize = 'on';
params.nonce = api.Widgets.data.nonce; params.nonce = api.settings.nonce['update-widget'];
params.theme = api.settings.theme.stylesheet; params.theme = api.settings.theme.stylesheet;
params.customized = wp.customize.previewer.query().customized; params.customized = wp.customize.previewer.query().customized;
@ -2058,11 +2058,6 @@
sidebar_widgets: api.Widgets.SidebarControl sidebar_widgets: api.Widgets.SidebarControl
}); });
// Refresh the nonce if login sends updated nonces over.
api.bind( 'nonce-refresh', function( nonces ) {
api.Widgets.data.nonce = nonces['update-widget'];
});
/** /**
* Init Customizer for widgets. * Init Customizer for widgets.
*/ */

View File

@ -801,20 +801,21 @@ final class WP_Customize_Manager {
*/ */
public function customize_preview_settings() { public function customize_preview_settings() {
$settings = array( $settings = array(
'theme' => array(
'stylesheet' => $this->get_stylesheet(),
'active' => $this->is_theme_active(),
),
'url' => array(
'self' => empty( $_SERVER['REQUEST_URI'] ) ? home_url( '/' ) : esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ),
),
'channel' => wp_unslash( $_POST['customize_messenger_channel'] ), 'channel' => wp_unslash( $_POST['customize_messenger_channel'] ),
'activePanels' => array(), 'activePanels' => array(),
'activeSections' => array(), 'activeSections' => array(),
'activeControls' => array(), 'activeControls' => array(),
'nonce' => $this->get_nonces(),
'_dirty' => array_keys( $this->unsanitized_post_values() ), '_dirty' => array_keys( $this->unsanitized_post_values() ),
); );
if ( 2 == $this->nonce_tick ) {
$settings['nonce'] = array(
'save' => wp_create_nonce( 'save-customize_' . $this->get_stylesheet() ),
'preview' => wp_create_nonce( 'preview-customize_' . $this->get_stylesheet() )
);
}
foreach ( $this->panels as $panel_id => $panel ) { foreach ( $this->panels as $panel_id => $panel ) {
if ( $panel->check_capabilities() ) { if ( $panel->check_capabilities() ) {
$settings['activePanels'][ $panel_id ] = $panel->active(); $settings['activePanels'][ $panel_id ] = $panel->active();
@ -1025,22 +1026,7 @@ final class WP_Customize_Manager {
wp_send_json_error( 'not_preview' ); wp_send_json_error( 'not_preview' );
} }
$nonces = array( wp_send_json_success( $this->get_nonces() );
'save' => wp_create_nonce( 'save-customize_' . $this->get_stylesheet() ),
'preview' => wp_create_nonce( 'preview-customize_' . $this->get_stylesheet() ),
);
/**
* Filter nonces for a customize_refresh_nonces AJAX request.
*
* @since 4.2.0
*
* @param array $nonces Array of refreshed nonces for save and
* preview actions.
* @param WP_Customize_Manager $this WP_Customize_Manager instance.
*/
$nonces = apply_filters( 'customize_refresh_nonces', $nonces, $this );
wp_send_json_success( $nonces );
} }
/** /**
@ -1635,6 +1621,32 @@ final class WP_Customize_Manager {
return $this->autofocus; return $this->autofocus;
} }
/**
* Get nonces for the Customizer.
*
* @since 4.5.0
* @return array Nonces.
*/
public function get_nonces() {
$nonces = array(
'save' => wp_create_nonce( 'save-customize_' . $this->get_stylesheet() ),
'preview' => wp_create_nonce( 'preview-customize_' . $this->get_stylesheet() ),
);
/**
* Filter nonces for Customizer.
*
* @since 4.2.0
*
* @param array $nonces Array of refreshed nonces for save and
* preview actions.
* @param WP_Customize_Manager $this WP_Customize_Manager instance.
*/
$nonces = apply_filters( 'customize_refresh_nonces', $nonces, $this );
return $nonces;
}
/** /**
* Print JavaScript settings for parent window. * Print JavaScript settings for parent window.
* *
@ -1695,10 +1707,7 @@ final class WP_Customize_Manager {
), ),
'panels' => array(), 'panels' => array(),
'sections' => array(), 'sections' => array(),
'nonce' => array( 'nonce' => $this->get_nonces(),
'save' => wp_create_nonce( 'save-customize_' . $this->get_stylesheet() ),
'preview' => wp_create_nonce( 'preview-customize_' . $this->get_stylesheet() ),
),
'autofocus' => array(), 'autofocus' => array(),
'documentTitleTmpl' => $this->get_document_title_template(), 'documentTitleTmpl' => $this->get_document_title_template(),
); );

View File

@ -48,6 +48,7 @@ final class WP_Customize_Nav_Menus {
$this->previewed_menus = array(); $this->previewed_menus = array();
$this->manager = $manager; $this->manager = $manager;
add_filter( 'customize_refresh_nonces', array( $this, 'filter_nonces' ) );
add_action( 'wp_ajax_load-available-menu-items-customizer', array( $this, 'ajax_load_available_items' ) ); add_action( 'wp_ajax_load-available-menu-items-customizer', array( $this, 'ajax_load_available_items' ) );
add_action( 'wp_ajax_search-available-menu-items-customizer', array( $this, 'ajax_search_available_items' ) ); add_action( 'wp_ajax_search-available-menu-items-customizer', array( $this, 'ajax_search_available_items' ) );
add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
@ -62,6 +63,20 @@ final class WP_Customize_Nav_Menus {
add_action( 'customize_preview_init', array( $this, 'customize_preview_init' ) ); add_action( 'customize_preview_init', array( $this, 'customize_preview_init' ) );
} }
/**
* Add nonce for customizing menus.
*
* @since 4.5.0
* @access public
*
* @param array $nonces Array of nonces.
* @return array $nonces Array of nonces.
*/
public function filter_nonces( $nonces ) {
$nonces['customize-menus'] = wp_create_nonce( 'customize-menus' );
return $nonces;
}
/** /**
* Ajax handler for loading available menu items. * Ajax handler for loading available menu items.
* *
@ -329,7 +344,6 @@ final class WP_Customize_Nav_Menus {
// Pass data to JS. // Pass data to JS.
$settings = array( $settings = array(
'nonce' => wp_create_nonce( 'customize-menus' ),
'allMenus' => wp_get_nav_menus(), 'allMenus' => wp_get_nav_menus(),
'itemTypes' => $this->available_item_types(), 'itemTypes' => $this->available_item_types(),
'l10n' => array( 'l10n' => array(
@ -939,12 +953,6 @@ final class WP_Customize_Nav_Menus {
'renderQueryVar' => self::RENDER_QUERY_VAR, 'renderQueryVar' => self::RENDER_QUERY_VAR,
'renderNonceValue' => wp_create_nonce( self::RENDER_AJAX_ACTION ), 'renderNonceValue' => wp_create_nonce( self::RENDER_AJAX_ACTION ),
'renderNoncePostKey' => self::RENDER_NONCE_POST_KEY, 'renderNoncePostKey' => self::RENDER_NONCE_POST_KEY,
'requestUri' => empty( $_SERVER['REQUEST_URI'] ) ? home_url( '/' ) : esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ),
'theme' => array(
'stylesheet' => $this->manager->get_stylesheet(),
'active' => $this->manager->is_theme_active(),
),
'previewCustomizeNonce' => wp_create_nonce( 'preview-customize_' . $this->manager->get_stylesheet() ),
'navMenuInstanceArgs' => $this->preview_nav_menu_instance_args, 'navMenuInstanceArgs' => $this->preview_nav_menu_instance_args,
'l10n' => array( 'l10n' => array(
'editNavMenuItemTooltip' => __( 'Shift-click to edit this menu item.' ), 'editNavMenuItemTooltip' => __( 'Shift-click to edit this menu item.' ),

View File

@ -661,7 +661,6 @@ final class WP_Customize_Widgets {
); );
$settings = array( $settings = array(
'nonce' => wp_create_nonce( 'update-widget' ),
'registeredSidebars' => array_values( $wp_registered_sidebars ), 'registeredSidebars' => array_values( $wp_registered_sidebars ),
'registeredWidgets' => $wp_registered_widgets, 'registeredWidgets' => $wp_registered_widgets,
'availableWidgets' => $available_widgets, // @todo Merge this with registered_widgets 'availableWidgets' => $available_widgets, // @todo Merge this with registered_widgets

View File

@ -13,12 +13,7 @@
renderQueryVar: null, renderQueryVar: null,
renderNonceValue: null, renderNonceValue: null,
renderNoncePostKey: null, renderNoncePostKey: null,
previewCustomizeNonce: null,
requestUri: '/', requestUri: '/',
theme: {
active: false,
stylesheet: ''
},
navMenuInstanceArgs: {}, navMenuInstanceArgs: {},
l10n: {} l10n: {}
}; };
@ -200,11 +195,11 @@
menuId = parseInt( menuId, 10 ); menuId = parseInt( menuId, 10 );
data = { data = {
nonce: settings.previewCustomizeNonce, // for Customize Preview nonce: wp.customize.settings.nonce.preview,
wp_customize: 'on' wp_customize: 'on'
}; };
if ( ! settings.theme.active ) { if ( ! wp.customize.settings.theme.active ) {
data.theme = settings.theme.stylesheet; data.theme = wp.customize.settings.theme.stylesheet;
} }
data[ settings.renderQueryVar ] = '1'; data[ settings.renderQueryVar ] = '1';
@ -239,7 +234,7 @@
request = wp.ajax.send( null, { request = wp.ajax.send( null, {
data: data, data: data,
url: settings.requestUri url: api.settings.url.self
} ); } );
request.done( function( data ) { request.done( function( data ) {
// If the menu is now not visible, refresh since the page layout may have changed. // If the menu is now not visible, refresh since the page layout may have changed.
@ -263,6 +258,9 @@
container.removeClass( 'customize-partial-refreshing' ); container.removeClass( 'customize-partial-refreshing' );
$( document ).trigger( 'customize-preview-menu-refreshed', [ eventParam ] ); $( document ).trigger( 'customize-preview-menu-refreshed', [ eventParam ] );
} ); } );
request.fail( function() {
api.preview.send( 'refresh' );
} );
}, },
refreshMenuInstanceDebounced : function( instanceNumber ) { refreshMenuInstanceDebounced : function( instanceNumber ) {

View File

@ -146,9 +146,7 @@
}); });
api.preview.bind( 'active', function() { api.preview.bind( 'active', function() {
if ( api.settings.nonce ) {
api.preview.send( 'nonce', api.settings.nonce ); api.preview.send( 'nonce', api.settings.nonce );
}
api.preview.send( 'documentTitle', document.title ); api.preview.send( 'documentTitle', document.title );
}); });
@ -163,6 +161,10 @@
} ); } );
} ); } );
api.preview.bind( 'nonce-refresh', function( nonce ) {
$.extend( api.settings.nonce, nonce );
} );
/* /*
* Send a message to the parent customize frame with a list of which * Send a message to the parent customize frame with a list of which
* containers and controls are active. * containers and controls are active.

View File

@ -368,6 +368,36 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
$this->assertEmpty( $this->manager->get_autofocus() ); $this->assertEmpty( $this->manager->get_autofocus() );
} }
/**
* Test get_nonces() method.
*
* @see WP_Customize_Manager::get_nonces()
*/
function test_nonces() {
$nonces = $this->manager->get_nonces();
$this->assertInternalType( 'array', $nonces );
$this->assertArrayHasKey( 'save', $nonces );
$this->assertArrayHasKey( 'preview', $nonces );
add_filter( 'customize_refresh_nonces', array( $this, 'filter_customize_refresh_nonces' ), 10, 2 );
$nonces = $this->manager->get_nonces();
$this->assertArrayHasKey( 'foo', $nonces );
$this->assertEquals( wp_create_nonce( 'foo' ), $nonces['foo'] );
}
/**
* Filter for customize_refresh_nonces.
*
* @param array $nonces Nonces.
* @param WP_Customize_Manager $manager Manager.
* @return array Nonces.
*/
function filter_customize_refresh_nonces( $nonces, $manager ) {
$this->assertInstanceOf( 'WP_Customize_Manager', $manager );
$nonces['foo'] = wp_create_nonce( 'foo' );
return $nonces;
}
/** /**
* Test customize_pane_settings() method. * Test customize_pane_settings() method.
* *
@ -401,6 +431,38 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase {
$this->assertArrayHasKey( 'preview', $data['nonce'] ); $this->assertArrayHasKey( 'preview', $data['nonce'] );
} }
/**
* Test customize_preview_settings() method.
*
* @see WP_Customize_Manager::customize_preview_settings()
*/
function test_customize_preview_settings() {
wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
$this->manager->register_controls();
$this->manager->prepare_controls();
$this->manager->set_post_value( 'foo', 'bar' );
$_POST['customize_messenger_channel'] = 'preview-0';
ob_start();
$this->manager->customize_preview_settings();
$content = ob_get_clean();
$this->assertEquals( 1, preg_match( '/var _wpCustomizeSettings = ({.+});/', $content, $matches ) );
$settings = json_decode( $matches[1], true );
$this->assertArrayHasKey( 'theme', $settings );
$this->assertArrayHasKey( 'url', $settings );
$this->assertArrayHasKey( 'channel', $settings );
$this->assertArrayHasKey( 'activePanels', $settings );
$this->assertArrayHasKey( 'activeSections', $settings );
$this->assertArrayHasKey( 'activeControls', $settings );
$this->assertArrayHasKey( 'nonce', $settings );
$this->assertArrayHasKey( '_dirty', $settings );
$this->assertArrayHasKey( 'preview', $settings['nonce'] );
$this->assertEquals( array( 'foo' ), $settings['_dirty'] );
}
/** /**
* @ticket 33552 * @ticket 33552
*/ */

View File

@ -647,12 +647,6 @@ class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase {
$this->assertContains( 'renderQueryVar', $data ); $this->assertContains( 'renderQueryVar', $data );
$this->assertContains( 'renderNonceValue', $data ); $this->assertContains( 'renderNonceValue', $data );
$this->assertContains( 'renderNoncePostKey', $data ); $this->assertContains( 'renderNoncePostKey', $data );
$this->assertContains( 'requestUri', $data );
$this->assertContains( 'theme', $data );
$this->assertContains( 'previewCustomizeNonce', $data );
$this->assertContains( 'navMenuInstanceArgs', $data ); $this->assertContains( 'navMenuInstanceArgs', $data );
$this->assertContains( 'requestUri', $data );
} }
} }