Ticket #32814: 32814.11.diff
File 32814.11.diff, 18.6 KB (added by , 10 years ago) |
---|
-
src/wp-admin/js/customize-nav-menus.js
diff --git src/wp-admin/js/customize-nav-menus.js src/wp-admin/js/customize-nav-menus.js index 7d5e054..b2d7033 100644
957 957 var control = this; 958 958 api.Control.prototype.initialize.call( control, id, options ); 959 959 control.active.validate = function() { 960 return api.section( control.section() ).active(); 960 var value, section = api.section( control.section() ); 961 if ( section ) { 962 value = section.active(); 963 } else { 964 value = false; 965 } 966 return value; 961 967 }; 962 968 }, 963 969 … … 1602 1608 * being deactivated. 1603 1609 */ 1604 1610 control.active.validate = function() { 1605 return api.section( control.section() ).active(); 1611 var value, section = api.section( control.section() ); 1612 if ( section ) { 1613 value = section.active(); 1614 } else { 1615 value = false; 1616 } 1617 return value; 1606 1618 }; 1607 1619 1608 1620 control.nameElement = new api.Element( control.container.find( '.menu-name-field' ) ); … … 1648 1660 * being deactivated. 1649 1661 */ 1650 1662 control.active.validate = function() { 1651 return api.section( control.section() ).active(); 1663 var value, section = api.section( control.section() ); 1664 if ( section ) { 1665 value = section.active(); 1666 } else { 1667 value = false; 1668 } 1669 return value; 1652 1670 }; 1653 1671 1654 1672 control.autoAddElement = new api.Element( control.container.find( 'input[type=checkbox].auto_add' ) ); … … 1691 1709 var control = this, 1692 1710 menuId = control.params.menu_id, 1693 1711 menu = control.setting(), 1694 name; 1712 name, 1713 widgetTemplate, 1714 select; 1695 1715 1696 1716 if ( 'undefined' === typeof this.params.menu_id ) { 1697 1717 throw new Error( 'params.menu_id was not defined' ); … … 1703 1723 * being deactivated. 1704 1724 */ 1705 1725 control.active.validate = function() { 1706 return api.section( control.section() ).active(); 1726 var value, section = api.section( control.section() ); 1727 if ( section ) { 1728 value = section.active(); 1729 } else { 1730 value = false; 1731 } 1732 return value; 1707 1733 }; 1708 1734 1709 1735 control.$controlSection = control.container.closest( '.control-section' ); … … 1725 1751 if ( menu ) { 1726 1752 name = displayNavMenuName( menu.name ); 1727 1753 1754 // Add the menu to the existing controls. 1728 1755 api.control.each( function( widgetControl ) { 1729 1756 if ( ! widgetControl.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== widgetControl.params.widget_id_base ) { 1730 1757 return; 1731 1758 } 1732 var select = widgetControl.container.find( 'select' ); 1733 if ( select.find( 'option[value=' + String( menuId ) + ']' ).length === 0 ) { 1759 widgetControl.container.find( '.nav-menu-widget-form-controls:first' ).show(); 1760 widgetControl.container.find( '.nav-menu-widget-no-menus-message:first' ).hide(); 1761 1762 select = widgetControl.container.find( 'select' ); 1763 if ( 0 === select.find( 'option[value=' + String( menuId ) + ']' ).length ) { 1734 1764 select.append( new Option( name, menuId ) ); 1735 1765 } 1736 1766 } ); 1737 $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first' ).append( new Option( name, menuId ) ); 1767 1768 // Add the menu to the widget template. 1769 widgetTemplate = $( '#available-widgets-list .widget-tpl:has( input.id_base[ value=nav_menu ] )' ); 1770 widgetTemplate.find( '.nav-menu-widget-form-controls:first' ).show(); 1771 widgetTemplate.find( '.nav-menu-widget-no-menus-message:first' ).hide(); 1772 select = widgetTemplate.find( '.widget-inside select:first' ); 1773 if ( 0 === select.find( 'option[value=' + String( menuId ) + ']' ).length ) { 1774 select.append( new Option( name, menuId ) ); 1775 } 1738 1776 } 1739 1777 }, 1740 1778 … … 1759 1797 var select = widgetControl.container.find( 'select' ); 1760 1798 select.find( 'option[value=' + String( menuId ) + ']' ).text( name ); 1761 1799 }); 1762 $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first option[value=' + String( menuId ) + ']' ).text( name );1763 1800 } 1764 1801 } ); 1765 1802 … … 1831 1868 menuItemControl.setting.set( setting ); 1832 1869 }); 1833 1870 }); 1834 });1835 1871 1872 }); 1836 1873 control.isReordering = false; 1837 1874 1838 1875 /** … … 1869 1906 var control = this, 1870 1907 section, 1871 1908 menuId = control.params.menu_id, 1872 removeSection; 1909 removeSection, 1910 widgetTemplate, 1911 navMenuCount = 0; 1873 1912 section = api.section( control.section() ); 1874 1913 removeSection = function() { 1875 1914 section.container.remove(); … … 1888 1927 removeSection(); 1889 1928 } 1890 1929 1930 api.each(function( setting ) { 1931 if ( /^nav_menu\[/.test( setting.id ) && false !== setting() ) { 1932 navMenuCount += 1; 1933 } 1934 }); 1935 1891 1936 // Remove the menu from any Custom Menu widgets. 1892 1937 api.control.each(function( widgetControl ) { 1893 1938 if ( ! widgetControl.extended( api.controlConstructor.widget_form ) || 'nav_menu' !== widgetControl.params.widget_id_base ) { … … 1897 1942 if ( select.val() === String( menuId ) ) { 1898 1943 select.prop( 'selectedIndex', 0 ).trigger( 'change' ); 1899 1944 } 1900 select.find( 'option[value=' + String( menuId ) + ']' ).remove(); 1945 1946 widgetControl.container.find( '.nav-menu-widget-form-controls:first' ).toggle( 0 !== navMenuCount ); 1947 widgetControl.container.find( '.nav-menu-widget-no-menus-message:first' ).toggle( 0 === navMenuCount ); 1948 widgetControl.container.find( 'option[value=' + String( menuId ) + ']' ).remove(); 1901 1949 }); 1902 $( '#available-widgets-list .widget-inside:has(input.id_base[value=nav_menu]) select:first option[value=' + String( menuId ) + ']' ).remove(); 1950 1951 // Remove the menu to the nav menu widget template. 1952 widgetTemplate = $( '#available-widgets-list .widget-tpl:has( input.id_base[ value=nav_menu ] )' ); 1953 widgetTemplate.find( '.nav-menu-widget-form-controls:first' ).toggle( 0 !== navMenuCount ); 1954 widgetTemplate.find( '.nav-menu-widget-no-menus-message:first' ).toggle( 0 === navMenuCount ); 1955 widgetTemplate.find( 'option[value=' + String( menuId ) + ']' ).remove(); 1903 1956 }, 1904 1957 1905 1958 // Setup theme location checkboxes. … … 2292 2345 2293 2346 // Focus on the new menu section. 2294 2347 api.section( customizeId ).focus(); // @todo should we focus on the new menu's control and open the add-items panel? Thinking user flow... 2348 2349 // Fix an issue with extra space at top immediately after creating new menu. 2350 $( '#menu-to-edit' ).css( 'margin-top', 0 ); 2295 2351 } 2296 2352 }); 2297 2353 … … 2431 2487 } 2432 2488 } ); 2433 2489 2490 /** 2491 * Update the saved menu in any custom menu widgets. 2492 * If the previous_term_id item is selected, reselect the 2493 * item with the updated term_id. 2494 */ 2495 api.control.each( function( setting ) { 2496 // Only act on nav_menu widgets. 2497 if ( ! setting.extended( api.controlConstructor.widget_form ) || 2498 'nav_menu' !== setting.params.widget_id_base ) { 2499 return; 2500 } 2501 var select, oldMenuOption, oldMenuSelected, newMenuOption; 2502 select = setting.container.find( 'select' ); 2503 oldMenuOption = select.find( 'option[value=' + String( update.previous_term_id ) + ']' ); 2504 oldMenuSelected = select.find( 'option[value=' + String( update.previous_term_id ) + ']:selected' ); 2505 newMenuOption = select.find( 'option[value=' + String( update.term_id ) + ']' ); 2506 2507 // Adjust menu options matching the old ID, setting them to the new ID. 2508 if ( oldMenuSelected.length !== 0 && newMenuOption !== 0 ) { 2509 // Remove the old option. 2510 oldMenuOption.remove(); 2511 // Select the new option. 2512 newMenuOption.attr( 'selected', true ).trigger( 'change' ); 2513 } 2514 2515 2516 } ); 2517 2434 2518 if ( oldSection.expanded.get() ) { 2435 2519 // @todo This doesn't seem to be working. 2436 2520 newSection.expand(); -
src/wp-admin/js/customize-widgets.js
diff --git src/wp-admin/js/customize-widgets.js src/wp-admin/js/customize-widgets.js index 2907b4f..f56a048 100644
1041 1041 params.wp_customize = 'on'; 1042 1042 params.nonce = api.Widgets.data.nonce; 1043 1043 params.theme = api.settings.theme.stylesheet; 1044 params.customized = wp.customize.previewer.query().customized; 1044 1045 1045 1046 data = $.param( params ); 1046 1047 $inputs = this._getInputs( $widgetContent ); -
src/wp-includes/class-wp-customize-setting.php
diff --git src/wp-includes/class-wp-customize-setting.php src/wp-includes/class-wp-customize-setting.php index fa94346..e07cb0b 100644
class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 1625 1625 $this->_original_value = $this->value(); 1626 1626 $this->_previewed_blog_id = get_current_blog_id(); 1627 1627 1628 add_filter( 'wp_get_nav_menus', array( $this, 'filter_wp_get_nav_menus' ), 10, 2 ); 1628 1629 add_filter( 'wp_get_nav_menu_object', array( $this, 'filter_wp_get_nav_menu_object' ), 10, 2 ); 1629 1630 add_filter( 'default_option_nav_menu_options', array( $this, 'filter_nav_menu_options' ) ); 1630 1631 add_filter( 'option_nav_menu_options', array( $this, 'filter_nav_menu_options' ) ); 1631 1632 } 1632 1633 1633 1634 /** 1635 * Filter the wp_get_nav_menus() result to ensure the inserted menu object is included, and the deleted one is removed. 1636 * 1637 * @since 4.3.0 1638 * @access public 1639 * 1640 * @see wp_get_nav_menus() 1641 * 1642 * @param array $menus An array of menu objects. 1643 * @param array $args An array of arguments used to retrieve menu objects. 1644 * @return array 1645 */ 1646 public function filter_wp_get_nav_menus( $menus, $args ) { 1647 if ( get_current_blog_id() !== $this->_previewed_blog_id ) { 1648 return $menus; 1649 } 1650 1651 $setting_value = $this->value(); 1652 $is_delete = ( false === $setting_value ); 1653 $index = -1; 1654 1655 // Find the existing menu item's position in the list. 1656 foreach ( $menus as $i => $menu ) { 1657 if ( (int) $this->term_id === (int) $menu->term_id || (int) $this->previous_term_id === (int) $menu->term_id ) { 1658 $index = $i; 1659 break; 1660 } 1661 } 1662 1663 if ( $is_delete ) { 1664 // Handle deleted menu by removing it from the list. 1665 if ( -1 !== $index ) { 1666 array_splice( $menus, $index, 1 ); 1667 } 1668 } else { 1669 // Handle menus being updated or inserted. 1670 $menu_obj = (object) array_merge( array( 1671 'term_id' => $this->term_id, 1672 'term_taxonomy_id' => $this->term_id, 1673 'slug' => sanitize_title( $setting_value['name'] ), 1674 'count' => 0, 1675 'term_group' => 0, 1676 'taxonomy' => self::TAXONOMY, 1677 'filter' => 'raw', 1678 ), $setting_value ); 1679 1680 array_splice( $menus, $index, ( -1 === $index ? 0 : 1 ), array( $menu_obj ) ); 1681 } 1682 1683 // Make sure the menu objects get re-sorted after an update/insert. 1684 if ( ! $is_delete && ! empty( $args['orderby'] ) ) { 1685 $this->_current_menus_sort_orderby = $args['orderby']; 1686 usort( $menus, array( $this, '_sort_menus_by_orderby' ) ); 1687 } 1688 // @todo add support for $args['hide_empty'] === true 1689 1690 return $menus; 1691 } 1692 1693 /** 1694 * Temporary non-closure passing of orderby value to function. 1695 * 1696 * @since 4.3.0 1697 * @access protected 1698 * @var string 1699 * 1700 * @see WP_Customize_Nav_Menu_Setting::filter_wp_get_nav_menus() 1701 * @see WP_Customize_Nav_Menu_Setting::_sort_menus_by_orderby() 1702 */ 1703 protected $_current_menus_sort_orderby; 1704 1705 /** 1706 * Sort menu objects by the class-supplied orderby property. 1707 * 1708 * This is a workaround for a lack of closures. 1709 * 1710 * @since 4.3.0 1711 * @access protected 1712 * @param object $menu1 1713 * @param object $menu2 1714 * @return int 1715 * 1716 * @see WP_Customize_Nav_Menu_Setting::filter_wp_get_nav_menus() 1717 */ 1718 protected function _sort_menus_by_orderby( $menu1, $menu2 ) { 1719 $key = $this->_current_menus_sort_orderby; 1720 return strcmp( $menu1->$key, $menu2->$key ); 1721 } 1722 1723 /** 1634 1724 * Filter the wp_get_nav_menu_object() result to supply the previewed menu object. 1635 1725 * 1636 1726 * Requesting a nav_menu object by anything but ID is not supported. … … class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 1761 1851 * To delete a menu, the client can send false as the value. 1762 1852 * 1763 1853 * @since 4.3.0 1764 * @access p ublic1854 * @access protected 1765 1855 * 1766 1856 * @see wp_update_nav_menu_object() 1767 1857 * … … class WP_Customize_Nav_Menu_Setting extends WP_Customize_Setting { 1864 1954 * Updates a nav_menu_options array. 1865 1955 * 1866 1956 * @since 4.3.0 1867 * @access p ublic1957 * @access protected 1868 1958 * 1869 1959 * @see WP_Customize_Nav_Menu_Setting::filter_nav_menu_options() 1870 1960 * @see WP_Customize_Nav_Menu_Setting::update() -
src/wp-includes/class-wp-customize-widgets.php
diff --git src/wp-includes/class-wp-customize-widgets.php src/wp-includes/class-wp-customize-widgets.php index cf93bb5..775e8bb 100644
final class WP_Customize_Widgets { 1241 1241 public function call_widget_update( $widget_id ) { 1242 1242 global $wp_registered_widget_updates, $wp_registered_widget_controls; 1243 1243 1244 $setting_id = $this->get_setting_id( $widget_id ); 1245 1246 /* 1247 * Make sure that other setting changes have previewed since this widget 1248 * may depend on them (e.g. Menus being present for Custom Menu widget). 1249 */ 1250 if ( ! did_action( 'customize_preview_init' ) ) { 1251 foreach ( $this->manager->settings() as $setting ) { 1252 if ( $setting->id !== $setting_id ) { 1253 $setting->preview(); 1254 } 1255 } 1256 } 1257 1244 1258 $this->start_capturing_option_updates(); 1245 1259 $parsed_id = $this->parse_widget_id( $widget_id ); 1246 1260 $option_name = 'widget_' . $parsed_id['id_base']; … … final class WP_Customize_Widgets { 1321 1335 * in place from WP_Customize_Setting::preview() will use this value 1322 1336 * instead of the default widget instance value (an empty array). 1323 1337 */ 1324 $setting_id = $this->get_setting_id( $widget_id );1325 1338 $this->manager->set_post_value( $setting_id, $instance ); 1326 1339 1327 1340 // Obtain the widget control with the updated instance in place. -
src/wp-includes/default-widgets.php
diff --git src/wp-includes/default-widgets.php src/wp-includes/default-widgets.php index cb6c2bb..22e61e5 100644
class WP_Widget_Tag_Cloud extends WP_Widget { 1570 1570 $menus = wp_get_nav_menus(); 1571 1571 1572 1572 // If no menus exists, direct the user to go and create some. 1573 if ( !$menus ) {1574 echo '<p>'. sprintf( __('No menus have been created yet. <a href="%s">Create some</a>.'), admin_url('nav-menus.php') ) .'</p>';1575 return;1576 }1577 1573 ?> 1578 <p> 1579 <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:') ?></label> 1580 <input type="text" class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo $title; ?>" /> 1581 </p> 1582 <p> 1583 <label for="<?php echo $this->get_field_id('nav_menu'); ?>"><?php _e('Select Menu:'); ?></label> 1584 <select id="<?php echo $this->get_field_id('nav_menu'); ?>" name="<?php echo $this->get_field_name('nav_menu'); ?>"> 1585 <option value="0"><?php _e( '— Select —' ) ?></option> 1586 <?php 1587 foreach ( $menus as $menu ) { 1588 echo '<option value="' . $menu->term_id . '"' 1589 . selected( $nav_menu, $menu->term_id, false ) 1590 . '>'. esc_html( $menu->name ) . '</option>'; 1574 <p class="nav-menu-widget-no-menus-message" <?php if ( ! empty( $menus ) ) { echo ' style="display:none" '; } ?>> 1575 <?php 1576 if ( isset( $GLOBALS['wp_customize'] ) && $GLOBALS['wp_customize'] instanceof WP_Customize_Manager ) { 1577 // @todo When expanding a panel, the JS should be smart enough to collapse any existing panels and sections. 1578 $url = 'javascript: wp.customize.section.each(function( section ){ section.collapse(); }); wp.customize.panel( "nav_menus" ).focus();'; 1579 } else { 1580 $url = admin_url( 'nav-menus.php' ); 1591 1581 } 1592 ?>1593 < /select>1582 ?> 1583 <?php echo sprintf( __( 'No menus have been created yet. <a href="%s">Create some</a>.' ), esc_attr( $url ) ); ?> 1594 1584 </p> 1585 <div class="nav-menu-widget-form-controls" <?php if ( empty( $menus ) ) { echo ' style="display:none" '; } ?>> 1586 <p> 1587 <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ) ?></label> 1588 <input type="text" class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo esc_attr( $title ); ?>"/> 1589 </p> 1590 <p> 1591 <label for="<?php echo $this->get_field_id( 'nav_menu' ); ?>"><?php _e( 'Select Menu:' ); ?></label> 1592 <select id="<?php echo $this->get_field_id( 'nav_menu' ); ?>" name="<?php echo $this->get_field_name( 'nav_menu' ); ?>"> 1593 <option value="0"><?php _e( '— Select —' ); ?></option> 1594 <?php foreach ( $menus as $menu ) : ?> 1595 <option value="<?php echo esc_attr( $menu->term_id ); ?>" <?php selected( $nav_menu, $menu->term_id ); ?>> 1596 <?php echo esc_html( $menu->name ); ?> 1597 </option> 1598 <?php endforeach; ?> 1599 </select> 1600 </p> 1601 </div> 1595 1602 <?php 1596 1603 } 1597 1604 } -
src/wp-includes/nav-menu.php
diff --git src/wp-includes/nav-menu.php src/wp-includes/nav-menu.php index d12abc5..29666f0 100644
12 12 * 13 13 * @since 3.0.0 14 14 * 15 * @param string $menu Menu ID, slug, or name .15 * @param string $menu Menu ID, slug, or name - or the menu object. 16 16 * @return object|false False if $menu param isn't supplied or term does not exist, menu object if successful. 17 17 */ 18 18 function wp_get_nav_menu_object( $menu ) { 19 19 $menu_obj = false; 20 if ( $menu ) { 20 21 if ( is_object( $menu ) ) { 22 $menu_obj = $menu; 23 } 24 25 if ( $menu && ! $menu_obj ) { 21 26 $menu_obj = get_term( $menu, 'nav_menu' ); 22 27 23 28 if ( ! $menu_obj ) { -
tests/phpunit/tests/customize/nav-menu-setting.php
diff --git tests/phpunit/tests/customize/nav-menu-setting.php tests/phpunit/tests/customize/nav-menu-setting.php index 5d99fd6..dd1b584 100644
class Test_WP_Customize_Nav_Menu_Setting extends WP_UnitTestCase { 211 211 212 212 $nav_menu_options = get_option( 'nav_menu_options', array( 'auto_add' => array() ) ); 213 213 $this->assertContains( $menu_id, $nav_menu_options['auto_add'] ); 214 215 $menus = wp_get_nav_menus(); 216 $menus_ids = wp_list_pluck( $menus, 'term_id' ); 217 $i = array_search( $menu_id, $menus_ids ); 218 $this->assertNotFalse( $i, 'Update-previewed menu does not appear in wp_get_nav_menus()' ); 219 $filtered_menu = $menus[ $i ]; 220 $this->assertEquals( 'Name 2', $filtered_menu->name ); 214 221 } 215 222 216 223 /** … … class Test_WP_Customize_Nav_Menu_Setting extends WP_UnitTestCase { 249 256 250 257 $nav_menu_options = $this->get_nav_menu_items_option(); 251 258 $this->assertNotContains( $menu_id, $nav_menu_options['auto_add'] ); 259 260 $menus = wp_get_nav_menus(); 261 $menus_ids = wp_list_pluck( $menus, 'term_id' ); 262 $i = array_search( $menu_id, $menus_ids ); 263 $this->assertNotFalse( $i, 'Insert-previewed menu was not injected into wp_get_nav_menus()' ); 264 $filtered_menu = $menus[ $i ]; 265 $this->assertEquals( 'New Menu Name 1', $filtered_menu->name ); 252 266 } 253 267 254 268 /**