Make WordPress Core

Ticket #11817: menus.5.diff

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

5 items / dropdown; more compact menu item listing

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

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

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

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

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

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

     
    14181418
    14191419        die();
    14201420        break;
     1421case 'menu-items-order' :
     1422        check_ajax_referer( 'save-menu-items', 'savemenu_items' );
     1423
     1424        if ( !current_user_can('switch_themes') )
     1425                die('-1');
     1426
     1427        unset( $_POST['savemenu_items'], $_POST['action'] );
     1428
     1429        // save menu_items order for all menus
     1430        if ( is_array($_POST['menus']) ) {
     1431                $menus = array();
     1432                foreach ( $_POST['menus'] as $key => $val ) {
     1433                        $sb = array();
     1434                        if ( !empty($val) ) {
     1435                                $val = explode(',', $val);
     1436                                foreach ( $val as $k => $v ) {
     1437                                        if ( strpos($v, 'menu-item-') === false )
     1438                                                continue;
     1439
     1440                                        $tmp = explode('_', $v, 2);
     1441                                        $sb[$k] = $tmp[1];
     1442                                }
     1443                        }
     1444                        $menus[$key] = $sb;
     1445                }
     1446                wp_set_menu_items($menus);
     1447                die('1');
     1448        }
     1449
     1450        die('-1');
     1451        break;
     1452case 'save-menu-item' :
     1453        check_ajax_referer( 'save-menu-items', 'savemenu_items' );
     1454
     1455        if ( !current_user_can('switch_themes') || !isset($_POST['id_base']) )
     1456                die('-1');
     1457
     1458        unset( $_POST['savemenu_items'], $_POST['action'] );
     1459
     1460        do_action('load-menus.php');
     1461        do_action('menus.php');
     1462        do_action('menu_admin_setup');
     1463
     1464        $id_base = $_POST['id_base'];
     1465        $menu_item_id = $_POST['menu-item-id'];
     1466        $menu_id = $_POST['menu'];
     1467        $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
     1468        $settings = isset($_POST['menu-item-' . $id_base]) && is_array($_POST['menu-item-' . $id_base]) ? $_POST['menu-item-' . $id_base] : false;
     1469        $error = '<p>' . __('An error has occured. Please reload the page and try again.') . '</p>';
     1470
     1471        $menus = wp_get_menu_items();
     1472        $menu = isset($menus[$menu_id]) ? $menus[$menu_id] : array();
     1473
     1474        // delete
     1475        if ( isset($_POST['delete_menu_item']) && $_POST['delete_menu_item'] ) {
     1476
     1477                if ( !isset($wp_registered_menu_items[$menu_item_id]) )
     1478                        die($error);
     1479
     1480                $menu = array_diff( $menu, array($menu_item_id) );
     1481                $_POST = array('menu' => $menu_id, 'menu-item-' . $id_base => array(), 'the-menu-item-id' => $menu_item_id, 'delete_menu_item' => '1');
     1482        } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
     1483                if ( !$multi_number )
     1484                        die($error);
     1485
     1486                $_POST['menu-item-' . $id_base] = array( $multi_number => array_shift($settings) );
     1487                $menu_item_id = $id_base . '-' . $multi_number;
     1488                $menu[] = $menu_item_id;
     1489        }
     1490        $_POST['menu-item-id'] = $menu;
     1491
     1492        foreach ( (array) $wp_registered_menu_item_updates as $name => $control ) {
     1493
     1494                if ( $name == $id_base ) {
     1495                        if ( !is_callable( $control['callback'] ) )
     1496                                continue;
     1497
     1498                        ob_start();
     1499                                call_user_func_array( $control['callback'], $control['params'] );
     1500                        ob_end_clean();
     1501                        break;
     1502                }
     1503        }
     1504
     1505        if ( isset($_POST['delete_menu_item']) && $_POST['delete_menu_item'] ) {
     1506                $menus[$menu_id] = $menu;
     1507                wp_set_menu_items($menus);
     1508                echo "deleted:$menu_item_id";
     1509                die();
     1510        }
     1511
     1512        if ( !empty($_POST['add_new']) )
     1513                die();
     1514
     1515        if ( $form = $wp_registered_menu_item_controls[$menu_item_id] )
     1516                call_user_func_array( $form['callback'], $form['params'] );
     1517
     1518        die();
     1519        break;
    14211520case 'image-editor':
    14221521        $attachment_id = intval($_POST['postid']);
    14231522        if ( empty($attachment_id) || !current_user_can('edit_post', $attachment_id) )
  • wp-admin/includes/menus.php

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

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

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

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

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

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

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