Make WordPress Core


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/nav-menu-template.php

    r14971 r15235  
    6969        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
    7070
    71         $classes = $value = '';
    72 
    73         $classes = array( 'menu-item', 'menu-item-type-' . $item->type );
    74         if ( !empty($item->classes) )
    75             $classes = array_merge( $classes, $item->classes );
    76 
    77         if ( 'custom' != $item->type ) {
    78             $classes[] = 'menu-item-object-' . $item->object;
    79             $classes[] = 'menu-item-object-' . $item->type . '-' . $item->object_id;
    80             if ( 'post_type' == $item->type && 'page' == $item->object ) {
    81                 // Back compat classes for pages to match wp_page_menu()
    82                 $classes[] = 'page_item';
    83                 $classes[] = 'page-item-' . $item->object_id;
    84                 if ( ! empty( $item->classes ) ) {
    85                     if ( in_array('current-menu-item', $classes) )
    86                         $classes[] = 'current_page_item';
    87                     if ( in_array('current-menu-parent', $classes) )
    88                         $classes[] = 'current_page_parent';
    89                     if ( in_array('current-menu-ancestor', $classes) )
    90                         $classes[] = 'current_page_ancestor';
    91                 }
    92             }
    93         } elseif ( 'custom' == $item->type && in_array('current-menu-item', $classes) && in_array('menu-item-home', $classes) ) {
    94             // Back compat for home limk to match wp_page_menu()
    95             $classes[] = 'current_page_item';
    96         }
    97 
    98         $classes = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
    99         $classes = ' class="' . esc_attr( $classes ) . '"';
    100 
    101         $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $classes .'>';
     71        $class_names = $value = '';
     72
     73        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
     74
     75        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
     76        $class_names = ' class="' . esc_attr( $class_names ) . '"';
     77
     78        $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
    10279
    10380        $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
     
    129106
    130107/**
    131  * Create HTML list of nav menu input items.
    132  *
    133  * @package WordPress
    134  * @since 3.0.0
    135  * @uses Walker_Nav_Menu
    136  */
    137 class Walker_Nav_Menu_Checklist extends Walker_Nav_Menu  {
    138 
    139     /**
    140      * @see Walker::start_el()
    141      * @since 3.0.0
    142      *
    143      * @param string $output Passed by reference. Used to append additional content.
    144      * @param object $item Menu item data object.
    145      * @param int $depth Depth of menu item. Used for padding.
    146      * @param int $current_page Menu item ID.
    147      * @param object $args
    148      */
    149     function start_el(&$output, $item, $depth, $args) {
    150         global $_nav_menu_placeholder;
    151 
    152         $_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval($_nav_menu_placeholder) - 1 : -1;
    153         $possible_object_id = isset( $item->post_type ) && 'nav_menu_item' == $item->post_type ? $item->object_id : $_nav_menu_placeholder;
    154         $possible_db_id = ( ! empty( $item->ID ) ) && ( 0 < $possible_object_id ) ? (int) $item->ID : 0;
    155 
    156         $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
    157 
    158         $output .= $indent . '<li>';
    159         $output .= '<label class="menu-item-title">';
    160         $output .= '<input type="checkbox" class="menu-item-checkbox';
    161         if ( ! empty( $item->_add_to_top ) ) {
    162             $output .= ' add-to-top';
    163         }
    164         $output .= '" name="menu-item[' . $possible_object_id . '][menu-item-object-id]" value="'. esc_attr( $item->object_id ) .'" /> ';
    165         $output .= empty( $item->label ) ? esc_html( $item->title ) : esc_html( $item->label );
    166         $output .= '</label>';
    167 
    168         // Menu item hidden fields
    169         $output .= '<input type="hidden" class="menu-item-db-id" name="menu-item[' . $possible_object_id . '][menu-item-db-id]" value="' . $possible_db_id . '" />';
    170         $output .= '<input type="hidden" class="menu-item-object" name="menu-item[' . $possible_object_id . '][menu-item-object]" value="'. esc_attr( $item->object ) .'" />';
    171         $output .= '<input type="hidden" class="menu-item-parent-id" name="menu-item[' . $possible_object_id . '][menu-item-parent-id]" value="'. esc_attr( $item->menu_item_parent ) .'" />';
    172         $output .= '<input type="hidden" class="menu-item-type" name="menu-item[' . $possible_object_id . '][menu-item-type]" value="'. esc_attr( $item->type ) .'" />';
    173         $output .= '<input type="hidden" class="menu-item-title" name="menu-item[' . $possible_object_id . '][menu-item-title]" value="'. esc_attr( $item->title ) .'" />';
    174         $output .= '<input type="hidden" class="menu-item-url" name="menu-item[' . $possible_object_id . '][menu-item-url]" value="'. esc_attr( $item->url ) .'" />';
    175         $output .= '<input type="hidden" class="menu-item-target" name="menu-item[' . $possible_object_id . '][menu-item-target]" value="'. esc_attr( $item->target ) .'" />';
    176         $output .= '<input type="hidden" class="menu-item-attr_title" name="menu-item[' . $possible_object_id . '][menu-item-attr_title]" value="'. esc_attr( $item->attr_title ) .'" />';
    177         $output .= '<input type="hidden" class="menu-item-description" name="menu-item[' . $possible_object_id . '][menu-item-description]" value="'. esc_attr( $item->description ) .'" />';
    178         $output .= '<input type="hidden" class="menu-item-classes" name="menu-item[' . $possible_object_id . '][menu-item-classes]" value="'. esc_attr( implode( ' ', $item->classes ) ) .'" />';
    179         $output .= '<input type="hidden" class="menu-item-xfn" name="menu-item[' . $possible_object_id . '][menu-item-xfn]" value="'. esc_attr( $item->xfn ) .'" />';
    180     }
    181 }
    182 
    183 /**
    184108 * Displays a navigation menu.
    185109 *
     
    187111 *
    188112 * menu - The menu that is desired.  Accepts (matching in order) id, slug, name. Defaults to blank.
    189  * menu_class - CSS class to use for the ul container of the menu list. Defaults to 'menu'.
     113 * menu_class - CSS class to use for the ul element which forms the menu. Defaults to 'menu'.
     114 * menu_id - The ID that is applied to the ul element which forms the menu. Defaults to the menu slug, incremented.
    190115 * container - Whether to wrap the ul, and what to wrap it with. Defaults to 'div'.
    191  * conatiner_class - the class that is applied to the container. Defaults to blank.
     116 * container_class - the class that is applied to the container. Defaults to 'menu-{menu slug}-container'.
     117 * container_id - The ID that is applied to the container. Defaults to blank.
    192118 * fallback_cb - If the menu doesn't exists, a callback function will fire. Defaults to 'wp_page_menu'.
    193119 * before - Text before the link text.
     
    198124 * depth - how many levels of the hierarchy are to be included.  0 means all.  Defaults to 0.
    199125 * walker - allows a custom walker to be specified.
    200  * context - the context the menu is used in.
    201126 * theme_location - the location in the theme to be used.  Must be registered with register_nav_menu() in order to be selectable by the user.
    202127 *
     
    206131 */
    207132function wp_nav_menu( $args = array() ) {
    208     $defaults = array( 'menu' => '', 'container' => 'div', 'container_class' => '', 'menu_class' => 'menu', 'echo' => true,
    209     'fallback_cb' => 'wp_page_menu', 'before' => '', 'after' => '', 'link_before' => '', 'link_after' => '',
    210     'depth' => 0, 'walker' => '', 'context' => 'frontend', 'theme_location' => '' );
     133    static $menu_id_slugs = array();
     134
     135    $defaults = array( 'menu' => '', 'container' => 'div', 'container_class' => '', 'container_id' => '', 'menu_class' => 'menu', 'menu_id' => '',
     136    'echo' => true, 'fallback_cb' => 'wp_page_menu', 'before' => '', 'after' => '', 'link_before' => '', 'link_after' => '',
     137    'depth' => 0, 'walker' => '', 'theme_location' => '' );
    211138
    212139    $args = wp_parse_args( $args, $defaults );
     
    236163        $menu_items = wp_get_nav_menu_items( $menu->term_id );
    237164
    238     // If no menu was found or if the menu has no items, call the fallback_cb
    239     if ( !$menu || is_wp_error($menu) || ( isset($menu_items) && empty($menu_items) ) ) {
    240         if ( 'frontend' == $args->context && ( function_exists($args->fallback_cb) || is_callable( $args->fallback_cb ) ) ) {
     165    // If no menu was found or if the menu has no items and no location was requested, call the fallback_cb if it exists
     166    if ( ( !$menu || is_wp_error($menu) || ( isset($menu_items) && empty($menu_items) && !$args->theme_location ) )
     167        && ( function_exists($args->fallback_cb) || is_callable( $args->fallback_cb ) ) )
    241168            return call_user_func( $args->fallback_cb, (array) $args );
    242         }
    243     }
    244169
    245170    // If no fallback function was specified and the menu doesn't exists, bail.
     
    247172        return false;
    248173
    249     $nav_menu = '';
    250     $items = '';
    251     $container_allowedtags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav' ) );
    252 
    253     if ( in_array( $args->container, $container_allowedtags ) ) {
    254         $class = $args->container_class ? ' class="' . esc_attr($args->container_class) . '"' : ' class="menu-'. $menu->slug .'-container"';
    255         $nav_menu .= '<'. $args->container . $class .'>';
     174    $nav_menu = $items = '';
     175
     176    $show_container = false;
     177    if ( $args->container ) {
     178        $allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav' ) );
     179        if ( in_array( $args->container, $allowed_tags ) ) {
     180            $show_container = true;
     181            $class = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-'. $menu->slug .'-container"';
     182            $id = $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"' : '';
     183            $nav_menu .= '<'. $args->container . $id . $class . '>';
     184        }
    256185    }
    257186
    258187    // Set up the $menu_item variables
    259     if ( 'frontend' == $args->context )
    260         _wp_menu_item_classes_by_context( $menu_items );
     188    _wp_menu_item_classes_by_context( $menu_items );
    261189
    262190    $sorted_menu_items = array();
     
    270198
    271199    // Attributes
    272     $attributes  = ' id="menu-' . $menu->slug . '"';
     200    if ( ! empty( $args->menu_id ) ) {
     201        $slug = $args->menu_id;
     202    } else {
     203        $slug = 'menu-' . $menu->slug;
     204        while ( in_array( $slug, $menu_id_slugs ) ) {
     205            if ( preg_match( '#-(\d+)$#', $slug, $matches ) )
     206                $slug = preg_replace('#-(\d+)$#', '-' . ++$matches[1], $slug);
     207            else
     208                $slug = $slug . '-1';
     209        }
     210    }
     211    $menu_id_slugs[] = $slug;
     212    $attributes = ' id="' . $slug . '"';
    273213    $attributes .= $args->menu_class ? ' class="'. $args->menu_class .'"' : '';
    274214
     
    283223    $nav_menu .= '</ul>';
    284224
    285     if ( in_array( $args->container, $container_allowedtags ) )
    286         $nav_menu .= '</'. $args->container .'>';
     225    if ( $show_container )
     226        $nav_menu .= '</' . $args->container . '>';
    287227
    288228    $nav_menu = apply_filters( 'wp_nav_menu', $nav_menu, $args );
     
    295235
    296236/**
    297  * Add the class property classes for the current frontend context, if applicable.
     237 * Add the class property classes for the current context, if applicable.
    298238 *
    299239 * @access private
     
    311251    $active_parent_item_ids = array();
    312252    $active_parent_object_ids = array();
     253    $possible_taxonomy_ancestors = array();
    313254    $possible_object_parents = array();
    314255    $home_page_id = (int) get_option( 'page_for_posts' );
     
    317258        foreach ( (array) get_object_taxonomies( $queried_object->post_type ) as $taxonomy ) {
    318259            if ( is_taxonomy_hierarchical( $taxonomy ) ) {
     260                $term_hierarchy = _get_term_hierarchy( $taxonomy );
    319261                $terms = wp_get_object_terms( $queried_object_id, $taxonomy, array( 'fields' => 'ids' ) );
    320                 if ( is_array( $terms ) )
     262                if ( is_array( $terms ) ) {
    321263                    $possible_object_parents = array_merge( $possible_object_parents, $terms );
     264                    $term_to_ancestor = array();
     265                    foreach ( (array) $term_hierarchy as $anc => $descs ) {
     266                        foreach ( (array) $descs as $desc )
     267                            $term_to_ancestor[ $desc ] = $anc;
     268                    }
     269
     270                    foreach ( $terms as $desc ) {
     271                        do {
     272                            $possible_taxonomy_ancestors[ $taxonomy ][] = $desc;
     273                            if ( isset( $term_to_ancestor[ $desc ] ) ) {
     274                                $_desc = $term_to_ancestor[ $desc ];
     275                                unset( $term_to_ancestor[ $desc ] );
     276                                $desc = $_desc;
     277                            } else {
     278                                $desc = 0;
     279                            }
     280                        } while ( ! empty( $desc ) );
     281                    }
     282                }
    322283            }
    323284        }
    324285    } elseif ( ! empty( $queried_object->post_type ) && is_post_type_hierarchical( $queried_object->post_type ) ) {
    325286        _get_post_ancestors( $queried_object );
     287    } elseif ( ! empty( $queried_object->taxonomy ) && is_taxonomy_hierarchical( $queried_object->taxonomy ) ) {
     288        $term_hierarchy = _get_term_hierarchy( $queried_object->taxonomy );
     289        $term_to_ancestor = array();
     290        foreach ( (array) $term_hierarchy as $anc => $descs ) {
     291            foreach ( (array) $descs as $desc )
     292                $term_to_ancestor[ $desc ] = $anc;
     293        }
     294        $desc = $queried_object->term_id;
     295        do {
     296            $possible_taxonomy_ancestors[ $queried_object->taxonomy ][] = $desc;
     297            if ( isset( $term_to_ancestor[ $desc ] ) ) {
     298                $_desc = $term_to_ancestor[ $desc ];
     299                unset( $term_to_ancestor[ $desc ] );
     300                $desc = $_desc;
     301            } else {
     302                $desc = 0;
     303            }
     304        } while ( ! empty( $desc ) );
    326305    }
    327306
     
    329308
    330309    foreach ( (array) $menu_items as $key => $menu_item ) {
     310        $classes = (array) $menu_item->classes;
     311        $classes[] = 'menu-item';
     312        $classes[] = 'menu-item-type-' . $menu_item->type;
     313
    331314        // if the menu item corresponds to a taxonomy term for the currently-queried non-hierarchical post object
    332315        if ( $wp_query->is_singular && 'taxonomy' == $menu_item->type && in_array( $menu_item->object_id, $possible_object_parents ) ) {
     
    344327            )
    345328        ) {
    346             $menu_items[$key]->classes[] = 'current-menu-item';
     329            $classes[] = 'current-menu-item';
     330            if ( 'post_type' == $menu_item->type && 'page' == $menu_item->object ) {
     331                // Back compat classes for pages to match wp_page_menu()
     332                $classes[] = 'page_item';
     333                $classes[] = 'page-item-' . $menu_item->object_id;
     334                $classes[] = 'current_page_item';
     335            }
    347336            $active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
    348337            $active_parent_object_ids[] = (int) $menu_item->post_parent;
     
    354343            $item_url = strpos( $menu_item->url, '#' ) ? substr( $menu_item->url, 0, strpos( $menu_item->url, '#' ) ) : $menu_item->url;
    355344            if ( $item_url == $current_url ) {
    356                 $menu_items[$key]->classes[] = 'current-menu-item';
    357                 if ( untrailingslashit($current_url) == home_url() )
    358                     $menu_items[$key]->classes[] = 'menu-item-home';
     345                $classes[] = 'current-menu-item';
     346                if ( untrailingslashit($current_url) == home_url() ) {
     347                    $classes[] = 'menu-item-home';
     348                    // Back compat for home limk to match wp_page_menu()
     349                    $classes[] = 'current_page_item';
     350                }
    359351                $active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
    360352                $active_parent_object_ids[] = (int) $menu_item->post_parent;
     
    362354            }
    363355        }
    364        
     356
    365357        // back-compat with wp_page_menu: add "current_page_parent" to static home page link for any non-page query
    366         if ( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && empty( $wp_query->is_page ) && $home_page_id == $menu_item->object_id )
    367             $menu_items[$key]->classes[] = 'current_page_parent';
     358        if ( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && empty( $wp_query->is_page ) && $home_page_id == $menu_item->object_id )
     359            $classes[] = 'current_page_parent';
     360
     361        $menu_items[$key]->classes = array_unique( $classes );
    368362    }
    369363
     
    373367    // set parent's class
    374368    foreach ( (array) $menu_items as $key => $parent_item ) {
     369        $classes = (array) $parent_item->classes;
     370
    375371        if (
    376372            isset( $parent_item->type ) &&
    377             'post_type' == $parent_item->type &&
    378             ! empty( $queried_object->post_type ) &&
    379             is_post_type_hierarchical( $queried_object->post_type ) &&
    380             in_array( $parent_item->object_id, $queried_object->ancestors )
    381         )
    382             $menu_items[$key]->classes[] = 'current-' . $queried_object->post_type . '-ancestor current-menu-ancestor';
     373            (
     374                // ancestral post object
     375                (
     376                    'post_type' == $parent_item->type &&
     377                    ! empty( $queried_object->post_type ) &&
     378                    is_post_type_hierarchical( $queried_object->post_type ) &&
     379                    in_array( $parent_item->object_id, $queried_object->ancestors )
     380                ) ||
     381
     382                // ancestral term
     383                (
     384                    'taxonomy' == $parent_item->type &&
     385                    isset( $possible_taxonomy_ancestors[ $parent_item->object ] ) &&
     386                    in_array( $parent_item->object_id, $possible_taxonomy_ancestors[ $parent_item->object ] )
     387                )
     388            )
     389        ) {
     390            $classes[] = empty( $queried_object->taxonomy ) ? 'current-' . $queried_object->post_type . '-ancestor' : 'current-' . $queried_object->taxonomy . '-ancestor';
     391            $classes[] = 'current-menu-ancestor';
     392        }
     393
    383394        if ( in_array( $parent_item->db_id, $active_parent_item_ids ) )
    384             $menu_items[$key]->classes[] = 'current-menu-parent';
     395            $classes[] = 'current-menu-parent';
    385396        if ( in_array( $parent_item->object_id, $active_parent_object_ids ) )
    386             $menu_items[$key]->classes[] = 'current-' . $active_object . '-parent';
     397            $classes[] = 'current-' . $active_object . '-parent';
     398
     399        if ( 'post_type' == $parent_item->type && 'page' == $parent_item->object ) {
     400            // Back compat classes for pages to match wp_page_menu()
     401            if ( in_array('current-menu-parent', $classes) )
     402                $classes[] = 'current_page_parent';
     403            if ( in_array('current-menu-ancestor', $classes) )
     404                $classes[] = 'current_page_ancestor';
     405        }
     406
     407        $menu_items[$key]->classes = array_unique( $classes );
    387408    }
    388409}
Note: See TracChangeset for help on using the changeset viewer.