Make WordPress Core

Ticket #11817: menus.3.diff

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

menu admin with dropdowns

  • wp-includes/load.php

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

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

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

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

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

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

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

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

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

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

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

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

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

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