From 304ab7c0e4c2c7afa4e16c48099c1529b8992944 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 27 Jan 2016 17:54:39 +0000 Subject: [PATCH] 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 --- src/wp-admin/js/customize-controls.js | 1 + src/wp-admin/js/customize-nav-menus.js | 2 +- src/wp-admin/js/customize-widgets.js | 7 +-- .../class-wp-customize-manager.php | 63 +++++++++++-------- .../class-wp-customize-nav-menus.php | 22 ++++--- .../class-wp-customize-widgets.php | 1 - .../js/customize-preview-nav-menus.js | 16 +++-- src/wp-includes/js/customize-preview.js | 8 ++- tests/phpunit/tests/customize/manager.php | 62 ++++++++++++++++++ tests/phpunit/tests/customize/nav-menus.php | 6 -- 10 files changed, 128 insertions(+), 60 deletions(-) diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js index 4901b5699f..caf296a809 100644 --- a/src/wp-admin/js/customize-controls.js +++ b/src/wp-admin/js/customize-controls.js @@ -3375,6 +3375,7 @@ api.bind( 'nonce-refresh', function( nonce ) { $.extend( api.settings.nonce, nonce ); $.extend( api.previewer.nonce, nonce ); + api.previewer.send( 'nonce-refresh', nonce ); }); // Create Settings diff --git a/src/wp-admin/js/customize-nav-menus.js b/src/wp-admin/js/customize-nav-menus.js index bcebb65e1e..c5549acbbf 100644 --- a/src/wp-admin/js/customize-nav-menus.js +++ b/src/wp-admin/js/customize-nav-menus.js @@ -323,7 +323,7 @@ availableMenuItemContainer.find( '.accordion-section-title' ).addClass( 'loading' ); self.loading = true; params = { - 'customize-menus-nonce': api.Menus.data.nonce, + 'customize-menus-nonce': api.settings.nonce['customize-menus'], 'wp_customize': 'on', 'type': type, 'object': object, diff --git a/src/wp-admin/js/customize-widgets.js b/src/wp-admin/js/customize-widgets.js index 595585c1ae..5ec3185b96 100644 --- a/src/wp-admin/js/customize-widgets.js +++ b/src/wp-admin/js/customize-widgets.js @@ -1107,7 +1107,7 @@ params = {}; params.action = 'update-widget'; params.wp_customize = 'on'; - params.nonce = api.Widgets.data.nonce; + params.nonce = api.settings.nonce['update-widget']; params.theme = api.settings.theme.stylesheet; params.customized = wp.customize.previewer.query().customized; @@ -2058,11 +2058,6 @@ 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. */ diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php index aa73ed7992..48ccc807ab 100644 --- a/src/wp-includes/class-wp-customize-manager.php +++ b/src/wp-includes/class-wp-customize-manager.php @@ -801,20 +801,21 @@ final class WP_Customize_Manager { */ public function customize_preview_settings() { $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'] ), 'activePanels' => array(), 'activeSections' => array(), 'activeControls' => array(), + 'nonce' => $this->get_nonces(), '_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 ) { if ( $panel->check_capabilities() ) { $settings['activePanels'][ $panel_id ] = $panel->active(); @@ -1025,22 +1026,7 @@ final class WP_Customize_Manager { wp_send_json_error( 'not_preview' ); } - $nonces = array( - '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 ); + wp_send_json_success( $this->get_nonces() ); } /** @@ -1635,6 +1621,32 @@ final class WP_Customize_Manager { 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. * @@ -1695,10 +1707,7 @@ final class WP_Customize_Manager { ), 'panels' => array(), 'sections' => array(), - 'nonce' => array( - 'save' => wp_create_nonce( 'save-customize_' . $this->get_stylesheet() ), - 'preview' => wp_create_nonce( 'preview-customize_' . $this->get_stylesheet() ), - ), + 'nonce' => $this->get_nonces(), 'autofocus' => array(), 'documentTitleTmpl' => $this->get_document_title_template(), ); diff --git a/src/wp-includes/class-wp-customize-nav-menus.php b/src/wp-includes/class-wp-customize-nav-menus.php index 2c90548c59..809eace303 100644 --- a/src/wp-includes/class-wp-customize-nav-menus.php +++ b/src/wp-includes/class-wp-customize-nav-menus.php @@ -48,6 +48,7 @@ final class WP_Customize_Nav_Menus { $this->previewed_menus = array(); $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_search-available-menu-items-customizer', array( $this, 'ajax_search_available_items' ) ); 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 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. * @@ -329,7 +344,6 @@ final class WP_Customize_Nav_Menus { // Pass data to JS. $settings = array( - 'nonce' => wp_create_nonce( 'customize-menus' ), 'allMenus' => wp_get_nav_menus(), 'itemTypes' => $this->available_item_types(), 'l10n' => array( @@ -939,12 +953,6 @@ final class WP_Customize_Nav_Menus { 'renderQueryVar' => self::RENDER_QUERY_VAR, 'renderNonceValue' => wp_create_nonce( self::RENDER_AJAX_ACTION ), '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, 'l10n' => array( 'editNavMenuItemTooltip' => __( 'Shift-click to edit this menu item.' ), diff --git a/src/wp-includes/class-wp-customize-widgets.php b/src/wp-includes/class-wp-customize-widgets.php index f26f8d1740..5a0e62b62a 100644 --- a/src/wp-includes/class-wp-customize-widgets.php +++ b/src/wp-includes/class-wp-customize-widgets.php @@ -661,7 +661,6 @@ final class WP_Customize_Widgets { ); $settings = array( - 'nonce' => wp_create_nonce( 'update-widget' ), 'registeredSidebars' => array_values( $wp_registered_sidebars ), 'registeredWidgets' => $wp_registered_widgets, 'availableWidgets' => $available_widgets, // @todo Merge this with registered_widgets diff --git a/src/wp-includes/js/customize-preview-nav-menus.js b/src/wp-includes/js/customize-preview-nav-menus.js index fe5f305729..5441b86887 100644 --- a/src/wp-includes/js/customize-preview-nav-menus.js +++ b/src/wp-includes/js/customize-preview-nav-menus.js @@ -13,12 +13,7 @@ renderQueryVar: null, renderNonceValue: null, renderNoncePostKey: null, - previewCustomizeNonce: null, requestUri: '/', - theme: { - active: false, - stylesheet: '' - }, navMenuInstanceArgs: {}, l10n: {} }; @@ -200,11 +195,11 @@ menuId = parseInt( menuId, 10 ); data = { - nonce: settings.previewCustomizeNonce, // for Customize Preview + nonce: wp.customize.settings.nonce.preview, wp_customize: 'on' }; - if ( ! settings.theme.active ) { - data.theme = settings.theme.stylesheet; + if ( ! wp.customize.settings.theme.active ) { + data.theme = wp.customize.settings.theme.stylesheet; } data[ settings.renderQueryVar ] = '1'; @@ -239,7 +234,7 @@ request = wp.ajax.send( null, { data: data, - url: settings.requestUri + url: api.settings.url.self } ); request.done( function( data ) { // If the menu is now not visible, refresh since the page layout may have changed. @@ -263,6 +258,9 @@ container.removeClass( 'customize-partial-refreshing' ); $( document ).trigger( 'customize-preview-menu-refreshed', [ eventParam ] ); } ); + request.fail( function() { + api.preview.send( 'refresh' ); + } ); }, refreshMenuInstanceDebounced : function( instanceNumber ) { diff --git a/src/wp-includes/js/customize-preview.js b/src/wp-includes/js/customize-preview.js index 1d1802736c..b6da7759b2 100644 --- a/src/wp-includes/js/customize-preview.js +++ b/src/wp-includes/js/customize-preview.js @@ -146,9 +146,7 @@ }); 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 ); }); @@ -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 * containers and controls are active. diff --git a/tests/phpunit/tests/customize/manager.php b/tests/phpunit/tests/customize/manager.php index e787cfa02b..4cf8d01544 100644 --- a/tests/phpunit/tests/customize/manager.php +++ b/tests/phpunit/tests/customize/manager.php @@ -368,6 +368,36 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase { $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. * @@ -401,6 +431,38 @@ class Tests_WP_Customize_Manager extends WP_UnitTestCase { $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 */ diff --git a/tests/phpunit/tests/customize/nav-menus.php b/tests/phpunit/tests/customize/nav-menus.php index dd620c3c30..2969a2dd89 100644 --- a/tests/phpunit/tests/customize/nav-menus.php +++ b/tests/phpunit/tests/customize/nav-menus.php @@ -647,12 +647,6 @@ class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { $this->assertContains( 'renderQueryVar', $data ); $this->assertContains( 'renderNonceValue', $data ); $this->assertContains( 'renderNoncePostKey', $data ); - $this->assertContains( 'requestUri', $data ); - $this->assertContains( 'theme', $data ); - $this->assertContains( 'previewCustomizeNonce', $data ); $this->assertContains( 'navMenuInstanceArgs', $data ); - $this->assertContains( 'requestUri', $data ); - } - }