WordPress.org

Make WordPress Core

Ticket #11817: menus.2.diff

File menus.2.diff, 93.2 KB (added by scribu, 8 years ago)

functional menus admin

  • wp-includes/default-menu-items.php

     
     1<?php
     2
     3/**
     4 * Home Menu Item class
     5 *
     6 * @since 3.0
     7 */
     8class WP_Menu_Item_Home extends WP_Menu_Item {
     9
     10        function WP_Menu_Item_Home() {
     11                $menu_item_ops = array('classname' => 'menu_item_home', 'description' => __('The site homepage') );
     12                $this->WP_Menu_Item('home', __('Home'), $menu_item_ops);
     13        }
     14       
     15        function display( $args, $instance ) {
     16                // TODO
     17        }
     18}
     19
     20/**
     21 * Page Menu Item class
     22 *
     23 * @since 3.0
     24 */
     25class WP_Menu_Item_Page extends WP_Menu_Item {
     26
     27        function WP_Menu_Item_Page() {
     28                $menu_item_ops = array('classname' => 'menu_item_page', 'description' => __('A WordPress page') );
     29                $this->WP_Menu_Item('page', __('Page'), $menu_item_ops);
     30        }
     31
     32        function display( $args, $instance ) {
     33                extract( $args );
     34
     35                $title = apply_filters('menu_title', empty( $instance['title'] ) ? __( 'Page' ) : $instance['title']);
     36                $sortby = empty( $instance['sortby'] ) ? 'menu_order' : $instance['sortby'];
     37                $exclude = empty( $instance['exclude'] ) ? '' : $instance['exclude'];
     38
     39                if ( $sortby == 'menu_order' )
     40                        $sortby = 'menu_order, post_title';
     41
     42                wp_list_page( apply_filters('menu_page_args', array('title_li' => '', 'sort_column' => $sortby, 'exclude' => $exclude) ) );
     43        }
     44
     45        function update( $new_instance, $old_instance ) {
     46                $instance = $old_instance;
     47                $instance['title'] = strip_tags($new_instance['title']);
     48                if ( in_array( $new_instance['sortby'], array( 'post_title', 'menu_order', 'ID' ) ) ) {
     49                        $instance['sortby'] = $new_instance['sortby'];
     50                } else {
     51                        $instance['sortby'] = 'menu_order';
     52                }
     53
     54                $instance['exclude'] = strip_tags( $new_instance['exclude'] );
     55
     56                return $instance;
     57        }
     58
     59        function form( $instance ) {
     60                //Defaults
     61                $instance = wp_parse_args( (array) $instance, array( 'sortby' => 'post_title', 'title' => '', 'exclude' => '') );
     62                $title = esc_attr( $instance['title'] );
     63                $exclude = esc_attr( $instance['exclude'] );
     64        ?>
     65                <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>
     66                <p>
     67                        <label for="<?php echo $this->get_field_id('sortby'); ?>"><?php _e( 'Sort by:' ); ?></label>
     68                        <select name="<?php echo $this->get_field_name('sortby'); ?>" id="<?php echo $this->get_field_id('sortby'); ?>" class="widefat">
     69                                <option value="post_title"<?php selected( $instance['sortby'], 'post_title' ); ?>><?php _e('Page title'); ?></option>
     70                                <option value="menu_order"<?php selected( $instance['sortby'], 'menu_order' ); ?>><?php _e('Page order'); ?></option>
     71                                <option value="ID"<?php selected( $instance['sortby'], 'ID' ); ?>><?php _e( 'Page ID' ); ?></option>
     72                        </select>
     73                </p>
     74                <p>
     75                        <label for="<?php echo $this->get_field_id('exclude'); ?>"><?php _e( 'Exclude:' ); ?></label> <input type="text" value="<?php echo $exclude; ?>" name="<?php echo $this->get_field_name('exclude'); ?>" id="<?php echo $this->get_field_id('exclude'); ?>" class="widefat" />
     76                        <br />
     77                        <small><?php _e( 'Page IDs, separated by commas.' ); ?></small>
     78                </p>
     79<?php
     80        }
     81}
     82
     83
     84/**
     85 * Link menu item class
     86 *
     87 * @since 3.0
     88 */
     89class WP_Menu_Item_Link extends WP_Menu_Item {
     90
     91        function WP_Menu_Item_Link() {
     92                $menu_item_ops = array('description' => __('An external link') );
     93                $this->WP_Menu_Item('link', __('Link'), $menu_item_ops);
     94        }
     95
     96        function display( $args, $instance ) {
     97                extract($args, EXTR_SKIP);
     98
     99                $show_description = isset($instance['description']) ? $instance['description'] : false;
     100                $show_name = isset($instance['name']) ? $instance['name'] : false;
     101                $show_rating = isset($instance['rating']) ? $instance['rating'] : false;
     102                $show_images = isset($instance['images']) ? $instance['images'] : true;
     103                $category = isset($instance['category']) ? $instance['category'] : false;
     104
     105                wp_list_bookmarks(apply_filters('menu_item_links_args', array(
     106                        'title_before' => $before_title, 'title_after' => $after_title,
     107                        'show_images' => $show_images, 'show_description' => $show_description,
     108                        'show_name' => $show_name, 'show_rating' => $show_rating,
     109                        'category' => $category, 'class' => 'linkcat menu_item'
     110                )));
     111        }
     112
     113        function update( $new_instance, $old_instance ) {
     114                $new_instance = (array) $new_instance;
     115                $instance = array( 'images' => 0, 'name' => 0, 'description' => 0, 'rating' => 0);
     116                foreach ( $instance as $field => $val ) {
     117                        if ( isset($new_instance[$field]) )
     118                                $instance[$field] = 1;
     119                }
     120                $instance['category'] = intval($new_instance['category']);
     121
     122                return $instance;
     123        }
     124
     125        function form( $instance ) {
     126
     127                //Defaults
     128                $instance = wp_parse_args( (array) $instance, array( 'images' => true, 'name' => true, 'description' => false, 'rating' => false, 'category' => false ) );
     129                $link_cats = get_terms( 'link_category');
     130?>
     131                <p>
     132                <label for="<?php echo $this->get_field_id('category'); ?>" class="screen-reader-text"><?php _e('Select Link Category'); ?></label>
     133                <select class="widefat" id="<?php echo $this->get_field_id('category'); ?>" name="<?php echo $this->get_field_name('category'); ?>">
     134                <option value=""><?php _e('All Links'); ?></option>
     135                <?php
     136                foreach ( $link_cats as $link_cat ) {
     137                        echo '<option value="' . intval($link_cat->term_id) . '"'
     138                                . ( $link_cat->term_id == $instance['category'] ? ' selected="selected"' : '' )
     139                                . '>' . $link_cat->name . "</option>\n";
     140                }
     141                ?>
     142                </select></p>
     143                <p>
     144                <input class="checkbox" type="checkbox" <?php checked($instance['images'], true) ?> id="<?php echo $this->get_field_id('images'); ?>" name="<?php echo $this->get_field_name('images'); ?>" />
     145                <label for="<?php echo $this->get_field_id('images'); ?>"><?php _e('Show Link Image'); ?></label><br />
     146                <input class="checkbox" type="checkbox" <?php checked($instance['name'], true) ?> id="<?php echo $this->get_field_id('name'); ?>" name="<?php echo $this->get_field_name('name'); ?>" />
     147                <label for="<?php echo $this->get_field_id('name'); ?>"><?php _e('Show Link Name'); ?></label><br />
     148                <input class="checkbox" type="checkbox" <?php checked($instance['description'], true) ?> id="<?php echo $this->get_field_id('description'); ?>" name="<?php echo $this->get_field_name('description'); ?>" />
     149                <label for="<?php echo $this->get_field_id('description'); ?>"><?php _e('Show Link Description'); ?></label><br />
     150                <input class="checkbox" type="checkbox" <?php checked($instance['rating'], true) ?> id="<?php echo $this->get_field_id('rating'); ?>" name="<?php echo $this->get_field_name('rating'); ?>" />
     151                <label for="<?php echo $this->get_field_id('rating'); ?>"><?php _e('Show Link Rating'); ?></label>
     152                </p>
     153<?php
     154        }
     155}
     156
     157/**
     158 * Category menu item class
     159 *
     160 * @since 3.0
     161 */
     162class WP_Menu_Item_Category extends WP_Menu_Item {
     163
     164        function WP_Menu_Item_Category() {
     165                $menu_item_ops = array( 'classname' => 'menu_item_category', 'description' => __('A WordPress category') );
     166                $this->WP_Menu_Item('category', __('Category'), $menu_item_ops);
     167        }
     168
     169        function display( $args, $instance ) {
     170                extract( $args );
     171
     172                $title = apply_filters('menu_item_title', empty( $instance['title'] ) ? __( 'Categories' ) : $instance['title']);
     173                $c = $instance['count'] ? '1' : '0';
     174                $h = $instance['hierarchical'] ? '1' : '0';
     175                $d = $instance['dropdown'] ? '1' : '0';
     176
     177                $cat_args = array('orderby' => 'name', 'show_count' => $c, 'hierarchical' => $h);
     178
     179                if ( $d ) {
     180                        $cat_args['show_option_none'] = __('Select Category');
     181                        wp_dropdown_categories(apply_filters('menu_item_category_dropdown_args', $cat_args));
     182?>
     183
     184<script type='text/javascript'>
     185/* <![CDATA[ */
     186        var dropdown = document.getElementById("cat");
     187        function onCatChange() {
     188                if ( dropdown.options[dropdown.selectedIndex].value > 0 ) {
     189                        location.href = "<?php echo home_url(); ?>/?cat="+dropdown.options[dropdown.selectedIndex].value;
     190                }
     191        }
     192        dropdown.onchange = onCatChange;
     193/* ]]> */
     194</script>
     195
     196<?php
     197                } else {
     198?>
     199                <ul>
     200<?php
     201                $cat_args['title_li'] = '';
     202                wp_list_categories(apply_filters('menu_item_category_args', $cat_args));
     203?>
     204                </ul>
     205<?php
     206                }
     207        }
     208
     209        function update( $new_instance, $old_instance ) {
     210                $instance = $old_instance;
     211                $instance['title'] = strip_tags($new_instance['title']);
     212                $instance['count'] = $new_instance['count'] ? 1 : 0;
     213                $instance['hierarchical'] = $new_instance['hierarchical'] ? 1 : 0;
     214                $instance['dropdown'] = $new_instance['dropdown'] ? 1 : 0;
     215
     216                return $instance;
     217        }
     218
     219        function form( $instance ) {
     220                //Defaults
     221                $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
     222                $title = esc_attr( $instance['title'] );
     223                $count = isset($instance['count']) ? (bool) $instance['count'] :false;
     224                $hierarchical = isset( $instance['hierarchical'] ) ? (bool) $instance['hierarchical'] : false;
     225                $dropdown = isset( $instance['dropdown'] ) ? (bool) $instance['dropdown'] : false;
     226?>
     227                <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Title:' ); ?></label>
     228                <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>
     229
     230                <p><input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('dropdown'); ?>" name="<?php echo $this->get_field_name('dropdown'); ?>"<?php checked( $dropdown ); ?> />
     231                <label for="<?php echo $this->get_field_id('dropdown'); ?>"><?php _e( 'Show as dropdown' ); ?></label><br />
     232
     233                <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>"<?php checked( $count ); ?> />
     234                <label for="<?php echo $this->get_field_id('count'); ?>"><?php _e( 'Show post counts' ); ?></label><br />
     235
     236                <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('hierarchical'); ?>" name="<?php echo $this->get_field_name('hierarchical'); ?>"<?php checked( $hierarchical ); ?> />
     237                <label for="<?php echo $this->get_field_id('hierarchical'); ?>"><?php _e( 'Show hierarchy' ); ?></label></p>
     238<?php
     239        }
     240}
     241
     242/**
     243 * Register all of the default WordPress menu items on startup.
     244 *
     245 * Calls 'menu_items_init' action after all of the WordPress menu items have been
     246 * registered.
     247 *
     248 * @since 3.0
     249 */
     250function wp_menu_items_init() {
     251        if ( !is_blog_installed() )
     252                return;
     253
     254        register_menu_item('WP_Menu_Item_Home');
     255        register_menu_item('WP_Menu_Item_Page');
     256        register_menu_item('WP_Menu_Item_Link');
     257        register_menu_item('WP_Menu_Item_Category');
     258
     259        do_action('menu_items_init');
     260}
     261
     262add_action('init', 'wp_menu_items_init', 1);
     263
  • wp-includes/menus.php

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

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

     
    1717        ));
    1818}
    1919
     20// Dynamic menu support
     21add_theme_support('menus');
     22register_menu(array(
     23        'before_menu' => '<ul id="%1$s" class="menu %2$s">',
     24        'after_menu' => '</ul>',
     25));
     26
    2027/** @ignore */
    2128function kubrick_head() {
    2229        $head = "<style type='text/css'>\n<!--";
  • wp-settings.php

     
    425425require (ABSPATH . WPINC . '/media.php');
    426426require (ABSPATH . WPINC . '/http.php');
    427427require (ABSPATH . WPINC . '/widgets.php');
     428require (ABSPATH . WPINC . '/menus.php');
    428429
    429430if ( is_multisite() ) {
    430431        require_once( ABSPATH . WPINC . '/ms-functions.php' );
     
    785786// Load in support for template functions which the theme supports
    786787require_if_theme_supports( 'post-thumbnails', ABSPATH . WPINC . '/post-thumbnail-template.php' );
    787788
     789// Menus init
     790if ( current_theme_supports( 'menus' ) ) {
     791        if ( apply_filters('load_default_menu_items', true) )
     792                require( ABSPATH . WPINC . '/default-menu-items.php' );
     793
     794        function _wp_add_menus_menu() {
     795                global $submenu;
     796                $submenu['themes.php'][8] = array( __( 'Menus' ), 'switch_themes', 'menus.php' );
     797                ksort( $submenu['themes.php'], SORT_NUMERIC );
     798        }
     799        add_action( '_admin_menu', '_wp_add_menus_menu' );
     800}
     801
     802
    788803/**
    789804 * Runs just before PHP shuts down execution.
    790805 *
  • wp-admin/admin-ajax.php

     
    13791379
    13801380        die();
    13811381        break;
     1382case 'menu-items-order' :
     1383        check_ajax_referer( 'save-menu-items', 'savemenu_items' );
     1384
     1385        if ( !current_user_can('switch_themes') )
     1386                die('-1');
     1387
     1388        unset( $_POST['savemenu_items'], $_POST['action'] );
     1389
     1390        // save menu_items order for all menus
     1391        if ( is_array($_POST['menus']) ) {
     1392                $menus = array();
     1393                foreach ( $_POST['menus'] as $key => $val ) {
     1394                        $sb = array();
     1395                        if ( !empty($val) ) {
     1396                                $val = explode(',', $val);
     1397                                foreach ( $val as $k => $v ) {
     1398                                        if ( strpos($v, 'menu-item-') === false )
     1399                                                continue;
     1400
     1401                                        $tmp = explode('_', $v, 2);
     1402                                        $sb[$k] = $tmp[1];
     1403                                }
     1404                        }
     1405                        $menus[$key] = $sb;
     1406                }
     1407                wp_set_menu_items($menus);
     1408                die('1');
     1409        }
     1410
     1411        die('-1');
     1412        break;
     1413case 'save-menu-item' :
     1414        check_ajax_referer( 'save-menu-items', 'savemenu_items' );
     1415
     1416        if ( !current_user_can('switch_themes') || !isset($_POST['id_base']) )
     1417                die('-1');
     1418
     1419        unset( $_POST['savemenu_items'], $_POST['action'] );
     1420
     1421        do_action('load-menus.php');
     1422        do_action('menus.php');
     1423        do_action('menu_admin_setup');
     1424
     1425        $id_base = $_POST['id_base'];
     1426        $menu_item_id = $_POST['menu-item-id'];
     1427        $menu_id = $_POST['menu'];
     1428        $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
     1429        $settings = isset($_POST['menu-item-' . $id_base]) && is_array($_POST['menu-item-' . $id_base]) ? $_POST['menu-item-' . $id_base] : false;
     1430        $error = '<p>' . __('An error has occured. Please reload the page and try again.') . '</p>';
     1431
     1432        $menus = wp_get_menu_items();
     1433        $menu = isset($menus[$menu_id]) ? $menus[$menu_id] : array();
     1434
     1435        // delete
     1436        if ( isset($_POST['delete_menu_item']) && $_POST['delete_menu_item'] ) {
     1437
     1438                if ( !isset($wp_registered_menu_items[$menu_item_id]) )
     1439                        die($error);
     1440
     1441                $menu = array_diff( $menu, array($menu_item_id) );
     1442                $_POST = array('menu' => $menu_id, 'menu-item-' . $id_base => array(), 'the-menu-item-id' => $menu_item_id, 'delete_menu_item' => '1');
     1443        } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
     1444                if ( !$multi_number )
     1445                        die($error);
     1446
     1447                $_POST['menu-item-' . $id_base] = array( $multi_number => array_shift($settings) );
     1448                $menu_item_id = $id_base . '-' . $multi_number;
     1449                $menu[] = $menu_item_id;
     1450        }
     1451        $_POST['menu-item-id'] = $menu;
     1452
     1453        foreach ( (array) $wp_registered_menu_item_updates as $name => $control ) {
     1454
     1455                if ( $name == $id_base ) {
     1456                        if ( !is_callable( $control['callback'] ) )
     1457                                continue;
     1458
     1459                        ob_start();
     1460                                call_user_func_array( $control['callback'], $control['params'] );
     1461                        ob_end_clean();
     1462                        break;
     1463                }
     1464        }
     1465
     1466        if ( isset($_POST['delete_menu_item']) && $_POST['delete_menu_item'] ) {
     1467                $menus[$menu_id] = $menu;
     1468                wp_set_menu_items($menus);
     1469                echo "deleted:$menu_item_id";
     1470                die();
     1471        }
     1472
     1473        if ( !empty($_POST['add_new']) )
     1474                die();
     1475
     1476        if ( $form = $wp_registered_menu_item_controls[$menu_item_id] )
     1477                call_user_func_array( $form['callback'], $form['params'] );
     1478
     1479        die();
     1480        break;
    13821481case 'image-editor':
    13831482        $attachment_id = intval($_POST['postid']);
    13841483        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        usort( $sort, create_function( '$a, $b', 'return strnatcasecmp( $a["name"], $b["name"] );' ) );
     24        $done = array();
     25
     26        foreach ( $sort as $menu_item ) {
     27                if ( in_array( $menu_item['callback'], $done, true ) ) // We already showed this multi-menu_item
     28                        continue;
     29
     30                $menu = is_active_menu_item( $menu_item['callback'], $menu_item['id'], false, false );
     31                $done[] = $menu_item['callback'];
     32
     33                if ( ! isset( $menu_item['params'][0] ) )
     34                        $menu_item['params'][0] = array();
     35
     36                $args = array( 'menu_item_id' => $menu_item['id'], 'menu_item_name' => $menu_item['name'], '_display' => 'template' );
     37
     38                if ( isset($wp_registered_menu_item_controls[$menu_item['id']]['id_base']) && isset($menu_item['params'][0]['number']) ) {
     39                        $id_base = $wp_registered_menu_item_controls[$menu_item['id']]['id_base'];
     40                        $args['_temp_id'] = "$id_base-__i__";
     41                        $args['_multi_num'] = next_menu_item_id_number($id_base);
     42                        $args['_add'] = 'multi';
     43                } else {
     44                        $args['_add'] = 'single';
     45                        if ( $menu )
     46                                $args['_hide'] = '1';
     47                }
     48
     49                $args = wp_list_menu_item_controls_dynamic_menu( array( 0 => $args, 1 => $menu_item['params'][0] ) );
     50                call_user_func_array( 'wp_menu_item_control', $args );
     51        }
     52}
     53
     54/**
     55 * Show the menu_items and their settings for a menu.
     56 * Used in the the admin menu_item config screen.
     57 *
     58 * @since 3.0
     59 *
     60 * @param string $menu id slug of the menu
     61 */
     62function wp_list_menu_item_controls( $menu ) {
     63        add_filter( 'dynamic_menu_params', 'wp_list_menu_item_controls_dynamic_menu' );
     64
     65        echo "<div id='$menu' class='menu-items-sortables'>\n";
     66
     67        $description = wp_menu_description( $menu );
     68
     69        if ( !empty( $description ) ) {
     70                echo "<div class='menu-description'>\n";
     71                echo "\t<p class='description'>$description</p>";
     72                echo "</div>\n";
     73        }
     74
     75        dynamic_menu( $menu );
     76        echo "</div>\n";
     77}
     78
     79/**
     80 * {@internal Missing Short Description}}
     81 *
     82 * @since 3.0
     83 *
     84 * @param array $params
     85 * @return array
     86 */
     87function wp_list_menu_item_controls_dynamic_menu( $params ) {
     88        global $wp_registered_menu_items;
     89        static $i = 0;
     90        $i++;
     91
     92        $menu_item_id = $params[0]['menu_item_id'];
     93        $id = isset($params[0]['_temp_id']) ? $params[0]['_temp_id'] : $menu_item_id;
     94        $hidden = isset($params[0]['_hide']) ? ' style="display:none;"' : '';
     95
     96        $params[0]['before_menu_item'] = "<div id='menu-item-${i}_$id' class='menu-item'$hidden>";
     97        $params[0]['after_menu_item'] = "</div>";
     98        if ( is_callable( $wp_registered_menu_items[$menu_item_id]['callback'] ) ) {
     99                $wp_registered_menu_items[$menu_item_id]['_callback'] = $wp_registered_menu_items[$menu_item_id]['callback'];
     100                $wp_registered_menu_items[$menu_item_id]['callback'] = 'wp_menu_item_control';
     101        }
     102
     103        return $params;
     104}
     105
     106function next_menu_item_id_number($id_base) {
     107        global $wp_registered_menu_items;
     108        $number = 1;
     109
     110        foreach ( $wp_registered_menu_items as $menu_item_id => $menu_item ) {
     111                if ( preg_match( '/' . $id_base . '-([0-9]+)$/', $menu_item_id, $matches ) )
     112                        $number = max($number, $matches[1]);
     113        }
     114        $number++;
     115
     116        return $number;
     117}
     118
     119/**
     120 * Meta menu_item used to display the control form for a menu_item.
     121 *
     122 * Called from dynamic_menu().
     123 *
     124 * @since 3.0
     125 *
     126 * @param array $menu_args
     127 * @return array
     128 */
     129function wp_menu_item_control( $menu_args ) {
     130        global $wp_registered_menu_items, $wp_registered_menu_item_controls, $menu_items_map;
     131
     132        $menu_item_id = $menu_args['menu_item_id'];
     133        $menu_id = isset($menu_args['id']) ? $menu_args['id'] : false;
     134        $key = $menu_id ? array_search( $menu_item_id, $menu_items_map[$menu_id] ) : '-1'; // position of menu_item in menu
     135        $control = isset($wp_registered_menu_item_controls[$menu_item_id]) ? $wp_registered_menu_item_controls[$menu_item_id] : array();
     136        $menu_item = $wp_registered_menu_items[$menu_item_id];
     137
     138        $id_format = $menu_item['id'];
     139        $menu_item_number = isset($control['params'][0]['number']) ? $control['params'][0]['number'] : '';
     140        $id_base = isset($control['id_base']) ? $control['id_base'] : $menu_item_id;
     141        $multi_number = isset($menu_args['_multi_num']) ? $menu_args['_multi_num'] : '';
     142        $add_new = isset($menu_args['_add']) ? $menu_args['_add'] : '';
     143
     144        $query_arg = array( 'editmenu_item' => $menu_item['id'] );
     145        if ( $add_new ) {
     146                $query_arg['addnew'] = 1;
     147                if ( $multi_number ) {
     148                        $query_arg['num'] = $multi_number;
     149                        $query_arg['base'] = $id_base;
     150                }
     151        } else {
     152                $query_arg['menu'] = $menu_id;
     153                $query_arg['key'] = $key;
     154        }
     155
     156        // We aren't showing a menu_item control, we're outputing a template for a mult-menu_item control
     157        if ( isset($menu_args['_display']) && 'template' == $menu_args['_display'] && $menu_item_number ) {
     158                // number == -1 implies a template where id numbers are replaced by a generic '__i__'
     159                $control['params'][0]['number'] = -1;
     160                // with id_base menu_item id's are constructed like {$id_base}-{$id_number}
     161                if ( isset($control['id_base']) )
     162                        $id_format = $control['id_base'] . '-__i__';
     163        }
     164
     165        $wp_registered_menu_items[$menu_item_id]['callback'] = $wp_registered_menu_items[$menu_item_id]['_callback'];
     166        unset($wp_registered_menu_items[$menu_item_id]['_callback']);
     167
     168        $menu_item_title = esc_html( strip_tags( $menu_args['menu_item_name'] ) );
     169        $has_form = 'noform';
     170
     171        echo $menu_args['before_menu_item']; ?>
     172        <div class="menu-item-top">
     173        <div class="menu-item-title-action">
     174                <a class="menu-item-action hide-if-no-js" href="#available-menu-items"></a>
     175                <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>
     176        </div>
     177        <div class="menu-item-title"><h4><?php echo $menu_item_title ?><span class="in-menu-item-title"></span></h4></div>
     178        </div>
     179
     180        <div class="menu-item-inside">
     181        <form action="" method="post">
     182        <div class="menu-item-content">
     183<?php
     184        if ( isset($control['callback']) )
     185                $has_form = call_user_func_array( $control['callback'], $control['params'] );
     186        else
     187                echo "\t\t<p>" . __('There are no options for this menu item.') . "</p>\n"; ?>
     188        </div>
     189        <input type="hidden" name="menu-item-id" class="menu-item-id" value="<?php echo esc_attr($id_format); ?>" />
     190        <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr($id_base); ?>" />
     191        <input type="hidden" name="menu-item-width" class="menu-item-width" value="<?php if (isset( $control['width'] )) echo esc_attr($control['width']); ?>" />
     192        <input type="hidden" name="menu-item-height" class="menu-item-height" value="<?php if (isset( $control['height'] )) echo esc_attr($control['height']); ?>" />
     193        <input type="hidden" name="menu_item_number" class="menu_item_number" value="<?php echo esc_attr($menu_item_number); ?>" />
     194        <input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr($multi_number); ?>" />
     195        <input type="hidden" name="add_new" class="add_new" value="<?php echo esc_attr($add_new); ?>" />
     196
     197        <div class="menu-item-control-actions">
     198                <div class="alignleft">
     199                <a class="menu-item-control-remove" href="#remove"><?php _e('Delete'); ?></a> |
     200                <a class="menu-item-control-close" href="#close"><?php _e('Close'); ?></a>
     201                </div>
     202                <div class="alignright<?php if ( 'noform' === $has_form ) echo ' menu-item-control-noform'; ?>">
     203                <img src="images/wpspin_light.gif" class="ajax-feedback " title="" alt="" />
     204                <input type="submit" name="savemenu_item" class="button-primary menu-item-control-save" value="<?php esc_attr_e('Save'); ?>" />
     205                </div>
     206                <br class="clear" />
     207        </div>
     208        </form>
     209        </div>
     210
     211        <div class="menu-item-description">
     212<?php echo ( $menu_item_description = wp_menu_item_description($menu_item_id) ) ? "$menu_item_description\n" : "$menu_item_title\n"; ?>
     213        </div>
     214<?php
     215        echo $menu_args['after_menu_item'];
     216        return $menu_args;
     217}
     218
  • 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-items-right').children('.menu-items-holder-wrap').children('.menu-name').click(function(){
     8                        var c = $(this).siblings('.menu-items-sortables'), p = $(this).parent();
     9                        if ( !p.hasClass('closed') ) {
     10                                c.sortable('disable');
     11                                p.addClass('closed');
     12                        } else {
     13                                p.removeClass('closed');
     14                                c.sortable('enable').sortable('refresh');
     15                        }
     16                });
     17
     18                $('#menu-items-left').children('.menu-items-holder-wrap').children('.menu-name').click(function() {
     19                        $(this).siblings('.menu-item-holder').parent().toggleClass('closed');
     20                });
     21
     22                menus.not('#wp_inactive_menu_items').each(function(){
     23                        var h = 50, H = $(this).children('.menu-item').length;
     24                        h = h + parseInt(H * 48, 10);
     25                        $(this).css( 'minHeight', h + 'px' );
     26                });
     27
     28                $('a.menu-item-action').live('click', function(){
     29                        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 );
     30                       
     31                        if ( inside.is(':hidden') ) {
     32                                if ( w > 250 && inside.closest('div.menu-items-sortables').length ) {
     33                                        css['width'] = w + 30 + 'px';
     34                                        if ( inside.closest('div.menu-item-liquid-right').length )
     35                                                css['marginLeft'] = 235 - w + 'px';
     36                                        menu_item.css(css);
     37                                }
     38                                wpMenus.fixLabels(menu_item);
     39                                inside.slideDown('fast');
     40                        } else {
     41                                inside.slideUp('fast', function() {
     42                                        menu_item.css({'width':'','marginLeft':''});
     43                                });
     44                        }
     45                        return false;
     46                });
     47
     48                $('input.menu-item-control-save').live('click', function(){
     49                        wpMenus.save( $(this).closest('div.menu-item'), 0, 1, 0 );
     50                        return false;
     51                });
     52
     53                $('a.menu-item-control-remove').live('click', function(){
     54                        wpMenus.save( $(this).closest('div.menu-item'), 1, 1, 0 );
     55                        return false;
     56                });
     57
     58                $('a.menu-item-control-close').live('click', function(){
     59                        wpMenus.close( $(this).closest('div.menu-item') );
     60                        return false;
     61                });
     62
     63                menus.children('.menu-item').each(function() {
     64                        wpMenus.appendTitle(this);
     65                        if ( $('p.menu-item-error', this).length )
     66                                $('a.menu-item-action', this).click();
     67                });
     68
     69                $('#menu-item-list').children('.menu-item').draggable({
     70                        connectToSortable: 'div.menu-items-sortables',
     71                        handle: '> .menu-item-top > .menu-item-title',
     72                        distance: 2,
     73                        helper: 'clone',
     74                        zIndex: 5,
     75                        containment: 'document',
     76                        start: function(e,ui) {
     77                                wpMenus.fixWebkit(1);
     78                                ui.helper.find('div.menu-item-description').hide();
     79                        },
     80                        stop: function(e,ui) {
     81                                if ( rem )
     82                                        $(rem).hide();
     83                                rem = '';
     84                                wpMenus.fixWebkit();
     85                        }
     86                });
     87
     88                menus.sortable({
     89                        placeholder: 'menu-item-placeholder',
     90                        items: '> .menu-item',
     91                        handle: '> .menu-item-top > .menu-item-title',
     92                        cursor: 'move',
     93                        distance: 2,
     94                        containment: 'document',
     95                        start: function(e,ui) {
     96                                wpMenus.fixWebkit(1);
     97                                ui.item.children('.menu-item-inside').hide();
     98                                ui.item.css({'marginLeft':'','width':''});
     99                        },
     100                        stop: function(e,ui) {
     101                                if ( ui.item.hasClass('ui-draggable') )
     102                                        ui.item.draggable('destroy');
     103
     104                                if ( ui.item.hasClass('deleting') ) {
     105                                        wpMenus.save( ui.item, 1, 0, 1 ); // delete menu item
     106                                        ui.item.remove();
     107                                        return;
     108                                }
     109
     110                                var add = ui.item.find('input.add_new').val(),
     111                                        n = ui.item.find('input.multi_number').val(),
     112                                        id = ui.item.attr('id'),
     113                                        sb = $(this).attr('id');
     114
     115                                ui.item.css({'marginLeft':'','width':''});
     116                                wpMenus.fixWebkit();
     117                                if ( add ) {
     118                                        if ( 'multi' == add ) {
     119                                                ui.item.html( ui.item.html().replace(/<[^<>]+>/g, function(m){ return m.replace(/__i__|%i%/g, n); }) );
     120                                                ui.item.attr( 'id', id.replace(/__i__|%i%/g, n) );
     121                                                n++;
     122                                                $('div#' + id).find('input.multi_number').val(n);
     123                                        } else if ( 'single' == add ) {
     124                                                ui.item.attr( 'id', 'new-' + id );
     125                                                rem = 'div#' + id;
     126                                        }
     127                                        wpMenus.save( ui.item, 0, 0, 1 );
     128                                        ui.item.find('input.add_new').val('');
     129                                        ui.item.find('a.menu-item-action').click();
     130                                        return;
     131                                }
     132                                wpMenus.saveOrder(sb);
     133                        },
     134                        receive: function(e,ui) {
     135                                if ( !$(this).is(':visible') )
     136                                        $(this).sortable('cancel');
     137                        }
     138                }).sortable('option', 'connectWith', 'div.menu-items-sortables').parent().filter('.closed').children('.menu-items-sortables').sortable('disable');
     139
     140                $('#available-menu-items').droppable({
     141                        tolerance: 'pointer',
     142                        accept: function(o){
     143                                return $(o).parent().attr('id') != 'menu-item-list';
     144                        },
     145                        drop: function(e,ui) {
     146                                ui.draggable.addClass('deleting');
     147                                $('#removing-menu-item').hide().children('span').html('');
     148                        },
     149                        over: function(e,ui) {
     150                                ui.draggable.addClass('deleting');
     151                                $('div.menu-item-placeholder').hide();
     152
     153                                if ( ui.draggable.hasClass('ui-sortable-helper') )
     154                                        $('#removing-menu-item').show().children('span')
     155                                        .html( ui.draggable.find('div.menu-item-title').children('h4').html() );
     156                        },
     157                        out: function(e,ui) {
     158                                ui.draggable.removeClass('deleting');
     159                                $('div.menu-item-placeholder').show();
     160                                $('#removing-menu-item').hide().children('span').html('');
     161                        }
     162                });
     163        },
     164
     165        saveOrder : function(sb) {
     166                if ( sb )
     167                        $('#' + sb).closest('div.menu-items-holder-wrap').find('img.ajax-feedback').css('visibility', 'visible');
     168
     169                var a = {
     170                        action: 'menu-items-order',
     171                        savemenu_items: $('#_wpnonce_menu_items').val(),
     172                        menus: []
     173                };
     174
     175                $('div.menu-items-sortables').each( function() {
     176                        a['menus[' + $(this).attr('id') + ']'] = $(this).sortable('toArray').join(',');
     177                });
     178
     179                $.post( ajaxurl, a, function() {
     180                        $('img.ajax-feedback').css('visibility', 'hidden');
     181                });
     182
     183                this.resize();
     184        },
     185
     186        save : function(menu_item, del, animate, order) {
     187                var sb = menu_item.closest('div.menu-items-sortables').attr('id'), data = menu_item.find('form').serialize(), a;
     188                menu_item = $(menu_item);
     189                $('.ajax-feedback', menu_item).css('visibility', 'visible');
     190
     191                a = {
     192                        action: 'save-menu-item',
     193                        savemenu_items: $('#_wpnonce_menu_items').val(),
     194                        menu: sb
     195                };
     196
     197                if ( del )
     198                        a['delete_menu_item'] = 1;
     199
     200                data += '&' + $.param(a);
     201
     202                $.post( ajaxurl, data, function(r){
     203                        var id;
     204
     205                        if ( del ) {
     206                                if ( !$('input.menu_item_number', menu_item).val() ) {
     207                                        id = $('input.menu-item-id', menu_item).val();
     208                                        $('#available-menu-items').find('input.menu-item-id').each(function(){
     209                                                if ( $(this).val() == id )
     210                                                        $(this).closest('div.menu-item').show();
     211                                        });
     212                                }
     213
     214                                if ( animate ) {
     215                                        order = 0;
     216                                        menu_item.slideUp('fast', function(){
     217                                                $(this).remove();
     218                                                wpMenus.saveOrder();
     219                                        });
     220                                } else {
     221                                        menu_item.remove();
     222                                        wpMenus.resize();
     223                                }
     224                        } else {
     225                                $('.ajax-feedback').css('visibility', 'hidden');
     226                                if ( r && r.length > 2 ) {
     227                                        $('div.menu-item-content', menu_item).html(r);
     228                                        wpMenus.appendTitle(menu_item);
     229                                        wpMenus.fixLabels(menu_item);
     230                                }
     231                        }
     232                        if ( order )
     233                                wpMenus.saveOrder();
     234                });
     235        },
     236
     237        appendTitle : function(menu_item) {
     238                var title = $('input[id*="-title"]', menu_item);
     239                if ( title = title.val() ) {
     240                        title = title.replace(/<[^<>]+>/g, '').replace(/</g, '&lt;').replace(/>/g, '&gt;');
     241                        $(menu_item).children('.menu-item-top').children('.menu-item-title').children()
     242                                .children('.in-menu-item-title').html(': ' + title);
     243                }
     244        },
     245
     246        resize : function() {
     247                $('div.menu-items-sortables').not('#wp_inactive_menu_items').each(function(){
     248                        var h = 50, H = $(this).children('.menu-item').length;
     249                        h = h + parseInt(H * 48, 10);
     250                        $(this).css( 'minHeight', h + 'px' );
     251                });
     252        },
     253
     254    fixWebkit : function(n) {
     255        n = n ? 'none' : '';
     256        $('body').css({
     257                        WebkitUserSelect: n,
     258                        KhtmlUserSelect: n
     259                });
     260    },
     261
     262    fixLabels : function(menu_item) {
     263                menu_item.children('.menu-item-inside').find('label').each(function(){
     264                        var f = $(this).attr('for');
     265                        if ( f && f == $('input', this).attr('id') )
     266                                $(this).removeAttr('for');
     267                });
     268        },
     269
     270    close : function(menu_item) {
     271                menu_item.children('.menu-item-inside').slideUp('fast', function(){
     272                        menu_item.css({'width':'','marginLeft':''});
     273                });
     274        }
     275};
     276
     277$(document).ready(function($){ wpMenus.init(); });
     278
     279})(jQuery);
  • wp-admin/menus.php

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

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