Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm trying to add a class to anchor links of children element in wp_nav_menu both for pages and posts. Is there a way to modify the Nav Menu Walker and do so?

Basically my custom walker looks like this:

class Main_Nav extends Walker_Nav_Menu {
        function start_lvl(&$output, $depth) {
            $indent = str_repeat("\t", $depth);
            $output .= "\n$indent<ul class=\"dropdown-menu\">\n";
        }
        function start_el(&$output, $item, $depth, $args) {

            if( $depth == 0) {
                    $output .= "<li class='menu'>";
            }               
            if( $depth == 1) {
                    $output .= "<li>";
            }
            $attributes  = '';
            ! empty( $item->attr_title ) and $attributes .= ' title="' . esc_attr( $item->attr_title ) .'"';
            ! empty( $item->target )and $attributes .= ' target="' . esc_attr( $item->target ) .'"';
            ! empty( $item->xfn )and $attributes .= ' rel="' . esc_attr( $item->xfn ) .'"';
            ! empty( $item->url )and $attributes .= ' href="' . esc_attr( $item->url ) .'"';

            $title = apply_filters( 'the_title', $item->title, $item->ID );

            if (/* THE MENU ELEMENT HAS CHILDREN */) {
                    $item_output = 
                    "<a $attributes class='menu'>"
                    . $title
                    . '</a> ';
            }

            else {
                    $item_output = 
                    "<a $attributes>"
                    . $title
                    . '</a> ';
            }

            $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth);

    }

}

As you see I don't know what the proper condition instead of /* THE ELEMENT HAS CHILDREN */.

Thank you.

UPDATE

Thanks to Tamil I updated the code as follows:

class Main_Nav extends Walker_Nav_Menu {
        function start_lvl(&$output, $depth) {
            $indent = str_repeat("\t", $depth);
            $output .= "\n$indent<ul class=\"dropdown-menu\">\n";
        }
        function start_el(&$output, $item, $depth, $args) {

            if( $depth == 0) {
                    $output .= "<li class='menu'>";
            }               
            if( $depth == 1) {
                    $output .= "<li>";
            }
            $attributes  = '';
            ! empty( $item->attr_title ) and $attributes .= ' title="' . esc_attr( $item->attr_title ) .'"';
            ! empty( $item->target )and $attributes .= ' target="' . esc_attr( $item->target ) .'"';
            ! empty( $item->xfn )and $attributes .= ' rel="' . esc_attr( $item->xfn ) .'"';
            ! empty( $item->url )and $attributes .= ' href="' . esc_attr( $item->url ) .'"';

            $title = apply_filters( 'the_title', $item->title, $item->ID );

            global $wpdb;
            $query = $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->posts WHERE post_status ='publish' AND post_type='nav_menu_item' AND post_parent=%d", $item->ID);
            $child_count = $wpdb->get_var($query);

            if($child_count > 0) { /* THE MENU ELEMENT HAS CHILDREN */
                 $item_output = 
                    "<a $attributes class='menu'>"
                    . $title
                    . '</a> ';
            } else {
                    $item_output = 
                    "<a $attributes>"
                    . $title
                    . '</a> ';
            }

            $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth);

    }

}

No luck though :(

share|improve this question

2 Answers 2

up vote 2 down vote accepted

I was able to add a "parent" CSS class to the anchor tag of menu items who have children by following this answer: Add 'has_children' class to parent li when modifying Walker_Nav_Menu

Here's an example:

class Main_Nav extends Walker_Nav_Menu {
  /**
   * @see Walker::start_el()
   * @since 3.0.0
   *
   * @param string $output Passed by reference. Used to append additional content.
   * @param object $item Menu item data object.
   * @param int $depth Depth of menu item. Used for padding.
   * @param int $current_page Menu item ID.
   * @param object $args
   */
  function start_el(&$output, $item, $depth, $args) {
    global $wp_query;
    $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

    $class_names = $value = '';

    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $classes[] = 'menu-item-' . $item->ID;

    $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
    $class_names = ' class="' . esc_attr( $class_names ) . '"';

    $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
    $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';

    $output .= $indent . '<li' . $id . $value . $class_names .'>';

    $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        ) .'"' : '';

    // Check our custom has_children property.
    if ( $args->has_children ) {
      $attributes .= ' class="menu parent"';
    }

    $item_output = $args->before;
    $item_output .= '<a'. $attributes .'>';
    $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
    $item_output .= '</a>';
    $item_output .= $args->after;

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

  function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
    $id_field = $this->db_fields['id'];
    if ( is_object( $args[0] ) ) {
      $args[0]->has_children = ! empty( $children_elements[$element->$id_field] );
    }
    return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
  }

}
share|improve this answer

If the items used are from the table {$wpdb->prefix}posts, then you can query for posts with

post_parent = $item->ID and post_status = 'publish'

If the query returns any post then it has children and you can add the required class.

If its for pages the code in following page can be used.

http://www.jeangalea.com/wordpress/check-wordpress-page-childrensubpages/

However there doesn't seems to be a direct way to find if child exists.

UPDATE: Added code as per your request.

global $wpdb;
$query = $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->posts WHERE post_status ='publish' AND post_type='nav_menu_item' AND post_parent=%d", $item->ID);
$child_count = $wpdb->get_var($query);
if($child_count > 0) { /* THE MENU ELEMENT HAS CHILDREN */
   .....
} else {
   .....
}
share|improve this answer
    
I believe the question is if the Menu Item has children not the post or page. –  Kevin Langley Jr. Dec 23 '11 at 7:14
    
@tamil, how would the code look like with your suggestions? –  Sergey Dec 23 '11 at 7:18
    
@Sergey Added code as per your request. –  tamilsweet Dec 23 '11 at 7:29
    
I tried yr code, but it didnt work. Please note, I'm using pages not posts. Is there any difference? –  Sergey Dec 23 '11 at 7:31
    
@KevinLangleyJr. Thanks for pointing out. I overlooked the question. –  tamilsweet Dec 23 '11 at 7:32

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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