WordPress.org

Make WordPress Core

Ticket #11817: menus.3.diff

File menus.3.diff, 91.2 KB (added by scribu, 4 years ago)

menu admin with dropdowns

  • wp-includes/load.php

     
    383383 
    384384        // Load in support for template functions which the theme supports 
    385385        require_if_theme_supports( 'post-thumbnails', ABSPATH . WPINC . '/post-thumbnail-template.php' ); 
     386 
     387        // Menus init 
     388        if ( current_theme_supports( 'menus' ) ) { 
     389                if ( apply_filters('load_default_menu_items', true) ) 
     390                        require( ABSPATH . WPINC . '/default-menu-items.php' ); 
     391 
     392                function _wp_add_menus_menu() { 
     393                        global $submenu; 
     394                        $submenu['themes.php'][8] = array( __( 'Menus' ), 'switch_themes', 'menus.php' ); 
     395                        ksort( $submenu['themes.php'], SORT_NUMERIC ); 
     396                } 
     397                add_action( '_admin_menu', '_wp_add_menus_menu' ); 
     398        } 
    386399} 
    387400 
    388401/** 
     
    444457        return false; 
    445458} 
    446459 
    447 ?> 
    448  No newline at end of file 
     460?> 
  • wp-includes/default-menu-items.php

     
     1<?php 
     2 
     3/** 
     4 * Page Menu Item class 
     5 * 
     6 * @since 3.0 
     7 */ 
     8class WP_Menu_Item_Page extends WP_Menu_Item { 
     9 
     10        function WP_Menu_Item_Page() { 
     11                $menu_item_ops = array('classname' => 'menu_item_page', 'description' => __('A WordPress page') ); 
     12                $this->WP_Menu_Item('page', __('Page'), $menu_item_ops); 
     13        } 
     14 
     15        function display( $args, $instance ) { 
     16                extract( $args ); 
     17 
     18                $title = $this->get_title($instance); 
     19 
     20                // TODO 
     21        } 
     22 
     23        function get_title($instance) { 
     24                return empty( $instance['title'] ) ? get_the_title($instance['page_id']) : $instance['title']; 
     25        } 
     26 
     27        function update( $new_instance, $old_instance ) { 
     28                $instance = $old_instance; 
     29                $instance['title'] = strip_tags($new_instance['title']); 
     30 
     31                return $instance; 
     32        } 
     33 
     34        function form( $instance ) { 
     35                $instance = wp_parse_args( (array) $instance, array( 'page_id' => 0, 'title' => '') ); 
     36 
     37                $page_id = absint( $instance['page_id'] ); 
     38 
     39                $title = esc_attr($this->get_title($instance)); 
     40        ?> 
     41                <input id="<?php echo $this->get_field_id('page_id'); ?>" name="<?php echo $this->get_field_name('page_id'); ?>" type="hidden" value="<?php echo $page_id; ?>" /> 
     42                <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p> 
     43<?php 
     44        } 
     45} 
     46 
     47 
     48/** 
     49 * Category menu item class 
     50 * 
     51 * @since 3.0 
     52 */ 
     53class WP_Menu_Item_Category extends WP_Menu_Item { 
     54 
     55        function WP_Menu_Item_Category() { 
     56                $menu_item_ops = array( 'classname' => 'menu_item_category', 'description' => __('A WordPress category') ); 
     57                $this->WP_Menu_Item('category', __('Category'), $menu_item_ops); 
     58        } 
     59 
     60        function display( $args, $instance ) { 
     61                extract( $args ); 
     62 
     63                $title = $this->get_title($instance); 
     64 
     65                // TODO 
     66        } 
     67 
     68        function get_title( $instance ) { 
     69                return empty( $instance['title'] ) ? get_term($category_id, 'category')->name : $instance['title']; 
     70        } 
     71 
     72        function update( $new_instance, $old_instance ) { 
     73                $instance = $old_instance; 
     74                $instance['title'] = strip_tags($new_instance['title']); 
     75 
     76                return $instance; 
     77        } 
     78 
     79        function form( $instance ) { 
     80                $instance = wp_parse_args( (array) $instance, array( 'category_id' => 0, 'title' => '') ); 
     81 
     82                $category_id = absint( $instance['category_id'] ); 
     83 
     84                $title = esc_attr($this->get_title($instance)); 
     85        ?> 
     86                <input id="<?php echo $this->get_field_id('category_id'); ?>" name="<?php echo $this->get_field_name('category_id'); ?>" type="hidden" value="<?php echo $category_id; ?>" /> 
     87                <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p> 
     88<?php 
     89        } 
     90} 
     91 
     92 
     93/** 
     94 * Home Menu Item class 
     95 * 
     96 * @since 3.0 
     97 */ 
     98class WP_Menu_Item_Home extends WP_Menu_Item { 
     99 
     100        function WP_Menu_Item_Home() { 
     101                $menu_item_ops = array('classname' => 'menu_item_home', 'description' => __('The site homepage') ); 
     102                $this->WP_Menu_Item('home', __('Home'), $menu_item_ops); 
     103        } 
     104 
     105        function display( $args, $instance ) { 
     106                extract($args); 
     107 
     108                $title = $this->get_title($instance); 
     109 
     110                echo '<a href="' . home_url() . '">' . $title . '</a>'; 
     111        } 
     112 
     113        function get_title( $instance ) { 
     114                return empty( $instance['title'] ) ? __('Home') : $instance['title']; 
     115        } 
     116 
     117        function update( $new_instance, $old_instance ) { 
     118                $instance = $old_instance; 
     119                $instance['title'] = strip_tags($new_instance['title']); 
     120 
     121                return $instance; 
     122        } 
     123 
     124        function form( $instance ) { 
     125                //Defaults 
     126                $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) ); 
     127                $title = esc_attr($this->get_title($instance)); 
     128        ?> 
     129                <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p> 
     130<?php 
     131        } 
     132} 
     133 
     134/** 
     135 * Link menu item class 
     136 * 
     137 * @since 3.0 
     138 */ 
     139class WP_Menu_Item_Link extends WP_Menu_Item { 
     140 
     141        function WP_Menu_Item_Link() { 
     142                $menu_item_ops = array('description' => __('An external link') ); 
     143                $this->WP_Menu_Item('link', __('Link'), $menu_item_ops); 
     144        } 
     145 
     146        function display( $args, $instance ) { 
     147                echo '<a href="' . esc_attr($instance['url']) . '">' . esc_html($instance['title']) . '</a>'; 
     148        } 
     149 
     150        function update( $new_instance, $old_instance ) { 
     151                $instance = $old_instance; 
     152                $instance['url'] = trim($new_instance['url']); 
     153                $instance['title'] = strip_tags($new_instance['title']); 
     154 
     155                return $instance; 
     156        } 
     157 
     158        function form( $instance ) { 
     159                //Defaults 
     160                $instance = wp_parse_args( (array) $instance, array( 'url' => '', 'title' => '' ) ); 
     161                $url = esc_attr( $instance['url'] ); 
     162                $title = esc_attr( $instance['title'] ); 
     163        ?> 
     164                <p><label for="<?php echo $this->get_field_id('url'); ?>"><?php _e('URL:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('url'); ?>" name="<?php echo $this->get_field_name('url'); ?>" type="text" value="<?php echo $url; ?>" /></p> 
     165                <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p> 
     166<?php 
     167        } 
     168} 
     169 
     170 
     171/** 
     172 * Register all of the default WordPress menu items on startup. 
     173 * 
     174 * Calls 'menu_items_init' action after all of the WordPress menu items have been 
     175 * registered. 
     176 * 
     177 * @since 3.0 
     178 */ 
     179function wp_menu_items_init() { 
     180        if ( !is_blog_installed() ) 
     181                return; 
     182 
     183        register_menu_item('WP_Menu_Item_Page'); 
     184        register_menu_item('WP_Menu_Item_Category'); 
     185        register_menu_item('WP_Menu_Item_Home'); 
     186        register_menu_item('WP_Menu_Item_Link'); 
     187 
     188        do_action('menu_items_init'); 
     189} 
     190 
     191add_action('init', 'wp_menu_items_init', 1); 
     192 
  • wp-includes/menus.php

     
     1<?php 
     2/** 
     3 * API for creating dynamic menus without hardcoding functionality into 
     4 * themes. Includes both internal WordPress routines and theme use routines. 
     5 * 
     6 * @link http://codex.wordpress.org/Plugins/WordPress_Menu_Items WordPress Menu_Items 
     7 * @link http://codex.wordpress.org/Plugins/WordPress_Menu_Items_Api Menu_Items API 
     8 * 
     9 * @package WordPress 
     10 * @subpackage Menus 
     11 */ 
     12 
     13/** 
     14 * This class must be extended for each menu item and WP_Menu_Item::menu_item(), WP_Menu_Item::update() 
     15 * and WP_Menu_Item::form() need to be over-ridden. 
     16 * 
     17 * @package WordPress 
     18 * @subpackage Menu_Items 
     19 * @since 3.0 
     20 */ 
     21class WP_Menu_Item { 
     22 
     23        var $id_base;                   // Root id for all menu_items of this type. 
     24        var $name;                              // Name for this menu_item type. 
     25        var $menu_item_options; // Option array passed to wp_register_menu_item() 
     26        var $control_options;   // Option array passed to wp_register_menu_item_control() 
     27 
     28        var $number = false;    // Unique ID number of the current instance. 
     29        var $id = false;                // Unique ID string of the current instance (id_base-number) 
     30        var $updated = false;   // Set true when we update the data after a POST submit - makes sure we don't do it twice. 
     31 
     32        // Member functions that you must over-ride. 
     33 
     34        /** Echo the menu_item content. 
     35         * 
     36         * Subclasses should over-ride this function to generate their menu_item code. 
     37         * 
     38         * @param array $args Display arguments including before_title, after_title, before_menu_item, and after_menu_item. 
     39         * @param array $instance The settings for the particular instance of the menu_item 
     40         */ 
     41        function output($args, $instance) { 
     42                die('function WP_Menu_Item::menu_item() must be over-ridden in a sub-class.'); 
     43        } 
     44 
     45        /** Update a particular instance. 
     46         * 
     47         * This function should check that $new_instance is set correctly. 
     48         * The newly calculated value of $instance should be returned. 
     49         * If "false" is returned, the instance won't be saved/updated. 
     50         * 
     51         * @param array $new_instance New settings for this instance as input by the user via form() 
     52         * @param array $old_instance Old settings for this instance 
     53         * @return array Settings to save or bool false to cancel saving 
     54         */ 
     55        function update($new_instance, $old_instance) { 
     56                return $new_instance; 
     57        } 
     58 
     59        /** Echo the settings update form 
     60         * 
     61         * @param array $instance Current settings 
     62         */ 
     63        function form($instance) { 
     64                echo '<p class="no-options-menu_item">' . __('There are no options for this menu item.') . '</p>'; 
     65                return 'noform'; 
     66        } 
     67 
     68        // Functions you'll need to call. 
     69 
     70        /** 
     71         * PHP4 constructor 
     72         */ 
     73        function WP_Menu_Item( $id_base = false, $name, $menu_item_options = array(), $control_options = array() ) { 
     74                $this->__construct( $id_base, $name, $menu_item_options, $control_options ); 
     75        } 
     76 
     77        /** 
     78         * PHP5 constructor 
     79         * 
     80         * @param string $id_base Optional Base ID for the menu_item, lower case, 
     81         * if left empty a portion of the menu_item's class name will be used. Has to be unique. 
     82         * @param string $name Name for the menu_item displayed on the configuration page. 
     83         * @param array $menu_item_options Optional Passed to wp_register_menu_item() 
     84         *       - description: shown on the configuration page 
     85         *       - classname 
     86         * @param array $control_options Optional Passed to wp_register_menu_item_control() 
     87         *       - width: required if more than 250px 
     88         *       - height: currently not used but may be needed in the future 
     89         */ 
     90        function __construct( $id_base = false, $name, $menu_item_options = array(), $control_options = array() ) { 
     91                $this->id_base = empty($id_base) ? preg_replace( '/(wp_)?menu_item_/', '', strtolower(get_class($this)) ) : strtolower($id_base); 
     92                $this->name = $name; 
     93                $this->option_name = 'menu_item_' . $this->id_base; 
     94                $this->menu_item_options = wp_parse_args( $menu_item_options, array('classname' => $this->option_name) ); 
     95                $this->control_options = wp_parse_args( $control_options, array('id_base' => $this->id_base) ); 
     96        } 
     97 
     98        /** 
     99         * Constructs name attributes for use in form() fields 
     100         * 
     101         * This function should be used in form() methods to create name attributes for fields to be saved by update() 
     102         * 
     103         * @param string $field_name Field name 
     104         * @return string Name attribute for $field_name 
     105         */ 
     106        function get_field_name($field_name) { 
     107                return 'menu-item-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']'; 
     108        } 
     109 
     110        /** 
     111         * Constructs id attributes for use in form() fields 
     112         * 
     113         * This function should be used in form() methods to create id attributes for fields to be saved by update() 
     114         * 
     115         * @param string $field_name Field name 
     116         * @return string ID attribute for $field_name 
     117         */ 
     118        function get_field_id($field_name) { 
     119                return 'menu-item-' . $this->id_base . '-' . $this->number . '-' . $field_name; 
     120        } 
     121 
     122        // Private Functions. Don't worry about these. 
     123 
     124        function _register() { 
     125                $settings = $this->get_settings(); 
     126                $empty = true; 
     127 
     128                if ( is_array($settings) ) { 
     129                        foreach ( array_keys($settings) as $number ) { 
     130                                if ( is_numeric($number) ) { 
     131                                        $this->_set($number); 
     132                                        $this->_register_one($number); 
     133                                        $empty = false; 
     134                                } 
     135                        } 
     136                } 
     137 
     138                if ( $empty ) { 
     139                        // If there are none, we register the menu_item's existance with a 
     140                        // generic template 
     141                        $this->_set(1); 
     142                        $this->_register_one(); 
     143                } 
     144        } 
     145 
     146        function _set($number) { 
     147                $this->number = $number; 
     148                $this->id = $this->id_base . '-' . $number; 
     149        } 
     150 
     151        function _get_display_callback() { 
     152                return array(&$this, 'display_callback'); 
     153        } 
     154 
     155        function _get_update_callback() { 
     156                return array(&$this, 'update_callback'); 
     157        } 
     158 
     159        function _get_form_callback() { 
     160                return array(&$this, 'form_callback'); 
     161        } 
     162 
     163        /** Generate the actual menu_item content. 
     164         *      Just finds the instance and calls output(). 
     165         *      Do NOT over-ride this function. */ 
     166        function display_callback( $args, $menu_item_args = 1 ) { 
     167                if ( is_numeric($menu_item_args) ) 
     168                        $menu_item_args = array( 'number' => $menu_item_args ); 
     169 
     170                $menu_item_args = wp_parse_args( $menu_item_args, array( 'number' => -1 ) ); 
     171                $this->_set( $menu_item_args['number'] ); 
     172                $instance = $this->get_settings(); 
     173 
     174                if ( array_key_exists( $this->number, $instance ) ) { 
     175                        $instance = $instance[$this->number]; 
     176                        // filters the menu_item's settings, return false to stop displaying the menu_item 
     177                        $instance = apply_filters('menu_item_display_callback', $instance, $this, $args); 
     178                        if ( false !== $instance ) 
     179                                $this->output($args, $instance); 
     180                } 
     181        } 
     182 
     183        /** Deal with changed settings. 
     184         *      Do NOT over-ride this function. */ 
     185        function update_callback( $menu_item_args = 1 ) { 
     186                global $wp_registered_menu_items; 
     187 
     188                if ( is_numeric($menu_item_args) ) 
     189                        $menu_item_args = array( 'number' => $menu_item_args ); 
     190 
     191                $menu_item_args = wp_parse_args( $menu_item_args, array( 'number' => -1 ) ); 
     192                $all_instances = $this->get_settings(); 
     193 
     194                // We need to update the data 
     195                if ( $this->updated ) 
     196                        return; 
     197 
     198                $wp_menu_items = wp_get_menu_items(); 
     199 
     200                if ( isset($_POST['delete_menu_item']) && $_POST['delete_menu_item'] ) { 
     201                        // Delete the settings for this instance of the menu_item 
     202                        if ( isset($_POST['the-menu-item-id']) ) 
     203                                $del_id = $_POST['the-menu-item-id']; 
     204                        else 
     205                                return; 
     206 
     207                        if ( isset($wp_registered_menu_items[$del_id]['params'][0]['number']) ) { 
     208                                $number = $wp_registered_menu_items[$del_id]['params'][0]['number']; 
     209 
     210                                if ( $this->id_base . '-' . $number == $del_id ) 
     211                                        unset($all_instances[$number]); 
     212                        } 
     213                } else { 
     214                        if ( isset($_POST['menu-item-' . $this->id_base]) && is_array($_POST['menu-item-' . $this->id_base]) ) { 
     215                                $settings = $_POST['menu-item-' . $this->id_base]; 
     216                        } elseif ( isset($_POST['id_base']) && $_POST['id_base'] == $this->id_base ) { 
     217                                $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['menu_item_number']; 
     218                                $settings = array( $num => array() ); 
     219                        } else { 
     220                                return; 
     221                        } 
     222 
     223                        foreach ( $settings as $number => $new_instance ) { 
     224                                $new_instance = stripslashes_deep($new_instance); 
     225                                $this->_set($number); 
     226 
     227                                $old_instance = isset($all_instances[$number]) ? $all_instances[$number] : array(); 
     228 
     229                                $instance = $this->update($new_instance, $old_instance); 
     230 
     231                                // filters the menu_item's settings before saving, return false to cancel saving (keep the old settings if updating) 
     232                                $instance = apply_filters('menu_item_update_callback', $instance, $new_instance, $old_instance, $this); 
     233                                if ( false !== $instance ) 
     234                                        $all_instances[$number] = $instance; 
     235 
     236                                break; // run only once 
     237                        } 
     238                } 
     239 
     240                $this->save_settings($all_instances); 
     241                $this->updated = true; 
     242        } 
     243 
     244        /** Generate the control form. 
     245         *      Do NOT over-ride this function. */ 
     246        function form_callback( $menu_item_args = 1 ) { 
     247                if ( is_numeric($menu_item_args) ) 
     248                        $menu_item_args = array( 'number' => $menu_item_args ); 
     249 
     250                $menu_item_args = wp_parse_args( $menu_item_args, array( 'number' => -1 ) ); 
     251                $all_instances = $this->get_settings(); 
     252 
     253                if ( -1 == $menu_item_args['number'] ) { 
     254                        // We echo out a form where 'number' can be set later 
     255                        $this->_set('__i__'); 
     256                        $instance = array(); 
     257                } else { 
     258                        $this->_set($menu_item_args['number']); 
     259                        $instance = $all_instances[ $menu_item_args['number'] ]; 
     260                } 
     261 
     262                // filters the menu_item admin form before displaying, return false to stop displaying it 
     263                $instance = apply_filters('menu_item_form_callback', $instance, $this); 
     264 
     265                $return = null; 
     266                if ( false !== $instance ) { 
     267                        $return = $this->form($instance); 
     268                        // add extra fields in the menu_item form - be sure to set $return to null if you add any 
     269                        // if the menu_item has no form the text echoed from the default form method can be hidden using css 
     270                        do_action_ref_array( 'in_menu_item_form', array(&$this, &$return, $instance) ); 
     271                } 
     272                return $return; 
     273        } 
     274 
     275        /** Helper function: Registers a single instance. */ 
     276        function _register_one($number = -1) { 
     277                wp_register_menu_item(  $this->id, $this->name, $this->_get_display_callback(), $this->menu_item_options, array( 'number' => $number ) ); 
     278                _register_menu_item_update_callback( $this->id_base, $this->_get_update_callback(), $this->control_options, array( 'number' => -1 ) ); 
     279                _register_menu_item_form_callback(      $this->id, $this->name, $this->_get_form_callback(), $this->control_options, array( 'number' => $number ) ); 
     280        } 
     281 
     282        function save_settings($settings) { 
     283                update_option( $this->option_name, $settings ); 
     284        } 
     285 
     286        function get_settings() { 
     287                $settings = get_option($this->option_name); 
     288 
     289                if ( false === $settings && isset($this->alt_option_name) ) 
     290                        $settings = get_option($this->alt_option_name); 
     291 
     292                if ( !is_array($settings) ) 
     293                        $settings = array(); 
     294 
     295                unset($settings['__i__']); 
     296                return $settings; 
     297        } 
     298} 
     299 
     300/** 
     301 * Singleton that registers and instantiates WP_Menu_Item classes. 
     302 * 
     303 * @package WordPress 
     304 * @subpackage Menu_Items 
     305 * @since 3.0 
     306 */ 
     307class WP_Menu_Item_Factory { 
     308        var $menu_items = array(); 
     309 
     310        function WP_Menu_Item_Factory() { 
     311                add_action( 'menu_items_init', array( &$this, '_register_menu_items' ), 100 ); 
     312        } 
     313 
     314        function register($menu_item_class) { 
     315                $this->menu_items[$menu_item_class] = & new $menu_item_class(); 
     316        } 
     317 
     318        function unregister($menu_item_class) { 
     319                if ( isset($this->menu_items[$menu_item_class]) ) 
     320                        unset($this->menu_items[$menu_item_class]); 
     321        } 
     322 
     323        function _register_menu_items() { 
     324                global $wp_registered_menu_items; 
     325                $keys = array_keys($this->menu_items); 
     326                $registered = array_keys($wp_registered_menu_items); 
     327                $registered = array_map('_get_menu_item_id_base', $registered); 
     328 
     329                foreach ( $keys as $key ) { 
     330                        // don't register new menu_item if old menu_item with the same id is already registered 
     331                        if ( in_array($this->menu_items[$key]->id_base, $registered, true) ) { 
     332                                unset($this->menu_items[$key]); 
     333                                continue; 
     334                        } 
     335 
     336                        $this->menu_items[$key]->_register(); 
     337                } 
     338        } 
     339} 
     340 
     341/* Global Variables */ 
     342 
     343/** @ignore */ 
     344global $wp_registered_menus, $wp_registered_menu_items, $wp_registered_menu_item_controls, $wp_registered_menu_item_updates; 
     345 
     346/** 
     347 * Stores the menus, since many themes can have more than one. 
     348 * 
     349 * @global array $wp_registered_menus 
     350 * @since 3.0.0 
     351 */ 
     352$wp_registered_menus = array(); 
     353 
     354/** 
     355 * Stores the registered menu_items. 
     356 * 
     357 * @global array $wp_registered_menu_items 
     358 * @since 3.0.0 
     359 */ 
     360$wp_registered_menu_items = array(); 
     361 
     362/** 
     363 * Stores the registered menu_item control (options). 
     364 * 
     365 * @global array $wp_registered_menu_item_controls 
     366 * @since 3.0.0 
     367 */ 
     368$wp_registered_menu_item_controls = array(); 
     369$wp_registered_menu_item_updates = array(); 
     370 
     371/** 
     372 * Private 
     373 */ 
     374$_wp_menu_items = array(); 
     375 
     376/* Template tags & API functions */ 
     377 
     378/** 
     379 * Register a menu_item 
     380 * 
     381 * Registers a WP_Menu_Item menu_item 
     382 * 
     383 * @since 3.0.0 
     384 * 
     385 * @see WP_Menu_Item 
     386 * @see WP_Menu_Item_Factory 
     387 * @uses WP_Menu_Item_Factory 
     388 * 
     389 * @param string $menu_item_class The name of a class that extends WP_Menu_Item 
     390 */ 
     391function register_menu_item($menu_item_class) { 
     392        global $wp_menu_item_factory; 
     393 
     394        $wp_menu_item_factory->register($menu_item_class); 
     395} 
     396 
     397/** 
     398 * Unregister a menu_item 
     399 * 
     400 * Unregisters a WP_Menu_Item menu_item. Useful for unregistering default menu_items. 
     401 * Run within a function hooked to the menu_items_init action. 
     402 * 
     403 * @since 3.0.0 
     404 * 
     405 * @see WP_Menu_Item 
     406 * @see WP_Menu_Item_Factory 
     407 * @uses WP_Menu_Item_Factory 
     408 * 
     409 * @param string $menu_item_class The name of a class that extends WP_Menu_Item 
     410 */ 
     411function unregister_menu_item($menu_item_class) { 
     412        global $wp_menu_item_factory; 
     413 
     414        $wp_menu_item_factory->unregister($menu_item_class); 
     415} 
     416 
     417/** 
     418 * Creates multiple menus. 
     419 * 
     420 * If you wanted to quickly create multiple menus for a theme or internally. 
     421 * This function will allow you to do so. If you don't pass the 'name' and/or 
     422 * 'id' in $args, then they will be built for you. 
     423 * 
     424 * The default for the name is "Menu #", with '#' being replaced with the 
     425 * number the menu is currently when greater than one. If first menu, the 
     426 * name will be just "Menu". The default for id is "menu-" followed by the 
     427 * number the menu creation is currently at. 
     428 * 
     429 * @since 3.0.0 
     430 * 
     431 * @see register_menu() The second parameter is documented by register_menu() and is the same here. 
     432 * @uses parse_str() Converts a string to an array to be used in the rest of the function. 
     433 * @uses register_menu() Sends single menu information [name, id] to this 
     434 *      function to handle building the menu. 
     435 * 
     436 * @param int $number Number of menus to create. 
     437 * @param string|array $args Builds Menu based off of 'name' and 'id' values. 
     438 */ 
     439function register_menus($number = 1, $args = array()) { 
     440        global $wp_registered_menus; 
     441        $number = (int) $number; 
     442 
     443        if ( is_string($args) ) 
     444                parse_str($args, $args); 
     445 
     446        for ( $i=1; $i <= $number; $i++ ) { 
     447                $_args = $args; 
     448 
     449                if ( $number > 1 ) { 
     450                        $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Menu %d'), $i); 
     451                } else { 
     452                        $_args['name'] = isset($args['name']) ? $args['name'] : __('Menu'); 
     453                } 
     454 
     455                if ( !isset($args['id']) ) { 
     456                        $n = count($wp_registered_menus); 
     457                        do { 
     458                                $n++; 
     459                                $_args['id'] = "menu-$n"; 
     460                        } while (isset($wp_registered_menus[$_args['id']])); 
     461                } 
     462 
     463                register_menu($_args); 
     464        } 
     465} 
     466 
     467/** 
     468 * Builds the definition for a single menu and returns the ID. 
     469 * 
     470 * The $args parameter takes either a string or an array with 'name' and 'id' 
     471 * contained in either usage. It will be noted that the values will be applied 
     472 * to all menus, so if creating more than one, it will be advised to allow 
     473 * for WordPress to create the defaults for you. 
     474 * 
     475 * Example for string would be <code>'name=whatever;id=whatever1'</code> and for 
     476 * the array it would be <code>array( 
     477 *    'name' => 'whatever', 
     478 *    'id' => 'whatever1')</code>. 
     479 * 
     480 * name - The name of the menu, which presumably the title which will be 
     481 *     displayed. 
     482 * id - The unique identifier by which the menu will be called by. 
     483 * before_menu_item - The content that will prepended to the menu_items when they are 
     484 *     displayed. 
     485 * after_menu_item - The content that will be appended to the menu_items when they are 
     486 *     displayed. 
     487 * before_title - The content that will be prepended to the title when displayed. 
     488 * after_title - the content that will be appended to the title when displayed. 
     489 * 
     490 * <em>Content</em> is assumed to be HTML and should be formatted as such, but 
     491 * doesn't have to be. 
     492 * 
     493 * @since 3.0.0 
     494 * @uses $wp_registered_menus Stores the new menu in this array by menu ID. 
     495 * @uses parse_str() Converts a string to an array to be used in the rest of the function. 
     496 * @usedby register_menus() 
     497 * 
     498 * @param string|array $args Builds Menu based off of 'name' and 'id' values 
     499 * @return string The menu id that was added. 
     500 */ 
     501function register_menu($args = array()) { 
     502        global $wp_registered_menus; 
     503 
     504        $i = count($wp_registered_menus) + 1; 
     505 
     506        $defaults = array( 
     507                'name' => sprintf(__('Menu %d'), $i ), 
     508                'id' => "menu-$i", 
     509                'description' => '', 
     510                'before_menu' => '<ul id="%1$s" class="menu %2$s">', 
     511                'after_menu' => "</ul>\n", 
     512        ); 
     513 
     514        $menu = wp_parse_args($args, $defaults); 
     515 
     516        $wp_registered_menus[$menu['id']] = $menu; 
     517 
     518        return $menu['id']; 
     519} 
     520 
     521/** 
     522 * Removes a menu from the list. 
     523 * 
     524 * @since 3.0.0 
     525 * 
     526 * @uses $wp_registered_menus Stores the new menu in this array by menu ID. 
     527 * 
     528 * @param string $name The ID of the menu when it was added. 
     529 */ 
     530function unregister_menu( $name ) { 
     531        global $wp_registered_menus; 
     532 
     533        if ( isset( $wp_registered_menus[$name] ) ) 
     534                unset( $wp_registered_menus[$name] ); 
     535} 
     536 
     537/** 
     538 * Register menu_item for use in menus. 
     539 * 
     540 * The default menu_item option is 'classname' that can be override. 
     541 * 
     542 * The function can also be used to unregister menu_items when $output_callback 
     543 * parameter is an empty string. 
     544 * 
     545 * @since 3.0.0 
     546 * 
     547 * @uses $wp_registered_menu_items Uses stored registered menu_items. 
     548 * @uses $wp_register_menu_item_defaults Retrieves menu_item defaults. 
     549 * 
     550 * @param int|string $id Menu_Item ID. 
     551 * @param string $name Menu_Item display title. 
     552 * @param callback $output_callback Run when menu_item is called. 
     553 * @param array|string Optional. $options Menu_Item Options. 
     554 * @param mixed $params,... Menu_Item parameters to add to menu_item. 
     555 * @return null Will return if $output_callback is empty after removing menu_item. 
     556 */ 
     557function wp_register_menu_item($id, $name, $output_callback, $options = array()) { 
     558        global $wp_registered_menu_items, $wp_registered_menu_item_controls, $wp_registered_menu_item_updates; 
     559 
     560        $id = strtolower($id); 
     561 
     562        if ( empty($output_callback) ) { 
     563                unset($wp_registered_menu_items[$id]); 
     564                return; 
     565        } 
     566 
     567        $id_base = _get_menu_item_id_base($id); 
     568        if ( !is_callable($output_callback) ) { 
     569                if ( isset($wp_registered_menu_item_controls[$id]) ) 
     570                        unset($wp_registered_menu_item_controls[$id]); 
     571 
     572                if ( isset($wp_registered_menu_item_updates[$id_base]) ) 
     573                        unset($wp_registered_menu_item_updates[$id_base]); 
     574 
     575                return; 
     576        } 
     577 
     578        $defaults = array('classname' => $output_callback); 
     579        $options = wp_parse_args($options, $defaults); 
     580        $menu_item = array( 
     581                'name' => $name, 
     582                'id' => $id, 
     583                'callback' => $output_callback, 
     584                'params' => array_slice(func_get_args(), 4) 
     585        ); 
     586        $menu_item = array_merge($menu_item, $options); 
     587 
     588        if ( is_callable($output_callback) && ( !isset($wp_registered_menu_items[$id]) || did_action( 'menu_items_init' ) ) ) 
     589                $wp_registered_menu_items[$id] = $menu_item; 
     590} 
     591 
     592/** 
     593 * Retrieve description for menu_item. 
     594 * 
     595 * When registering menu_items, the options can also include 'description' that 
     596 * describes the menu_item for display on the menu_item administration panel or 
     597 * in the theme. 
     598 * 
     599 * @since 3.0.0 
     600 * 
     601 * @param int|string $id Menu_Item ID. 
     602 * @return string Menu_Item description, if available. Null on failure to retrieve description. 
     603 */ 
     604function wp_menu_item_description( $id ) { 
     605        if ( !is_scalar($id) ) 
     606                return; 
     607 
     608        global $wp_registered_menu_items; 
     609 
     610        if ( isset($wp_registered_menu_items[$id]['description']) ) 
     611                return esc_html( $wp_registered_menu_items[$id]['description'] ); 
     612} 
     613 
     614/** 
     615 * Retrieve description for a menu. 
     616 * 
     617 * When registering menus a 'description' parameter can be included that 
     618 * describes the menu for display on the menu_item administration panel. 
     619 * 
     620 * @since 3.0.0 
     621 * 
     622 * @param int|string $id menu ID. 
     623 * @return string Menu description, if available. Null on failure to retrieve description. 
     624 */ 
     625function wp_menu_description( $id ) { 
     626        if ( !is_scalar($id) ) 
     627                return; 
     628 
     629        global $wp_registered_menus; 
     630 
     631        if ( isset($wp_registered_menus[$id]['description']) ) 
     632                return esc_html( $wp_registered_menus[$id]['description'] ); 
     633} 
     634 
     635 
     636/** 
     637 * Remove menu_item from menu. 
     638 * 
     639 * @since 3.0.0 
     640 * 
     641 * @param int|string $id Menu_Item ID. 
     642 */ 
     643function wp_unregister_menu_item($id) { 
     644        wp_register_menu_item($id, '', ''); 
     645        wp_unregister_menu_item_control($id); 
     646} 
     647 
     648/** 
     649 * Registers menu_item control callback for customizing options. 
     650 * 
     651 * The options contains the 'height', 'width', and 'id_base' keys. The 'height' 
     652 * option is never used. The 'width' option is the width of the fully expanded 
     653 * control form, but try hard to use the default width. The 'id_base' is for 
     654 * multi-menu_items (menu_items which allow multiple instances such as the text 
     655 * menu_item), an id_base must be provided. The menu_item id will end up looking like 
     656 * {$id_base}-{$unique_number}. 
     657 * 
     658 * @since 3.0.0 
     659 * 
     660 * @param int|string $id Menu ID. 
     661 * @param string $name Menu display name. 
     662 * @param callback $control_callback Run when menu is displayed. 
     663 * @param array|string $options Optional. Menu_Item options. See above long description. 
     664 * @param mixed $params,... Optional. Additional parameters to add to menu_item. 
     665 */ 
     666function wp_register_menu_item_control($id, $name, $control_callback, $options = array()) { 
     667        global $wp_registered_menu_item_controls, $wp_registered_menu_item_updates, $wp_registered_menu_items; 
     668 
     669        $id = strtolower($id); 
     670        $id_base = _get_menu_item_id_base($id); 
     671 
     672        if ( empty($control_callback) ) { 
     673                unset($wp_registered_menu_item_controls[$id]); 
     674                unset($wp_registered_menu_item_updates[$id_base]); 
     675                return; 
     676        } 
     677 
     678        if ( !is_callable($control_callback) ) { 
     679                if ( isset($wp_registered_menu_items[$id]) ) 
     680                        unset($wp_registered_menu_items[$id]); 
     681 
     682                return; 
     683        } 
     684 
     685        if ( isset($wp_registered_menu_item_controls[$id]) && !did_action( 'menu_items_init' ) ) 
     686                return; 
     687 
     688        $defaults = array('width' => 250, 'height' => 200 ); // height is never used 
     689        $options = wp_parse_args($options, $defaults); 
     690        $options['width'] = (int) $options['width']; 
     691        $options['height'] = (int) $options['height']; 
     692 
     693        $menu_item = array( 
     694                'name' => $name, 
     695                'id' => $id, 
     696                'callback' => $control_callback, 
     697                'params' => array_slice(func_get_args(), 4) 
     698        ); 
     699        $menu_item = array_merge($menu_item, $options); 
     700 
     701        $wp_registered_menu_item_controls[$id] = $menu_item; 
     702 
     703        if ( isset($wp_registered_menu_item_updates[$id_base]) ) 
     704                return; 
     705 
     706        if ( isset($menu_item['params'][0]['number']) ) 
     707                $menu_item['params'][0]['number'] = -1; 
     708 
     709        unset($menu_item['width'], $menu_item['height'], $menu_item['name'], $menu_item['id']); 
     710        $wp_registered_menu_item_updates[$id_base] = $menu_item; 
     711} 
     712 
     713function _register_menu_item_update_callback($id_base, $update_callback, $options = array()) { 
     714        global $wp_registered_menu_item_updates; 
     715 
     716        if ( isset($wp_registered_menu_item_updates[$id_base]) ) { 
     717                if ( empty($update_callback) ) 
     718                        unset($wp_registered_menu_item_updates[$id_base]); 
     719                return; 
     720        } 
     721 
     722        $menu_item = array( 
     723                'callback' => $update_callback, 
     724                'params' => array_slice(func_get_args(), 3) 
     725        ); 
     726 
     727        $menu_item = array_merge($menu_item, $options); 
     728        $wp_registered_menu_item_updates[$id_base] = $menu_item; 
     729} 
     730 
     731function _register_menu_item_form_callback($id, $name, $form_callback, $options = array()) { 
     732        global $wp_registered_menu_item_controls; 
     733 
     734        $id = strtolower($id); 
     735 
     736        if ( empty($form_callback) ) { 
     737                unset($wp_registered_menu_item_controls[$id]); 
     738                return; 
     739        } 
     740 
     741        if ( isset($wp_registered_menu_item_controls[$id]) && !did_action( 'menu_items_init' ) ) 
     742                return; 
     743 
     744        $defaults = array('width' => 250, 'height' => 200 ); 
     745        $options = wp_parse_args($options, $defaults); 
     746        $options['width'] = (int) $options['width']; 
     747        $options['height'] = (int) $options['height']; 
     748 
     749        $menu_item = array( 
     750                'name' => $name, 
     751                'id' => $id, 
     752                'callback' => $form_callback, 
     753                'params' => array_slice(func_get_args(), 4) 
     754        ); 
     755        $menu_item = array_merge($menu_item, $options); 
     756 
     757        $wp_registered_menu_item_controls[$id] = $menu_item; 
     758} 
     759 
     760/** 
     761 * Remove control callback for menu_item. 
     762 * 
     763 * @since 3.0.0 
     764 * @uses wp_register_menu_item_control() Unregisters by using empty callback. 
     765 * 
     766 * @param int|string $id Menu_Item ID. 
     767 */ 
     768function wp_unregister_menu_item_control($id) { 
     769        return wp_register_menu_item_control($id, '', ''); 
     770} 
     771 
     772/** 
     773 * Display dynamic menu. 
     774 * 
     775 * By default it displays the default menu or 'menu-1'. The 'menu-1' is 
     776 * not named by the theme, the actual name is '1', but 'menu-' is added to 
     777 * the registered menus for the name. If you named your menu 'after-post', 
     778 * then the parameter $index will still be 'after-post', but the lookup will be 
     779 * for 'menu-after-post'. 
     780 * 
     781 * It is confusing for the $index parameter, but just know that it should just 
     782 * work. When you register the menu in the theme, you will use the same name 
     783 * for this function or "Pay no heed to the man behind the curtain." Just accept 
     784 * it as an oddity of WordPress menu register and display. 
     785 * 
     786 * @since 3.0.0 
     787 * 
     788 * @param int|string $index Optional, default is 1. Name or ID of dynamic menu. 
     789 * @return bool True, if menu_item menu was found and called. False if not found or not called. 
     790 */ 
     791function dynamic_menu($index = 1) { 
     792        global $wp_registered_menus, $wp_registered_menu_items; 
     793 
     794        if ( is_int($index) ) { 
     795                $index = "menu-$index"; 
     796        } else { 
     797                $index = sanitize_title($index); 
     798                foreach ( (array) $wp_registered_menus as $key => $value ) { 
     799                        if ( sanitize_title($value['name']) == $index ) { 
     800                                $index = $key; 
     801                                break; 
     802                        } 
     803                } 
     804        } 
     805 
     806        $wp_menu_items = wp_get_menu_items(); 
     807 
     808        if ( empty($wp_registered_menus[$index]) || !array_key_exists($index, $wp_menu_items) || !is_array($wp_menu_items[$index]) || empty($wp_menu_items[$index]) ) 
     809                return false; 
     810 
     811        $menu = $wp_registered_menus[$index]; 
     812 
     813        $did_one = false; 
     814        foreach ( (array) $wp_menu_items[$index] as $id ) { 
     815 
     816                if ( !isset($wp_registered_menu_items[$id]) ) continue; 
     817 
     818                $params = array_merge( 
     819                        array( array_merge( $menu, array('menu_item_id' => $id, 'menu_item_name' => $wp_registered_menu_items[$id]['name']) ) ), 
     820                        (array) $wp_registered_menu_items[$id]['params'] 
     821                ); 
     822 
     823                // Substitute HTML id and class attributes into before_menu_item 
     824                $classname_ = ''; 
     825                foreach ( (array) $wp_registered_menu_items[$id]['classname'] as $cn ) { 
     826                        if ( is_string($cn) ) 
     827                                $classname_ .= '_' . $cn; 
     828                        elseif ( is_object($cn) ) 
     829                                $classname_ .= '_' . get_class($cn); 
     830                } 
     831                $classname_ = ltrim($classname_, '_'); 
     832                $params[0]['before_menu_item'] = sprintf($params[0]['before_menu'], $id, $classname_); 
     833 
     834                $params = apply_filters( 'dynamic_menu_params', $params ); 
     835 
     836                $callback = $wp_registered_menu_items[$id]['callback']; 
     837 
     838                if ( is_callable($callback) ) { 
     839                        call_user_func_array($callback, $params); 
     840                        $did_one = true; 
     841                } 
     842        } 
     843 
     844        return $did_one; 
     845} 
     846 
     847/** 
     848 * Whether menu_item is displayied on the front-end. 
     849 * 
     850 * Either $callback or $id_base can be used 
     851 * $id_base is the first argument when extending WP_Menu_Item class 
     852 * Without the optional $menu_item_id parameter, returns the ID of the first menu 
     853 * in which the first instance of the menu_item with the given callback or $id_base is found. 
     854 * With the $menu_item_id parameter, returns the ID of the menu where 
     855 * the menu_item with that callback/$id_base AND that ID is found. 
     856 * 
     857 * NOTE: $menu_item_id and $id_base are the same for single menu_items. To be effective 
     858 * this function has to run after menu_items have initialized, at action 'init' or later. 
     859 * 
     860 * @since 3.0.0 
     861 * 
     862 * @param callback Optional, Menu_Item callback to check. 
     863 * @param int $menu_item_id Optional, but needed for checking. Menu_Item ID. 
     864 * @param string $id_base Optional, the base ID of a menu_item created by extending WP_Menu_Item. 
     865 * @param bool $skip_inactive Optional, whether to check in 'wp_inactive_menu_items'. 
     866 * @return mixed false if menu_item is not active or id of menu in which the menu_item is active. 
     867 */ 
     868function is_active_menu_item($callback = false, $menu_item_id = false, $id_base = false, $skip_inactive = true) { 
     869        global $wp_registered_menu_items; 
     870 
     871        $wp_menu_items = wp_get_menu_items(); 
     872 
     873        if ( is_array($wp_menu_items) ) { 
     874                foreach ( $wp_menu_items as $menu => $menu_items ) { 
     875                        if ( $skip_inactive && 'wp_inactive_menu_items' == $menu ) 
     876                                continue; 
     877 
     878                        if ( is_array($menu_items) ) { 
     879                                foreach ( $menu_items as $menu_item ) { 
     880                                        if ( ( $callback && isset($wp_registered_menu_items[$menu_item]['callback']) && $wp_registered_menu_items[$menu_item]['callback'] == $callback ) || ( $id_base && _get_menu_item_id_base($menu_item) == $id_base ) ) { 
     881                                                if ( !$menu_item_id || $menu_item_id == $wp_registered_menu_items[$menu_item]['id'] ) 
     882                                                        return $menu; 
     883                                        } 
     884                                } 
     885                        } 
     886                } 
     887        } 
     888        return false; 
     889} 
     890 
     891/** 
     892 * Whether the dynamic menu is enabled and used by theme. 
     893 * 
     894 * @since 3.0.0 
     895 * 
     896 * @return bool True, if using menu_items. False, if not using menu_items. 
     897 */ 
     898function is_dynamic_menu() { 
     899        global $wp_registered_menu_items, $wp_registered_menus; 
     900        $wp_menu_items = get_option('wp_menu_items'); 
     901        foreach ( (array) $wp_registered_menus as $index => $menu ) { 
     902                if ( count($wp_menu_items[$index]) ) { 
     903                        foreach ( (array) $wp_menu_items[$index] as $menu_item ) 
     904                                if ( array_key_exists($menu_item, $wp_registered_menu_items) ) 
     905                                        return true; 
     906                } 
     907        } 
     908        return false; 
     909} 
     910 
     911/** 
     912 * Whether a menu is in use. 
     913 * 
     914 * @since 3.0 
     915 * 
     916 * @param mixed $index, menu name, id or number to check. 
     917 * @return bool true if the menu is in use, false otherwise. 
     918 */ 
     919function is_active_menu( $index ) { 
     920        $index = ( is_int($index) ) ? "menu-$index" : sanitize_title($index); 
     921        $wp_menu_items = wp_get_menu_items(); 
     922        if ( isset($wp_menu_items[$index]) && !empty($wp_menu_items[$index]) ) 
     923                return true; 
     924 
     925        return false; 
     926} 
     927 
     928/* Internal Functions */ 
     929 
     930/** 
     931 * Retrieve full list of menus and their menu_items. 
     932 * 
     933 * Will upgrade menu menu_item list, if needed. Will also save updated list, if 
     934 * needed. 
     935 * 
     936 * @since 3.0.0 
     937 * @access private 
     938 * 
     939 * @return array Upgraded list of menu_items to version 3 array format when called from the admin. 
     940 */ 
     941function wp_get_menu_items() { 
     942        global $wp_registered_menu_items, $wp_registered_menus, $_wp_menu_items; 
     943 
     944        // If loading from front page, consult $_wp_menu_items rather than options 
     945        // to see if wp_convert_menu_item_settings() has made manipulations in memory. 
     946        if ( !is_admin() ) { 
     947                if ( empty($_wp_menu_items) ) 
     948                        $_wp_menu_items = get_option('wp_menu_items', array()); 
     949 
     950                $wp_menu_items = $_wp_menu_items; 
     951        } else { 
     952                $wp_menu_items = get_option('wp_menu_items', array()); 
     953                $_wp_menu_items = array(); 
     954 
     955                if ( isset($wp_menu_items['wp_inactive_menu_items']) || empty($wp_menu_items) ) 
     956                        $wp_menu_items['array_version'] = 3; 
     957                elseif ( !isset($wp_menu_items['array_version']) ) 
     958                        $wp_menu_items['array_version'] = 1; 
     959 
     960                switch ( $wp_menu_items['array_version'] ) { 
     961                        case 1 : 
     962                                foreach ( (array) $wp_menu_items as $index => $menu ) 
     963                                if ( is_array($menu) ) 
     964                                foreach ( (array) $menu as $i => $name ) { 
     965                                        $id = strtolower($name); 
     966                                        if ( isset($wp_registered_menu_items[$id]) ) { 
     967                                                $_wp_menu_items[$index][$i] = $id; 
     968                                                continue; 
     969                                        } 
     970                                        $id = sanitize_title($name); 
     971                                        if ( isset($wp_registered_menu_items[$id]) ) { 
     972                                                $_wp_menu_items[$index][$i] = $id; 
     973                                                continue; 
     974                                        } 
     975 
     976                                        $found = false; 
     977 
     978                                        foreach ( $wp_registered_menu_items as $menu_item_id => $menu_item ) { 
     979                                                if ( strtolower($menu_item['name']) == strtolower($name) ) { 
     980                                                        $_wp_menu_items[$index][$i] = $menu_item['id']; 
     981                                                        $found = true; 
     982                                                        break; 
     983                                                } elseif ( sanitize_title($menu_item['name']) == sanitize_title($name) ) { 
     984                                                        $_wp_menu_items[$index][$i] = $menu_item['id']; 
     985                                                        $found = true; 
     986                                                        break; 
     987                                                } 
     988                                        } 
     989 
     990                                        if ( $found ) 
     991                                                continue; 
     992 
     993                                        unset($_wp_menu_items[$index][$i]); 
     994                                } 
     995                                $_wp_menu_items['array_version'] = 2; 
     996                                $wp_menu_items = $_wp_menu_items; 
     997                                unset($_wp_menu_items); 
     998 
     999                        case 2 : 
     1000                                $menus = array_keys( $wp_registered_menus ); 
     1001                                if ( !empty( $menus ) ) { 
     1002                                        // Move the known-good ones first 
     1003                                        foreach ( (array) $menus as $id ) { 
     1004                                                if ( array_key_exists( $id, $wp_menu_items ) ) { 
     1005                                                        $_wp_menu_items[$id] = $wp_menu_items[$id]; 
     1006                                                        unset($wp_menu_items[$id], $menus[$id]); 
     1007                                                } 
     1008                                        } 
     1009 
     1010                                        // move the rest to wp_inactive_menu_items 
     1011                                        if ( !isset($_wp_menu_items['wp_inactive_menu_items']) ) 
     1012                                                $_wp_menu_items['wp_inactive_menu_items'] = array(); 
     1013 
     1014                                        if ( !empty($wp_menu_items) ) { 
     1015                                                foreach ( $wp_menu_items as $lost => $val ) { 
     1016                                                        if ( is_array($val) ) 
     1017                                                                $_wp_menu_items['wp_inactive_menu_items'] = array_merge( (array) $_wp_menu_items['wp_inactive_menu_items'], $val ); 
     1018                                                } 
     1019                                        } 
     1020 
     1021                                        $wp_menu_items = $_wp_menu_items; 
     1022                                        unset($_wp_menu_items); 
     1023                                } 
     1024                } 
     1025        } 
     1026 
     1027        if ( isset($wp_menu_items['array_version']) ) 
     1028                unset($wp_menu_items['array_version']); 
     1029 
     1030        $wp_menu_items = apply_filters('wp_menu_items', $wp_menu_items); 
     1031        return $wp_menu_items; 
     1032} 
     1033 
     1034/** 
     1035 * Set the menu menu_item option to update menus. 
     1036 * 
     1037 * @since 3.0.0 
     1038 * @access private 
     1039 * 
     1040 * @param array $wp_menu_items Menu menu_items and their settings. 
     1041 */ 
     1042function wp_set_menu_items( $wp_menu_items ) { 
     1043        if ( !isset( $wp_menu_items['array_version'] ) ) 
     1044                $wp_menu_items['array_version'] = 3; 
     1045        update_option( 'wp_menu_items', $wp_menu_items ); 
     1046} 
     1047 
     1048/** 
     1049 * Retrieve default registered menus list. 
     1050 * 
     1051 * @since 3.0.0 
     1052 * @access private 
     1053 * 
     1054 * @return array 
     1055 */ 
     1056function wp_get_menu_item_defaults() { 
     1057        global $wp_registered_menus; 
     1058 
     1059        $defaults = array(); 
     1060 
     1061        foreach ( (array) $wp_registered_menus as $index => $menu ) 
     1062                $defaults[$index] = array(); 
     1063 
     1064        return $defaults; 
     1065} 
     1066 
     1067/** 
     1068 * Private 
     1069 */ 
     1070function _get_menu_item_id_base($id) { 
     1071        return preg_replace( '/-[0-9]+$/', '', $id ); 
     1072} 
     1073 
     1074// Initialization code 
     1075 
     1076/*ignore*/ 
     1077global $wp_menu_item_factory; 
     1078 
     1079/** 
     1080 * WordPress Menu Item Factory Object 
     1081 * @global object $wp_menu_item_factory 
     1082 * @since 3.0 
     1083 */ 
     1084$wp_menu_item_factory =& new WP_Menu_Item_Factory(); 
     1085 
  • wp-includes/script-loader.php

     
    326326                $scripts->add( 'admin-widgets', "/wp-admin/js/widgets$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable' ), '20090824' ); 
    327327                $scripts->add_data( 'admin-widgets', 'group', 1 ); 
    328328 
     329                $scripts->add( 'admin-menus', "/wp-admin/js/menus$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable' ), '20090824' ); 
     330                $scripts->add_data( 'admin-menus', 'group', 1 ); 
     331 
    329332                $scripts->add( 'word-count', "/wp-admin/js/word-count$suffix.js", array( 'jquery' ), '20090422' ); 
    330333                $scripts->add_data( 'word-count', 'group', 1 ); 
    331334                $scripts->localize( 'word-count', 'wordCountL10n', array( 
     
    426429 
    427430        $suffix = defined('STYLE_DEBUG') && STYLE_DEBUG ? '.dev' : ''; 
    428431 
    429         $rtl_styles = array( 'wp-admin', 'global', 'colors', 'dashboard', 'ie', 'install', 'login', 'media', 'theme-editor', 'upload', 'widgets', 'press-this', 'plugin-install', 'farbtastic' ); 
     432        $rtl_styles = array( 'wp-admin', 'global', 'colors', 'dashboard', 'ie', 'install', 'login', 'media', 'theme-editor', 'upload', 'widgets', 'menus', 'press-this', 'plugin-install', 'farbtastic' ); 
    430433 
    431434        // all colors stylesheets need to have the same query strings (cache manifest compat) 
    432435        $colors_version = '20091227'; 
     
    448451        $styles->add( 'global', "/wp-admin/css/global$suffix.css", array(), '20100108' ); 
    449452        $styles->add( 'media', "/wp-admin/css/media$suffix.css", array(), '20091029' ); 
    450453        $styles->add( 'widgets', "/wp-admin/css/widgets$suffix.css", array(), '20091118' ); 
     454        $styles->add( 'menus', "/wp-admin/css/menus$suffix.css", array(), '20100109' ); 
    451455        $styles->add( 'dashboard', "/wp-admin/css/dashboard$suffix.css", array(), '20091211' ); 
    452456        $styles->add( 'install', "/wp-admin/css/install$suffix.css", array(), '20090514' ); 
    453457        $styles->add( 'theme-editor', "/wp-admin/css/theme-editor$suffix.css", array(), '20090625' ); 
  • wp-content/themes/default/functions.php

     
    1717        )); 
    1818} 
    1919 
     20// Dynamic menu support 
     21add_theme_support('menus'); 
     22register_menus(2); 
     23 
    2024/** @ignore */ 
    2125function kubrick_head() { 
    2226        $head = "<style type='text/css'>\n<!--"; 
  • wp-settings.php

     
    101101require (ABSPATH . WPINC . '/media.php'); 
    102102require (ABSPATH . WPINC . '/http.php'); 
    103103require (ABSPATH . WPINC . '/widgets.php'); 
     104require (ABSPATH . WPINC . '/menus.php'); 
    104105 
    105106if ( is_multisite() ) { 
    106107        require_once( ABSPATH . WPINC . '/ms-functions.php' ); 
     
    221222// Everything is loaded and initialized. 
    222223do_action('init'); 
    223224 
    224 ?> 
    225  No newline at end of file 
     225?> 
  • wp-admin/admin-ajax.php

     
    13821382 
    13831383        die(); 
    13841384        break; 
     1385case 'menu-items-order' : 
     1386        check_ajax_referer( 'save-menu-items', 'savemenu_items' ); 
     1387 
     1388        if ( !current_user_can('switch_themes') ) 
     1389                die('-1'); 
     1390 
     1391        unset( $_POST['savemenu_items'], $_POST['action'] ); 
     1392 
     1393        // save menu_items order for all menus 
     1394        if ( is_array($_POST['menus']) ) { 
     1395                $menus = array(); 
     1396                foreach ( $_POST['menus'] as $key => $val ) { 
     1397                        $sb = array(); 
     1398                        if ( !empty($val) ) { 
     1399                                $val = explode(',', $val); 
     1400                                foreach ( $val as $k => $v ) { 
     1401                                        if ( strpos($v, 'menu-item-') === false ) 
     1402                                                continue; 
     1403 
     1404                                        $tmp = explode('_', $v, 2); 
     1405                                        $sb[$k] = $tmp[1]; 
     1406                                } 
     1407                        } 
     1408                        $menus[$key] = $sb; 
     1409                } 
     1410                wp_set_menu_items($menus); 
     1411                die('1'); 
     1412        } 
     1413 
     1414        die('-1'); 
     1415        break; 
     1416case 'save-menu-item' : 
     1417        check_ajax_referer( 'save-menu-items', 'savemenu_items' ); 
     1418 
     1419        if ( !current_user_can('switch_themes') || !isset($_POST['id_base']) ) 
     1420                die('-1'); 
     1421 
     1422        unset( $_POST['savemenu_items'], $_POST['action'] ); 
     1423 
     1424        do_action('load-menus.php'); 
     1425        do_action('menus.php'); 
     1426        do_action('menu_admin_setup'); 
     1427 
     1428        $id_base = $_POST['id_base']; 
     1429        $menu_item_id = $_POST['menu-item-id']; 
     1430        $menu_id = $_POST['menu']; 
     1431        $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0; 
     1432        $settings = isset($_POST['menu-item-' . $id_base]) && is_array($_POST['menu-item-' . $id_base]) ? $_POST['menu-item-' . $id_base] : false; 
     1433        $error = '<p>' . __('An error has occured. Please reload the page and try again.') . '</p>'; 
     1434 
     1435        $menus = wp_get_menu_items(); 
     1436        $menu = isset($menus[$menu_id]) ? $menus[$menu_id] : array(); 
     1437 
     1438        // delete 
     1439        if ( isset($_POST['delete_menu_item']) && $_POST['delete_menu_item'] ) { 
     1440 
     1441                if ( !isset($wp_registered_menu_items[$menu_item_id]) ) 
     1442                        die($error); 
     1443 
     1444                $menu = array_diff( $menu, array($menu_item_id) ); 
     1445                $_POST = array('menu' => $menu_id, 'menu-item-' . $id_base => array(), 'the-menu-item-id' => $menu_item_id, 'delete_menu_item' => '1'); 
     1446        } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) { 
     1447                if ( !$multi_number ) 
     1448                        die($error); 
     1449 
     1450                $_POST['menu-item-' . $id_base] = array( $multi_number => array_shift($settings) ); 
     1451                $menu_item_id = $id_base . '-' . $multi_number; 
     1452                $menu[] = $menu_item_id; 
     1453        } 
     1454        $_POST['menu-item-id'] = $menu; 
     1455 
     1456        foreach ( (array) $wp_registered_menu_item_updates as $name => $control ) { 
     1457 
     1458                if ( $name == $id_base ) { 
     1459                        if ( !is_callable( $control['callback'] ) ) 
     1460                                continue; 
     1461 
     1462                        ob_start(); 
     1463                                call_user_func_array( $control['callback'], $control['params'] ); 
     1464                        ob_end_clean(); 
     1465                        break; 
     1466                } 
     1467        } 
     1468 
     1469        if ( isset($_POST['delete_menu_item']) && $_POST['delete_menu_item'] ) { 
     1470                $menus[$menu_id] = $menu; 
     1471                wp_set_menu_items($menus); 
     1472                echo "deleted:$menu_item_id"; 
     1473                die(); 
     1474        } 
     1475 
     1476        if ( !empty($_POST['add_new']) ) 
     1477                die(); 
     1478 
     1479        if ( $form = $wp_registered_menu_item_controls[$menu_item_id] ) 
     1480                call_user_func_array( $form['callback'], $form['params'] ); 
     1481 
     1482        die(); 
     1483        break; 
    13851484case 'image-editor': 
    13861485        $attachment_id = intval($_POST['postid']); 
    13871486        if ( empty($attachment_id) || !current_user_can('edit_post', $attachment_id) ) 
  • wp-admin/includes/menus.php

     
     1<?php 
     2/** 
     3 * WordPress Menus Administration API 
     4 * 
     5 * @package WordPress 
     6 * @subpackage Administration 
     7 */ 
     8 
     9/** 
     10 * Display list of the available menu items, either all or matching search. 
     11 * 
     12 * The search parameter are search terms separated by spaces. 
     13 * 
     14 * @since 3.0 
     15 * 
     16 * @param string $show Optional, default is all. What to display, can be 'all', 'unused', or 'used'. 
     17 * @param string $_search Optional. Search for menu_items. Should be unsanitized. 
     18 */ 
     19function wp_list_menu_items() { 
     20        global $wp_registered_menu_items, $menu_items_map, $wp_registered_menu_item_controls; 
     21 
     22        $sort = $wp_registered_menu_items; 
     23 
     24        usort( $sort, create_function( '$a, $b', 'return strnatcasecmp( $a["name"], $b["name"] );' ) ); 
     25        $done = array(); 
     26        $special_items = array(__('Page'), __('Category')); 
     27 
     28        foreach ( $sort as $menu_item ) { 
     29                if ( in_array( $menu_item['callback'], $done, true ) ) // We already showed this multi-menu_item 
     30                        continue; 
     31 
     32                $menu = is_active_menu_item( $menu_item['callback'], $menu_item['id'], false, false ); 
     33                $done[] = $menu_item['callback']; 
     34 
     35                if ( ! isset( $menu_item['params'][0] ) ) 
     36                        $menu_item['params'][0] = array(); 
     37 
     38                $args = array( 'menu_item_id' => $menu_item['id'], 'menu_item_name' => $menu_item['name'], '_display' => 'template' ); 
     39 
     40                if ( isset($wp_registered_menu_item_controls[$menu_item['id']]['id_base']) && isset($menu_item['params'][0]['number']) ) { 
     41                        $id_base = $wp_registered_menu_item_controls[$menu_item['id']]['id_base']; 
     42                        $args['_temp_id'] = "$id_base-__i__"; 
     43                        $args['_multi_num'] = next_menu_item_id_number($id_base); 
     44                        $args['_add'] = 'multi'; 
     45                } else { 
     46                        $args['_add'] = 'single'; 
     47                        if ( $menu ) 
     48                                $args['_hide'] = '1'; 
     49                } 
     50 
     51                if ( in_array( $menu_item['name'], $special_items ) ) // Don't list special menu items here 
     52                        $args['_hide'] = '1'; 
     53 
     54                $args = wp_list_menu_item_controls_dynamic_menu( array( 0 => $args, 1 => $menu_item['params'][0] ) ); 
     55                call_user_func_array( 'wp_menu_item_control', $args ); 
     56        } 
     57} 
     58 
     59/** 
     60 * Show the menu_items and their settings for a menu. 
     61 * Used in the the admin menu_item config screen. 
     62 * 
     63 * @since 3.0 
     64 * 
     65 * @param string $menu id slug of the menu 
     66 */ 
     67function wp_list_menu_item_controls( $menu ) { 
     68        add_filter( 'dynamic_menu_params', 'wp_list_menu_item_controls_dynamic_menu' ); 
     69 
     70        echo "<div id='$menu' class='menu-items-sortables'>\n"; 
     71 
     72        $description = wp_menu_description( $menu ); 
     73 
     74        if ( !empty( $description ) ) { 
     75                echo "<div class='menu-description'>\n"; 
     76                echo "\t<p class='description'>$description</p>";  
     77                echo "</div>\n"; 
     78        } 
     79 
     80        dynamic_menu( $menu ); 
     81        echo "</div>\n"; 
     82} 
     83 
     84/** 
     85 * {@internal Missing Short Description}} 
     86 * 
     87 * @since 3.0 
     88 * 
     89 * @param array $params 
     90 * @return array 
     91 */ 
     92function wp_list_menu_item_controls_dynamic_menu( $params ) { 
     93        global $wp_registered_menu_items; 
     94        static $i = 0; 
     95        $i++; 
     96 
     97        $menu_item_id = $params[0]['menu_item_id']; 
     98        $id = isset($params[0]['_temp_id']) ? $params[0]['_temp_id'] : $menu_item_id; 
     99        $hidden = isset($params[0]['_hide']) ? ' style="display:none;"' : ''; 
     100 
     101        $params[0]['before_menu_item'] = "<div id='menu-item-${i}_$id' class='menu-item'$hidden>"; 
     102        $params[0]['after_menu_item'] = "</div>"; 
     103        if ( is_callable( $wp_registered_menu_items[$menu_item_id]['callback'] ) ) { 
     104                $wp_registered_menu_items[$menu_item_id]['_callback'] = $wp_registered_menu_items[$menu_item_id]['callback']; 
     105                $wp_registered_menu_items[$menu_item_id]['callback'] = 'wp_menu_item_control'; 
     106        } 
     107 
     108        return $params; 
     109} 
     110 
     111function next_menu_item_id_number($id_base) { 
     112        global $wp_registered_menu_items; 
     113        $number = 1; 
     114 
     115        foreach ( $wp_registered_menu_items as $menu_item_id => $menu_item ) { 
     116                if ( preg_match( '/' . $id_base . '-([0-9]+)$/', $menu_item_id, $matches ) ) 
     117                        $number = max($number, $matches[1]); 
     118        } 
     119        $number++; 
     120 
     121        return $number; 
     122} 
     123 
     124/** 
     125 * Meta menu_item used to display the control form for a menu_item. 
     126 * 
     127 * Called from dynamic_menu(). 
     128 * 
     129 * @since 3.0 
     130 * 
     131 * @param array $menu_args 
     132 * @return array 
     133 */ 
     134function wp_menu_item_control( $menu_args ) { 
     135        global $wp_registered_menu_items, $wp_registered_menu_item_controls, $menu_items_map; 
     136 
     137        $menu_item_id = $menu_args['menu_item_id']; 
     138        $menu_id = isset($menu_args['id']) ? $menu_args['id'] : false; 
     139        $key = $menu_id ? array_search( $menu_item_id, $menu_items_map[$menu_id] ) : '-1'; // position of menu_item in menu 
     140        $control = isset($wp_registered_menu_item_controls[$menu_item_id]) ? $wp_registered_menu_item_controls[$menu_item_id] : array(); 
     141        $menu_item = $wp_registered_menu_items[$menu_item_id]; 
     142 
     143        $id_format = $menu_item['id']; 
     144        $menu_item_number = isset($control['params'][0]['number']) ? $control['params'][0]['number'] : ''; 
     145        $id_base = isset($control['id_base']) ? $control['id_base'] : $menu_item_id; 
     146        $multi_number = isset($menu_args['_multi_num']) ? $menu_args['_multi_num'] : ''; 
     147        $add_new = isset($menu_args['_add']) ? $menu_args['_add'] : ''; 
     148 
     149        $query_arg = array( 'editmenu_item' => $menu_item['id'] ); 
     150        if ( $add_new ) { 
     151                $query_arg['addnew'] = 1; 
     152                if ( $multi_number ) { 
     153                        $query_arg['num'] = $multi_number; 
     154                        $query_arg['base'] = $id_base; 
     155                } 
     156        } else { 
     157                $query_arg['menu'] = $menu_id; 
     158                $query_arg['key'] = $key; 
     159        } 
     160 
     161        // We aren't showing a menu_item control, we're outputing a template for a mult-menu_item control 
     162        if ( isset($menu_args['_display']) && 'template' == $menu_args['_display'] && $menu_item_number ) { 
     163                // number == -1 implies a template where id numbers are replaced by a generic '__i__' 
     164                $control['params'][0]['number'] = -1; 
     165                // with id_base menu_item id's are constructed like {$id_base}-{$id_number} 
     166                if ( isset($control['id_base']) ) 
     167                        $id_format = $control['id_base'] . '-__i__'; 
     168        } 
     169 
     170        $wp_registered_menu_items[$menu_item_id]['callback'] = $wp_registered_menu_items[$menu_item_id]['_callback']; 
     171        unset($wp_registered_menu_items[$menu_item_id]['_callback']); 
     172 
     173        $menu_item_title = esc_html( strip_tags( $menu_args['menu_item_name'] ) ); 
     174        $has_form = 'noform'; 
     175 
     176        echo $menu_args['before_menu_item']; ?> 
     177        <div class="menu-item-top"> 
     178        <div class="menu-item-title-action"> 
     179                <a class="menu-item-action hide-if-no-js" href="#available-menu-items"></a> 
     180                <a class="menu-item-control-edit hide-if-js" href="<?php echo esc_url( add_query_arg( $query_arg ) ); ?>"><span class="edit"><?php _e('Edit'); ?></span><span class="add"><?php _e('Add'); ?></span></a> 
     181        </div> 
     182        <div class="menu-item-title"><h4><?php echo $menu_item_title ?><span class="in-menu-item-title"></span></h4></div> 
     183        </div> 
     184 
     185        <div class="menu-item-inside"> 
     186        <form action="" method="post"> 
     187        <div class="menu-item-content"> 
     188<?php 
     189        if ( isset($control['callback']) ) 
     190                $has_form = call_user_func_array( $control['callback'], $control['params'] ); 
     191        else 
     192                echo "\t\t<p>" . __('There are no options for this menu item.') . "</p>\n"; ?> 
     193        </div> 
     194        <input type="hidden" name="menu-item-id" class="menu-item-id" value="<?php echo esc_attr($id_format); ?>" /> 
     195        <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr($id_base); ?>" /> 
     196        <input type="hidden" name="menu-item-width" class="menu-item-width" value="<?php if (isset( $control['width'] )) echo esc_attr($control['width']); ?>" /> 
     197        <input type="hidden" name="menu-item-height" class="menu-item-height" value="<?php if (isset( $control['height'] )) echo esc_attr($control['height']); ?>" /> 
     198        <input type="hidden" name="menu_item_number" class="menu_item_number" value="<?php echo esc_attr($menu_item_number); ?>" /> 
     199        <input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr($multi_number); ?>" /> 
     200        <input type="hidden" name="add_new" class="add_new" value="<?php echo esc_attr($add_new); ?>" /> 
     201 
     202        <div class="menu-item-control-actions"> 
     203                <div class="alignleft"> 
     204                <a class="menu-item-control-remove" href="#remove"><?php _e('Delete'); ?></a> | 
     205                <a class="menu-item-control-close" href="#close"><?php _e('Close'); ?></a> 
     206                </div> 
     207                <div class="alignright<?php if ( 'noform' === $has_form ) echo ' menu-item-control-noform'; ?>"> 
     208                <img src="images/wpspin_light.gif" class="ajax-feedback " title="" alt="" /> 
     209                <input type="submit" name="savemenu_item" class="button-primary menu-item-control-save" value="<?php esc_attr_e('Save'); ?>" /> 
     210                </div> 
     211                <br class="clear" /> 
     212        </div> 
     213        </form> 
     214        </div> 
     215 
     216        <div class="menu-item-description"> 
     217<?php echo ( $menu_item_description = wp_menu_item_description($menu_item_id) ) ? "$menu_item_description\n" : "$menu_item_title\n"; ?> 
     218        </div> 
     219<?php 
     220        echo $menu_args['after_menu_item']; 
     221        return $menu_args; 
     222} 
     223 
  • wp-admin/js/menus.dev.js

     
     1(function($) { 
     2        window.wpMenus = { 
     3                 
     4        addItem : function(item) { 
     5                var add = item.find('input.add_new').val(), 
     6                        n = item.find('input.multi_number').val(), 
     7                        id = item.attr('id'); 
     8 
     9                if ( ! add ) 
     10                        return false; 
     11 
     12                item.html( item.html().replace(/<[^<>]+>/g, function(m){ return m.replace(/__i__|%i%/g, n); }) ); 
     13                item.attr( 'id', id.replace(/__i__|%i%/g, n) ); 
     14                n++; 
     15                $('div#' + id).find('input.multi_number').val(n); 
     16 
     17                return true; 
     18        }, 
     19 
     20        init : function() { 
     21                var rem, menus = $('div.menu-items-sortables'); 
     22 
     23                $('#menu-item-dropdowns select').change(function(ev) { 
     24                        var active_menu = $('.menu-item-liquid-right .menu-items-sortables').not('#wp_inactive_menu_items, .ui-sortable-disabled').eq(0); 
     25 
     26                        if ( ! active_menu.length ) 
     27                                return; 
     28 
     29                        var select = $(this), 
     30                                selected = select.find('option:selected'), 
     31                                item_type = select.parents('.menu-item-dropdown').attr('id').replace('-dropdown', ''); 
     32                                item_id = selected.val(), 
     33                                item_title = $.trim(selected.text().replace('&nbsp;', '')); 
     34 
     35                        if ( ! item_id ) 
     36                                return; 
     37 
     38                        var menu_item = $('.menu-item[id*="' + item_type + '-__i__"]').clone(true).show(); 
     39 
     40                        active_menu.append(menu_item); 
     41 
     42                        wpMenus.addItem(menu_item); 
     43 
     44                        menu_item 
     45                                .find('input[id*="-' + item_type + '_id"]') 
     46                                        .val(item_id) 
     47                                .end() 
     48                                .find('input[id*="-title"]') 
     49                                        .val(item_title) 
     50                                .end(); 
     51                        wpMenus.appendTitle(menu_item.get()); 
     52 
     53                        wpMenus.save( menu_item, 0, 0, 1 ); 
     54                        menu_item.find('input.add_new').val(''); 
     55                }); 
     56 
     57                $('#menu-items-right').children('.menu-items-holder-wrap').children('.menu-name').click(function(){ 
     58                        var c = $(this).siblings('.menu-items-sortables'), p = $(this).parent(); 
     59                        if ( !p.hasClass('closed') ) { 
     60                                c.sortable('disable'); 
     61                                p.addClass('closed'); 
     62                        } else { 
     63                                p.removeClass('closed'); 
     64                                c.sortable('enable').sortable('refresh'); 
     65                        } 
     66                }); 
     67 
     68                $('#menu-items-left').children('.menu-items-holder-wrap').children('.menu-name').click(function() { 
     69                        $(this).siblings('.menu-item-holder').parent().toggleClass('closed'); 
     70                }); 
     71 
     72                menus.not('#wp_inactive_menu_items').each(function(){ 
     73                        var h = 50, H = $(this).children('.menu-item').length; 
     74                        h = h + parseInt(H * 48, 10); 
     75                        $(this).css( 'minHeight', h + 'px' ); 
     76                }); 
     77 
     78                $('a.menu-item-action').live('click', function(){ 
     79                        var css = {}, menu_item = $(this).closest('div.menu-item'), inside = menu_item.children('.menu-item-inside'), w = parseInt( menu_item.find('input.menu-item-width').val(), 10 ); 
     80                         
     81                        if ( inside.is(':hidden') ) { 
     82                                if ( w > 250 && inside.closest('div.menu-items-sortables').length ) { 
     83                                        css['width'] = w + 30 + 'px'; 
     84                                        if ( inside.closest('div.menu-item-liquid-right').length ) 
     85                                                css['marginLeft'] = 235 - w + 'px'; 
     86                                        menu_item.css(css); 
     87                                } 
     88                                wpMenus.fixLabels(menu_item); 
     89                                inside.slideDown('fast'); 
     90                        } else { 
     91                                inside.slideUp('fast', function() { 
     92                                        menu_item.css({'width':'','marginLeft':''}); 
     93                                }); 
     94                        } 
     95                        return false; 
     96                }); 
     97 
     98                $('input.menu-item-control-save').live('click', function(){ 
     99                        wpMenus.save( $(this).closest('div.menu-item'), 0, 1, 0 ); 
     100                        return false; 
     101                }); 
     102 
     103                $('a.menu-item-control-remove').live('click', function(){ 
     104                        wpMenus.save( $(this).closest('div.menu-item'), 1, 1, 0 ); 
     105                        return false; 
     106                }); 
     107 
     108                $('a.menu-item-control-close').live('click', function(){ 
     109                        wpMenus.close( $(this).closest('div.menu-item') ); 
     110                        return false; 
     111                }); 
     112 
     113                menus.children('.menu-item').each(function() { 
     114                        wpMenus.appendTitle(this); 
     115                        if ( $('p.menu-item-error', this).length ) 
     116                                $('a.menu-item-action', this).click(); 
     117                }); 
     118 
     119                $('#menu-item-list').children('.menu-item').draggable({ 
     120                        connectToSortable: 'div.menu-items-sortables', 
     121                        handle: '> .menu-item-top > .menu-item-title', 
     122                        distance: 2, 
     123                        helper: 'clone', 
     124                        zIndex: 5, 
     125                        containment: 'document', 
     126                        start: function(e,ui) { 
     127                                wpMenus.fixWebkit(1); 
     128                                ui.helper.find('div.menu-item-description').hide(); 
     129                        }, 
     130                        stop: function(e,ui) { 
     131                                if ( rem ) 
     132                                        $(rem).hide(); 
     133                                rem = ''; 
     134                                wpMenus.fixWebkit(); 
     135                        } 
     136                }); 
     137 
     138                menus.sortable({ 
     139                        placeholder: 'menu-item-placeholder', 
     140                        items: '> .menu-item', 
     141                        handle: '> .menu-item-top > .menu-item-title', 
     142                        cursor: 'move', 
     143                        distance: 2, 
     144                        containment: 'document', 
     145                        start: function(e,ui) { 
     146                                wpMenus.fixWebkit(1); 
     147                                ui.item.children('.menu-item-inside').hide(); 
     148                                ui.item.css({'marginLeft':'','width':''}); 
     149                        }, 
     150                        stop: function(e,ui) { 
     151                                if ( ui.item.hasClass('ui-draggable') ) 
     152                                        ui.item.draggable('destroy'); 
     153 
     154                                if ( ui.item.hasClass('deleting') ) { 
     155                                        wpMenus.save( ui.item, 1, 0, 1 ); // delete menu item 
     156                                        ui.item.remove(); 
     157                                        return; 
     158                                } 
     159 
     160                                var sb = $(this).attr('id'); 
     161                                 
     162                                ui.item.css({'marginLeft':'','width':''}); 
     163                                wpMenus.fixWebkit(); 
     164 
     165                                if ( wpMenus.addItem(ui.item) ) { 
     166                                        wpMenus.save( ui.item, 0, 0, 1 ); 
     167                                        ui.item.find('input.add_new').val(''); 
     168                                        ui.item.find('a.menu-item-action').click(); 
     169                                        return; 
     170                                } 
     171 
     172                                wpMenus.saveOrder(sb); 
     173                        }, 
     174                        receive: function(e,ui) { 
     175                                if ( !$(this).is(':visible') ) 
     176                                        $(this).sortable('cancel'); 
     177                        } 
     178                }).sortable('option', 'connectWith', 'div.menu-items-sortables').parent().filter('.closed').children('.menu-items-sortables').sortable('disable'); 
     179 
     180                $('#available-menu-items').droppable({ 
     181                        tolerance: 'pointer', 
     182                        accept: function(o){ 
     183                                return $(o).parent().attr('id') != 'menu-item-list'; 
     184                        }, 
     185                        drop: function(e,ui) { 
     186                                ui.draggable.addClass('deleting'); 
     187                                $('#removing-menu-item').hide().children('span').html(''); 
     188                        }, 
     189                        over: function(e,ui) { 
     190                                ui.draggable.addClass('deleting'); 
     191                                $('div.menu-item-placeholder').hide(); 
     192 
     193                                if ( ui.draggable.hasClass('ui-sortable-helper') ) 
     194                                        $('#removing-menu-item').show().children('span') 
     195                                        .html( ui.draggable.find('div.menu-item-title').children('h4').html() ); 
     196                        }, 
     197                        out: function(e,ui) { 
     198                                ui.draggable.removeClass('deleting'); 
     199                                $('div.menu-item-placeholder').show(); 
     200                                $('#removing-menu-item').hide().children('span').html(''); 
     201                        } 
     202                }); 
     203        }, 
     204 
     205        saveOrder : function(sb) { 
     206                if ( sb ) 
     207                        $('#' + sb).closest('div.menu-items-holder-wrap').find('img.ajax-feedback').css('visibility', 'visible'); 
     208 
     209                var a = { 
     210                        action: 'menu-items-order', 
     211                        savemenu_items: $('#_wpnonce_menu_items').val(), 
     212                        menus: [] 
     213                }; 
     214 
     215                $('div.menu-items-sortables').each( function() { 
     216                        a['menus[' + $(this).attr('id') + ']'] = $(this).sortable('toArray').join(','); 
     217                }); 
     218 
     219                $.post( ajaxurl, a, function() { 
     220                        $('img.ajax-feedback').css('visibility', 'hidden'); 
     221                }); 
     222 
     223                this.resize(); 
     224        }, 
     225 
     226        save : function(menu_item, del, animate, order) { 
     227                var sb = menu_item.closest('div.menu-items-sortables').attr('id'), data = menu_item.find('form').serialize(), a; 
     228                menu_item = $(menu_item); 
     229                $('.ajax-feedback', menu_item).css('visibility', 'visible'); 
     230 
     231                a = { 
     232                        action: 'save-menu-item', 
     233                        savemenu_items: $('#_wpnonce_menu_items').val(), 
     234                        menu: sb 
     235                }; 
     236 
     237                if ( del ) 
     238                        a['delete_menu_item'] = 1; 
     239 
     240                data += '&' + $.param(a); 
     241 
     242                $.post( ajaxurl, data, function(r){ 
     243                        var id; 
     244 
     245                        if ( del ) { 
     246                                if ( !$('input.menu_item_number', menu_item).val() ) { 
     247                                        id = $('input.menu-item-id', menu_item).val(); 
     248                                        $('#available-menu-items').find('input.menu-item-id').each(function(){ 
     249                                                if ( $(this).val() == id ) 
     250                                                        $(this).closest('div.menu-item').show(); 
     251                                        }); 
     252                                } 
     253 
     254                                if ( animate ) { 
     255                                        order = 0; 
     256                                        menu_item.slideUp('fast', function(){ 
     257                                                $(this).remove(); 
     258                                                wpMenus.saveOrder(); 
     259                                        }); 
     260                                } else { 
     261                                        menu_item.remove(); 
     262                                        wpMenus.resize(); 
     263                                } 
     264                        } else { 
     265                                $('.ajax-feedback').css('visibility', 'hidden'); 
     266                                if ( r && r.length > 2 ) { 
     267                                        $('div.menu-item-content', menu_item).html(r); 
     268                                        wpMenus.appendTitle(menu_item); 
     269                                        wpMenus.fixLabels(menu_item); 
     270                                } 
     271                        } 
     272                        if ( order ) 
     273                                wpMenus.saveOrder(); 
     274                }); 
     275        }, 
     276 
     277        appendTitle : function(menu_item) { 
     278                var title = $('input[id*="-title"]', menu_item); 
     279                if ( title = title.val() ) { 
     280                        title = title.replace(/<[^<>]+>/g, '').replace(/</g, '&lt;').replace(/>/g, '&gt;'); 
     281                        $(menu_item).children('.menu-item-top').children('.menu-item-title').children() 
     282                                .children('.in-menu-item-title').html(': ' + title); 
     283                } 
     284        }, 
     285 
     286        resize : function() { 
     287                $('div.menu-items-sortables').not('#wp_inactive_menu_items').each(function(){ 
     288                        var h = 50, H = $(this).children('.menu-item').length; 
     289                        h = h + parseInt(H * 48, 10); 
     290                        $(this).css( 'minHeight', h + 'px' ); 
     291                }); 
     292        }, 
     293 
     294    fixWebkit : function(n) { 
     295        n = n ? 'none' : ''; 
     296        $('body').css({ 
     297                        WebkitUserSelect: n, 
     298                        KhtmlUserSelect: n 
     299                }); 
     300    }, 
     301 
     302    fixLabels : function(menu_item) { 
     303                menu_item.children('.menu-item-inside').find('label').each(function(){ 
     304                        var f = $(this).attr('for'); 
     305                        if ( f && f == $('input', this).attr('id') ) 
     306                                $(this).removeAttr('for'); 
     307                }); 
     308        }, 
     309 
     310    close : function(menu_item) { 
     311                menu_item.children('.menu-item-inside').slideUp('fast', function(){ 
     312                        menu_item.css({'width':'','marginLeft':''}); 
     313                }); 
     314        } 
     315}; 
     316 
     317$(document).ready(function($){ wpMenus.init(); }); 
     318 
     319})(jQuery); 
  • wp-admin/menus.php

     
     1<?php 
     2/** 
     3 * Menus administration panel. 
     4 * 
     5 * @package WordPress 
     6 * @subpackage Administration 
     7 */ 
     8 
     9/** WordPress Administration Bootstrap */ 
     10require_once( 'admin.php' ); 
     11 
     12/** WordPress Administration Menus API */ 
     13require_once(ABSPATH . 'wp-admin/includes/menus.php'); 
     14 
     15if ( ! current_user_can('switch_themes') ) 
     16        wp_die( __( 'Cheatin&#8217; uh?' )); 
     17 
     18wp_admin_css( 'menus' ); 
     19 
     20$menus_access = get_user_setting( 'menus_access' ); 
     21if ( isset($_GET['menus-access']) ) { 
     22        $menus_access = 'on' == $_GET['menus-access'] ? 'on' : 'off'; 
     23        set_user_setting( 'menus_access', $menus_access ); 
     24} 
     25 
     26if ( 'on' == $menus_access ) 
     27        add_filter( 'admin_body_class', create_function('', '{return " menus_access ";}') ); 
     28else 
     29        wp_enqueue_script('admin-menus'); 
     30 
     31do_action( 'menu_admin_setup' ); 
     32 
     33$title = __( 'Menus' ); 
     34$parent_file = 'themes.php'; 
     35 
     36// register the inactive_menu_items area as menu 
     37register_menu(array( 
     38        'name' => __('Inactive Menu Items'), 
     39        'id' => 'wp_inactive_menu_items', 
     40        'description' => '', 
     41        'before_menu' => '', 
     42        'after_menu' => '', 
     43)); 
     44 
     45// These are the menu_items grouped by menu 
     46$menu_items_map = wp_get_menu_items(); 
     47if ( empty( $menu_items_map ) ) 
     48        $menu_items_map = wp_get_menu_item_defaults(); 
     49 
     50// look for "lost" menu_items, this has to run at least on each theme change 
     51function retrieve_menu_items() { 
     52        global $wp_registered_menu_item_updates, $wp_registered_menus, $menu_items_map, $wp_registered_menu_items; 
     53 
     54        $_menus_menu_items = array(); 
     55        $menus = array_keys($wp_registered_menus); 
     56 
     57        unset( $menu_items_map['array_version'] ); 
     58 
     59        $old = array_keys($menu_items_map); 
     60        sort($old); 
     61        sort($menus); 
     62 
     63        if ( $old == $menus ) 
     64                return; 
     65 
     66        // Move the known-good ones first 
     67        foreach ( $menus as $id ) { 
     68                if ( array_key_exists( $id, $menu_items_map ) ) { 
     69                        $_menus_menu_items[$id] = $menu_items_map[$id]; 
     70                        unset($menu_items_map[$id], $menus[$id]); 
     71                } 
     72        } 
     73 
     74        // if new theme has less menus than the old theme 
     75        if ( !empty($menu_items_map) ) { 
     76                foreach ( $menu_items_map as $lost => $val ) { 
     77                        if ( is_array($val) ) 
     78                                $_menus_menu_items['wp_inactive_menu_items'] = array_merge( (array) $_menus_menu_items['wp_inactive_menu_items'], $val ); 
     79                } 
     80        } 
     81 
     82        // discard invalid, theme-specific menu_items from menus 
     83        $shown_menu_items = array(); 
     84        foreach ( $_menus_menu_items as $menu => $menu_items ) { 
     85                if ( !is_array($menu_items) ) 
     86                        continue; 
     87 
     88                $_menu_items = array(); 
     89                foreach ( $menu_items as $menu_item ) { 
     90                        if ( isset($wp_registered_menu_items[$menu_item]) ) 
     91                                $_menu_items[] = $menu_item; 
     92                } 
     93                $_menus_menu_items[$menu] = $_menu_items; 
     94                $shown_menu_items = array_merge($shown_menu_items, $_menu_items); 
     95        } 
     96 
     97        $menu_items_map = $_menus_menu_items; 
     98        unset($_menus_menu_items, $_menu_items); 
     99 
     100        // find hidden/lost multi-menu_item instances 
     101        $lost_menu_items = array(); 
     102        foreach ( $wp_registered_menu_items as $key => $val ) { 
     103                if ( in_array($key, $shown_menu_items, true) ) 
     104                        continue; 
     105 
     106                $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key); 
     107 
     108                if ( 2 > (int) $number ) 
     109                        continue; 
     110 
     111                $lost_menu_items[] = $key; 
     112        } 
     113 
     114        $menu_items_map['wp_inactive_menu_items'] = array_merge($lost_menu_items, (array) $menu_items_map['wp_inactive_menu_items']); 
     115        wp_set_menu_items($menu_items_map); 
     116} 
     117retrieve_menu_items(); 
     118 
     119if ( !count($wp_registered_menus) == 1 ) { 
     120        // If only "wp_inactive_menu_items" is defined the theme has no menus, die. 
     121        require_once( 'admin-header.php' ); 
     122?> 
     123 
     124        <div class="wrap"> 
     125        <?php screen_icon(); ?> 
     126        <h2><?php echo esc_html( $title ); ?></h2> 
     127                <div class="error"> 
     128                        <p><?php _e( 'No Menus Defined' ); ?></p> 
     129                </div> 
     130                <p><?php _e( 'The theme you are currently using isn&#8217;t menu-aware, meaning that it has no menus that you are able to change. For information on making your theme menu-aware, please <a href="http://codex.wordpress.org/Custom_Menus_In_Themes">follow these instructions</a>.' ); ?></p> 
     131        </div> 
     132 
     133<?php 
     134        require_once( 'admin-footer.php' ); 
     135        exit; 
     136} 
     137 
     138// We're saving a menu_item without js 
     139if ( isset($_POST['savemenu_item']) || isset($_POST['removemenu_item']) ) { 
     140        $menu_item_id = $_POST['menu-item-id']; 
     141        check_admin_referer("save-delete-menu-item-$menu_item_id"); 
     142 
     143        $number = isset($_POST['multi_number']) ? (int) $_POST['multi_number'] : ''; 
     144        if ( $number ) { 
     145                foreach ( $_POST as $key => $val ) { 
     146                        if ( is_array($val) && preg_match('/__i__|%i%/', key($val)) ) { 
     147                                $_POST[$key] = array( $number => array_shift($val) ); 
     148                                break; 
     149                        } 
     150                } 
     151        } 
     152 
     153        $menu_id = $_POST['menu']; 
     154        $position = isset($_POST[$menu_id . '_position']) ? (int) $_POST[$menu_id . '_position'] - 1 : 0; 
     155 
     156        $id_base = $_POST['id_base']; 
     157        $menu = isset($menu_items_map[$menu_id]) ? $menu_items_map[$menu_id] : array(); 
     158 
     159        // delete 
     160        if ( isset($_POST['removemenu_item']) && $_POST['removemenu_item'] ) { 
     161 
     162                if ( !in_array($menu_item_id, $menu, true) ) { 
     163                        wp_redirect('menu_items.php?error=0'); 
     164                        exit; 
     165                } 
     166 
     167                $menu = array_diff( $menu, array($menu_item_id) ); 
     168                $_POST = array('menu' => $menu_id, 'menu-item-' . $id_base => array(), 'the-menu-item-id' => $menu_item_id, 'delete_menu_item' => '1'); 
     169        } 
     170 
     171        $_POST['menu-item-id'] = $menu; 
     172 
     173        foreach ( (array) $wp_registered_menu_item_updates as $name => $control ) { 
     174                if ( $name != $id_base || !is_callable($control['callback']) ) 
     175                        continue; 
     176 
     177                ob_start(); 
     178                        call_user_func_array( $control['callback'], $control['params'] ); 
     179                ob_end_clean(); 
     180 
     181                break; 
     182        } 
     183 
     184        $menu_items_map[$menu_id] = $menu; 
     185 
     186        // remove old position 
     187        if ( !isset($_POST['delete_menu_item']) ) { 
     188                foreach ( $menu_items_map as $key => $sb ) { 
     189                        if ( is_array($sb) ) 
     190                                $menu_items_map[$key] = array_diff( $sb, array($menu_item_id) ); 
     191                } 
     192                array_splice( $menu_items_map[$menu_id], $position, 0, $menu_item_id ); 
     193        } 
     194 
     195        wp_set_menu_items($menu_items_map); 
     196        wp_redirect('menu_items.php?message=0'); 
     197        exit; 
     198} 
     199 
     200// Output the menu_item form without js 
     201if ( isset($_GET['editmenu_item']) && $_GET['editmenu_item'] ) { 
     202        $menu_item_id = $_GET['editmenu_item']; 
     203 
     204        if ( isset($_GET['addnew']) ) { 
     205                // Default to the first menu 
     206                $menu = array_shift( $keys = array_keys($wp_registered_menus) ); 
     207 
     208                if ( isset($_GET['base']) && isset($_GET['num']) ) { // multi-menu_item 
     209                        // Copy minimal info from an existing instance of this menu_item to a new instance 
     210                        foreach ( $wp_registered_menu_item_controls as $control ) { 
     211                                if ( $_GET['base'] === $control['id_base'] ) { 
     212                                        $control_callback = $control['callback']; 
     213                                        $multi_number = (int) $_GET['num']; 
     214                                        $control['params'][0]['number'] = -1; 
     215                                        $menu_item_id = $control['id'] = $control['id_base'] . '-' . $multi_number; 
     216                                        $wp_registered_menu_item_controls[$control['id']] = $control; 
     217                                        break; 
     218                                } 
     219                        } 
     220                } 
     221        } 
     222 
     223        if ( isset($wp_registered_menu_item_controls[$menu_item_id]) && !isset($control) ) { 
     224                $control = $wp_registered_menu_item_controls[$menu_item_id]; 
     225                $control_callback = $control['callback']; 
     226        } elseif ( !isset($wp_registered_menu_item_controls[$menu_item_id]) && isset($wp_registered_menu_items[$menu_item_id]) ) { 
     227                $name = esc_html( strip_tags($wp_registered_menu_items[$menu_item_id]['name']) ); 
     228        } 
     229 
     230        if ( !isset($name) ) 
     231                $name = esc_html( strip_tags($control['name']) ); 
     232 
     233        if ( !isset($menu) ) 
     234                $menu = isset($_GET['menu']) ? $_GET['menu'] : 'wp_inactive_menu_items'; 
     235 
     236        if ( !isset($multi_number) ) 
     237                $multi_number = isset($control['params'][0]['number']) ? $control['params'][0]['number'] : ''; 
     238 
     239        $id_base = isset($control['id_base']) ? $control['id_base'] : $control['id']; 
     240 
     241        // show the menu item form 
     242        $width = ' style="width:' . max($control['width'], 350) . 'px"'; 
     243        $key = isset($_GET['key']) ? (int) $_GET['key'] : 0; 
     244 
     245        require_once( 'admin-header.php' ); ?> 
     246        <div class="wrap"> 
     247        <?php screen_icon(); ?> 
     248        <h2><?php echo esc_html( $title ); ?></h2> 
     249        <div class="editmenu_item"<?php echo $width; ?>> 
     250        <h3><?php printf( __( 'Widget %s' ), $name ); ?></h3> 
     251 
     252        <form action="menus.php" method="post"> 
     253        <div class="menu-item-inside"> 
     254<?php 
     255        if ( is_callable( $control_callback ) ) 
     256                call_user_func_array( $control_callback, $control['params'] ); 
     257        else 
     258                echo '<p>' . __('There are no options for this menu item.') . "</p>\n"; ?> 
     259        </div> 
     260 
     261        <p class="describe"><?php _e('Select both the menu for this menu item and the position of the menu item in that menu.'); ?></p> 
     262        <div class="menu-item-position"> 
     263        <table class="widefat"><thead><tr><th><?php _e('menu'); ?></th><th><?php _e('Position'); ?></th></tr></thead><tbody> 
     264<?php 
     265        foreach ( $wp_registered_menus as $sbname => $sbvalue ) { 
     266                echo "\t\t<tr><td><label><input type='radio' name='menu' value='" . esc_attr($sbname) . "'" . checked( $sbname, $menu, false ) . " /> $sbvalue[name]</label></td><td>"; 
     267                if ( 'wp_inactive_menu_items' == $sbname ) { 
     268                        echo '&nbsp;'; 
     269                } else { 
     270                        if ( !isset($menu_items_map[$sbname]) || !is_array($menu_items_map[$sbname]) ) { 
     271                                $j = 1; 
     272                                $menu_items_map[$sbname] = array(); 
     273                        } else { 
     274                                $j = count($menu_items_map[$sbname]); 
     275                                if ( isset($_GET['addnew']) || !in_array($menu_item_id, $menu_items_map[$sbname], true) ) 
     276                                        $j++; 
     277                        } 
     278                        $selected = ''; 
     279                        echo "\t\t<select name='{$sbname}_position'>\n"; 
     280                        echo "\t\t<option value=''>" . __('-- select --') . "</option>\n"; 
     281                        for ( $i = 1; $i <= $j; $i++ ) { 
     282                                if ( in_array($menu_item_id, $menu_items_map[$sbname], true) ) 
     283                                        $selected = selected( $i, $key + 1, false ); 
     284                                echo "\t\t<option value='$i'$selected> $i </option>\n"; 
     285                        } 
     286                        echo "\t\t</select>\n"; 
     287                } 
     288                echo "</td></tr>\n"; 
     289        } ?> 
     290        </tbody></table> 
     291        </div> 
     292 
     293        <div class="menu-item-control-actions"> 
     294<?php   if ( isset($_GET['addnew']) ) { ?> 
     295        <a href="menus.php" class="button alignleft"><?php _e('Cancel'); ?></a> 
     296<?php   } else { ?> 
     297        <input type="submit" name="removemenu_item" class="button alignleft" value="<?php esc_attr_e('Delete'); ?>" /> 
     298<?php   } ?> 
     299        <input type="submit" name="savemenu_item" class="button-primary alignright" value="<?php esc_attr_e('Save Widget'); ?>" /> 
     300        <input type="hidden" name="menu-item-id" class="menu-item-id" value="<?php echo esc_attr($menu_item_id); ?>" /> 
     301        <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr($id_base); ?>" /> 
     302        <input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr($multi_number); ?>" /> 
     303<?php   wp_nonce_field("save-delete-menu-item-$menu_item_id"); ?> 
     304        <br class="clear" /> 
     305        </div> 
     306        </form> 
     307        </div> 
     308        </div> 
     309<?php 
     310        require_once( 'admin-footer.php' ); 
     311        exit; 
     312} 
     313 
     314$messages = array( 
     315        __('Changes saved.') 
     316); 
     317 
     318$errors = array( 
     319        __('Error while saving.'), 
     320        __('Error in displaying the menu item settings form.') 
     321); 
     322 
     323require_once( 'admin-header.php' ); ?> 
     324 
     325<div class="wrap"> 
     326<?php screen_icon(); ?> 
     327<h2><?php echo esc_html( $title ); ?></h2> 
     328 
     329<?php if ( isset($_GET['message']) && isset($messages[$_GET['message']]) ) { ?> 
     330<div id="message" class="updated"><p><?php echo $messages[$_GET['message']]; ?></p></div> 
     331<?php } ?> 
     332<?php if ( isset($_GET['error']) && isset($errors[$_GET['error']]) ) { ?> 
     333<div id="message" class="error"><p><?php echo $errors[$_GET['error']]; ?></p></div> 
     334<?php } ?> 
     335 
     336<div class="menu-item-liquid-left"> 
     337<div id="menu-items-left"> 
     338        <div id="special-menu-items" class="menu-items-holder-wrap"> 
     339                <div class="menu-name"> 
     340                <div class="menu-name-arrow"><br /></div> 
     341                <h3><?php _e('Special Menu Items'); ?> <span id="removing-menu-item"><?php _e('Deactivate'); ?> <span></span></span></h3></div> 
     342                <div class="menu-item-holder"> 
     343                <p class="description"><?php _e('Select menu items from here to add them to the currently open menu on the right.'); ?></p> 
     344                <div id="menu-item-dropdowns"> 
     345                        <div id="page-dropdown" class="menu-item-dropdown"> 
     346                                <p><?php _e('Add a page:'); ?></p> 
     347                                <?php wp_dropdown_pages(array('name' => 'category-dropdown', 'hide_if_empty' => false, 'orderby' => 'name', 'hierarchical' => true, 'show_option_none' => ' ')); ?> 
     348                        </div> 
     349                        <div id="category-dropdown" class="menu-item-dropdown"> 
     350                                <p><?php _e('Add a category:'); ?></p> 
     351                                <?php wp_dropdown_categories(array('name' => 'category-dropdown', 'hide_empty' => 0, 'hide_if_empty' => false, 'orderby' => 'name', 'hierarchical' => true, 'show_option_none' => ' ')); ?> 
     352                        </div> 
     353                </div> 
     354 
     355                <br class='clear' /> 
     356                </div> 
     357                <br class="clear" /> 
     358        </div> 
     359 
     360        <div id="available-menu-items" class="menu-items-holder-wrap"> 
     361                <div class="menu-name"> 
     362                <div class="menu-name-arrow"><br /></div> 
     363                <h3><?php _e('Available Menu Items'); ?> <span id="removing-menu-item"><?php _e('Deactivate'); ?> <span></span></span></h3></div> 
     364                <div class="menu-item-holder"> 
     365                <p class="description"><?php _e('Drag menu items from here to a menu on the right to activate them. Drag menu items back here to deactivate them and delete their settings.'); ?></p> 
     366                <div id="menu-item-list"> 
     367                <?php wp_list_menu_items(); ?> 
     368                </div> 
     369                <br class='clear' /> 
     370                </div> 
     371                <br class="clear" /> 
     372        </div> 
     373 
     374        <div class="menu-items-holder-wrap"> 
     375                <div class="menu-name"> 
     376                <div class="menu-name-arrow"><br /></div> 
     377                <h3><?php _e('Inactive Menu Items'); ?> 
     378                <span><img src="images/wpspin_light.gif" class="ajax-feedback" title="" alt="" /></span></h3></div> 
     379                <div class="menu-item-holder inactive"> 
     380                <p class="description"><?php _e('Drag menu items here to remove them from the menu but keep their settings.'); ?></p> 
     381                <?php wp_list_menu_item_controls('wp_inactive_menu_items'); ?> 
     382                <br class="clear" /> 
     383                </div> 
     384        </div> 
     385</div> 
     386</div> 
     387 
     388<div class="menu-item-liquid-right"> 
     389<div id="menu-items-right"> 
     390<?php 
     391$i = 0; 
     392foreach ( $wp_registered_menus as $menu => $registered_menu ) { 
     393        if ( 'wp_inactive_menu_items' == $menu ) 
     394                continue; 
     395        $closed = $i ? ' closed' : ''; ?> 
     396        <div class="menu-items-holder-wrap<?php echo $closed; ?>"> 
     397        <div class="menu-name"> 
     398        <div class="menu-name-arrow"><br /></div> 
     399        <h3><?php echo esc_html( $registered_menu['name'] ); ?> 
     400        <span><img src="images/wpspin_dark.gif" class="ajax-feedback" title="" alt="" /></span></h3></div> 
     401        <?php wp_list_menu_item_controls( $menu ); // Show the control forms for each of the menu_items in this menu ?> 
     402        </div> 
     403<?php 
     404        $i++; 
     405} ?> 
     406</div> 
     407</div> 
     408<form action="" method="post"> 
     409<?php wp_nonce_field( 'save-menu-items', '_wpnonce_menu_items', false ); ?> 
     410</form> 
     411<br class="clear" /> 
     412</div> 
     413 
     414<?php 
     415do_action( 'menu_admin_page' ); 
     416require_once( 'admin-footer.php' ); 
  • wp-admin/css/menus.dev.css

     
     1html, 
     2body { 
     3        min-width: 950px; 
     4} 
     5 
     6/* 2 column liquid layout */ 
     7div.menu-item-liquid-left { 
     8        float: left; 
     9        clear: left; 
     10        width: 100%; 
     11        margin-right: -325px; 
     12} 
     13 
     14div#menu-items-left { 
     15        margin-left: 5px; 
     16        margin-right: 325px; 
     17} 
     18 
     19div#menu-items-right { 
     20        width: 285px; 
     21        margin: 0 auto; 
     22} 
     23 
     24div.menu-item-liquid-right { 
     25        float: right; 
     26        clear: right; 
     27        width: 300px; 
     28} 
     29 
     30.menu-item-liquid-right .menu-item, 
     31#wp_inactive_menu_items .menu-item, 
     32.menu-item-liquid-right .menu-description { 
     33        width: 250px; 
     34        margin: 0 auto 20px; 
     35        overflow: hidden; 
     36} 
     37 
     38.menu-item-liquid-right .menu-description { 
     39        margin-bottom: 10px; 
     40} 
     41 
     42#wp_inactive_menu_items .menu-item { 
     43        float: left; 
     44} 
     45 
     46div.menu-name h3 { 
     47        margin: 0; 
     48        padding: 5px 12px; 
     49        font-size: 13px; 
     50        height: 19px; 
     51        overflow: hidden; 
     52        white-space: nowrap; 
     53} 
     54 
     55div.menu-name { 
     56        background-repeat: repeat-x; 
     57        background-position: 0 0; 
     58        cursor: pointer; 
     59        font-size: 13px; 
     60        border-width: 1px; 
     61        border-style: solid; 
     62        -moz-border-radius-topleft: 8px; 
     63        -moz-border-radius-topright: 8px; 
     64        -webkit-border-top-right-radius: 8px; 
     65        -webkit-border-top-left-radius: 8px; 
     66        -khtml-border-top-right-radius: 8px; 
     67        -khtml-border-top-left-radius: 8px; 
     68        border-top-right-radius: 8px; 
     69        border-top-left-radius: 8px; 
     70} 
     71 
     72.js .closed .menu-name { 
     73        -moz-border-radius-bottomleft: 8px; 
     74        -moz-border-radius-bottomright: 8px; 
     75        -webkit-border-bottom-right-radius: 8px; 
     76        -webkit-border-bottom-left-radius: 8px; 
     77        -khtml-border-bottom-right-radius: 8px; 
     78        -khtml-border-bottom-left-radius: 8px; 
     79        border-bottom-right-radius: 8px; 
     80        border-bottom-left-radius: 8px; 
     81} 
     82 
     83.menu-item-liquid-right .menu-items-sortables, 
     84#menu-items-left .menu-item-holder { 
     85        border-width: 0 1px 1px; 
     86        border-style: none solid solid; 
     87    -moz-border-radius-bottomleft: 8px; 
     88        -moz-border-radius-bottomright: 8px; 
     89        -webkit-border-bottom-right-radius: 8px; 
     90        -webkit-border-bottom-left-radius: 8px; 
     91        -khtml-border-bottom-right-radius: 8px; 
     92        -khtml-border-bottom-left-radius: 8px; 
     93        border-bottom-right-radius: 8px; 
     94        border-bottom-left-radius: 8px; 
     95} 
     96 
     97.js .closed .menu-items-sortables, 
     98.js .closed .menu-item-holder { 
     99        display: none; 
     100} 
     101 
     102.menu-item-liquid-right .menu-items-sortables { 
     103        padding: 15px 0 0; 
     104} 
     105 
     106#menu-item-list, 
     107#wp_inactive_menu_items { 
     108        padding:0 5px; 
     109} 
     110 
     111#wp_inactive_menu_items .menu-item { 
     112        margin: 0 10px 15px; 
     113} 
     114 
     115#menu-item-list .menu-item { 
     116        width: 250px; 
     117        margin: 0 10px 15px; 
     118        border: 0 none; 
     119        float: left; 
     120} 
     121 
     122#menu-item-list .menu-item-description { 
     123        padding: 5px 8px; 
     124} 
     125 
     126#menu-item-list .menu-item-top { 
     127        border-width: 1px; 
     128        border-style: solid; 
     129        -moz-border-radius: 6px; 
     130        -khtml-border-radius: 6px; 
     131        -webkit-border-radius: 6px; 
     132        border-radius: 6px; 
     133} 
     134 
     135.menu-item-placeholder { 
     136        border-width: 1px; 
     137        border-style: dashed; 
     138        margin: 0 auto 20px; 
     139        height: 26px; 
     140        width: 250px; 
     141} 
     142 
     143#wp_inactive_menu_items .menu-item-placeholder { 
     144        margin: 0 10px 20px; 
     145        float: left; 
     146} 
     147 
     148div.menu-items-holder-wrap { 
     149        padding: 0; 
     150        margin: 10px 0 20px; 
     151} 
     152 
     153#menu-items-left #available-menu-items { 
     154        background-color: transparent; 
     155        border: 0 none; 
     156} 
     157 
     158ul#menu-item-list { 
     159        list-style: none; 
     160        margin: 0; 
     161        padding: 0; 
     162        min-height: 100px; 
     163} 
     164 
     165.menu-item .menu-item-top { 
     166        font-size: 12px; 
     167        font-weight: bold; 
     168        height: 26px; 
     169        overflow: hidden; 
     170} 
     171 
     172.menu-item-top .menu-item-title { 
     173        padding: 5px 9px; 
     174} 
     175 
     176.menu-item-top .menu-item-title-action { 
     177        float: right; 
     178} 
     179 
     180a.menu-item-action { 
     181        display: block; 
     182        width: 24px; 
     183        height: 26px; 
     184} 
     185 
     186#available-menu-items a.menu-item-action { 
     187        display: none; 
     188} 
     189 
     190.menu-item-top a.menu-item-action { 
     191        background: url("../images/menu-bits.gif") no-repeat scroll 0 -110px; 
     192} 
     193 
     194.menu-item .menu-item-inside, 
     195.menu-item .menu-item-description { 
     196        padding: 12px 12px 10px; 
     197        font-size: 11px; 
     198        line-height: 16px; 
     199} 
     200 
     201.menu-item-inside, 
     202.menu-item-description { 
     203        display: none; 
     204} 
     205 
     206#available-menu-items .menu-item-description { 
     207        display: block; 
     208} 
     209 
     210.menu-item .menu-item-inside p { 
     211        margin: 0 0 1em; 
     212        padding: 0; 
     213} 
     214 
     215.menu-item-title h4 { 
     216        margin: 0; 
     217        line-height: 1.3; 
     218        overflow: hidden; 
     219        white-space: nowrap; 
     220} 
     221 
     222.menu-items-sortables { 
     223        min-height: 90px; 
     224} 
     225 
     226.menu-item-control-actions { 
     227        margin-top: 8px; 
     228} 
     229 
     230.menu-item-control-actions a { 
     231        text-decoration: none; 
     232} 
     233 
     234.menu-item-control-actions a:hover { 
     235        text-decoration: underline; 
     236} 
     237 
     238.menu-item-control-actions .ajax-feedback { 
     239        padding-bottom: 3px; 
     240} 
     241 
     242.menu-item-control-actions div.alignleft { 
     243        margin-top: 6px; 
     244} 
     245 
     246div#menu-info { 
     247        padding: 0 1em; 
     248        margin-bottom: 1em; 
     249        font-size: 11px; 
     250} 
     251 
     252.menu-item-title a, 
     253.menu-item-title a:hover { 
     254        text-decoration: none; 
     255        border-bottom: none; 
     256} 
     257 
     258.menu-item-control-edit { 
     259        display: block; 
     260        font-size: 11px; 
     261        font-weight: normal; 
     262        line-height: 26px; 
     263        padding: 0 8px 0 0; 
     264} 
     265 
     266a.menu-item-control-edit { 
     267        text-decoration: none; 
     268} 
     269 
     270.menu-item-control-edit .add, 
     271.menu-item-control-edit .edit { 
     272        display: none; 
     273} 
     274 
     275#available-menu-items .menu-item-control-edit .add, 
     276#menu-items-right .menu-item-control-edit .edit, 
     277#wp_inactive_menu_items .menu-item-control-edit .edit { 
     278        display: inline; 
     279} 
     280 
     281.editmenu-item { 
     282        margin: 0 auto 15px; 
     283} 
     284 
     285.editmenu-item .menu-item-inside { 
     286        display: block; 
     287        border-width: 1px; 
     288        border-style: solid; 
     289        padding: 10px; 
     290        -moz-border-radius: 6px; 
     291        -khtml-border-radius: 6px; 
     292        -webkit-border-radius: 6px; 
     293        border-radius: 6px; 
     294} 
     295 
     296.menu-item-holder { 
     297        padding-top: 2px; 
     298} 
     299 
     300.menu-item-holder p.description { 
     301        margin: 5px 15px 8px; 
     302} 
     303 
     304.menu-item-position { 
     305        margin-top: 8px; 
     306} 
     307 
     308.menu-name-arrow { 
     309        float: right; 
     310        height: 29px; 
     311        width: 26px; 
     312} 
     313 
     314#menu-item-dropdowns { 
     315        padding: 0; 
     316} 
     317 
     318.menu-item-dropdown { 
     319        float:left; 
     320        margin:0 15px 20px 15px; 
     321} 
     322 
     323.menu-item-dropdown p { 
     324        margin-top: .5em; 
     325} 
     326 
     327.menu-item-title .in-menu-item-title { 
     328        font-size: 11px; 
     329        white-space: nowrap; 
     330} 
     331 
     332#removing-menu-item { 
     333        display: none; 
     334        font-weight: normal; 
     335        padding-left: 15px; 
     336        font-size: 12px; 
     337} 
     338 
     339.menu-item-control-noform, 
     340#access-off, 
     341.menu-items_access .menu-item-action, 
     342.menu-items_access .menu-name-arrow, 
     343.menu-items_access #access-on, 
     344.menu-items_access .menu-item-holder .description { 
     345        display: none; 
     346} 
     347 
     348.menu-items_access .menu-item-holder, 
     349.menu-items_access #menu-item-list { 
     350        padding-top: 10px; 
     351} 
     352 
     353.menu-items_access #access-off { 
     354        display: inline; 
     355} 
     356 
     357.menu-items_access #wpbody-content .menu-item-title-action, 
     358.menu-items_access #wpbody-content .menu-item-control-edit, 
     359.menu-items_access .closed .menu-items-sortables, 
     360.menu-items_access .closed .menu-item-holder { 
     361        display: block; 
     362} 
     363 
     364.menu-items_access .closed .menu-name { 
     365        -moz-border-radius-bottomleft: 0; 
     366        -moz-border-radius-bottomright: 0; 
     367        -webkit-border-bottom-right-radius: 0; 
     368        -webkit-border-bottom-left-radius: 0; 
     369        -khtml-border-bottom-right-radius: 0; 
     370        -khtml-border-bottom-left-radius: 0; 
     371        border-bottom-right-radius: 0; 
     372        border-bottom-left-radius: 0; 
     373} 
     374 
     375.menu-items_access .menu-name, 
     376.menu-items_access .menu-item .menu-item-top { 
     377        cursor: default; 
     378} 
     379 
  • wp-admin/css/colors-fresh.dev.css

     
    33} 
    44 
    55* html input, 
    6 * html .widget { 
     6* html .widget,  
     7* html .menu-item { 
    78        border-color: #dfdfdf; 
    89} 
    910 
     
    131132} 
    132133 
    133134.widget .widget-top, 
     135.menu-item .menu-item-top, 
    134136.postbox h3, 
    135137.stuffbox h3 { 
    136138        background: #dfdfdf url("../images/gray-grad.png") repeat-x left top; 
     
    644646} 
    645647 
    646648.widget, 
    647 #widget-list .widget-top, 
     649.menu-item, 
     650#widget-list .widget-top,  
     651#menu-item-list .menu-item-top, 
    648652.postbox, 
    649653#titlediv, 
    650654#poststuff .postarea, 
     
    652656        border-color: #dfdfdf; 
    653657} 
    654658 
    655 .widget, 
     659.widget,  
     660.menu-item, 
    656661.postbox { 
    657662        background-color: #fff; 
    658663} 
     
    661666        color: #464646; 
    662667} 
    663668 
    664 .widget .widget-top, 
     669#widget-list .widget-top,  
     670#menu-item-list .menu-item-top, 
    665671.ui-sortable .postbox h3:hover { 
    666672        color: #000; 
    667673} 
     
    741747.file-error, 
    742748abbr.required, 
    743749.widget-control-remove:hover, 
     750.menu-item-control-remove:hover, 
    744751table.widefat .delete a:hover, 
    745752table.widefat .trash a:hover, 
    746753table.widefat .spam a:hover, 
     
    10141021#editorcontainer, 
    10151022#post-status-info, 
    10161023#titlediv #title, 
    1017 .editwidget .widget-inside { 
     1024.editwidget .widget-inside, 
     1025.editmenu-item .menu-item-inside { 
    10181026        border-color: #dfdfdf; 
    10191027} 
    10201028 
     
    16161624} 
    16171625 
    16181626div.widgets-sortables, 
    1619 #widgets-left .inactive { 
     1627div.menu-items-sortables, 
     1628#widgets-left .inactive, 
     1629#menu-items-left .inactive { 
    16201630        background-color: #f1f1f1; 
    16211631        border-color: #ddd; 
    16221632} 
    16231633 
    1624 #available-widgets .widget-holder { 
     1634#available-widgets .widget-holder, 
     1635#special-menu-items .menu-item-holder, 
     1636#available-menu-items .menu-item-holder { 
    16251637        background-color: #fff; 
    16261638        border-color: #ddd; 
    16271639} 
    16281640 
    1629 #widgets-left .sidebar-name { 
     1641#widgets-left .sidebar-name,  
     1642#menu-items-left .menu-name { 
    16301643        background-color: #aaa; 
    16311644        background-image: url(../images/ed-bg.gif); 
    16321645        text-shadow: #fff 0 1px 0; 
    16331646        border-color: #dfdfdf; 
    16341647} 
    16351648 
    1636 #widgets-right .sidebar-name { 
     1649#widgets-right .sidebar-name, 
     1650#menu-items-right .menu-name { 
    16371651        background-image: url(../images/fav.png); 
    16381652        text-shadow: #3f3f3f 0 -1px 0; 
    16391653        background-color: #636363; 
     
    16421656} 
    16431657 
    16441658.sidebar-name:hover, 
    1645 #removing-widget { 
     1659.menu-name:hover, 
     1660#removing-widget, 
     1661#removing-menu-item { 
    16461662        color: #d54e21; 
    16471663} 
    16481664 
    1649 #removing-widget span { 
     1665#removing-widget span, 
     1666#removing-menu-item span { 
    16501667        color: black; 
    16511668} 
    16521669 
    1653 #widgets-left .sidebar-name-arrow { 
     1670#widgets-left .sidebar-name-arrow, 
     1671#menu-items-left .menu-name-arrow { 
    16541672        background: transparent url(../images/menu-bits.gif) no-repeat scroll left -109px; 
    16551673} 
    16561674 
    1657 #widgets-right .sidebar-name-arrow { 
     1675#widgets-right .sidebar-name-arrow, 
     1676#menu-items-right .menu-name-arrow { 
    16581677        background: transparent url(../images/fav-arrow.gif) no-repeat scroll 0 -1px; 
    16591678} 
    16601679 
    1661 .in-widget-title { 
     1680.in-widget-title, 
     1681.in-menu-item-title { 
    16621682        color: #606060; 
    16631683} 
    16641684 
    1665 .deleting .widget-title * { 
     1685.deleting .widget-title *, 
     1686.deleting .menu-item-title * { 
    16661687        color: #aaa; 
    16671688} 
    16681689 
  • wp-admin/css/menus-rtl.css

     
     1 
     2ul#menu-item-list li.menu-item-list-item div.menu-item-description { 
     3        margin: 0 200px 0 0; 
     4        padding: 0 4em 0 0; 
     5} 
     6.menu-item-control-save, 
     7.menu-item-control-remove { 
     8        margin-right: 0; 
     9        margin-left: 8px; 
     10        float: right; 
     11} 
  • wp-admin/css/wp-admin.dev.css

     
    16531653} 
    16541654 
    16551655.widget .widget-top, 
     1656.menu-item .menu-item-top, 
    16561657.postbox h3 { 
    16571658        cursor: move; 
    16581659        -webkit-user-select: none; 
     
    17001701} 
    17011702 
    17021703.widget, 
     1704.menu-item, 
    17031705.postbox, 
    17041706.stuffbox { 
    17051707        margin-bottom: 20px; 
     
    17131715} 
    17141716 
    17151717.widget .widget-top, 
     1718.menu-item .menu-item-top, 
    17161719.postbox h3, 
    17171720.postbox h3, 
    17181721.stuffbox h3 {