1

I have been away of wordpress for quite a while and never practiced that much. I have a few problems even tho I looked on the internet for an answer... regarding the wp_nav_menu behaviour.

Hope you guys will be able to help and understand my english.

The problem is the following: Short version: I'm trying to rewrite the way <li> will be outputted from the PHP in the HTML. Right now, it's the default way of Wordpress to output the navigation. There is a nav -> ul -> li -> a. I am trying with the filter to rework the li to have something like <li><a href="#' . $url . '"><span>' . $title . '</span><i class="fa ' . $list_ico_class . '"/></a></li> You can see this last line at the end of the filter :)

Long version: I have a primary navigation which display the categories of a custom post type "projects" (doing a new version of my portfolio). I would have probably 3 categories: Design, Frontend, Applications. The menu items would then be those 3 categories + a blog link.

I am trying to add a custom class for each list item depending on the title of the item. After looking on the internet, the solution seemed to be to create a function that would filter the content.

I wrote the following based on different sources:

add_filter( 'wp_nav_menu_items', 'my_custom_menu_item', 10, 2 );
function my_custom_menu_item ( $items, $args ) {
    if (is_single() && $args->theme_location == 'primary') {
        foreach ( (array) $menu_items as $key => $menu_item ) {
            $title = $menu_item->title;
            $url = $menu_item->url;

            if ($title == 'Design') {
                $list_ico_class = 'fa-pencil';
            }
            else if ($title == 'Frontend') {
                $list_ico_class = 'fa-desktop';
            }
            else if ($title == 'Applications') {
                $list_ico_class = 'fa-code';
            }
            else if ($title == 'Blog') {
                $list_ico_class = 'fa-user';
            }
            else {
                $list_ico_class = 'fa-question';
            }

            $menu_list .= '<li><a href="#' . $url . '"><span>' . $title . '</span><i class="fa ' . $list_ico_class . '"/></a></li>';
        }
    }
    return $menu_items;
}

Then, in my header.php template, I did the menu in a "regular" way since I am not sure how to proceed..

<nav class="site-navigation main-navigation">
                <span class="nav-info">Smoothly go to<i class="fa fa-long-arrow-right"></i></span>
                <?php

                    $main_nav_values = array(
                        'theme_location'  => 'primary',
                        'menu'            => '',
                        'container'       => 'false',
                        'container_class' => '',
                        'container_id'    => '',
                        'menu_class'      => 'main-navigation', 'site-navigation',
                        'menu_id'         => 'primary-menu',
                        'echo'            => true,
                        'fallback_cb'     => 'wp_page_menu',
                        'before'          => '',
                        'after'           => '',
                        'link_before'     => '',
                        'link_after'      => '',
                        'items_wrap'      => '<ul id="%1$s">%3$s</ul>',
                        'depth'           => 0,
                        'walker'          => ''
                    );

                    wp_nav_menu($main_nav_values);

                    ?>
            </nav> <!-- .site-navigation .main-navigation -->

The menu doesn't appear anymore unfortunately when the filter function is present... Not triggering any error, probably just a null object ?

I tried following what's suggested here: http://codex.wordpress.org/Plugin_API/Filter_Reference/nav_menu_css_class and there Get menu item slug

The desired output would be the following:

<nav class="site-navigation main-navigation">
        <span class="nav-info">Smoothly go to<i class="fa fa-long-arrow-right"></i></span>
        <ul>
            <li><a href=""><span>Design</span><i class="fa fa-pencil"></i></a></li>
            <li><a href=""><span>Frontend development</span><i class="fa fa-desktop"></i></a></li>
            <li><a href=""><span>Application & Games</span><i class="fa fa-code"></i></a></li>
            <li><a href=""><span>Blog</span><i class="fa fa-user"></i></a></li>
        </ul>
    </nav> <!-- .site-navigation .main-navigation -->

Any idea what would be my mistake ? thanks in advance, feel free to ask if more details are needed!

6
  • Your code uses $menu_items but that variable is never set.
    – s_ha_dum
    May 28, 2015 at 20:21
  • it is true, thank you for you answer. How could I store each individual menu_item, in the menu_items variable ?
    – JetXS
    May 28, 2015 at 20:29
  • The existing menu items are in $item but honestly say m not clear on what you are trying to do.
    – s_ha_dum
    May 28, 2015 at 20:34
  • Sorry english is not my native language... I'll try to rewrite :) @s_ha_dum Short version: I'm trying to rewrite the way <li> will be outputted from the PHP in the HTML. Right now, it's the default way of Wordpress to output the navigation. There is a nav -> ul -> li -> a. I am trying with the filter to rework the li to have something like <li><a href="#' . $url . '"><span>' . $title . '</span><i class="fa ' . $list_ico_class . '"/></a></li> You can see this last line at the end of the filter :) Is that better explained ? ahah
    – JetXS
    May 28, 2015 at 20:42
  • No one will fault you for your command of the language, just do your best. Please edit that new information into the question though.
    – s_ha_dum
    May 28, 2015 at 20:45

1 Answer 1

1

Found the answer.

It might not be the best way to do it but it is working for now.

I was looking on using a filter when the solution seems to be using a custom walker.

class edited_menu_walker extends Walker_Nav_Menu {
    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;

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

        $output .= $indent . '<li id="menu-item-'. $item->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        ) .'"' : '';

        //Store the span in a variable
        $prepend = '<span>';

        //Check the title of the item, deduct the class name needed for FontAwesome
        if ($item->title == 'Design') {
            $theIcoName = 'fa-pencil';
        } else if ($item->title == 'Frontend') {
            $theIcoName = 'fa-desktop';
        } else if ($item->title == 'Applications') {
            $theIcoName = 'fa-code';
        } else if ($item->title == 'Blog') {
            $theIcoName = 'fa-user';
        } else {
            $theIcoName = 'fa-question';
        }

        //Create the FontAwesome ready <i> element
        $ico = '<i class="fa '.$theIcoName.'"></i>';

        //Close the span and add the calculated icon
        $append = '</span>'.$ico;

        if($depth != 0) {
            $ico = $append = $prepend = "";
        }

        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before .$prepend.apply_filters( 'the_title', $item->title, $item->ID ).$append; //add prepend to open the span storing the title, append to close this span and add the FontAwesome icon in an <i> element
        $item_output .= $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

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

You have to add this code in your function.php file.

The first half of the code is the "original wordpress walker". On the second half, where the code is a bit commented, I did some "cooking".

To store the text (item title) of the menu item, I create a variable '$prepend' opening the span element.

After that, I wrote some conditions that will determine, based on the title of the item, what should be the class of the '' element used to display the icon from FontAwesome.

If no title is found in the list, a question mark will be displayed by default with the class 'fa-question'. That's my "safety net" to notice that something went wront in my template and that I have to go modify my code for an eventual new icon/menu-item.

When, this deduction is made, we create the '$append' variable that will be closing the '' but also adding right after it the + next to fa, the correct class.

We finally construct the output at the end with '$item_output=' between ''.

I hope it is clear enough.. If someone got a better solution, feel free to share.

Your Answer

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

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