Skip to content

Instantly share code, notes, and snippets.

@Dreamelf
Last active September 3, 2023 12:45
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save Dreamelf/d63b2a6a05236e66f31ee46e7f4d4482 to your computer and use it in GitHub Desktop.
Save Dreamelf/d63b2a6a05236e66f31ee46e7f4d4482 to your computer and use it in GitHub Desktop.
UIkit 3.0 wordpress menu
/**
* Offcanvas menu
*/
function your_themename_offcanvas_menu() { ?>
<div id="offcanvas-menu" uk-offcanvas="flip: true">
<div class="uk-offcanvas-bar">
<button class="uk-offcanvas-close" type="button" uk-close></button>
<?php if ( has_nav_menu( 'menu-1' ) ) : ?>
<h3><?php _e('Menu', 'your_themename'); ?></h3>
<?php
wp_nav_menu( array(
'menu' => 'menu-1',
'theme_location' => 'menu-1',
'depth' => 2,
'container' => 'ul',
'items_wrap' => '<ul id="%1$s" class="%2$s" uk-nav>%3$s</ul>',
'menu_class' => 'uk-nav uk-nav-default uk-nav-parent-icon',
'fallback_cb' => 'your_themename_top_menu::fallback',
'walker' => new your_themename_offcanvas_menu()
)); ?>
<?php endif; ?>
</div>
</div>
<?php }
add_action( 'your_themename_offcanvas_menu', 'your_themename_offcanvas_menu' );
/**
* Top menu
*/
function your_themename_top_menu() { ?>
<nav class="uk-navbar-container <?php echo $transparent; ?>" uk-navbar="mode: click; dropbar: true; dropbar-mode: push">
<div class="uk-navbar-left">
<a class="uk-navbar-item logo" href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home" title="<?php bloginfo( 'name' ); ?>">
<?php echo '<img src="'. esc_url(get_template_directory_uri()) .'/assets/img/logo.svg" alt="" width="25" height="25" />'; ?>
<span><?php //bloginfo( 'name' ); ?></span></a>
</div>
<div class="uk-navbar-center">
<?php wp_nav_menu( array(
'menu' => 'menu-1',
'theme_location' => 'menu-1',
'depth' => 1,
'container' => '',
'menu_class' => 'uk-navbar-nav uk-visible@s',
'fallback_cb' => 'your_themename_top_menu::fallback',
'walker' => new your_themename_top_menu())
); ?>
</div>
<div class="uk-navbar-right">
<a class="uk-navbar-toggle" href="#offcanvas-menu" uk-toggle>
<span uk-navbar-toggle-icon></span>
</a>
</div>
</nav>
<?php }
add_action( 'your_themename_top_menu', 'your_themename_top_menu');
<?php
/**
* Class Name: your_themename_top_menu
* Description: A custom WordPress nav walker class to implement UIkit menu markup
*/
class your_themename_top_menu extends Walker_Nav_Menu {
/**
* @see Walker::start_lvl()
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for padding.
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent<div class=\"uk-navbar-dropdown\">\n<ul role=\"menu\" class=\"uk-nav uk-navbar-dropdown-nav\">\n";
}
/**
* Ends the list of after the elements are added.
*
* @see Walker_Nav_Menu::end_lvl()
*
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for padding.
* @param array $args Not used.
*/
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent</ul></div>";
}
/**
* @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
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$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 ) );
if ( $args->has_children )
$class_names .= ' uk-parent';
$dropdown = ''; /*
if ( $args->has_children && $depth == 0)
$dropdown .= ' data-uk-dropdown="{mode:\'click\'}"';*/
if ( in_array( 'current-menu-item', $classes ) || in_array('current-menu-parent', $classes))
$class_names .= ' uk-active';
$class_names = $class_names ? ' class="' . 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 . $dropdown . '>';
$atts = array();
$atts['title'] = ! empty( $item->title ) ? $item->title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
// If item has_children add atts to a.
if ( $args->has_children && $depth === 0 ) {
$atts['href'] = '#';
// $atts['data-toggle'] = 'dropdown';
// $atts['class'] = 'dropdown-toggle';
// $atts['aria-haspopup'] = 'true';
} else {
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
}
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$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 .= ( $args->has_children && 0 === $depth ) ? '</a>' : '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
/**
* Traverse elements to create list from elements.
*
* Display one element if the element doesn't have any children otherwise,
* display the element and its children. Will only traverse up to the max
* depth and no ignore elements under that depth.
*
* This method shouldn't be called directly, use the walk() method instead.
*
* @see Walker::start_el()
* @since 2.5.0
*
* @param object $element Data object
* @param array $children_elements List of elements to continue traversing.
* @param int $max_depth Max depth to traverse.
* @param int $depth Depth of current element.
* @param array $args
* @param string $output Passed by reference. Used to append additional content.
* @return null Null on failure with no changes to parameters.
*/
public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
if ( ! $element )
return;
$id_field = $this->db_fields['id'];
// Display this element.
if ( is_object( $args[0] ) )
$args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] );
parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
/**
* Menu Fallback
* =============
* If this function is assigned to the wp_nav_menu's fallback_cb variable
* and a manu has not been assigned to the theme location in the WordPress
* menu manager the function with display nothing to a non-logged in user,
* and will add a link to the WordPress menu manager if logged in as an admin.
*
* @param array $args passed from the wp_nav_menu function.
*
*/
public static function fallback( $args ) {
if ( current_user_can( 'manage_options' ) ) {
extract( $args );
$fb_output = null;
if ( $container ) {
$fb_output = '<' . $container;
if ( $container_id )
$fb_output .= ' id="' . $container_id . '"';
if ( $container_class )
$fb_output .= ' class="' . $container_class . '"';
$fb_output .= '>';
}
$fb_output .= '<ul';
if ( $menu_id )
$fb_output .= ' id="' . $menu_id . '"';
if ( $menu_class )
$fb_output .= ' class="' . $menu_class . '"';
$fb_output .= '>';
$fb_output .= '<li><a href="' . admin_url( 'nav-menus.php' ) . '">'. __('Add a menu', 'your themename') .'</a></li>';
$fb_output .= '</ul>';
if ( $container )
$fb_output .= '</' . $container . '>';
echo $fb_output;
}
}
}
/**
* Class Name: your_themename_primary_menu
* Description: A custom WordPress nav walker class to implement UIkit menu markup
*/
class your_themename_primary_menu extends Walker_Nav_Menu {
/**
* @see Walker::start_lvl()
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for padding.
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent<div class=\"uk-navbar-dropdown\">\n<ul role=\"menu\" class=\"uk-nav uk-navbar-dropdown-nav\">\n";
}
/**
* Ends the list of after the elements are added.
*
* @see Walker_Nav_Menu::end_lvl()
*
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for padding.
* @param array $args Not used.
*/
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent</ul></div>";
}
/**
* @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
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$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 ) );
if ( $args->has_children )
$class_names .= ' uk-parent';
$dropdown = ''; /*
if ( $args->has_children && $depth == 0)
$dropdown .= ' data-uk-dropdown="{mode:\'click\'}"';*/
if ( in_array( 'current-menu-item', $classes ) || in_array('current-menu-parent', $classes))
$class_names .= ' uk-active';
$class_names = $class_names ? ' class="' . 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 . $dropdown . '>';
$atts = array();
$atts['title'] = ! empty( $item->title ) ? $item->title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
// If item has_children add atts to a.
if ( $args->has_children && $depth === 0 ) {
$atts['href'] = '#';
// $atts['data-toggle'] = 'dropdown';
// $atts['class'] = 'dropdown-toggle';
// $atts['aria-haspopup'] = 'true';
} else {
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
}
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$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 .= ( $args->has_children && 0 === $depth ) ? '</a>' : '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
/**
* Traverse elements to create list from elements.
*
* Display one element if the element doesn't have any children otherwise,
* display the element and its children. Will only traverse up to the max
* depth and no ignore elements under that depth.
*
* This method shouldn't be called directly, use the walk() method instead.
*
* @see Walker::start_el()
* @since 2.5.0
*
* @param object $element Data object
* @param array $children_elements List of elements to continue traversing.
* @param int $max_depth Max depth to traverse.
* @param int $depth Depth of current element.
* @param array $args
* @param string $output Passed by reference. Used to append additional content.
* @return null Null on failure with no changes to parameters.
*/
public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
if ( ! $element )
return;
$id_field = $this->db_fields['id'];
// Display this element.
if ( is_object( $args[0] ) )
$args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] );
parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
/**
* Menu Fallback
* =============
* If this function is assigned to the wp_nav_menu's fallback_cb variable
* and a manu has not been assigned to the theme location in the WordPress
* menu manager the function with display nothing to a non-logged in user,
* and will add a link to the WordPress menu manager if logged in as an admin.
*
* @param array $args passed from the wp_nav_menu function.
*
*/
public static function fallback( $args ) {
if ( current_user_can( 'manage_options' ) ) {
extract( $args );
$fb_output = null;
if ( $container ) {
$fb_output = '<' . $container;
if ( $container_id )
$fb_output .= ' id="' . $container_id . '"';
if ( $container_class )
$fb_output .= ' class="' . $container_class . '"';
$fb_output .= '>';
}
$fb_output .= '<ul';
if ( $menu_id )
$fb_output .= ' id="' . $menu_id . '"';
if ( $menu_class )
$fb_output .= ' class="' . $menu_class . '"';
$fb_output .= '>';
$fb_output .= '<li><a href="' . admin_url( 'nav-menus.php' ) . '">'. __('Add a menu', 'your themename') .'</a></li>';
$fb_output .= '</ul>';
if ( $container )
$fb_output .= '</' . $container . '>';
echo $fb_output;
}
}
}
/**
* Class Name: your_themename_offcanvas_output
* Description: A custom WordPress nav walker class to implement UIkit menu markup
*/
class your_themename_offcanvas_menu extends Walker_Nav_Menu {
/**
* @see Walker::start_lvl()
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for padding.
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent<ul role=\"menu\" class=\"uk-nav-parent-icon uk-nav-sub\">\n";
}
/**
* @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
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$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 ) );
if ( $args->has_children )
$class_names .= ' uk-parent';
if ( in_array( 'current-menu-item', $classes ) || in_array('current-menu-parent', $classes))
$class_names .= ' uk-active';
$class_names = $class_names ? ' class="' . 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 . '>';
$atts = array();
$atts['title'] = ! empty( $item->title ) ? $item->title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
// If item has_children add atts to a.
if ( $args->has_children && $depth === 0 ) {
$atts['href'] = '#';
// $atts['data-toggle'] = 'dropdown';
// $atts['class'] = 'dropdown-toggle';
// $atts['aria-haspopup'] = 'true';
} else {
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
}
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$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 );
}
/**
* Traverse elements to create list from elements.
*
* Display one element if the element doesn't have any children otherwise,
* display the element and its children. Will only traverse up to the max
* depth and no ignore elements under that depth.
*
* This method shouldn't be called directly, use the walk() method instead.
*
* @see Walker::start_el()
* @since 2.5.0
*
* @param object $element Data object
* @param array $children_elements List of elements to continue traversing.
* @param int $max_depth Max depth to traverse.
* @param int $depth Depth of current element.
* @param array $args
* @param string $output Passed by reference. Used to append additional content.
* @return null Null on failure with no changes to parameters.
*/
public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
if ( ! $element )
return;
$id_field = $this->db_fields['id'];
// Display this element.
if ( is_object( $args[0] ) )
$args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] );
parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
/**
* Menu Fallback
* =============
* If this function is assigned to the wp_nav_menu's fallback_cb variable
* and a manu has not been assigned to the theme location in the WordPress
* menu manager the function with display nothing to a non-logged in user,
* and will add a link to the WordPress menu manager if logged in as an admin.
*
* @param array $args passed from the wp_nav_menu function.
*
*/
public static function fallback( $args ) {
if ( current_user_can( 'manage_options' ) ) {
extract( $args );
$fb_output = null;
if ( $container ) {
$fb_output = '<' . $container;
if ( $container_id )
$fb_output .= ' id="' . $container_id . '"';
if ( $container_class )
$fb_output .= ' class="' . $container_class . '"';
$fb_output .= '>';
}
$fb_output .= '<ul';
if ( $menu_id )
$fb_output .= ' id="' . $menu_id . '"';
if ( $menu_class )
$fb_output .= ' class="' . $menu_class . '"';
$fb_output .= '>';
$fb_output .= '<li><a href="' . admin_url( 'nav-menus.php' ) . '">'. __('Add a menu', 'your themename') .'</a></li>';
$fb_output .= '</ul>';
if ( $container )
$fb_output .= '</' . $container . '>';
echo $fb_output;
}
}
}
@FlinkQc
Copy link

FlinkQc commented Apr 12, 2019

A big thank you ! Amazing work :)

@IsraSenior
Copy link

Thanks you so much, nice work!

@Dreamelf
Copy link
Author

Dreamelf commented Aug 1, 2019

THX! Your welcom! :)

@tasz
Copy link

tasz commented Sep 10, 2019

Thank you very much!

@carlovarchetta
Copy link

Hi! Is there a Readme file with the instructions?

For now I included the functions in functions.php, I put the php file in a assets folder.

With bs4navwalker I had to use only this command in functions.php : require_once('assets/bs4navwalker.php');
Later I put the dynamic menu in header.php.

How can I do to include your uikitwalker?
Thanks
Carlo

@tasz
Copy link

tasz commented Oct 16, 2019

<?php
	/**
		* Class Name: your_themename_top_menu
		* Description: A custom WordPress nav walker class to implement UIkit menu markup
	*/
	class uikit_top_w_menu extends Walker_Nav_Menu {
		
		/**
			* @see Walker::start_lvl()
			* @since 3.0.0
			*
			* @param string $output Passed by reference. Used to append additional content.
			* @param int $depth Depth of page. Used for padding.
		*/
		public function start_lvl( &$output, $depth = 0, $args = array() ) {
			$indent = str_repeat( "\t", $depth );
			$output .= "\n$indent<div class=\"uk-navbar-dropdown\">\n<ul role=\"menu\" class=\"uk-nav uk-navbar-dropdown-nav\">\n";
		}
		
		/**
			* Ends the list of after the elements are added.
			*
			* @see Walker_Nav_Menu::end_lvl()
			*
			* @since 3.0.0
			*
			* @param string $output Passed by reference. Used to append additional content.
			* @param int    $depth  Depth of page. Used for padding.
			* @param array  $args   Not used.
		*/
		public function end_lvl( &$output, $depth = 0, $args = array() ) {
			$indent = str_repeat( "\t", $depth );
			$output .= "\n$indent</ul></div>";
		}
		
		/**
			* @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
		*/
		public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
			$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 ) );
			
			if ( $args->has_children )
			$class_names .= ' uk-parent';
			
			$dropdown = ''; /*
				if ( $args->has_children && $depth == 0)
			$dropdown .= ' data-uk-dropdown="{mode:\'click\'}"';*/
			
			if ( in_array( 'current-menu-item', $classes ) || in_array('current-menu-parent', $classes))
			$class_names .= ' uk-active';
			
			$class_names = $class_names ? ' class="' . 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 . $dropdown . '>';
			
			$atts = array();
			$atts['title']  = ! empty( $item->title )	? $item->title	: '';
			$atts['target'] = ! empty( $item->target )	? $item->target	: '';
			$atts['rel']    = ! empty( $item->xfn )		? $item->xfn	: '';
			
			// If item has_children add atts to a.
			//if ( $args->has_children && $depth === 0 ) {
				//$atts['href']          = '#';
				// $atts['data-toggle']   = 'dropdown';
				// $atts['class']         = 'dropdown-toggle';
				// $atts['aria-haspopup'] = 'true';
				//} else {
				$atts['href'] = ! empty( $item->url ) ? $item->url : '';
			//}
			
			$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );
			
			$attributes = '';
			foreach ( $atts as $attr => $value ) {
				if ( ! empty( $value ) ) {
					$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
					$attributes .= ' ' . $attr . '="' . $value . '"';
				}
			}
			
			$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 .= ( $args->has_children && 0 === $depth ) ? '</a>' : '</a>';
			$item_output .= $args->after;
			
			$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
		}
		
		/**
			* Traverse elements to create list from elements.
			*
			* Display one element if the element doesn't have any children otherwise,
			* display the element and its children. Will only traverse up to the max
			* depth and no ignore elements under that depth.
			*
			* This method shouldn't be called directly, use the walk() method instead.
			*
			* @see Walker::start_el()
			* @since 2.5.0
			*
			* @param object $element Data object
			* @param array $children_elements List of elements to continue traversing.
			* @param int $max_depth Max depth to traverse.
			* @param int $depth Depth of current element.
			* @param array $args
			* @param string $output Passed by reference. Used to append additional content.
			* @return null Null on failure with no changes to parameters.
		*/
		public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
			if ( ! $element )
            return;
			
			$id_field = $this->db_fields['id'];
			
			// Display this element.
			if ( is_object( $args[0] ) )
			$args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] );
			
			parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
		}
		
		/**
			* Menu Fallback
			* =============
			* If this function is assigned to the wp_nav_menu's fallback_cb variable
			* and a manu has not been assigned to the theme location in the WordPress
			* menu manager the function with display nothing to a non-logged in user,
			* and will add a link to the WordPress menu manager if logged in as an admin.
			*
			* @param array $args passed from the wp_nav_menu function.
			*
		*/
		public static function fallback( $args ) {
			if ( current_user_can( 'manage_options' ) ) {
				
				extract( $args );
				
				$fb_output = null;
				
				if ( $container ) {
					$fb_output = '<' . $container;
					
					if ( $container_id )
					$fb_output .= ' id="' . $container_id . '"';
					
					if ( $container_class )
					$fb_output .= ' class="' . $container_class . '"';
					
					$fb_output .= '>';
				}
				
				$fb_output .= '<ul';
				
				if ( $menu_id )
				$fb_output .= ' id="' . $menu_id . '"';
				
				if ( $menu_class )
				$fb_output .= ' class="' . $menu_class . '"';
				
				$fb_output .= '>';
				$fb_output .= '<li><a href="' . admin_url( 'nav-menus.php' ) . '">'. __('Add a menu', 'your themename') .'</a></li>';
				$fb_output .= '</ul>';
				
				if ( $container )
				$fb_output .= '</' . $container . '>';
				
				echo $fb_output;
			}
		}
	}
	
	/**
		* Class Name: uikit_primary_menu
		* Description: A custom WordPress nav walker class to implement UIkit menu markup
	*/
	class uikit_primary_menu extends Walker_Nav_Menu {
		
		/**
			* @see Walker::start_lvl()
			* @since 3.0.0
			*
			* @param string $output Passed by reference. Used to append additional content.
			* @param int $depth Depth of page. Used for padding.
		*/
		public function start_lvl( &$output, $depth = 0, $args = array() ) {
			$indent = str_repeat( "\t", $depth );
			$output .= "\n$indent<div class=\"uk-navbar-dropdown\">\n<ul role=\"menu\" class=\"uk-nav uk-navbar-dropdown-nav\">\n";
		}
		
		/**
			* Ends the list of after the elements are added.
			*
			* @see Walker_Nav_Menu::end_lvl()
			*
			* @since 3.0.0
			*
			* @param string $output Passed by reference. Used to append additional content.
			* @param int    $depth  Depth of page. Used for padding.
			* @param array  $args   Not used.
		*/
		public function end_lvl( &$output, $depth = 0, $args = array() ) {
			$indent = str_repeat( "\t", $depth );
			$output .= "\n$indent</ul></div>";
		}
		
		/**
			* @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
		*/
		public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
			$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 ) );
			
			if ( $args->has_children )
			$class_names .= ' uk-parent';
			
			$dropdown = ''; /*
				if ( $args->has_children && $depth == 0)
			$dropdown .= ' data-uk-dropdown="{mode:\'click\'}"';*/
			
			if ( in_array( 'current-menu-item', $classes ) || in_array('current-menu-parent', $classes))
			$class_names .= ' uk-active';
			
			$class_names = $class_names ? ' class="' . 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 . $dropdown . '>';
			
			$atts = array();
			$atts['title']  = ! empty( $item->title )	? $item->title	: '';
			$atts['target'] = ! empty( $item->target )	? $item->target	: '';
			$atts['rel']    = ! empty( $item->xfn )		? $item->xfn	: '';
			
			// If item has_children add atts to a.
			// if ( $args->has_children && $depth === 0 ) {
				// $atts['href']          = '#';
				// // $atts['data-toggle']   = 'dropdown';
				// // $atts['class']         = 'dropdown-toggle';
				// // $atts['aria-haspopup'] = 'true';
				// } else {
				$atts['href'] = ! empty( $item->url ) ? $item->url : '';
			//}
			
			$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );
			
			$attributes = '';
			foreach ( $atts as $attr => $value ) {
				if ( ! empty( $value ) ) {
					$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
					$attributes .= ' ' . $attr . '="' . $value . '"';
				}
			}
			
			$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 .= ( $args->has_children && 0 === $depth ) ? '</a>' : '</a>';
			$item_output .= $args->after;
			
			$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
		}
		
		/**
			* Traverse elements to create list from elements.
			*
			* Display one element if the element doesn't have any children otherwise,
			* display the element and its children. Will only traverse up to the max
			* depth and no ignore elements under that depth.
			*
			* This method shouldn't be called directly, use the walk() method instead.
			*
			* @see Walker::start_el()
			* @since 2.5.0
			*
			* @param object $element Data object
			* @param array $children_elements List of elements to continue traversing.
			* @param int $max_depth Max depth to traverse.
			* @param int $depth Depth of current element.
			* @param array $args
			* @param string $output Passed by reference. Used to append additional content.
			* @return null Null on failure with no changes to parameters.
		*/
		public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
			if ( ! $element )
            return;
			
			$id_field = $this->db_fields['id'];
			
			// Display this element.
			if ( is_object( $args[0] ) )
			$args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] );
			
			parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
		}
		
		/**
			* Menu Fallback
			* =============
			* If this function is assigned to the wp_nav_menu's fallback_cb variable
			* and a manu has not been assigned to the theme location in the WordPress
			* menu manager the function with display nothing to a non-logged in user,
			* and will add a link to the WordPress menu manager if logged in as an admin.
			*
			* @param array $args passed from the wp_nav_menu function.
			*
		*/
		public static function fallback( $args ) {
			if ( current_user_can( 'manage_options' ) ) {
				
				extract( $args );
				
				$fb_output = null;
				
				if ( $container ) {
					$fb_output = '<' . $container;
					
					if ( $container_id )
					$fb_output .= ' id="' . $container_id . '"';
					
					if ( $container_class )
					$fb_output .= ' class="' . $container_class . '"';
					
					$fb_output .= '>';
				}
				
				$fb_output .= '<ul';
				
				if ( $menu_id )
				$fb_output .= ' id="' . $menu_id . '"';
				
				if ( $menu_class )
				$fb_output .= ' class="' . $menu_class . '"';
				
				$fb_output .= '>';
				$fb_output .= '<li><a href="' . admin_url( 'nav-menus.php' ) . '">'. __('Add a menu', 'your themename') .'</a></li>';
				$fb_output .= '</ul>';
				
				if ( $container )
				$fb_output .= '</' . $container . '>';
				
				echo $fb_output;
			}
		}
	}
	
	/**
		* Class Name: uikit_offcanvas_output
		* Description: A custom WordPress nav walker class to implement UIkit menu markup
	*/
	class uikit_offcanvas_w_menu extends Walker_Nav_Menu {
		
		/**
			* @see Walker::start_lvl()
			* @since 3.0.0
			*
			* @param string $output Passed by reference. Used to append additional content.
			* @param int $depth Depth of page. Used for padding.
		*/
		public function start_lvl( &$output, $depth = 0, $args = array() ) {
			$indent = str_repeat( "\t", $depth );
			$output .= "\n$indent<ul role=\"menu\" class=\"uk-nav-parent-icon uk-nav-sub\">\n";
		}
		
		/**
			* @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
		*/
		public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
			$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 ) );
			
			if ( $args->has_children )
			$class_names .= ' uk-parent';
			
			
			if ( in_array( 'current-menu-item', $classes )  || in_array('current-menu-parent', $classes))
			$class_names .= ' uk-active';
			
			$class_names = $class_names ? ' class="' . 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 . '>';
			
			$atts = array();
			$atts['title']  = ! empty( $item->title )	? $item->title	: '';
			$atts['target'] = ! empty( $item->target )	? $item->target	: '';
			$atts['rel']    = ! empty( $item->xfn )		? $item->xfn	: '';
			
			// If item has_children add atts to a.
			if ( $args->has_children && $depth === 0 ) {
				$atts['href']          = '#';
				// $atts['data-toggle']   = 'dropdown';
				// $atts['class']         = 'dropdown-toggle';
				// $atts['aria-haspopup'] = 'true';
				} else {
				$atts['href'] = ! empty( $item->url ) ? $item->url : '';
			}
			
			$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );
			
			$attributes = '';
			foreach ( $atts as $attr => $value ) {
				if ( ! empty( $value ) ) {
					$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
					$attributes .= ' ' . $attr . '="' . $value . '"';
				}
			}
			
			$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 );
		}
		
		/**
			* Traverse elements to create list from elements.
			*
			* Display one element if the element doesn't have any children otherwise,
			* display the element and its children. Will only traverse up to the max
			* depth and no ignore elements under that depth.
			*
			* This method shouldn't be called directly, use the walk() method instead.
			*
			* @see Walker::start_el()
			* @since 2.5.0
			*
			* @param object $element Data object
			* @param array $children_elements List of elements to continue traversing.
			* @param int $max_depth Max depth to traverse.
			* @param int $depth Depth of current element.
			* @param array $args
			* @param string $output Passed by reference. Used to append additional content.
			* @return null Null on failure with no changes to parameters.
		*/
		public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
			if ( ! $element )
            return;
			
			$id_field = $this->db_fields['id'];
			
			// Display this element.
			if ( is_object( $args[0] ) )
			$args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] );
			
			parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
		}
		
		/**
			* Menu Fallback
			* =============
			* If this function is assigned to the wp_nav_menu's fallback_cb variable
			* and a manu has not been assigned to the theme location in the WordPress
			* menu manager the function with display nothing to a non-logged in user,
			* and will add a link to the WordPress menu manager if logged in as an admin.
			*
			* @param array $args passed from the wp_nav_menu function.
			*
		*/
		public static function fallback( $args ) {
			if ( current_user_can( 'manage_options' ) ) {
				
				extract( $args );
				
				$fb_output = null;
				
				if ( $container ) {
					$fb_output = '<' . $container;
					
					if ( $container_id )
					$fb_output .= ' id="' . $container_id . '"';
					
					if ( $container_class )
					$fb_output .= ' class="' . $container_class . '"';
					
					$fb_output .= '>';
				}
				
				$fb_output .= '<ul';
				
				if ( $menu_id )
				$fb_output .= ' id="' . $menu_id . '"';
				
				if ( $menu_class )
				$fb_output .= ' class="' . $menu_class . '"';
				
				$fb_output .= '>';
				$fb_output .= '<li><a href="' . admin_url( 'nav-menus.php' ) . '">'. __('Add a menu', 'Lajuma 2019') .'</a></li>';
				$fb_output .= '</ul>';
				
				if ( $container )
				$fb_output .= '</' . $container . '>';
				
				echo $fb_output;
			}
		}
	}
	
	
	
	
	
	
	/**
		* Offcanvas menu
	*/
	function uikit_offcanvas_menu() { ?>
	
    <div id="offcanvas-menu" uk-offcanvas="flip: true">
        <div class="uk-offcanvas-bar">
			
            <button class="uk-offcanvas-close" type="button" uk-close></button>
            <?php if ( has_nav_menu( 'menu-1' ) ) : ?>
			<h3><?php _e('Menu', 'your_themename'); ?></h3>
			<?php 
				wp_nav_menu( array(
				'menu'              => 'mobile-menu',
				'theme_location'    => 'mobile-menu',
				'depth'             => 2,
				'container'         => 'ul',
				'items_wrap'        => '<ul id="%1$s" class="%2$s" uk-nav>%3$s</ul>',
				'menu_class'        => 'uk-nav uk-nav-default uk-nav-parent-icon',
				'fallback_cb'       => 'uikit_offcanvas_w_menu::fallback',
				'walker'            => new uikit_offcanvas_w_menu()
			)); ?>
            <?php endif; ?>   
			
		</div>
	</div>
	
	<?php }
	add_action( 'uikit_offcanvas_menu', 'uikit_offcanvas_menu' );
	
	
	/**
		* Offcanvas menu
	*/
	function uikit_modal_menu() { ?>
	<div id="modal-full" class="uk-modal-full" uk-modal>
		<div class="uk-modal-dialog">
			<button class="uk-modal-close-full uk-close-large" type="button" uk-close></button>
			<div class="uk-grid-collapse" uk-grid>
				<div uk-height-viewport></div>
				<div class="uk-container uk-width-7-10 uk-text-center">
					<div class="uk-section-large">
						<?php if ( has_nav_menu( 'modal-menu' ) ) : ?>
						<h3><?php _e('Menu', 'modal-menu'); ?></h3>
						<?php 
							wp_nav_menu( array(
							'menu'              => 'modal-menu',
							'theme_location'    => 'modal-menu',
							'depth'             => 2,
							'container'         => 'ul',
							'items_wrap'        => '<ul id="%1$s" class="%2$s" uk-nav>%3$s</ul>',
							'menu_class'        => 'uk-text-large uk-text-bold uk-nav uk-navbar-dropdown-nav',
							'fallback_cb'       => 'uikit_offcanvas_w_menu::fallback',
							'walker'            => new uikit_offcanvas_w_menu()
						)); ?>
						<?php endif; ?>  
						
					</div>	
				</div>
			</div>
		</div>
	</div>
	

	<?php }
	add_action( 'uikit_modal_menu', 'uikit_modal_menu' );
	
	
	
	
	
	/**
		* Top menu
	*/
	function uikit_top_menu() { ?>	 
	<nav class="uk-navbar-container  uk-margin  <?php echo 'uk-navbar-transparent'; ?>" uk-navbar>
		<div class="uk-visible@m uk-navbar-left">      
			<?php wp_nav_menu( array(
				'menu'              => 'top-menu',
				'theme_location'    => 'top-menu',
				'depth'             => 2,
				'container'         => '',
				'menu_class'        => 'uk-navbar-nav uk-visible@s',
				'fallback_cb'       => 'uikit_top_w_menu::fallback',
				'walker'            => new uikit_top_w_menu())
			); ?>  
		</div>
		
	    <div class="uk-navbar-right">
			<ul class="uk-navbar-nav">
				<li class="uk-hidden@m"><a href="#modal-full" uk-toggle><span class="uk-margin-small-right" uk-icon="icon: menu"></span> Menu</a></li>
			</ul>
		</div>
	</nav>
	<?php } 
	add_action( 'uikit_top_menu', 'uikit_top_menu');
	
	function wpb_custom_new_menu() {
		register_nav_menus(
		array(
		'top-menu' => __( 'Top menu' ),
		'modal-menu' => __( 'mobile Modal menu' ),
		'mobile-menu' => __( 'mobile Menu offcanvas' ),
		'footer-menu' => __( 'Footer Menu' )
		)
		);
	}
	add_action( 'init', 'wpb_custom_new_menu' );
	
	
	

Make new file wih this code. supposse uikitmenu.php
and include it in ur function,php as
require_once( get_stylesheet_directory() . '/includes/uikitmenu.php' );

you can use this in header.php
<?php do_action('uikit_top_menu'); ?>

@carlovarchetta
Copy link

carlovarchetta commented Oct 16, 2019

Hi @tasz

Thank you very much for your answer. Now it's ok for the desktop but I don't see anything when clicking on the mobile-menu-button, simply I see the button disappear, using the off-canvas menu. I do some changes like my off-canvas menu but nothing changed.

Have I to change the 'your_themename' with the name of my theme?

This is how I have the off-canvas menu

/**
      * Offcanvas menu
*/
function uikit_offcanvas_menu() { ?>

    <div id="offcanvas-menu" uk-offcanvas="overlay:true">
        <div class="uk-offcanvas-bar uk-flex uk-flex-column">

            <button class="uk-offcanvas-close" type="button" uk-close></button>
            <a class="uk-navbar-item uk-logo" href="index.html">
              <img src="assets/images/in-piemonte-puoi-logo-white.png" data-src="" width="" height="" alt="In piemonte puoi logo" uk-img>
            </a>
            <?php if ( has_nav_menu( 'menu-1' ) ) : ?>
			<h3><?php _e('Menu', 'your_themename'); ?></h3>
			<?php
				wp_nav_menu( array(
				'menu'              => 'mobile-menu',
				'theme_location'    => 'mobile-menu',
				'depth'             => 2,
				'container'         => 'ul',
				'items_wrap'        => '<ul id="%1$s" class="%2$s" uk-nav>%3$s</ul>',
				'menu_class'        => 'uk-nav uk-nav-default uk-nav-parent-icon',
				'fallback_cb'       => 'uikit_offcanvas_w_menu::fallback',
				'walker'            => new uikit_offcanvas_w_menu()
			)); ?>
            <?php endif; ?>

		</div>
	</div>

<?php }

add_action( 'uikit_offcanvas_menu', 'uikit_offcanvas_menu' );

@carlovarchetta
Copy link

Hi @tasz Just to say, I've solved the issue for the mobile, just a matter of target, thank you very much for the code.

@badabingbreda
Copy link

Thank you for this. Amazing!

@emanuelepinna
Copy link

Hi,
can you tell me how can i show the dropdown menu in Multiple columns?
I have add the following markup
<div class="uk-navbar-dropdown uk-navbar-dropdown-width-2"> <div class="uk-navbar-dropdown-grid uk-child-width-1-2" uk-grid>

in line 17 and 207 , the 2 columns are shown correctly, but the menu items remain in one column!

thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment