im trying to make non standart main navigation menu and stuck with submenu items, according to most tutorials and wordpress guides walker class works with simple menu types like:
<ul>
<li><a>Menu Item</a></li>
<li><a>Menu Item</a>
<ul>
<li><a>Submenu Item</a></li>
</ul>
</li>
</ul>
Which is not suitable for my menu structure:
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link">
<i class="nav-icons home_icon"></i>
<p>Home</p>
</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="nav-icons catalog_icon"></i>
<p>Catalog</p>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item">Catalog 1</a>
<a class="dropdown-item">Catalog 2</a>
</div>
</li>
</ul>
Im know that walker class forms menu with 4 functions (start_lvl, start_el, end_el, end_lvl) but is there any tutorial or any other info on how to make something simillar, or maybe someone could provide code sample to achieve result that im need? My menu will contain only 1 submenu level.
This for the Bootstrap nav menu walker class,
if (!class_exists('BootstrapBasicMyWalkerNavMenu')) {
class BootstrapBasicMyWalkerNavMenu extends Walker_Nav_Menu
{
//Overwrite display_element function to add has_children attribute. Not needed in >= Wordpress 3.4
/**
* #link https://gist.github.com/duanecilliers/1817371 copy from this url
*/
function display_element($element, &$children_elements, $max_depth, $depth = 0, $args, &$output)
{
if (!$element)
return;
$id_field = $this->db_fields['id'];
//display this element
if (is_array($args[0]))
$args[0]['has_children'] = !empty($children_elements[$element->$id_field]);
else if (is_object($args[0]))
$args[0]->has_children = !empty($children_elements[$element->$id_field]);
$cb_args = array_merge(array(&$output, $element, $depth), $args);
call_user_func_array(array(&$this, 'start_el'), $cb_args);
$id = $element->$id_field;
// descend only when the depth is right and there are childrens for this element
if (($max_depth == 0 || $max_depth > $depth + 1) && isset($children_elements[$id])) {
foreach ($children_elements[$id] as $child) {
if (!isset($newlevel)) {
$newlevel = true;
//start the child delimiter
$cb_args = array_merge(array(&$output, $depth), $args);
call_user_func_array(array(&$this, 'start_lvl'), $cb_args);
}
$this->display_element($child, $children_elements, $max_depth, $depth + 1, $args, $output);
}
unset($children_elements[$id]);
}
if (isset($newlevel) && $newlevel) {
//end the child delimiter
$cb_args = array_merge(array(&$output, $depth), $args);
call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
}
//end this element
$cb_args = array_merge(array(&$output, $element, $depth), $args);
call_user_func_array(array(&$this, 'end_el'), $cb_args);
}// display_element
/**
* #link https://gist.github.com/duanecilliers/1817371 copy from this url
*/
public function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0)
{
if ((is_object($item) && $item->title == null) || (!is_object($item))) {
return ;
}
$indent = ($depth) ? str_repeat("\t", $depth) : '';
$li_attributes = '';
$class_names = $value = '';
$classes = empty($item->classes) ? array() : (array) $item->classes;
//Add class and attribute to LI element that contains a submenu UL.
if (is_object($args) && $args->has_children) {
//$classes[] = 'dropdown';
$li_attributes .= ' data-dropdown="dropdown"';
}
$classes[] = 'menu-item-' . $item->ID;
//If we are on the current page, add the active class to that menu item.
$classes[] = ($item->current) ? 'active' : '';
//Make sure you still add all of the WordPress classes.
$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 . $li_attributes . '>';
//Add attributes to link element.
$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 .= (is_object($args) && $args->has_children) ? ' class="dropdown-toggle" data-toggle="dropdown"' : '';
$item_output = (is_object($args)) ? $args->before : '';
$item_output .= '<a' . $attributes . '>';
$item_output .= (is_object($args) ? $args->link_before : '') . apply_filters('the_title', $item->title, $item->ID) . (is_object($args) ? $args->link_after : '');
$item_output .= (is_object($args) && $args->has_children) ? ' <span class="caret"></span> ' : '';
$item_output .= '</a>';
$item_output .= (is_object($args) ? $args->after : '');
$output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
}// start_el
public function start_lvl(&$output, $depth = 0, $args = array())
{
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class=\"sub-menu dropdown-menu\">\n";
}
}
}
How to use this,
<?php wp_nav_menu(array('theme_location' => 'your-menu-location', 'container' => false, 'menu_class' => 'nav navbar-nav', 'walker' => new BootstrapBasicMyWalkerNavMenu())); ?>
Hope this will helps you.
For more information,
Understanding the Walker Class
WP Bootstrap Navwalker
Custom Nav Menu Walker Function
Related
I have this pretty basic custom walker for my nav. Is there any way to split the child menu items into columns, for example, if we have 6 child nav items in the first nav item, how can I put 3 in one column and 3 in another column?
I know I can do that with CSS, but I would extend it further to group items based on their count and that won't work with CSS.
class SC_Menu_Walker extends Walker_Nav_Menu {
function start_el(&$output, $item, $depth=0, $args=[], $id=0) {
global $wp_query;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$this->curItem = $item;
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
$class_names = ' class="'. esc_attr( $class_names ) . '"';
$output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
if ($item->url && $item->url != '#') {
$output .= '<a href="' . $item->url . '">';
} else {
$output .= '<span>';
}
$output .= $item->title;
}
function start_lvl(&$output, $depth = 0, $args = array()) {
$sc_page_item_label = get_post_meta( $this->curItem->object_id, '_sc_page_item_label', true );
$sc_page_item_description = get_post_meta( $this->curItem->object_id, '_sc_page_item_description', true );
$sc_page_item_url = get_post_meta( $this->curItem->object_id, '_sc_page_item_url', true );
$sc_page_item_page_url = get_page_link($sc_page_item_url);
$secondMenuClass="sub-menu__list o-sm-col-12 o-lg-col-7 u-font-size-medium";
$wrapperScrollStart="";
if ($depth == 1) {
$secondMenuClass="sub-menu__list sub-menu__list--scrollbar";
$wrapperScrollStart="<div class='sub-menu__inner'>";
$wrapperScrollEnd ='</div>';
}
$output .= '<div class="sub-menu sub">
<div class="o-custom-container">
<div class="sub-menu__wrapper_info o-sm-col-12 o-lg-col-5"><div class="o-lg-col-7"><h5>'.$sc_page_item_label.'</h5> <div class="u-font-size-medium">'.$sc_page_item_description.'</div></div>
<div>
<div class="c-learn-more-holder">
<div class="c-learn-more">
<div class="c-learn-more-title">Learn more</div>
</div>
</div>
</div>
</div>'.$wrapperScrollStart.'<ul class="'.$secondMenuClass.'">';
}
//end of the sub menu wrap
function end_lvl(&$output, $depth = 0, $args = array()) {
$wrapperScrollEnd = '';
if ($depth == 1) {
$wrapperScrollEnd ='</div>';
}
$wrapperScrollEnd ='</div>';
$output .= '</ul>'.$wrapperScrollEnd.'</div>';
}
}
I am using a custom walker for my menu which adds correct classes to parent ul/li/a elements. But, on every submenu LI and A tag i would like to remove all the styling but i cant figure out how to do it...
Any help would be greatly appreciated.
This is the code:
class CSS_Menu_Walker extends Walker {
var $db_fields = array('parent' => 'menu_item_parent', 'id' => 'db_id');
function start_lvl(&$output, $depth = 0, $args = array()) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class='sub-menu'>\n";
}
function end_lvl(&$output, $depth = 0, $args = array()) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}
function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
global $wp_query;
$indent = ($depth) ? str_repeat("\t", $depth) : '';
$class_names = $value = '';
$classes = empty($item->classes) ? array() : (array) $item->classes;
/* Add active class */
if (in_array('current-menu-item', $classes)) {
$classes[] = 'active';
unset($classes['current-menu-item']);
}
/* Check for children */
$children = get_posts(array('post_type' => 'nav_menu_item', 'nopaging' => true, 'numberposts' => 1, 'meta_key' => '_menu_item_menu_item_parent', 'meta_value' => $item->ID));
if (!empty($children)) {
$classes[] = 'nav-item-parent';
}
$class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item, $args));
$class_names = $class_names ? ' class="nav-item ' . esc_attr($class_names) . '"' : '';
$id = apply_filters('nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args);
$id = $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 ) .'"' : '';
$item_output = $args->before;
$item_output .= '<a'. $attributes .' class="nav-link">';
$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 end_el(&$output, $item, $depth = 0, $args = array()) {
$output .= "</li>\n";
}
}
This is how the code should be outputed:
<li class="nav-item"> <!-- This is done properly -->
<a href="#" class="nav-link "> <!-- This is done properly -->
Top Level Link
</a>
</li>
<li class="nav-item nav-item-parent"><!-- This is done properly -->
<a href="#" class="nav-link "> <!-- This is done properly -->
Top Level Link
</a>
<ul class="sub-menu">
<!-- LI and A get css classes from their parents (aka, nav-item and nav-link) and i dont need any classes on them -->
<li>Child Link</li>
<li>Child Link</li>
<li>Child Link</li>
</ul>
</li>
Using only CSS, you can target the element using its parent's class:
Example:
.nav-item ul li{
//Your css declarations
}
.nav-item ul li a{
//Your css declarations
}
Inspect the element and see what properties it gets from its parents.
For example if it gets padding of 15px from the parent, you can force to change the value:
.nav-item ul li a{
padding: 0 !important;
}
Hope it helps
I wanted to add number of posts for menu items that are categories.
For example:
Category 1 (5)
Category 2 (8)
Category 3 (2)
etc...
I edit walker:
get number:
$item_count = $depth == 0 ? get_posts( array(
'post_type' => 'post',
'numberposts' => -1,
'orderby' => 'category',
'order' => 'ASC'
) ) : false;
output:
$item_output .= $item_count ? ' <span>(' . count( $item_count ) . ')</span>' : '';
The result is a postscript to each menu item the number of all posts.
How to modify?
use wp_list_categories
<?php wp_list_categories(array('show_count' => true)); ?>
UPDATE for your instance:
with the full code from the link you provided in the comments we add an if statement right before the closing <a>
if($item->type == 'taxonomy'){
$cat = get_category( $item->object_id);
$item_output .= ' ('.$cat->count.')</a>';
}
FULL CODE:
/* Bootstrap_Walker for Wordpress
* Author: George Huger, Illuminati Karate, Inc
* More Info: http://illuminatikarate.com/blog/bootstrap-walker-for-wordpress
*
* Formats a Wordpress menu to be used as a Bootstrap dropdown menu (http://getbootstrap.com).
*
* Specifically, it makes these changes to the normal Wordpress menu output to support Bootstrap:
*
* - adds a 'dropdown' class to level-0 <li>'s which contain a dropdown
* - adds a 'dropdown-submenu' class to level-1 <li>'s which contain a dropdown
* - adds the 'dropdown-menu' class to level-1 and level-2 <ul>'s
*
* Supports menus up to 3 levels deep.
*
*/
class Bootstrap_Walker extends Walker_Nav_Menu
{
/* Start of the <ul>
*
* Note on $depth: Counterintuitively, $depth here means the "depth right before we start this menu".
* So basically add one to what you'd expect it to be
*/
function start_lvl(&$output, $depth)
{
$tabs = str_repeat("\t", $depth);
// If we are about to start the first submenu, we need to give it a dropdown-menu class
if ($depth == 0 || $depth == 1) { //really, level-1 or level-2, because $depth is misleading here (see note above)
$output .= "\n{$tabs}<ul class=\"dropdown-menu\">\n";
} else {
$output .= "\n{$tabs}<ul>\n";
}
return;
}
/* End of the <ul>
*
* Note on $depth: Counterintuitively, $depth here means the "depth right before we start this menu".
* So basically add one to what you'd expect it to be
*/
function end_lvl(&$output, $depth)
{
if ($depth == 0) { // This is actually the end of the level-1 submenu ($depth is misleading here too!)
// we don't have anything special for Bootstrap, so we'll just leave an HTML comment for now
$output .= '<!--.dropdown-->';
}
$tabs = str_repeat("\t", $depth);
$output .= "\n{$tabs}</ul>\n";
return;
}
/* Output the <li> and the containing <a>
* Note: $depth is "correct" at this level
*/
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;
/* If this item has a dropdown menu, add the 'dropdown' class for Bootstrap */
if ($item->hasChildren) {
$classes[] = 'dropdown';
// level-1 menus also need the 'dropdown-submenu' class
if($depth == 1) {
$classes[] = 'dropdown-submenu';
}
}
/* This is the stock Wordpress code that builds the <li> with all of its attributes */
$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 ) .'"' : '';
$item_output = $args->before;
/* If this item has a dropdown menu, make clicking on this link toggle it */
if ($item->hasChildren && $depth == 0) {
$item_output .= '<a'. $attributes .' class="dropdown-toggle" data-toggle="dropdown">';
} else {
$item_output .= '<a'. $attributes .'>';
}
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
/* Output the actual caret for the user to click on to toggle the menu */
if ($item->hasChildren && $depth == 0) {
$item_output .= '<b class="caret"></b></a>';
}elseif($item->type == 'taxonomy'){
$cat = get_category( $item->object_id);
$item_output .= ' ('.$cat->count.')</a>';
} else {
$item_output .= '</a>';
}
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
return;
}
/* Close the <li>
* Note: the <a> is already closed
* Note 2: $depth is "correct" at this level
*/
function end_el (&$output, $item, $depth, $args)
{
$output .= '</li>';
return;
}
/* Add a 'hasChildren' property to the item
* Code from: http://wordpress.org/support/topic/how-do-i-know-if-a-menu-item-has-children-or-is-a-leaf#post-3139633
*/
function display_element ($element, &$children_elements, $max_depth, $depth = 0, $args, &$output)
{
// check whether this item has children, and set $item->hasChildren accordingly
$element->hasChildren = isset($children_elements[$element->ID]) && !empty($children_elements[$element->ID]);
// continue with normal behavior
return parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
}
}
If you are using some custom post taxonomie you can change the code for this one :
if ($item->type == 'taxonomy'){
$term = get_term($item->object_id);
$item_output .= '<div class="meni-item-badge"> '.$term->count .'</div>';
}
Hope this help someone !!
Regards Mario
I've entered the description into the parent menu items in Wordpress, but they're not showing on my theme.
I know that a walker class can be used to make changes to the menu, but I don't know how to code it.
Here is what I want to achieve:
<nav id="main-menu" role="navigation">
<div class="menu-main-menu-container">
<ul id="menu-main-menu" class="menu">
<!-- REPEATING MENU ITEM START -->
<li class="menu-parent-item"><a>Face</a>
<ul class="sub-menu">
<li class="menu-image-container">
<div class="menu-image"></div>
<div class="menu-description">[Face menu item description]</div>
</li>
<li class="heading">Face</li>
<ul class="sub-menu">
<li class="menu-item">Sub menu 1</li>
<li class="menu-item">Sub menu 2</li>
<li class="menu-item">Sub menu 3</li>
</ul>
<li class="heading">Ear</li>
<ul class="sub-menu">
<li class="menu-item">Sub menu 1</li>
<li class="menu-item">Sub menu 2</li>
<li class="menu-item">Sub menu 3</li>
</ul>
<li class="heading">Eyes</li>
<ul class="sub-menu">
<li class="menu-item">Sub menu 1</li>
<li class="menu-item">Sub menu 2</li>
<li class="menu-item">Sub menu 3</li>
</ul>
</ul>
</li>
<!-- REPEATING MENU ITEM END -->
</ul>
</div>
As you can see, I only want the description of the parent menu item to be shown, but it needs to be within the first ul.sub-menu within the parent list item.
How could I code a walker that uses start_lvl, start_el and end_lvl to handle this efficiently?
ok i'm not sure if this is fool proof but here's my try:
so you would need to make sure description is on in the admin menu console (in the 'screen options' dropdown)
Your first menu item should be Face then Face again as its child then sub neu items as children to that.
Hope this helps!
in your functions.php
class Description_Walker extends Walker_Nav_Menu
{
/**
* Start the element output.
*
* #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. May be used for padding.
* #param array $args Additional strings.
* #return void
*/
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 );
}
function start_lvl( &$output, $depth=0, $args=array() ) {
// depth dependent classes
$indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent
$display_depth = ( $depth); // because it counts the first submenu as 0
$classes = array('sub-menu');
$class_names = implode( ' ', $classes );
// build html
$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
}
function start_el(&$output, $item, $depth = 0, $args = array(), $current_object_id = 0)
{
$classes = empty ( $item->classes ) ? array () : (array) $item->classes;
$class_names = join(
' '
, apply_filters(
'nav_menu_css_class'
, array_filter( $classes ), $item
)
);
if ($args->has_children && $depth == 0){
! empty ( $class_names )
and $class_names = ' class="menu-parent-item"';
}else if($depth == 1){
! empty ( $class_names )
and $class_names = ' class="heading"';
}else{
! empty ( $class_names )
and $class_names = ' class="'. esc_attr( $class_names ) .'"';
}
$output .= "<li id='menu-item-$item->ID' $class_names>" ;
$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 ) .'"';
// insert description for top level elements only
// you may change this
$description = ( ! empty ( $item->description ) and 0 == $depth )
? '<div class="menu-description">' . esc_attr( $item->description ) . '</div>' : '';
$title = apply_filters( 'the_title', $item->title, $item->ID );
if ( $depth == 0) {//top level items
$item_output = $args->before.$title.'</li><ul class="sub-menu"><li class="menu-image-container"><div class="menu-image"></div>'.$description.'</li>';
}
else if( $depth == 1){
$item_output = $args->before.$title.'</li>';
}
else{//everything else
$item_output = $args->before
. "<a $attributes>"
. $args->link_before
. $title
. '</a> '
. $args->link_after
. $args->after;
}
// Since $output is called by reference we don't need to return anything.
$output .= apply_filters(
'walker_nav_menu_start_el'
, $item_output
, $item
, $depth
, $args
);
}
}
in your header (or wherever your menu is)
<nav id="main-menu" role="navigation"><?php wp_nav_menu( array('menu' => 'Main', 'container' => 'div', 'container_class' => 'menu-main-menu-container', 'menu_id' => 'menu-main-menu', 'walker' => new Description_Walker )); ?></nav>
I managed to get the menu to display as before, whilst adding the parent menu description exactly where I wanted by simply just adding to what I already had.
I already had a walker that created the sub-menu image container, and the description container
// Submenu walker to add image
class submenu_walker extends Walker_Nav_Menu {
function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class='sub-menu'><li class='menu-image-container'><div class='menu-image'></div><div class='menu-description'></div></li>\n";
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent<li><div class='clear'></div></li></ul>\n";
}
}
Then I managed to find a function that uses start_el and could assign the description to a variable, but not output it, then just output the $item_output as normal.
function add_menu_description( $item_output, $item, $depth, $args ) {
$description = __( $item->post_content );
return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'add_menu_description', 10, 4);
Of course now I needed to use $description within my other submenu walker function, so I just created a global variable in both, and the output is exactly what I'm after!
FINAL OUTPUT
function add_menu_description( $item_output, $item, $depth, $args ) {
global $description;
$description = __( $item->post_content );
return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'add_menu_description', 10, 4);
// Submenu walker to add image
class submenu_walker extends Walker_Nav_Menu {
function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
global $description;
$output .= "\n$indent<ul class='sub-menu'><li class='menu-image-container'><div class='menu-image'></div><div class='menu-description'>".$description."</div></li>\n";
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent<li><div class='clear'></div></li></ul>\n";
}
}
How can I do this:
I want to create menu using wp_nav_menu() and to customize it's output html a little. I want to put < i > in link < a > inside every < li > item of the menu.
I know that I can acomplish this using background-image of < li > items in css, but my goal is to use font icons inside navigation.
I also know that in order to acomplish this we can use walker function inside wp_nav_menu()or use wp_get_nav_menu_object() function, but I simply can't make it right to work.
Have you tried the before or the link_before options?
before will output before the <a> and link_before will output inside the <a> before the text.
http://codex.wordpress.org/Function_Reference/wp_nav_menu
$settings = array(
'before' => '<i class="icon"></i>',
'link_before' => '<i class="icon"></i>'
);
wp_nav_menu( $settings );
Use wp walker function and insert wp menu description there. Explaining more below -
Just put this code in your theme's functions.php file:
class fluent_themes_custom_walker_nav_menu extends Walker_Nav_Menu {
private $blog_sidebar_pos = "";
// add classes to ul sub-menus
function start_lvl( &$output, $depth = 0, $args = Array() ) {
// 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(
'dropdown-menu',
( $display_depth % 2 ? 'menu-odd' : 'menu-even' ),
( $display_depth >=2 ? '' : '' ),
'menu-depth-' . $display_depth
);
$class_names = implode( ' ', $classes );
// build html
$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
}
// add main/sub classes to li's and links
function start_el( &$output, $item, $depth = 0, $args = Array(), $id = 0 ) {
global $wp_query, $wpdb;
$indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent
// depth dependent classes
$depth_classes = array(
( $depth == 0 ? '' : '' ), //class for the top level menu which got sub-menu
( $depth >=1 ? '' : 'dropdown' ), //class for the level-1 sub-menu which got level-2 sub-menu
( $depth >=2 ? 'sub-sub-menu-item' : '' ), //class for the level-2 sub-menu which got level-3 sub-menu
( $depth % 2 ? 'menu-item-odd' : 'menu-item-even' ),
'menu-item-depth-' . $depth
);
$depth_class_names = esc_attr( implode( ' ', $depth_classes ) );
// passed classes
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );
// build html
$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="' . ( $depth > 0 ? '' : '' ) . '"';
// Check if menu item is in main menu
$has_children = $wpdb->get_var("SELECT COUNT(meta_id)
FROM wp_postmeta
WHERE meta_key='_menu_item_menu_item_parent'
AND meta_value='".$item->ID."'");
if ( $depth == 0 && $has_children > 0 ) {
// These lines adds your custom class and attribute
$attributes .= ' class="dropdown-toggle"';
$attributes .= ' data-toggle="dropdown"';
$attributes .= ' data-hover="dropdown"';
$attributes .= ' data-animations="fadeInUp"';
}
$description = ! empty( $item->description ) ? '<i class="fa '.esc_attr( $item->description ).'" aria-hidden="true"></i>' : '';
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $description.$args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after; //If you want the description to be output after <a>
//$item_output .= $description.$args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after; //If you want the description to be output before </a>
// Add the caret if menu level is 0
if ( $depth == 0 && $has_children > 0 ) {
$item_output .= ' <i class="fa fa-caret-down"></i>';
}
$item_output .= '</a>';
$item_output .= $args->after;
// build html
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args, $id );
}
} //End Walker_Nav_Menu
See this line:
$description = ! empty( $item->description ) ? '<i class="fa '.esc_attr( $item->description ).'" aria-hidden="true"></i>' : '';
And this line:
$item_output .= $description.$args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
Here you see $item->desctiption is a variable. For example: if you put fa-user as menu item description of a menu. The html output of the above line will be:
The full html output of the menu will be something like this:
<ul class="top-nav nav-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-hover="dropdown" data-toggle="dropdown" data-animations="fadeInUp">
<i class="fa fa-user" aria-hidden="true"></i>My Profile
<i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu ">
<li><i class="icon-bargraph"></i> Dashboard</li>
<li><i class="icon-gears"></i> Profile Setting</li>
<li><i class="icon-heart"></i> Questions</li>
<li><i class="icon-lock"></i> Logout</li>
</ul>
</li>
</ul>
However, here is your wp nav menu code in your header.php file or in any other theme files:
wp_nav_menu( array('theme_location' => 'top_bar_login','container' => false,'container_id' => '','conatiner_class' => '','menu_class' => 'top-nav nav-right','echo' => true,'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>','depth' => 10, 'walker' => new fluent_themes_custom_walker_nav_menu) );
If you are not sure where is the description of wordpress menu, or you want more details with screenshot. You can read this article Adding Different Icons To Different Items Of WP Nav Menu
I'am also trying to add icons in my menu.
I've tried before and link_before options but I did't find the way to get any item's variables inside these args.
My aim is to get the following output using Title Attribute set in Custom Link from Customize Menus
<li id="menu-item-30" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-30">
<a title="social-facebook" href="http://facebook.com">
<i class="fi-social-facebook"></i>Facebook Page
</a>
</li>
<li id="menu-item-30" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-30">
<a title="social-google-plus+" href="http://plus.google.com">
<i class="fi-social-google-plus"></i>Google+ Page
</a>
</li>
I've also check the other answer but I don't know how to add thumbnails in the Custom Link of the Customize Menus.
paste code to the page where you output your nav
<?php
wp_nav_menu(
array(
'theme_location' => 'primary',
'container' => false,
'walker' => new my_nav_walker()
)
);
?>
and then call walker.php in functions.php
require get_template_directory().'/inc/walker.php';
copy class Walker_Nav_Menu in class-walker-nav-menu.php from wp-includes folder
change Walker_Nav_Menu class to my_nav_walker
and then inside function start_el of my_nav_walker class
make a variable called $description as:
$description = ! empty( $item->description ) ? '<i class="fa '.esc_attr( $item->description ).'" ></i>' : '';
Paste this code inside start_el function of my_nav_walker class
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $description.$args->link_before . $title . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
if you add fa-user in description of menu item from backend user icon appear between a href tag inside li