WordPress.org

Make WordPress Core

Ticket #11817: menus.5.diff

File menus.5.diff, 88.7 KB (added by scribu, 3 years ago)

5 items / dropdown; more compact menu item listing

  • 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( $instance ); 
     17                extract( $args ); 
     18 
     19                $title = $this->get_title($instance); 
     20 
     21                echo $before_item . '<a href="' . get_page_link($page_id) . '">' . $title . '</a>' . $after_item; 
     22        } 
     23 
     24        function get_title($instance) { 
     25                return empty( $instance['title'] ) ? get_the_title($instance['page_id']) : $instance['title']; 
     26        } 
     27 
     28        function update( $new_instance, $old_instance ) { 
     29                $instance = $old_instance; 
     30 
     31                $instance['page_id'] = absint($new_instance['page_id']); 
     32                $instance['title'] = strip_tags($new_instance['title']); 
     33 
     34                return $instance; 
     35        } 
     36 
     37        function form( $instance ) { 
     38                $instance = wp_parse_args( (array) $instance, array( 'page_id' => 0, 'title' => '') ); 
     39 
     40                $page_id = absint( $instance['page_id'] ); 
     41 
     42                $title = esc_attr($this->get_title($instance)); 
     43?> 
     44                <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; ?>" /> 
     45                <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> 
     46<?php if ( $page_id ) : ?> 
     47                <p>Preview: <a href="<?php echo get_page_link($page_id); ?>"><?php echo $title; ?></a></p> 
     48<?php endif; 
     49        } 
     50} 
     51 
     52 
     53/** 
     54 * Category menu item class 
     55 * 
     56 * @since 3.0 
     57 */ 
     58class WP_Menu_Item_Category extends WP_Menu_Item { 
     59 
     60        function WP_Menu_Item_Category() { 
     61                $menu_item_ops = array( 'classname' => 'menu_item_category', 'description' => __('A WordPress category') ); 
     62                $this->WP_Menu_Item('category', __('Category'), $menu_item_ops); 
     63        } 
     64 
     65        function display( $args, $instance ) { 
     66                extract( $instance ); 
     67                extract( $args ); 
     68 
     69                $title = $this->get_title($instance); 
     70 
     71                echo $before_item . '<a href="' . get_category_link($category_id) . '">' . $title . '</a>' . $after_item; 
     72        } 
     73 
     74        function get_title( $instance ) { 
     75                if ( ! empty( $instance['title'] ) ) 
     76                        return $instance['title']; 
     77                 
     78                $cat = get_term($category_id, 'category'); 
     79 
     80                if ( is_wp_error($cat) ) 
     81                        return false; 
     82                         
     83                return $cat->name; 
     84        } 
     85 
     86        function update( $new_instance, $old_instance ) { 
     87                $instance = $old_instance; 
     88 
     89                $instance['category_id'] = absint($new_instance['category_id']); 
     90                $instance['title'] = strip_tags($new_instance['title']); 
     91 
     92                return $instance; 
     93        } 
     94 
     95        function form( $instance ) { 
     96                $instance = wp_parse_args( (array) $instance, array( 'category_id' => 0, 'title' => '') ); 
     97 
     98                $category_id = absint( $instance['category_id'] ); 
     99                 
     100                if ( $category_id ) 
     101                        $title = $this->get_title($instance); 
     102                else 
     103                        $title = ''; 
     104 
     105                if ( false === $title ) 
     106                        return; 
     107 
     108                $title = esc_attr($title); 
     109?> 
     110                <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; ?>" /> 
     111                <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> 
     112 
     113<?php if ( $category_id ) : ?> 
     114                <p>Preview: <a href="<?php echo get_category_link($category_id); ?>"><?php echo $title; ?></a></p> 
     115<?php endif; 
     116        } 
     117} 
     118 
     119 
     120/** 
     121 * Home Menu Item class 
     122 * 
     123 * @since 3.0 
     124 */ 
     125class WP_Menu_Item_Home extends WP_Menu_Item { 
     126 
     127        function WP_Menu_Item_Home() { 
     128                $menu_item_ops = array('classname' => 'menu_item_home', 'description' => __('The site homepage') ); 
     129                $this->WP_Menu_Item('home', __('Home'), $menu_item_ops); 
     130        } 
     131 
     132        function display( $args, $instance ) { 
     133                extract( $instance ); 
     134                extract($args); 
     135 
     136                $title = $this->get_title($instance); 
     137 
     138                echo $before_item . '<a href="' . home_url() . '">' . $title . '</a>' . $after_item; 
     139        } 
     140 
     141        function get_title( $instance ) { 
     142                return empty( $instance['title'] ) ? __('Home') : $instance['title']; 
     143        } 
     144 
     145        function update( $new_instance, $old_instance ) { 
     146                $instance = $old_instance; 
     147 
     148                $instance['title'] = strip_tags($new_instance['title']); 
     149 
     150                return $instance; 
     151        } 
     152 
     153        function form( $instance ) { 
     154                //Defaults 
     155                $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) ); 
     156                $title = esc_attr($this->get_title($instance)); 
     157        ?> 
     158                <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> 
     159<?php 
     160        } 
     161} 
     162 
     163/** 
     164 * Link menu item class 
     165 * 
     166 * @since 3.0 
     167 */ 
     168class WP_Menu_Item_Link extends WP_Menu_Item { 
     169 
     170        function WP_Menu_Item_Link() { 
     171                $menu_item_ops = array('description' => __('An external link') ); 
     172                $this->WP_Menu_Item('link', __('Link'), $menu_item_ops); 
     173        } 
     174 
     175        function display( $args, $instance ) { 
     176                extract( $instance ); 
     177                extract( $args ); 
     178 
     179                echo $before_item . '<a href="' . esc_attr($url) . '">' . $title . '</a>' . $after_item; 
     180        } 
     181 
     182        function update( $new_instance, $old_instance ) { 
     183                $instance = $old_instance; 
     184 
     185                $instance['url'] = trim($new_instance['url']); 
     186                $instance['title'] = strip_tags($new_instance['title']); 
     187 
     188                return $instance; 
     189        } 
     190 
     191        function form( $instance ) { 
     192                //Defaults 
     193                $instance = wp_parse_args( (array) $instance, array( 'url' => '', 'title' => '' ) ); 
     194                $url = esc_attr( $instance['url'] ); 
     195                $title = esc_attr( $instance['title'] ); 
     196        ?> 
     197                <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> 
     198                <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> 
     199<?php 
     200        } 
     201} 
     202 
     203 
     204/** 
     205 * Register all of the default WordPress menu items on startup. 
     206 * 
     207 * Calls 'menu_items_init' action after all of the WordPress menu items have been 
     208 * registered. 
     209 * 
     210 * @since 3.0 
     211 */ 
     212function wp_menu_items_init() { 
     213        if ( !is_blog_installed() ) 
     214                return; 
     215 
     216        register_menu_item('WP_Menu_Item_Page'); 
     217        register_menu_item('WP_Menu_Item_Category'); 
     218        register_menu_item('WP_Menu_Item_Home'); 
     219        register_menu_item('WP_Menu_Item_Link'); 
     220 
     221        do_action('menu_items_init'); 
     222} 
     223 
     224add_action('init', 'wp_menu_items_init', 1); 
     225 
  • 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        add_theme_support('menus'); 
     505 
     506        $i = count($wp_registered_menus) + 1; 
     507 
     508        $defaults = array( 
     509                'name' => sprintf(__('Menu %d'), $i ), 
     510                'id' => "menu-$i", 
     511                'description' => '', 
     512                'before_menu' => '<ul id="%1$s" class="menu %2$s">', 
     513                'after_menu' => "</ul>\n", 
     514        ); 
     515 
     516        $menu = wp_parse_args($args, $defaults); 
     517 
     518        $wp_registered_menus[$menu['id']] = $menu; 
     519 
     520        return $menu['id']; 
     521} 
     522 
     523/** 
     524 * Removes a menu from the list. 
     525 * 
     526 * @since 3.0.0 
     527 * 
     528 * @uses $wp_registered_menus Stores the new menu in this array by menu ID. 
     529 * 
     530 * @param string $name The ID of the menu when it was added. 
     531 */ 
     532function unregister_menu( $name ) { 
     533        global $wp_registered_menus; 
     534 
     535        if ( isset( $wp_registered_menus[$name] ) ) 
     536                unset( $wp_registered_menus[$name] ); 
     537} 
     538 
     539/** 
     540 * Register menu_item for use in menus. 
     541 * 
     542 * The default menu_item option is 'classname' that can be override. 
     543 * 
     544 * The function can also be used to unregister menu_items when $output_callback 
     545 * parameter is an empty string. 
     546 * 
     547 * @since 3.0.0 
     548 * 
     549 * @uses $wp_registered_menu_items Uses stored registered menu_items. 
     550 * @uses $wp_register_menu_item_defaults Retrieves menu_item defaults. 
     551 * 
     552 * @param int|string $id Menu_Item ID. 
     553 * @param string $name Menu_Item display title. 
     554 * @param callback $output_callback Run when menu_item is called. 
     555 * @param array|string Optional. $options Menu_Item Options. 
     556 * @param mixed $params,... Menu_Item parameters to add to menu_item. 
     557 * @return null Will return if $output_callback is empty after removing menu_item. 
     558 */ 
     559function wp_register_menu_item($id, $name, $output_callback, $options = array()) { 
     560        global $wp_registered_menu_items, $wp_registered_menu_item_controls, $wp_registered_menu_item_updates; 
     561 
     562        $id = strtolower($id); 
     563 
     564        if ( empty($output_callback) ) { 
     565                unset($wp_registered_menu_items[$id]); 
     566                return; 
     567        } 
     568 
     569        $id_base = _get_menu_item_id_base($id); 
     570        if ( !is_callable($output_callback) ) { 
     571                if ( isset($wp_registered_menu_item_controls[$id]) ) 
     572                        unset($wp_registered_menu_item_controls[$id]); 
     573 
     574                if ( isset($wp_registered_menu_item_updates[$id_base]) ) 
     575                        unset($wp_registered_menu_item_updates[$id_base]); 
     576 
     577                return; 
     578        } 
     579 
     580        $defaults = array('classname' => $output_callback); 
     581        $options = wp_parse_args($options, $defaults); 
     582        $menu_item = array( 
     583                'name' => $name, 
     584                'id' => $id, 
     585                'callback' => $output_callback, 
     586                'params' => array_slice(func_get_args(), 4) 
     587        ); 
     588        $menu_item = array_merge($menu_item, $options); 
     589 
     590        if ( is_callable($output_callback) && ( !isset($wp_registered_menu_items[$id]) || did_action( 'menu_items_init' ) ) ) 
     591                $wp_registered_menu_items[$id] = $menu_item; 
     592} 
     593 
     594/** 
     595 * Retrieve description for menu_item. 
     596 * 
     597 * When registering menu_items, the options can also include 'description' that 
     598 * describes the menu_item for display on the menu_item administration panel or 
     599 * in the theme. 
     600 * 
     601 * @since 3.0.0 
     602 * 
     603 * @param int|string $id Menu_Item ID. 
     604 * @return string Menu_Item description, if available. Null on failure to retrieve description. 
     605 */ 
     606function wp_menu_item_description( $id ) { 
     607        if ( !is_scalar($id) ) 
     608                return; 
     609 
     610        global $wp_registered_menu_items; 
     611 
     612        if ( isset($wp_registered_menu_items[$id]['description']) ) 
     613                return esc_html( $wp_registered_menu_items[$id]['description'] ); 
     614} 
     615 
     616/** 
     617 * Retrieve description for a menu. 
     618 * 
     619 * When registering menus a 'description' parameter can be included that 
     620 * describes the menu for display on the menu_item administration panel. 
     621 * 
     622 * @since 3.0.0 
     623 * 
     624 * @param int|string $id menu ID. 
     625 * @return string Menu description, if available. Null on failure to retrieve description. 
     626 */ 
     627function wp_menu_description( $id ) { 
     628        if ( !is_scalar($id) ) 
     629                return; 
     630 
     631        global $wp_registered_menus; 
     632 
     633        if ( isset($wp_registered_menus[$id]['description']) ) 
     634                return esc_html( $wp_registered_menus[$id]['description'] ); 
     635} 
     636 
     637 
     638/** 
     639 * Remove menu_item from menu. 
     640 * 
     641 * @since 3.0.0 
     642 * 
     643 * @param int|string $id Menu_Item ID. 
     644 */ 
     645function wp_unregister_menu_item($id) { 
     646        wp_register_menu_item($id, '', ''); 
     647        wp_unregister_menu_item_control($id); 
     648} 
     649 
     650/** 
     651 * Registers menu_item control callback for customizing options. 
     652 * 
     653 * The options contains the 'height', 'width', and 'id_base' keys. The 'height' 
     654 * option is never used. The 'width' option is the width of the fully expanded 
     655 * control form, but try hard to use the default width. The 'id_base' is for 
     656 * multi-menu_items (menu_items which allow multiple instances such as the text 
     657 * menu_item), an id_base must be provided. The menu_item id will end up looking like 
     658 * {$id_base}-{$unique_number}. 
     659 * 
     660 * @since 3.0.0 
     661 * 
     662 * @param int|string $id Menu ID. 
     663 * @param string $name Menu display name. 
     664 * @param callback $control_callback Run when menu is displayed. 
     665 * @param array|string $options Optional. Menu_Item options. See above long description. 
     666 * @param mixed $params,... Optional. Additional parameters to add to menu_item. 
     667 */ 
     668function wp_register_menu_item_control($id, $name, $control_callback, $options = array()) { 
     669        global $wp_registered_menu_item_controls, $wp_registered_menu_item_updates, $wp_registered_menu_items; 
     670 
     671        $id = strtolower($id); 
     672        $id_base = _get_menu_item_id_base($id); 
     673 
     674        if ( empty($control_callback) ) { 
     675                unset($wp_registered_menu_item_controls[$id]); 
     676                unset($wp_registered_menu_item_updates[$id_base]); 
     677                return; 
     678        } 
     679 
     680        if ( !is_callable($control_callback) ) { 
     681                if ( isset($wp_registered_menu_items[$id]) ) 
     682                        unset($wp_registered_menu_items[$id]); 
     683 
     684                return; 
     685        } 
     686 
     687        if ( isset($wp_registered_menu_item_controls[$id]) && !did_action( 'menu_items_init' ) ) 
     688                return; 
     689 
     690        $defaults = array('width' => 250, 'height' => 200 ); // height is never used 
     691        $options = wp_parse_args($options, $defaults); 
     692        $options['width'] = (int) $options['width']; 
     693        $options['height'] = (int) $options['height']; 
     694 
     695        $menu_item = array( 
     696                'name' => $name, 
     697                'id' => $id, 
     698                'callback' => $control_callback, 
     699                'params' => array_slice(func_get_args(), 4) 
     700        ); 
     701        $menu_item = array_merge($menu_item, $options); 
     702 
     703        $wp_registered_menu_item_controls[$id] = $menu_item; 
     704 
     705        if ( isset($wp_registered_menu_item_updates[$id_base]) ) 
     706                return; 
     707 
     708        if ( isset($menu_item['params'][0]['number']) ) 
     709                $menu_item['params'][0]['number'] = -1; 
     710 
     711        unset($menu_item['width'], $menu_item['height'], $menu_item['name'], $menu_item['id']); 
     712        $wp_registered_menu_item_updates[$id_base] = $menu_item; 
     713} 
     714 
     715function _register_menu_item_update_callback($id_base, $update_callback, $options = array()) { 
     716        global $wp_registered_menu_item_updates; 
     717 
     718        if ( isset($wp_registered_menu_item_updates[$id_base]) ) { 
     719                if ( empty($update_callback) ) 
     720                        unset($wp_registered_menu_item_updates[$id_base]); 
     721                return; 
     722        } 
     723 
     724        $menu_item = array( 
     725                'callback' => $update_callback, 
     726                'params' => array_slice(func_get_args(), 3) 
     727        ); 
     728 
     729        $menu_item = array_merge($menu_item, $options); 
     730        $wp_registered_menu_item_updates[$id_base] = $menu_item; 
     731} 
     732 
     733function _register_menu_item_form_callback($id, $name, $form_callback, $options = array()) { 
     734        global $wp_registered_menu_item_controls; 
     735 
     736        $id = strtolower($id); 
     737 
     738        if ( empty($form_callback) ) { 
     739                unset($wp_registered_menu_item_controls[$id]); 
     740                return; 
     741        } 
     742 
     743        if ( isset($wp_registered_menu_item_controls[$id]) && !did_action( 'menu_items_init' ) ) 
     744                return; 
     745 
     746        $defaults = array('width' => 250, 'height' => 200 ); 
     747        $options = wp_parse_args($options, $defaults); 
     748        $options['width'] = (int) $options['width']; 
     749        $options['height'] = (int) $options['height']; 
     750 
     751        $menu_item = array( 
     752                'name' => $name, 
     753                'id' => $id, 
     754                'callback' => $form_callback, 
     755                'params' => array_slice(func_get_args(), 4) 
     756        ); 
     757        $menu_item = array_merge($menu_item, $options); 
     758 
     759        $wp_registered_menu_item_controls[$id] = $menu_item; 
     760} 
     761 
     762/** 
     763 * Remove control callback for menu_item. 
     764 * 
     765 * @since 3.0.0 
     766 * @uses wp_register_menu_item_control() Unregisters by using empty callback. 
     767 * 
     768 * @param int|string $id Menu_Item ID. 
     769 */ 
     770function wp_unregister_menu_item_control($id) { 
     771        return wp_register_menu_item_control($id, '', ''); 
     772} 
     773 
     774/** 
     775 * Display dynamic menu. 
     776 * 
     777 * By default it displays the default menu or 'menu-1'. The 'menu-1' is 
     778 * not named by the theme, the actual name is '1', but 'menu-' is added to 
     779 * the registered menus for the name. If you named your menu 'after-post', 
     780 * then the parameter $index will still be 'after-post', but the lookup will be 
     781 * for 'menu-after-post'. 
     782 * 
     783 * It is confusing for the $index parameter, but just know that it should just 
     784 * work. When you register the menu in the theme, you will use the same name 
     785 * for this function or "Pay no heed to the man behind the curtain." Just accept 
     786 * it as an oddity of WordPress menu register and display. 
     787 * 
     788 * @since 3.0.0 
     789 * 
     790 * @param int|string $index Optional, default is 1. Name or ID of dynamic menu. 
     791 * @return bool True, if menu_item menu was found and called. False if not found or not called. 
     792 */ 
     793function dynamic_menu($index = 1) { 
     794        global $wp_registered_menus, $wp_registered_menu_items; 
     795 
     796        if ( is_int($index) ) { 
     797                $index = "menu-$index"; 
     798        } else { 
     799                $index = sanitize_title($index); 
     800                foreach ( (array) $wp_registered_menus as $key => $value ) { 
     801                        if ( sanitize_title($value['name']) == $index ) { 
     802                                $index = $key; 
     803                                break; 
     804                        } 
     805                } 
     806        } 
     807 
     808        $wp_menu_items = wp_get_menu_items(); 
     809 
     810        if ( empty($wp_registered_menus[$index]) || !array_key_exists($index, $wp_menu_items) || !is_array($wp_menu_items[$index]) || empty($wp_menu_items[$index]) ) 
     811                return false; 
     812 
     813        $menu = $wp_registered_menus[$index]; 
     814 
     815        $did_one = false; 
     816        foreach ( (array) $wp_menu_items[$index] as $id ) { 
     817 
     818                if ( !isset($wp_registered_menu_items[$id]) ) continue; 
     819 
     820                $params = array_merge( 
     821                        array( array_merge( $menu, array('menu_item_id' => $id, 'menu_item_name' => $wp_registered_menu_items[$id]['name']) ) ), 
     822                        (array) $wp_registered_menu_items[$id]['params'] 
     823                ); 
     824 
     825                // Substitute HTML id and class attributes into before_menu_item 
     826                $classname_ = ''; 
     827                foreach ( (array) $wp_registered_menu_items[$id]['classname'] as $cn ) { 
     828                        if ( is_string($cn) ) 
     829                                $classname_ .= '_' . $cn; 
     830                        elseif ( is_object($cn) ) 
     831                                $classname_ .= '_' . get_class($cn); 
     832                } 
     833                $classname_ = ltrim($classname_, '_'); 
     834                $params[0]['before_menu_item'] = sprintf($params[0]['before_menu'], $id, $classname_); 
     835 
     836                $params = apply_filters( 'dynamic_menu_params', $params ); 
     837 
     838                $callback = $wp_registered_menu_items[$id]['callback']; 
     839 
     840                if ( is_callable($callback) ) { 
     841                        call_user_func_array($callback, $params); 
     842                        $did_one = true; 
     843                } 
     844        } 
     845 
     846        return $did_one; 
     847} 
     848 
     849/** 
     850 * Whether menu_item is displayied on the front-end. 
     851 * 
     852 * Either $callback or $id_base can be used 
     853 * $id_base is the first argument when extending WP_Menu_Item class 
     854 * Without the optional $menu_item_id parameter, returns the ID of the first menu 
     855 * in which the first instance of the menu_item with the given callback or $id_base is found. 
     856 * With the $menu_item_id parameter, returns the ID of the menu where 
     857 * the menu_item with that callback/$id_base AND that ID is found. 
     858 * 
     859 * NOTE: $menu_item_id and $id_base are the same for single menu_items. To be effective 
     860 * this function has to run after menu_items have initialized, at action 'init' or later. 
     861 * 
     862 * @since 3.0.0 
     863 * 
     864 * @param callback Optional, Menu_Item callback to check. 
     865 * @param int $menu_item_id Optional, but needed for checking. Menu_Item ID. 
     866 * @param string $id_base Optional, the base ID of a menu_item created by extending WP_Menu_Item. 
     867 * @param bool $skip_inactive Optional, whether to check in 'wp_inactive_menu_items'. 
     868 * @return mixed false if menu_item is not active or id of menu in which the menu_item is active. 
     869 */ 
     870function is_active_menu_item($callback = false, $menu_item_id = false, $id_base = false, $skip_inactive = true) { 
     871        global $wp_registered_menu_items; 
     872 
     873        $wp_menu_items = wp_get_menu_items(); 
     874 
     875        if ( is_array($wp_menu_items) ) { 
     876                foreach ( $wp_menu_items as $menu => $menu_items ) { 
     877                        if ( $skip_inactive && 'wp_inactive_menu_items' == $menu ) 
     878                                continue; 
     879 
     880                        if ( is_array($menu_items) ) { 
     881                                foreach ( $menu_items as $menu_item ) { 
     882                                        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 ) ) { 
     883                                                if ( !$menu_item_id || $menu_item_id == $wp_registered_menu_items[$menu_item]['id'] ) 
     884                                                        return $menu; 
     885                                        } 
     886                                } 
     887                        } 
     888                } 
     889        } 
     890        return false; 
     891} 
     892 
     893/** 
     894 * Whether the dynamic menu is enabled and used by theme. 
     895 * 
     896 * @since 3.0.0 
     897 * 
     898 * @return bool True, if using menu_items. False, if not using menu_items. 
     899 */ 
     900function is_dynamic_menu() { 
     901        global $wp_registered_menu_items, $wp_registered_menus; 
     902        $wp_menu_items = get_option('wp_menu_items'); 
     903        foreach ( (array) $wp_registered_menus as $index => $menu ) { 
     904                if ( count($wp_menu_items[$index]) ) { 
     905                        foreach ( (array) $wp_menu_items[$index] as $menu_item ) 
     906                                if ( array_key_exists($menu_item, $wp_registered_menu_items) ) 
     907                                        return true; 
     908                } 
     909        } 
     910        return false; 
     911} 
     912 
     913/** 
     914 * Whether a menu is in use. 
     915 * 
     916 * @since 3.0 
     917 * 
     918 * @param mixed $index, menu name, id or number to check. 
     919 * @return bool true if the menu is in use, false otherwise. 
     920 */ 
     921function is_active_menu( $index ) { 
     922        $index = ( is_int($index) ) ? "menu-$index" : sanitize_title($index); 
     923        $wp_menu_items = wp_get_menu_items(); 
     924        if ( isset($wp_menu_items[$index]) && !empty($wp_menu_items[$index]) ) 
     925                return true; 
     926 
     927        return false; 
     928} 
     929 
     930/* Internal Functions */ 
     931 
     932/** 
     933 * Retrieve full list of menus and their menu_items. 
     934 * 
     935 * Will upgrade menu menu_item list, if needed. Will also save updated list, if 
     936 * needed. 
     937 * 
     938 * @since 3.0.0 
     939 * @access private 
     940 * 
     941 * @return array Upgraded list of menu_items to version 3 array format when called from the admin. 
     942 */ 
     943function wp_get_menu_items() { 
     944        global $wp_registered_menu_items, $wp_registered_menus, $_wp_menu_items; 
     945 
     946        // If loading from front page, consult $_wp_menu_items rather than options 
     947        // to see if wp_convert_menu_item_settings() has made manipulations in memory. 
     948        if ( !is_admin() ) { 
     949                if ( empty($_wp_menu_items) ) 
     950                        $_wp_menu_items = get_option('wp_menu_items', array()); 
     951 
     952                $wp_menu_items = $_wp_menu_items; 
     953        } else { 
     954                $wp_menu_items = get_option('wp_menu_items', array()); 
     955                $_wp_menu_items = array(); 
     956 
     957                if ( isset($wp_menu_items['wp_inactive_menu_items']) || empty($wp_menu_items) ) 
     958                        $wp_menu_items['array_version'] = 3; 
     959                elseif ( !isset($wp_menu_items['array_version']) ) 
     960                        $wp_menu_items['array_version'] = 1; 
     961 
     962                switch ( $wp_menu_items['array_version'] ) { 
     963                        case 1 : 
     964                                foreach ( (array) $wp_menu_items as $index => $menu ) 
     965                                if ( is_array($menu) ) 
     966                                foreach ( (array) $menu as $i => $name ) { 
     967                                        $id = strtolower($name); 
     968                                        if ( isset($wp_registered_menu_items[$id]) ) { 
     969                                                $_wp_menu_items[$index][$i] = $id; 
     970                                                continue; 
     971                                        } 
     972                                        $id = sanitize_title($name); 
     973                                        if ( isset($wp_registered_menu_items[$id]) ) { 
     974                                                $_wp_menu_items[$index][$i] = $id; 
     975                                                continue; 
     976                                        } 
     977 
     978                                        $found = false; 
     979 
     980                                        foreach ( $wp_registered_menu_items as $menu_item_id => $menu_item ) { 
     981                                                if ( strtolower($menu_item['name']) == strtolower($name) ) { 
     982                                                        $_wp_menu_items[$index][$i] = $menu_item['id']; 
     983                                                        $found = true; 
     984                                                        break; 
     985                                                } elseif ( sanitize_title($menu_item['name']) == sanitize_title($name) ) { 
     986                                                        $_wp_menu_items[$index][$i] = $menu_item['id']; 
     987                                                        $found = true; 
     988                                                        break; 
     989                                                } 
     990                                        } 
     991 
     992                                        if ( $found ) 
     993                                                continue; 
     994 
     995                                        unset($_wp_menu_items[$index][$i]); 
     996                                } 
     997                                $_wp_menu_items['array_version'] = 2; 
     998                                $wp_menu_items = $_wp_menu_items; 
     999                                unset($_wp_menu_items); 
     1000 
     1001                        case 2 : 
     1002                                $menus = array_keys( $wp_registered_menus ); 
     1003                                if ( !empty( $menus ) ) { 
     1004                                        // Move the known-good ones first 
     1005                                        foreach ( (array) $menus as $id ) { 
     1006                                                if ( array_key_exists( $id, $wp_menu_items ) ) { 
     1007                                                        $_wp_menu_items[$id] = $wp_menu_items[$id]; 
     1008                                                        unset($wp_menu_items[$id], $menus[$id]); 
     1009                                                } 
     1010                                        } 
     1011 
     1012                                        // move the rest to wp_inactive_menu_items 
     1013                                        if ( !isset($_wp_menu_items['wp_inactive_menu_items']) ) 
     1014                                                $_wp_menu_items['wp_inactive_menu_items'] = array(); 
     1015 
     1016                                        if ( !empty($wp_menu_items) ) { 
     1017                                                foreach ( $wp_menu_items as $lost => $val ) { 
     1018                                                        if ( is_array($val) ) 
     1019                                                                $_wp_menu_items['wp_inactive_menu_items'] = array_merge( (array) $_wp_menu_items['wp_inactive_menu_items'], $val ); 
     1020                                                } 
     1021                                        } 
     1022 
     1023                                        $wp_menu_items = $_wp_menu_items; 
     1024                                        unset($_wp_menu_items); 
     1025                                } 
     1026                } 
     1027        } 
     1028 
     1029        if ( isset($wp_menu_items['array_version']) ) 
     1030                unset($wp_menu_items['array_version']); 
     1031 
     1032        $wp_menu_items = apply_filters('wp_menu_items', $wp_menu_items); 
     1033        return $wp_menu_items; 
     1034} 
     1035 
     1036/** 
     1037 * Set the menu menu_item option to update menus. 
     1038 * 
     1039 * @since 3.0.0 
     1040 * @access private 
     1041 * 
     1042 * @param array $wp_menu_items Menu menu_items and their settings. 
     1043 */ 
     1044function wp_set_menu_items( $wp_menu_items ) { 
     1045        if ( !isset( $wp_menu_items['array_version'] ) ) 
     1046                $wp_menu_items['array_version'] = 3; 
     1047        update_option( 'wp_menu_items', $wp_menu_items ); 
     1048} 
     1049 
     1050/** 
     1051 * Retrieve default registered menus list. 
     1052 * 
     1053 * @since 3.0.0 
     1054 * @access private 
     1055 * 
     1056 * @return array 
     1057 */ 
     1058function wp_get_menu_item_defaults() { 
     1059        global $wp_registered_menus; 
     1060 
     1061        $defaults = array(); 
     1062 
     1063        foreach ( (array) $wp_registered_menus as $index => $menu ) 
     1064                $defaults[$index] = array(); 
     1065 
     1066        return $defaults; 
     1067} 
     1068 
     1069/** 
     1070 * Private 
     1071 */ 
     1072function _get_menu_item_id_base($id) { 
     1073        return preg_replace( '/-[0-9]+$/', '', $id ); 
     1074} 
     1075 
     1076// Initialization code 
     1077 
     1078/*ignore*/ 
     1079global $wp_menu_item_factory; 
     1080 
     1081/** 
     1082 * WordPress Menu Item Factory Object 
     1083 * @global object $wp_menu_item_factory 
     1084 * @since 3.0 
     1085 */ 
     1086$wp_menu_item_factory =& new WP_Menu_Item_Factory(); 
     1087 
  • 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 
     21register_menus(2); 
     22 
    2023/** @ignore */ 
    2124function kubrick_head() { 
    2225        $head = "<style type='text/css'>\n<!--"; 
  • wp-settings.php

     
    123123require( ABSPATH . WPINC . '/media.php' ); 
    124124require( ABSPATH . WPINC . '/http.php' ); 
    125125require( ABSPATH . WPINC . '/widgets.php' ); 
     126require (ABSPATH . WPINC . '/menus.php'); 
    126127 
    127128// Load multisite-specific files. 
    128129if ( is_multisite() ) { 
     
    270271// Load any template functions the theme supports. 
    271272require_if_theme_supports( 'post-thumbnails', ABSPATH . WPINC . '/post-thumbnail-template.php' ); 
    272273 
     274// Menus init 
     275if ( current_theme_supports( 'menus' ) ) { 
     276        if ( apply_filters('load_default_menu_items', true) ) 
     277                require( ABSPATH . WPINC . '/default-menu-items.php' ); 
     278 
     279        function _wp_add_menus_menu() { 
     280                global $submenu; 
     281                $submenu['themes.php'][8] = array( __( 'Menus' ), 'switch_themes', 'menus.php' ); 
     282                ksort( $submenu['themes.php'], SORT_NUMERIC ); 
     283        } 
     284        add_action( '_admin_menu', '_wp_add_menus_menu' ); 
     285} 
     286 
    273287register_shutdown_function( 'shutdown_action_hook' ); 
    274288 
    275289// Set up current user. 
     
    278292// Everything is loaded and initialized. 
    279293do_action( 'init' ); 
    280294 
    281 ?> 
    282  No newline at end of file 
     295?> 
  • wp-admin/admin-ajax.php

     
    14181418 
    14191419        die(); 
    14201420        break; 
     1421case 'menu-items-order' : 
     1422        check_ajax_referer( 'save-menu-items', 'savemenu_items' ); 
     1423 
     1424        if ( !current_user_can('switch_themes') ) 
     1425                die('-1'); 
     1426 
     1427        unset( $_POST['savemenu_items'], $_POST['action'] ); 
     1428 
     1429        // save menu_items order for all menus 
     1430        if ( is_array($_POST['menus']) ) { 
     1431                $menus = array(); 
     1432                foreach ( $_POST['menus'] as $key => $val ) { 
     1433                        $sb = array(); 
     1434                        if ( !empty($val) ) { 
     1435                                $val = explode(',', $val); 
     1436                                foreach ( $val as $k => $v ) { 
     1437                                        if ( strpos($v, 'menu-item-') === false ) 
     1438                                                continue; 
     1439 
     1440                                        $tmp = explode('_', $v, 2); 
     1441                                        $sb[$k] = $tmp[1]; 
     1442                                } 
     1443                        } 
     1444                        $menus[$key] = $sb; 
     1445                } 
     1446                wp_set_menu_items($menus); 
     1447                die('1'); 
     1448        } 
     1449 
     1450        die('-1'); 
     1451        break; 
     1452case 'save-menu-item' : 
     1453        check_ajax_referer( 'save-menu-items', 'savemenu_items' ); 
     1454 
     1455        if ( !current_user_can('switch_themes') || !isset($_POST['id_base']) ) 
     1456                die('-1'); 
     1457 
     1458        unset( $_POST['savemenu_items'], $_POST['action'] ); 
     1459 
     1460        do_action('load-menus.php'); 
     1461        do_action('menus.php'); 
     1462        do_action('menu_admin_setup'); 
     1463 
     1464        $id_base = $_POST['id_base']; 
     1465        $menu_item_id = $_POST['menu-item-id']; 
     1466        $menu_id = $_POST['menu']; 
     1467        $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0; 
     1468        $settings = isset($_POST['menu-item-' . $id_base]) && is_array($_POST['menu-item-' . $id_base]) ? $_POST['menu-item-' . $id_base] : false; 
     1469        $error = '<p>' . __('An error has occured. Please reload the page and try again.') . '</p>'; 
     1470 
     1471        $menus = wp_get_menu_items(); 
     1472        $menu = isset($menus[$menu_id]) ? $menus[$menu_id] : array(); 
     1473 
     1474        // delete 
     1475        if ( isset($_POST['delete_menu_item']) && $_POST['delete_menu_item'] ) { 
     1476 
     1477                if ( !isset($wp_registered_menu_items[$menu_item_id]) ) 
     1478                        die($error); 
     1479 
     1480                $menu = array_diff( $menu, array($menu_item_id) ); 
     1481                $_POST = array('menu' => $menu_id, 'menu-item-' . $id_base => array(), 'the-menu-item-id' => $menu_item_id, 'delete_menu_item' => '1'); 
     1482        } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) { 
     1483                if ( !$multi_number ) 
     1484                        die($error); 
     1485 
     1486                $_POST['menu-item-' . $id_base] = array( $multi_number => array_shift($settings) ); 
     1487                $menu_item_id = $id_base . '-' . $multi_number; 
     1488                $menu[] = $menu_item_id; 
     1489        } 
     1490        $_POST['menu-item-id'] = $menu; 
     1491 
     1492        foreach ( (array) $wp_registered_menu_item_updates as $name => $control ) { 
     1493 
     1494                if ( $name == $id_base ) { 
     1495                        if ( !is_callable( $control['callback'] ) ) 
     1496                                continue; 
     1497 
     1498                        ob_start(); 
     1499                                call_user_func_array( $control['callback'], $control['params'] ); 
     1500                        ob_end_clean(); 
     1501                        break; 
     1502                } 
     1503        } 
     1504 
     1505        if ( isset($_POST['delete_menu_item']) && $_POST['delete_menu_item'] ) { 
     1506                $menus[$menu_id] = $menu; 
     1507                wp_set_menu_items($menus); 
     1508                echo "deleted:$menu_item_id"; 
     1509                die(); 
     1510        } 
     1511 
     1512        if ( !empty($_POST['add_new']) ) 
     1513                die(); 
     1514 
     1515        if ( $form = $wp_registered_menu_item_controls[$menu_item_id] ) 
     1516                call_user_func_array( $form['callback'], $form['params'] ); 
     1517 
     1518        die(); 
     1519        break; 
    14211520case 'image-editor': 
    14221521        $attachment_id = intval($_POST['postid']); 
    14231522        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 
     27        foreach ( $sort as $menu_item ) { 
     28                if ( in_array( $menu_item['callback'], $done, true ) ) // We already showed this multi-menu_item 
     29                        continue; 
     30 
     31                $menu = is_active_menu_item( $menu_item['callback'], $menu_item['id'], false, false ); 
     32                $done[] = $menu_item['callback']; 
     33 
     34                if ( ! isset( $menu_item['params'][0] ) ) 
     35                        $menu_item['params'][0] = array(); 
     36 
     37                $args = array( 'menu_item_id' => $menu_item['id'], 'menu_item_name' => $menu_item['name'], '_display' => 'template' ); 
     38 
     39                if ( isset($wp_registered_menu_item_controls[$menu_item['id']]['id_base']) && isset($menu_item['params'][0]['number']) ) { 
     40                        $id_base = $wp_registered_menu_item_controls[$menu_item['id']]['id_base']; 
     41                        $args['_temp_id'] = "$id_base-__i__"; 
     42                        $args['_multi_num'] = next_menu_item_id_number($id_base); 
     43                        $args['_add'] = 'multi'; 
     44                } else { 
     45                        $args['_add'] = 'single'; 
     46                        if ( $menu ) 
     47                                $args['_hide'] = '1'; 
     48                } 
     49 
     50                $args = wp_list_menu_item_controls_dynamic_menu( array( 0 => $args, 1 => $menu_item['params'][0] ) ); 
     51                call_user_func_array( 'wp_menu_item_control', $args ); 
     52        } 
     53} 
     54 
     55/** 
     56 * Show the menu_items and their settings for a menu. 
     57 * Used in the the admin menu_item config screen. 
     58 * 
     59 * @since 3.0 
     60 * 
     61 * @param string $menu id slug of the menu 
     62 */ 
     63function wp_list_menu_item_controls( $menu ) { 
     64        add_filter( 'dynamic_menu_params', 'wp_list_menu_item_controls_dynamic_menu' ); 
     65 
     66        echo "<div id='$menu' class='menu-items-sortables'>\n"; 
     67 
     68        $description = wp_menu_description( $menu ); 
     69 
     70        if ( !empty( $description ) ) { 
     71                echo "<div class='menu-description'>\n"; 
     72                echo "\t<p class='description'>$description</p>";  
     73                echo "</div>\n"; 
     74        } 
     75 
     76        dynamic_menu( $menu ); 
     77        echo "</div>\n"; 
     78} 
     79 
     80/** 
     81 * {@internal Missing Short Description}} 
     82 * 
     83 * @since 3.0 
     84 * 
     85 * @param array $params 
     86 * @return array 
     87 */ 
     88function wp_list_menu_item_controls_dynamic_menu( $params ) { 
     89        global $wp_registered_menu_items; 
     90        static $i = 0; 
     91        $i++; 
     92 
     93        $menu_item_id = $params[0]['menu_item_id']; 
     94        $id = isset($params[0]['_temp_id']) ? $params[0]['_temp_id'] : $menu_item_id; 
     95        $hidden = isset($params[0]['_hide']) ? ' style="display:none;"' : ''; 
     96 
     97        $params[0]['before_menu_item'] = "<div id='menu-item-${i}_$id' class='menu-item'$hidden>"; 
     98        $params[0]['after_menu_item'] = "</div>"; 
     99        if ( is_callable( $wp_registered_menu_items[$menu_item_id]['callback'] ) ) { 
     100                $wp_registered_menu_items[$menu_item_id]['_callback'] = $wp_registered_menu_items[$menu_item_id]['callback']; 
     101                $wp_registered_menu_items[$menu_item_id]['callback'] = 'wp_menu_item_control'; 
     102        } 
     103 
     104        return $params; 
     105} 
     106 
     107function next_menu_item_id_number($id_base) { 
     108        global $wp_registered_menu_items; 
     109        $number = 1; 
     110 
     111        foreach ( $wp_registered_menu_items as $menu_item_id => $menu_item ) { 
     112                if ( preg_match( '/' . $id_base . '-([0-9]+)$/', $menu_item_id, $matches ) ) 
     113                        $number = max($number, $matches[1]); 
     114        } 
     115        $number++; 
     116 
     117        return $number; 
     118} 
     119 
     120/** 
     121 * Meta menu_item used to display the control form for a menu_item. 
     122 * 
     123 * Called from dynamic_menu(). 
     124 * 
     125 * @since 3.0 
     126 * 
     127 * @param array $menu_args 
     128 * @return array 
     129 */ 
     130function wp_menu_item_control( $menu_args ) { 
     131        global $wp_registered_menu_items, $wp_registered_menu_item_controls, $menu_items_map; 
     132 
     133        $menu_item_id = $menu_args['menu_item_id']; 
     134        $menu_id = isset($menu_args['id']) ? $menu_args['id'] : false; 
     135        $key = $menu_id ? array_search( $menu_item_id, $menu_items_map[$menu_id] ) : '-1'; // position of menu_item in menu 
     136        $control = isset($wp_registered_menu_item_controls[$menu_item_id]) ? $wp_registered_menu_item_controls[$menu_item_id] : array(); 
     137        $menu_item = $wp_registered_menu_items[$menu_item_id]; 
     138 
     139        $id_format = $menu_item['id']; 
     140        $menu_item_number = isset($control['params'][0]['number']) ? $control['params'][0]['number'] : ''; 
     141        $id_base = isset($control['id_base']) ? $control['id_base'] : $menu_item_id; 
     142        $multi_number = isset($menu_args['_multi_num']) ? $menu_args['_multi_num'] : ''; 
     143        $add_new = isset($menu_args['_add']) ? $menu_args['_add'] : ''; 
     144 
     145        $query_arg = array( 'editmenu_item' => $menu_item['id'] ); 
     146        if ( $add_new ) { 
     147                $query_arg['addnew'] = 1; 
     148                if ( $multi_number ) { 
     149                        $query_arg['num'] = $multi_number; 
     150                        $query_arg['base'] = $id_base; 
     151                } 
     152        } else { 
     153                $query_arg['menu'] = $menu_id; 
     154                $query_arg['key'] = $key; 
     155        } 
     156 
     157        // We aren't showing a menu_item control, we're outputing a template for a mult-menu_item control 
     158        if ( isset($menu_args['_display']) && 'template' == $menu_args['_display'] && $menu_item_number ) { 
     159                // number == -1 implies a template where id numbers are replaced by a generic '__i__' 
     160                $control['params'][0]['number'] = -1; 
     161                // with id_base menu_item id's are constructed like {$id_base}-{$id_number} 
     162                if ( isset($control['id_base']) ) 
     163                        $id_format = $control['id_base'] . '-__i__'; 
     164        } 
     165 
     166        $wp_registered_menu_items[$menu_item_id]['callback'] = $wp_registered_menu_items[$menu_item_id]['_callback']; 
     167        unset($wp_registered_menu_items[$menu_item_id]['_callback']); 
     168 
     169        $menu_item_title = esc_html( strip_tags( $menu_args['menu_item_name'] ) ); 
     170        $has_form = 'noform'; 
     171 
     172        echo $menu_args['before_menu_item']; ?> 
     173        <div class="menu-item-top"> 
     174        <div class="menu-item-title-action"> 
     175                <a class="menu-item-action hide-if-no-js" href="#available-menu-items"></a> 
     176                <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> 
     177        </div> 
     178        <div class="menu-item-title"><h4><?php echo $menu_item_title ?><span class="in-menu-item-title"></span></h4></div> 
     179        </div> 
     180 
     181        <div class="menu-item-inside"> 
     182        <form action="" method="post"> 
     183        <div class="menu-item-content"> 
     184<?php 
     185        if ( isset($control['callback']) ) 
     186                $has_form = call_user_func_array( $control['callback'], $control['params'] ); 
     187        else 
     188                echo "\t\t<p>" . __('There are no options for this menu item.') . "</p>\n"; ?> 
     189        </div> 
     190        <input type="hidden" name="menu-item-id" class="menu-item-id" value="<?php echo esc_attr($id_format); ?>" /> 
     191        <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr($id_base); ?>" /> 
     192        <input type="hidden" name="menu-item-width" class="menu-item-width" value="<?php if (isset( $control['width'] )) echo esc_attr($control['width']); ?>" /> 
     193        <input type="hidden" name="menu-item-height" class="menu-item-height" value="<?php if (isset( $control['height'] )) echo esc_attr($control['height']); ?>" /> 
     194        <input type="hidden" name="menu_item_number" class="menu_item_number" value="<?php echo esc_attr($menu_item_number); ?>" /> 
     195        <input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr($multi_number); ?>" /> 
     196        <input type="hidden" name="add_new" class="add_new" value="<?php echo esc_attr($add_new); ?>" /> 
     197 
     198        <div class="menu-item-control-actions"> 
     199                <div class="alignleft"> 
     200                <a class="menu-item-control-remove" href="#remove"><?php _e('Delete'); ?></a> | 
     201                <a class="menu-item-control-close" href="#close"><?php _e('Close'); ?></a> 
     202                </div> 
     203                <div class="alignright<?php if ( 'noform' === $has_form ) echo ' menu-item-control-noform'; ?>"> 
     204                <img src="images/wpspin_light.gif" class="ajax-feedback " title="" alt="" /> 
     205                <input type="submit" name="savemenu_item" class="button-primary menu-item-control-save" value="<?php esc_attr_e('Save'); ?>" /> 
     206                </div> 
     207                <br class="clear" /> 
     208        </div> 
     209        </form> 
     210        </div> 
     211 
     212        <div class="menu-item-description"> 
     213<?php echo ( $menu_item_description = wp_menu_item_description($menu_item_id) ) ? "$menu_item_description\n" : "$menu_item_title\n"; ?> 
     214        </div> 
     215<?php 
     216        echo $menu_args['after_menu_item']; 
     217        return $menu_args; 
     218} 
     219 
  • wp-admin/js/menus.dev.js

     
     1(function($) { 
     2        window.wpMenus = { 
     3                 
     4        init : function() { 
     5                var rem, menus = $('div.menu-items-sortables'); 
     6 
     7                $('.menu-item-dropdown select').attr('size', 7).change(function(ev) { 
     8                        var active_menu = $('.menu-item-liquid-right .menu-items-sortables').not('.ui-sortable-disabled').eq(0); 
     9 
     10                        if ( ! active_menu.length ) 
     11                                return; 
     12 
     13                        var select = $(this), 
     14                                selected = select.find('option:selected'), 
     15                                item_type = select.parents('.menu-item-dropdown').attr('id').replace('-dropdown', ''), 
     16                                item_id = selected.val(), 
     17                                item_title = ''; 
     18 
     19                        if ( 'other' == item_type ) 
     20                                item_type = item_id; 
     21                        else 
     22                                item_title = $.trim(selected.text().replace('&nbsp;', '')); 
     23 
     24                        if ( '' == item_id ) 
     25                                return; 
     26 
     27                        wpMenus.addItem(active_menu, item_type, item_id, item_title); 
     28                }); 
     29 
     30                $('#menu-items-right').children('.menu-items-holder-wrap').children('.menu-name').click(function(){ 
     31                        var c = $(this).siblings('.menu-items-sortables'), p = $(this).parent(); 
     32                        if ( !p.hasClass('closed') ) { 
     33                                c.sortable('disable'); 
     34                                p.addClass('closed'); 
     35                        } else { 
     36                                p.removeClass('closed'); 
     37                                c.sortable('enable').sortable('refresh'); 
     38                        } 
     39                }); 
     40 
     41                $('#menu-items-left').children('.menu-items-holder-wrap').children('.menu-name').click(function() { 
     42                        $(this).siblings('.menu-item-holder').parent().toggleClass('closed'); 
     43                }); 
     44 
     45                wpMenus.resize(); 
     46 
     47                $('a.menu-item-action').live('click', function(){ 
     48                        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 ); 
     49                         
     50                        if ( inside.is(':hidden') ) { 
     51                                if ( w > 250 && inside.closest('div.menu-items-sortables').length ) { 
     52                                        css['width'] = w + 30 + 'px'; 
     53                                        if ( inside.closest('div.menu-item-liquid-right').length ) 
     54                                                css['marginLeft'] = 235 - w + 'px'; 
     55                                        menu_item.css(css); 
     56                                } 
     57                                wpMenus.fixLabels(menu_item); 
     58                                inside.slideDown('fast'); 
     59                        } else { 
     60                                inside.slideUp('fast', function() { 
     61                                        menu_item.css({'width':'','marginLeft':''}); 
     62                                }); 
     63                        } 
     64                        return false; 
     65                }); 
     66 
     67                $('input.menu-item-control-save').live('click', function(){ 
     68                        wpMenus.save( $(this).closest('div.menu-item'), 0, 1, 0 ); 
     69                        return false; 
     70                }); 
     71 
     72                $('a.menu-item-control-remove').live('click', function(){ 
     73                        wpMenus.save( $(this).closest('div.menu-item'), 1, 1, 0 ); 
     74                        return false; 
     75                }); 
     76 
     77                $('a.menu-item-control-close').live('click', function(){ 
     78                        wpMenus.close( $(this).closest('div.menu-item') ); 
     79                        return false; 
     80                }); 
     81 
     82                menus.children('.menu-item').each(function() { 
     83                        wpMenus.appendTitle(this); 
     84                        if ( $('p.menu-item-error', this).length ) 
     85                                $('a.menu-item-action', this).click(); 
     86                }); 
     87 
     88                $('#menu-item-list').children('.menu-item').draggable({ 
     89                        connectToSortable: 'div.menu-items-sortables', 
     90                        handle: '> .menu-item-top > .menu-item-title', 
     91                        distance: 2, 
     92                        helper: 'clone', 
     93                        zIndex: 5, 
     94                        containment: 'document', 
     95                        start: function(e,ui) { 
     96                                wpMenus.fixWebkit(1); 
     97                                ui.helper.find('div.menu-item-description').hide(); 
     98                        }, 
     99                        stop: function(e,ui) { 
     100                                if ( rem ) 
     101                                        $(rem).hide(); 
     102                                rem = ''; 
     103                                wpMenus.fixWebkit(); 
     104                        } 
     105                }); 
     106 
     107                menus.sortable({ 
     108                        placeholder: 'menu-item-placeholder', 
     109                        items: '> .menu-item', 
     110                        handle: '> .menu-item-top > .menu-item-title', 
     111                        cursor: 'move', 
     112                        distance: 2, 
     113                        containment: 'document', 
     114                        start: function(e,ui) { 
     115                                wpMenus.fixWebkit(1); 
     116                                ui.item.children('.menu-item-inside').hide(); 
     117                                ui.item.css({'marginLeft':'','width':''}); 
     118                        }, 
     119                        stop: function(e,ui) { 
     120                                if ( ui.item.hasClass('ui-draggable') ) 
     121                                        ui.item.draggable('destroy'); 
     122 
     123                                if ( ui.item.hasClass('deleting') ) { 
     124                                        wpMenus.save( ui.item, 1, 0, 1 ); // delete menu item 
     125                                        ui.item.remove(); 
     126                                        return; 
     127                                } 
     128 
     129                                var sb = $(this).attr('id'); 
     130                                 
     131                                ui.item.css({'marginLeft':'','width':''}); 
     132 
     133                                wpMenus.fixWebkit(); 
     134 
     135                                wpMenus.saveOrder(sb); 
     136                        }, 
     137                        receive: function(e,ui) { 
     138                                if ( !$(this).is(':visible') ) 
     139                                        $(this).sortable('cancel'); 
     140                        } 
     141                }).sortable('option', 'connectWith', 'div.menu-items-sortables').parent().filter('.closed').children('.menu-items-sortables').sortable('disable'); 
     142 
     143                $('#available-menu-items').droppable({ 
     144                        tolerance: 'pointer', 
     145                        accept: function(o){ 
     146                                return $(o).parent().attr('id') != 'menu-item-list'; 
     147                        }, 
     148                        drop: function(e,ui) { 
     149                                ui.draggable.addClass('deleting'); 
     150                                $('#removing-menu-item').hide().children('span').html(''); 
     151                        }, 
     152                        over: function(e,ui) { 
     153                                ui.draggable.addClass('deleting'); 
     154                                $('div.menu-item-placeholder').hide(); 
     155 
     156                                if ( ui.draggable.hasClass('ui-sortable-helper') ) 
     157                                        $('#removing-menu-item').show().children('span') 
     158                                        .html( ui.draggable.find('div.menu-item-title').children('h4').html() ); 
     159                        }, 
     160                        out: function(e,ui) { 
     161                                ui.draggable.removeClass('deleting'); 
     162                                $('div.menu-item-placeholder').show(); 
     163                                $('#removing-menu-item').hide().children('span').html(''); 
     164                        } 
     165                }); 
     166        }, 
     167 
     168        addItem : function(active_menu, item_type, item_id, item_title) { 
     169                var item = $('.menu-item[id*="' + item_type + '-__i__"]').clone(true), 
     170                        n = item.find('input.multi_number').val(), 
     171                        id = item.attr('id'); 
     172 
     173                active_menu.append(item); 
     174 
     175                item.html( item.html().replace(/<[^<>]+>/g, function(m){ return m.replace(/__i__|%i%/g, n); }) ); 
     176                item.attr( 'id', id.replace(/__i__|%i%/g, n) ); 
     177                n++; 
     178                $('div#' + id).find('input.multi_number').val(n); 
     179 
     180                item.find('input[id*="-' + item_type + '_id"]').val(item_id); 
     181 
     182                if ( item_title ) 
     183                        item.find('input[id*="-title"]').val(item_title); 
     184 
     185                wpMenus.appendTitle(item.get()); 
     186 
     187                wpMenus.save( item, 0, 0, 1 ); 
     188 
     189                return true; 
     190        }, 
     191 
     192        saveOrder : function(sb) { 
     193                if ( sb ) 
     194                        $('#' + sb).closest('div.menu-items-holder-wrap').find('img.ajax-feedback').css('visibility', 'visible'); 
     195 
     196                var a = { 
     197                        action: 'menu-items-order', 
     198                        savemenu_items: $('#_wpnonce_menu_items').val(), 
     199                        menus: [] 
     200                }; 
     201 
     202                $('div.menu-items-sortables').each( function() { 
     203                        a['menus[' + $(this).attr('id') + ']'] = $(this).sortable('toArray').join(','); 
     204                }); 
     205 
     206                $.post( ajaxurl, a, function() { 
     207                        $('img.ajax-feedback').css('visibility', 'hidden'); 
     208                }); 
     209 
     210                wpMenus.resize(); 
     211        }, 
     212 
     213        save : function(menu_item, del, animate, order) { 
     214                var sb = menu_item.closest('div.menu-items-sortables').attr('id'), data = menu_item.find('form').serialize(), a; 
     215                menu_item = $(menu_item); 
     216                $('.ajax-feedback', menu_item).css('visibility', 'visible'); 
     217 
     218                a = { 
     219                        action: 'save-menu-item', 
     220                        savemenu_items: $('#_wpnonce_menu_items').val(), 
     221                        menu: sb 
     222                }; 
     223 
     224                if ( del ) 
     225                        a['delete_menu_item'] = 1; 
     226 
     227                data += '&' + $.param(a); 
     228 
     229                $.post( ajaxurl, data, function(r){ 
     230                        var id; 
     231 
     232                        if ( del ) { 
     233                                if ( !$('input.menu_item_number', menu_item).val() ) { 
     234                                        id = $('input.menu-item-id', menu_item).val(); 
     235                                        $('#available-menu-items').find('input.menu-item-id').each(function(){ 
     236                                                if ( $(this).val() == id ) 
     237                                                        $(this).closest('div.menu-item').show(); 
     238                                        }); 
     239                                } 
     240 
     241                                if ( animate ) { 
     242                                        order = 0; 
     243                                        menu_item.slideUp('fast', function(){ 
     244                                                $(this).remove(); 
     245                                                wpMenus.saveOrder(); 
     246                                        }); 
     247                                } else { 
     248                                        menu_item.remove(); 
     249                                        wpMenus.resize(); 
     250                                } 
     251                        } else { 
     252                                $('.ajax-feedback').css('visibility', 'hidden'); 
     253                                if ( r && r.length > 2 ) { 
     254                                        $('div.menu-item-content', menu_item).html(r); 
     255                                        wpMenus.appendTitle(menu_item); 
     256                                        wpMenus.fixLabels(menu_item); 
     257                                } 
     258                        } 
     259                        if ( order ) 
     260                                wpMenus.saveOrder(); 
     261                }); 
     262        }, 
     263 
     264        appendTitle : function(menu_item) { 
     265                var title = $('input[id*="-title"]', menu_item); 
     266                if ( title = title.val() ) { 
     267                        title = title.replace(/<[^<>]+>/g, '').replace(/</g, '&lt;').replace(/>/g, '&gt;'); 
     268                        $(menu_item).children('.menu-item-top').children('.menu-item-title').children() 
     269                                .children('.in-menu-item-title').html(': ' + title); 
     270                } 
     271        }, 
     272 
     273        resize : function() { 
     274                $('div.menu-items-sortables').each(function(){ 
     275                        var h = 0, H = $(this).children('.menu-item').length; 
     276                        h = h + parseInt(H * 38, 10); 
     277                        $(this).css( 'minHeight', h + 'px' ); 
     278                }); 
     279        }, 
     280 
     281    fixWebkit : function(n) { 
     282        n = n ? 'none' : ''; 
     283        $('body').css({ 
     284                        WebkitUserSelect: n, 
     285                        KhtmlUserSelect: n 
     286                }); 
     287    }, 
     288 
     289    fixLabels : function(menu_item) { 
     290                menu_item.children('.menu-item-inside').find('label').each(function(){ 
     291                        var f = $(this).attr('for'); 
     292                        if ( f && f == $('input', this).attr('id') ) 
     293                                $(this).removeAttr('for'); 
     294                }); 
     295        }, 
     296 
     297    close : function(menu_item) { 
     298                menu_item.children('.menu-item-inside').slideUp('fast', function(){ 
     299                        menu_item.css({'width':'','marginLeft':''}); 
     300                }); 
     301        } 
     302}; 
     303 
     304$(document).ready(function($){ wpMenus.init(); }); 
     305 
     306})(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// These are the menu_items grouped by menu 
     37$menu_items_map = wp_get_menu_items(); 
     38if ( empty( $menu_items_map ) ) 
     39        $menu_items_map = wp_get_menu_item_defaults(); 
     40 
     41// look for "lost" menu_items, this has to run at least on each theme change 
     42function retrieve_menu_items() { 
     43        global $wp_registered_menu_item_updates, $wp_registered_menus, $menu_items_map, $wp_registered_menu_items; 
     44 
     45        $_menus_menu_items = array(); 
     46        $menus = array_keys($wp_registered_menus); 
     47 
     48        unset( $menu_items_map['array_version'] ); 
     49 
     50        $old = array_keys($menu_items_map); 
     51        sort($old); 
     52        sort($menus); 
     53 
     54        if ( $old == $menus ) 
     55                return; 
     56 
     57        // Move the known-good ones first 
     58        foreach ( $menus as $id ) { 
     59                if ( array_key_exists( $id, $menu_items_map ) ) { 
     60                        $_menus_menu_items[$id] = $menu_items_map[$id]; 
     61                        unset($menu_items_map[$id], $menus[$id]); 
     62                } 
     63        } 
     64 
     65        // discard invalid, theme-specific menu_items from menus 
     66        $shown_menu_items = array(); 
     67        foreach ( $_menus_menu_items as $menu => $menu_items ) { 
     68                if ( !is_array($menu_items) ) 
     69                        continue; 
     70 
     71                $_menu_items = array(); 
     72                foreach ( $menu_items as $menu_item ) { 
     73                        if ( isset($wp_registered_menu_items[$menu_item]) ) 
     74                                $_menu_items[] = $menu_item; 
     75                } 
     76                $_menus_menu_items[$menu] = $_menu_items; 
     77                $shown_menu_items = array_merge($shown_menu_items, $_menu_items); 
     78        } 
     79 
     80        $menu_items_map = $_menus_menu_items; 
     81        unset($_menus_menu_items, $_menu_items); 
     82 
     83        // find hidden/lost multi-menu_item instances 
     84        $lost_menu_items = array(); 
     85        foreach ( $wp_registered_menu_items as $key => $val ) { 
     86                if ( in_array($key, $shown_menu_items, true) ) 
     87                        continue; 
     88 
     89                $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key); 
     90 
     91                if ( 2 > (int) $number ) 
     92                        continue; 
     93 
     94                $lost_menu_items[] = $key; 
     95        } 
     96 
     97        wp_set_menu_items($menu_items_map); 
     98} 
     99retrieve_menu_items(); 
     100 
     101if ( ! count($wp_registered_menus) ) { 
     102        // The theme has no menus, die. 
     103        require_once( 'admin-header.php' ); 
     104?> 
     105 
     106        <div class="wrap"> 
     107        <?php screen_icon(); ?> 
     108        <h2><?php echo esc_html( $title ); ?></h2> 
     109                <div class="error"> 
     110                        <p><?php _e( 'No Menus Defined' ); ?></p> 
     111                </div> 
     112                <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> 
     113        </div> 
     114 
     115<?php 
     116        require_once( 'admin-footer.php' ); 
     117        exit; 
     118} 
     119 
     120// We're saving a menu_item without js 
     121if ( isset($_POST['savemenu_item']) || isset($_POST['removemenu_item']) ) { 
     122        $menu_item_id = $_POST['menu-item-id']; 
     123        check_admin_referer("save-delete-menu-item-$menu_item_id"); 
     124 
     125        $number = isset($_POST['multi_number']) ? (int) $_POST['multi_number'] : ''; 
     126        if ( $number ) { 
     127                foreach ( $_POST as $key => $val ) { 
     128                        if ( is_array($val) && preg_match('/__i__|%i%/', key($val)) ) { 
     129                                $_POST[$key] = array( $number => array_shift($val) ); 
     130                                break; 
     131                        } 
     132                } 
     133        } 
     134 
     135        $menu_id = $_POST['menu']; 
     136        $position = isset($_POST[$menu_id . '_position']) ? (int) $_POST[$menu_id . '_position'] - 1 : 0; 
     137 
     138        $id_base = $_POST['id_base']; 
     139        $menu = isset($menu_items_map[$menu_id]) ? $menu_items_map[$menu_id] : array(); 
     140 
     141        // delete 
     142        if ( isset($_POST['removemenu_item']) && $_POST['removemenu_item'] ) { 
     143 
     144                if ( !in_array($menu_item_id, $menu, true) ) { 
     145                        wp_redirect('menu_items.php?error=0'); 
     146                        exit; 
     147                } 
     148 
     149                $menu = array_diff( $menu, array($menu_item_id) ); 
     150                $_POST = array('menu' => $menu_id, 'menu-item-' . $id_base => array(), 'the-menu-item-id' => $menu_item_id, 'delete_menu_item' => '1'); 
     151        } 
     152 
     153        $_POST['menu-item-id'] = $menu; 
     154 
     155        foreach ( (array) $wp_registered_menu_item_updates as $name => $control ) { 
     156                if ( $name != $id_base || !is_callable($control['callback']) ) 
     157                        continue; 
     158 
     159                ob_start(); 
     160                        call_user_func_array( $control['callback'], $control['params'] ); 
     161                ob_end_clean(); 
     162 
     163                break; 
     164        } 
     165 
     166        $menu_items_map[$menu_id] = $menu; 
     167 
     168        // remove old position 
     169        if ( !isset($_POST['delete_menu_item']) ) { 
     170                foreach ( $menu_items_map as $key => $sb ) { 
     171                        if ( is_array($sb) ) 
     172                                $menu_items_map[$key] = array_diff( $sb, array($menu_item_id) ); 
     173                } 
     174                array_splice( $menu_items_map[$menu_id], $position, 0, $menu_item_id ); 
     175        } 
     176 
     177        wp_set_menu_items($menu_items_map); 
     178        wp_redirect('menu_items.php?message=0'); 
     179        exit; 
     180} 
     181 
     182// Output the menu_item form without js 
     183if ( isset($_GET['editmenu_item']) && $_GET['editmenu_item'] ) { 
     184        $menu_item_id = $_GET['editmenu_item']; 
     185 
     186        if ( isset($_GET['addnew']) ) { 
     187                // Default to the first menu 
     188                $menu = array_shift( $keys = array_keys($wp_registered_menus) ); 
     189 
     190                if ( isset($_GET['base']) && isset($_GET['num']) ) { // multi-menu_item 
     191                        // Copy minimal info from an existing instance of this menu_item to a new instance 
     192                        foreach ( $wp_registered_menu_item_controls as $control ) { 
     193                                if ( $_GET['base'] === $control['id_base'] ) { 
     194                                        $control_callback = $control['callback']; 
     195                                        $multi_number = (int) $_GET['num']; 
     196                                        $control['params'][0]['number'] = -1; 
     197                                        $menu_item_id = $control['id'] = $control['id_base'] . '-' . $multi_number; 
     198                                        $wp_registered_menu_item_controls[$control['id']] = $control; 
     199                                        break; 
     200                                } 
     201                        } 
     202                } 
     203        } 
     204 
     205        if ( isset($wp_registered_menu_item_controls[$menu_item_id]) && !isset($control) ) { 
     206                $control = $wp_registered_menu_item_controls[$menu_item_id]; 
     207                $control_callback = $control['callback']; 
     208        } elseif ( !isset($wp_registered_menu_item_controls[$menu_item_id]) && isset($wp_registered_menu_items[$menu_item_id]) ) { 
     209                $name = esc_html( strip_tags($wp_registered_menu_items[$menu_item_id]['name']) ); 
     210        } 
     211 
     212        if ( !isset($name) ) 
     213                $name = esc_html( strip_tags($control['name']) ); 
     214 
     215        if ( !isset($menu) && isset($_GET['menu']) ) 
     216                $menu = $_GET['menu']; 
     217 
     218        if ( !isset($multi_number) ) 
     219                $multi_number = isset($control['params'][0]['number']) ? $control['params'][0]['number'] : ''; 
     220 
     221        $id_base = isset($control['id_base']) ? $control['id_base'] : $control['id']; 
     222 
     223        // show the menu item form 
     224        $width = ' style="width:' . max($control['width'], 350) . 'px"'; 
     225        $key = isset($_GET['key']) ? (int) $_GET['key'] : 0; 
     226 
     227        require_once( 'admin-header.php' ); ?> 
     228        <div class="wrap"> 
     229        <?php screen_icon(); ?> 
     230        <h2><?php echo esc_html( $title ); ?></h2> 
     231        <div class="editmenu_item"<?php echo $width; ?>> 
     232        <h3><?php printf( __( 'Widget %s' ), $name ); ?></h3> 
     233 
     234        <form action="menus.php" method="post"> 
     235        <div class="menu-item-inside"> 
     236<?php 
     237        if ( is_callable( $control_callback ) ) 
     238                call_user_func_array( $control_callback, $control['params'] ); 
     239        else 
     240                echo '<p>' . __('There are no options for this menu item.') . "</p>\n"; ?> 
     241        </div> 
     242 
     243        <p class="describe"><?php _e('Select both the menu for this menu item and the position of the menu item in that menu.'); ?></p> 
     244        <div class="menu-item-position"> 
     245        <table class="widefat"><thead><tr><th><?php _e('menu'); ?></th><th><?php _e('Position'); ?></th></tr></thead><tbody> 
     246<?php 
     247        foreach ( $wp_registered_menus as $sbname => $sbvalue ) { 
     248                echo "\t\t<tr><td><label><input type='radio' name='menu' value='" . esc_attr($sbname) . "'" . checked( $sbname, $menu, false ) . " /> $sbvalue[name]</label></td><td>"; 
     249                if ( 'wp_inactive_menu_items' == $sbname ) { 
     250                        echo '&nbsp;'; 
     251                } else { 
     252                        if ( !isset($menu_items_map[$sbname]) || !is_array($menu_items_map[$sbname]) ) { 
     253                                $j = 1; 
     254                                $menu_items_map[$sbname] = array(); 
     255                        } else { 
     256                                $j = count($menu_items_map[$sbname]); 
     257                                if ( isset($_GET['addnew']) || !in_array($menu_item_id, $menu_items_map[$sbname], true) ) 
     258                                        $j++; 
     259                        } 
     260                        $selected = ''; 
     261                        echo "\t\t<select name='{$sbname}_position'>\n"; 
     262                        echo "\t\t<option value=''>" . __('-- select --') . "</option>\n"; 
     263                        for ( $i = 1; $i <= $j; $i++ ) { 
     264                                if ( in_array($menu_item_id, $menu_items_map[$sbname], true) ) 
     265                                        $selected = selected( $i, $key + 1, false ); 
     266                                echo "\t\t<option value='$i'$selected> $i </option>\n"; 
     267                        } 
     268                        echo "\t\t</select>\n"; 
     269                } 
     270                echo "</td></tr>\n"; 
     271        } ?> 
     272        </tbody></table> 
     273        </div> 
     274 
     275        <div class="menu-item-control-actions"> 
     276<?php   if ( isset($_GET['addnew']) ) { ?> 
     277        <a href="menus.php" class="button alignleft"><?php _e('Cancel'); ?></a> 
     278<?php   } else { ?> 
     279        <input type="submit" name="removemenu_item" class="button alignleft" value="<?php esc_attr_e('Delete'); ?>" /> 
     280<?php   } ?> 
     281        <input type="submit" name="savemenu_item" class="button-primary alignright" value="<?php esc_attr_e('Save Widget'); ?>" /> 
     282        <input type="hidden" name="menu-item-id" class="menu-item-id" value="<?php echo esc_attr($menu_item_id); ?>" /> 
     283        <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr($id_base); ?>" /> 
     284        <input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr($multi_number); ?>" /> 
     285<?php   wp_nonce_field("save-delete-menu-item-$menu_item_id"); ?> 
     286        <br class="clear" /> 
     287        </div> 
     288        </form> 
     289        </div> 
     290        </div> 
     291<?php 
     292        require_once( 'admin-footer.php' ); 
     293        exit; 
     294} 
     295 
     296$messages = array( 
     297        __('Changes saved.') 
     298); 
     299 
     300$errors = array( 
     301        __('Error while saving.'), 
     302        __('Error in displaying the menu item settings form.') 
     303); 
     304 
     305require_once( 'admin-header.php' ); ?> 
     306 
     307<div class="wrap"> 
     308<?php screen_icon(); ?> 
     309<h2><?php echo esc_html( $title ); ?></h2> 
     310 
     311<?php if ( isset($_GET['message']) && isset($messages[$_GET['message']]) ) { ?> 
     312<div id="message" class="updated"><p><?php echo $messages[$_GET['message']]; ?></p></div> 
     313<?php } ?> 
     314<?php if ( isset($_GET['error']) && isset($errors[$_GET['error']]) ) { ?> 
     315<div id="message" class="error"><p><?php echo $errors[$_GET['error']]; ?></p></div> 
     316<?php } ?> 
     317 
     318<div class="menu-item-liquid-left"> 
     319<div id="menu-items-left"> 
     320        <div id="special-menu-items" class="menu-items-holder-wrap"> 
     321                <div class="menu-name"> 
     322                <div class="menu-name-arrow"><br /></div> 
     323                <h3><?php _e('Special Menu Items'); ?> <span id="removing-menu-item"><?php _e('Deactivate'); ?> <span></span></span></h3></div> 
     324                <div class="menu-item-holder"> 
     325                <p class="description"><?php _e('Select menu items from here to add them to the currently open menu on the right.'); ?></p> 
     326                <div id="menu-item-dropdowns"> 
     327                        <div id="page-dropdown" class="menu-item-dropdown"> 
     328                                <p><?php _e('Add page:'); ?></p> 
     329                                <?php wp_dropdown_pages(array('name' => '', 'show_option_none' => ' ', 'hide_if_empty' => false, 'orderby' => 'name', 'hierarchical' => true)); ?> 
     330                        </div> 
     331                        <div id="category-dropdown" class="menu-item-dropdown"> 
     332                                <p><?php _e('Add category:'); ?></p> 
     333                                <?php wp_dropdown_categories(array('name' => '', 'show_option_none' => ' ', 'hide_empty' => 0, 'hide_if_empty' => false, 'orderby' => 'name', 'hierarchical' => true)); ?> 
     334                        </div> 
     335                        <div id="other-dropdown" class="menu-item-dropdown"> 
     336                                <p><?php _e('Add other item:'); ?></p> 
     337                                <select> 
     338                                        <option value=""> </option> 
     339                                        <option value="home">Home</option> 
     340                                        <option value="link">Link</option> 
     341                                </select> 
     342                        </div> 
     343                </div> 
     344 
     345                <br class='clear' /> 
     346                </div> 
     347                <br class="clear" /> 
     348        </div> 
     349 
     350        <div id="menu-item-list"> 
     351        <?php wp_list_menu_items(); ?> 
     352        </div> 
     353</div> 
     354</div> 
     355 
     356<div class="menu-item-liquid-right"> 
     357<div id="menu-items-right"> 
     358<?php 
     359$i = 0; 
     360foreach ( $wp_registered_menus as $menu => $registered_menu ) { 
     361        $closed = $i ? ' closed' : ''; ?> 
     362        <div class="menu-items-holder-wrap<?php echo $closed; ?>"> 
     363        <div class="menu-name"> 
     364        <div class="menu-name-arrow"><br /></div> 
     365        <h3><?php echo esc_html( $registered_menu['name'] ); ?> 
     366        <span><img src="images/wpspin_dark.gif" class="ajax-feedback" title="" alt="" /></span></h3></div> 
     367        <?php wp_list_menu_item_controls( $menu ); // Show the control forms for each of the menu_items in this menu ?> 
     368        </div> 
     369<?php 
     370        $i++; 
     371} ?> 
     372</div> 
     373</div> 
     374<form action="" method="post"> 
     375<?php wp_nonce_field( 'save-menu-items', '_wpnonce_menu_items', false ); ?> 
     376</form> 
     377<br class="clear" /> 
     378</div> 
     379 
     380<?php 
     381do_action( 'menu_admin_page' ); 
     382require_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.menu-item-liquid-right .menu-description { 
     32        width: 250px; 
     33        margin: 0 auto 10px; 
     34        overflow: hidden; 
     35} 
     36 
     37.menu-item-liquid-right .menu-description { 
     38        margin-bottom: 10px; 
     39} 
     40 
     41#menu-item-dropdowns select { 
     42        height: auto !important; 
     43} 
     44 
     45div.menu-name h3 { 
     46        margin: 0; 
     47        padding: 5px 12px; 
     48        font-size: 13px; 
     49        height: 19px; 
     50        overflow: hidden; 
     51        white-space: nowrap; 
     52} 
     53 
     54div.menu-name { 
     55        background-repeat: repeat-x; 
     56        background-position: 0 0; 
     57        cursor: pointer; 
     58        font-size: 13px; 
     59        border-width: 1px; 
     60        border-style: solid; 
     61        -moz-border-radius-topleft: 8px; 
     62        -moz-border-radius-topright: 8px; 
     63        -webkit-border-top-right-radius: 8px; 
     64        -webkit-border-top-left-radius: 8px; 
     65        -khtml-border-top-right-radius: 8px; 
     66        -khtml-border-top-left-radius: 8px; 
     67        border-top-right-radius: 8px; 
     68        border-top-left-radius: 8px; 
     69} 
     70 
     71.js .closed .menu-name { 
     72        -moz-border-radius-bottomleft: 8px; 
     73        -moz-border-radius-bottomright: 8px; 
     74        -webkit-border-bottom-right-radius: 8px; 
     75        -webkit-border-bottom-left-radius: 8px; 
     76        -khtml-border-bottom-right-radius: 8px; 
     77        -khtml-border-bottom-left-radius: 8px; 
     78        border-bottom-right-radius: 8px; 
     79        border-bottom-left-radius: 8px; 
     80} 
     81 
     82.menu-item-liquid-right .menu-items-sortables, 
     83#menu-items-left .menu-item-holder { 
     84        border-width: 0 1px 1px; 
     85        border-style: none solid solid; 
     86    -moz-border-radius-bottomleft: 8px; 
     87        -moz-border-radius-bottomright: 8px; 
     88        -webkit-border-bottom-right-radius: 8px; 
     89        -webkit-border-bottom-left-radius: 8px; 
     90        -khtml-border-bottom-right-radius: 8px; 
     91        -khtml-border-bottom-left-radius: 8px; 
     92        border-bottom-right-radius: 8px; 
     93        border-bottom-left-radius: 8px; 
     94} 
     95 
     96.js .closed .menu-items-sortables, 
     97.js .closed .menu-item-holder { 
     98        display: none; 
     99} 
     100 
     101.menu-item-liquid-right .menu-items-sortables { 
     102        padding: 15px 0 5px; 
     103} 
     104 
     105.menu-item-placeholder { 
     106        border-width: 1px; 
     107        border-style: dashed; 
     108        margin: 0 auto 20px; 
     109        height: 26px; 
     110        width: 250px; 
     111} 
     112 
     113div.menu-items-holder-wrap { 
     114        padding: 0; 
     115        margin: 10px 0 20px; 
     116} 
     117 
     118.menu-item .menu-item-top { 
     119        font-size: 12px; 
     120        font-weight: bold; 
     121        height: 26px; 
     122        overflow: hidden; 
     123} 
     124 
     125.menu-item-top .menu-item-title { 
     126        padding: 5px 9px; 
     127} 
     128 
     129.menu-item-top .menu-item-title-action { 
     130        float: right; 
     131} 
     132 
     133a.menu-item-action { 
     134        display: block; 
     135        width: 24px; 
     136        height: 26px; 
     137} 
     138 
     139.menu-item-top a.menu-item-action { 
     140        background: url("../images/menu-bits.gif") no-repeat scroll 0 -110px; 
     141} 
     142 
     143.menu-item .menu-item-inside, 
     144.menu-item .menu-item-description { 
     145        padding: 12px 12px 10px; 
     146        font-size: 11px; 
     147        line-height: 16px; 
     148} 
     149 
     150.menu-item-inside, 
     151.menu-item-description { 
     152        display: none; 
     153} 
     154 
     155.menu-item .menu-item-inside p { 
     156        margin: 0 0 1em; 
     157        padding: 0; 
     158} 
     159 
     160.menu-item-title h4 { 
     161        margin: 0; 
     162        line-height: 1.3; 
     163        overflow: hidden; 
     164        white-space: nowrap; 
     165} 
     166 
     167.menu-items-sortables { 
     168        min-height: 90px; 
     169} 
     170 
     171.menu-item-control-actions { 
     172        margin-top: 8px; 
     173} 
     174 
     175.menu-item-control-actions a { 
     176        text-decoration: none; 
     177} 
     178 
     179.menu-item-control-actions a:hover { 
     180        text-decoration: underline; 
     181} 
     182 
     183.menu-item-control-actions .ajax-feedback { 
     184        padding-bottom: 3px; 
     185} 
     186 
     187.menu-item-control-actions div.alignleft { 
     188        margin-top: 6px; 
     189} 
     190 
     191div#menu-info { 
     192        padding: 0 1em; 
     193        margin-bottom: 1em; 
     194        font-size: 11px; 
     195} 
     196 
     197.menu-item-title a, 
     198.menu-item-title a:hover { 
     199        text-decoration: none; 
     200        border-bottom: none; 
     201} 
     202 
     203.menu-item-control-edit { 
     204        display: block; 
     205        font-size: 11px; 
     206        font-weight: normal; 
     207        line-height: 26px; 
     208        padding: 0 8px 0 0; 
     209} 
     210 
     211a.menu-item-control-edit { 
     212        text-decoration: none; 
     213} 
     214 
     215.menu-item-control-edit .add, 
     216.menu-item-control-edit .edit { 
     217        display: none; 
     218} 
     219 
     220#menu-items-right .menu-item-control-edit .edit { 
     221        display: inline; 
     222} 
     223 
     224.editmenu-item { 
     225        margin: 0 auto 15px; 
     226} 
     227 
     228.editmenu-item .menu-item-inside { 
     229        display: block; 
     230        border-width: 1px; 
     231        border-style: solid; 
     232        padding: 10px; 
     233        -moz-border-radius: 6px; 
     234        -khtml-border-radius: 6px; 
     235        -webkit-border-radius: 6px; 
     236        border-radius: 6px; 
     237} 
     238 
     239.menu-item-holder { 
     240        padding-top: 2px; 
     241} 
     242 
     243.menu-item-holder p.description { 
     244        margin: 5px 15px 8px; 
     245} 
     246 
     247.menu-item-position { 
     248        margin-top: 8px; 
     249} 
     250 
     251.menu-name-arrow { 
     252        float: right; 
     253        height: 29px; 
     254        width: 26px; 
     255} 
     256 
     257#menu-item-dropdowns { 
     258        padding: 0; 
     259} 
     260 
     261.menu-item-dropdown { 
     262        float:left; 
     263        margin:0 15px 20px 15px; 
     264} 
     265 
     266.menu-item-dropdown p { 
     267        margin-top: .5em; 
     268} 
     269 
     270.menu-item-title .in-menu-item-title { 
     271        font-size: 11px; 
     272        white-space: nowrap; 
     273} 
     274 
     275#removing-menu-item { 
     276        display: none; 
     277        font-weight: normal; 
     278        padding-left: 15px; 
     279        font-size: 12px; 
     280} 
     281 
     282.menu-item-control-noform, 
     283#access-off, 
     284.menu-items_access .menu-item-action, 
     285.menu-items_access .menu-name-arrow, 
     286.menu-items_access #access-on, 
     287.menu-items_access .menu-item-holder .description { 
     288        display: none; 
     289} 
     290 
     291.menu-items_access .menu-item-holder { 
     292        padding-top: 10px; 
     293} 
     294 
     295#menu-item-list { 
     296        display: none; 
     297} 
     298 
     299.menu-items_access #access-off { 
     300        display: inline; 
     301} 
     302 
     303.menu-items_access #wpbody-content .menu-item-title-action, 
     304.menu-items_access #wpbody-content .menu-item-control-edit, 
     305.menu-items_access .closed .menu-items-sortables, 
     306.menu-items_access .closed .menu-item-holder { 
     307        display: block; 
     308} 
     309 
     310.menu-items_access .closed .menu-name { 
     311        -moz-border-radius-bottomleft: 0; 
     312        -moz-border-radius-bottomright: 0; 
     313        -webkit-border-bottom-right-radius: 0; 
     314        -webkit-border-bottom-left-radius: 0; 
     315        -khtml-border-bottom-right-radius: 0; 
     316        -khtml-border-bottom-left-radius: 0; 
     317        border-bottom-right-radius: 0; 
     318        border-bottom-left-radius: 0; 
     319} 
     320 
     321.menu-items_access .menu-name, 
     322.menu-items_access .menu-item .menu-item-top { 
     323        cursor: default; 
     324} 
     325 
  • 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 {