0

I created a custom menu with dropdowns. (just CSS no JavaScript).
I also added a custom CSS class for the first menu item.

So far so good.

The point were I get stuck is adding a custom dropdown only for the first menu item which is different from the other item dropdowns. Also I would like to set a different has-children style for the first item.

Does anybody know how this can be done?

Here is my custom walker:

class topmenu_walker_nav_menu extends Walker_Nav_Menu {

    function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
        $id_field = $this->db_fields['id'];
        if ( !empty( $children_elements[$element->$id_field] ) && ( depth == 0 ) ) {
            $element->classes[] = 'has-children'; // Use any classname you like
        }
        Walker_Nav_Menu::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

function start_lvl( &$output, $depth ) {
    // depth dependent classes
    $indent = ( $depth > 0  ? str_repeat( "\t", $depth ) : '' ); // code indent
    $display_depth = ( $depth + 1); // because it counts the first submenu as 0
    $classes = array(
        'subnav',
        ( $display_depth % 2  ? 'menu-odd' : 'menu-even' ),
        ( $display_depth >=2 ? 'sub-sub-menu' : '' ),
        'menu-depth-' . $display_depth
        );
    $class_names = implode( ' ', $classes );

    // build html
    $output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
}


 function start_el( &$output, $item, $depth, $args ) {
    global $wp_query;
    $indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent

    // depth dependent classes
    $depth_classes = array(
        ( $depth == 0 ? 'main-menu-item' : 'sub-menu-item' ),
        ( $depth >=2 ? 'sub-sub-menu-item' : '' ),
        ( $depth % 2 ? 'menu-item-odd' : 'menu-item-even' ),
        'menu-item-depth-' . $depth
    );
    $depth_class_names = esc_attr( implode( ' ', $depth_classes ) );

    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );

    $output .= $indent . '<li id="nav-menu-item-'. $item->ID . '" class="' . $depth_class_names . ' ' . $class_names . '">';

    // link attributes
    $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
    $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
    $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
    $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';
    $attributes .= ' class="menu-link ' . ( $depth > 0 ? 'sub-menu-link' : 'main-menu-link' ) . '"';

    $item_output = sprintf( '%1$s<a%2$s>%3$s%4$s%5$s</a>%6$s',
        $args->before,
        $attributes,
        $args->link_before,
        apply_filters( 'the_title', $item->title, $item->ID ),
        $args->link_after,
        $args->after
    );

    // build html
    $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}

add_filter( 'wp_nav_menu_objects', 'tgm_filter_menu_class', 10, 2 );
/**
 * Filters the first and last nav menu objects in your menus
 * to add custom classes.
 *
 * @since 1.0.0
 *
 * @param object $objects An array of nav menu objects
 * @param object $args Nav menu object args
 * @return object $objects Amended array of nav menu objects with new class
 */
function tgm_filter_menu_class( $objects, $args ) {

    // Only apply the classes to the primary navigation menu
    if ( isset( $args->theme_location ) )
        if ( 'main-menu' !== $args->theme_location )
            return $objects;

    // Add "first-menu-item" class to the first menu object
    $objects[1]->classes[] = 'settingsitem';

    // Add "last-menu-item" class to the last menu object
    $objects[count( $objects )]->classes[] = 'last-menu-item';

    // Return the menu objects
    return $objects;

}


    function output_top_menu() {

    echo '<div class="nav-container"><div class="container">';
    wp_nav_menu( array('depth' => 2, 'container_class' => 'nav', 'menu_id' => '', 'walker' => new topmenu_walker_nav_menu(), 'theme_location'=>'main-menu') );  
    echo '</div></div>';


    }

Here is my CSS:

.nav-container {
    background: #232323;
        width:100%;
margin-bottom: -5px;
    height: 60px;
    display: inline-block;
}

.nav {
    background: #232323;
    width:996px;
margin-bottom: -5px;
    height: 60px;
    display: inline-block;
}

.nav li {
    float: left;
    list-style-type: none;
    position: relative;
}

.nav li a {
    font-size: 16px; 
    color: white;
    display: block;
    line-height: 60px;
    padding: 0 26px;
    text-decoration: none;
    border-left: 1px solid #2e2e2e;
    font-family: Montserrat, sans-serif;
    text-shadow: 0 0 1px rgba(255, 255, 255, 0.5);
}
.nav li a:hover {
    background-color: #2e2e2e;
}


#settings a {
    padding: 18px;
    height: 24px;
    font-size: 10px;
    line-height: 24px;

}



.settingsitem a {
    font-size: 16px; 
    color: white;
    display: block;
    line-height: 60px;
    padding: 0 26px;
    text-decoration: none;
    border-left: 1px solid #2e2e2e;
    font-family: Montserrat, sans-serif;
    text-shadow: 0 0 1px rgba(255, 255, 255, 0.5);


}
#options a{
    border-left: 0 none;
}
#options>a {
    background-image: url(triangle.png);
    background-position: 85% center;
    background-repeat: no-repeat;
    padding-right: 42px;
}
.subnav {
    visibility: hidden;
    position: absolute;
    top: 110%;
    right: 0;
    width: 200px;
    height: auto;
    opacity: 0;
    transition: all 0.1s;
    background: #232323;
        z-index:1000;
}
.subnav li {
    float: none;
}
.subnav li a {
    border-bottom: 1px solid #2e2e2e;
}
#options:hover .subnav {
    visibility: visible;
    top: 100%;
    opacity: 1;
}

.nav li.has-children a{
    border-left: 1px solid #2e2e2e;
}
.nav li.has-children>a {
    background-image: url(triangle.png);
    background-position: 85% center;
    background-repeat: no-repeat;
    padding-right: 42px;
}

.nav li.has-children:hover .subnav {
    visibility: visible;
    top: 100%;
    opacity: 1;
}
2
  • Don't you have a class specific to the first item?
    – s_ha_dum
    Commented Jul 1, 2013 at 21:33
  • yes - I just updated my question with the code. Can you help? Thank you very much! Class for the first item should be .settingsitem
    – Simon H.
    Commented Jul 1, 2013 at 21:42

2 Answers 2

1

Well, the answer depends on what you mean by "custom dropdown only for the first menu item which is different from the other item dropdowns" - different how? If it's just stylistic, that extra class should be enough. You just have to make sure the css for it is specific enough to override the defaults. So if your css selectors on the other dropdowns are

.nav li.has-children a{ ... }
.nav li.has-children>a { ... }
.nav li.has-children:hover .subnav { ... }

then to override them for just that first item, if I'm understanding your nav markup right, you'd need something like this (after your existing css):

.nav li.settingsitem a { ... }
.nav li.settingsitem > a { ... }
.nav li.settingsitem:hover .subnav { ... }
0

This question has been answered.

In nutshell, it says that you need to add a submenu with the same slug, and callback function of the custom menu, to override the first default submenu.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.