Skip to content

Instantly share code, notes, and snippets.

@Micemade
Last active March 6, 2019 14:06
Show Gist options
  • Save Micemade/7d65a83d5c4608dd6d6e61ff5e777d37 to your computer and use it in GitHub Desktop.
Save Micemade/7d65a83d5c4608dd6d6e61ff5e777d37 to your computer and use it in GitHub Desktop.
<?php
/**
* CUSTOM WP NAV MENU - no walker
*
* @package WordPress
* @subpackage My theme
*
* @details custom replacement menu for wp_nav_menu()
* with a "little" help from :
* David Baker - https://dtbaker.net/
* https://stackoverflow.com/questions/8840319/build-a-tree-from-a-flat-array-in-php
* https://developer.wordpress.org/reference/functions/wp_get_nav_menu_items/
*/
/**
* Menu function
*
* @param string $theme_location - registered theme menu locations.
* @return void - output html for menu
*/
function my_theme_menu_f( $theme_location ) {
$locations = get_nav_menu_locations();
if ( ( $theme_location ) && $locations && isset( $locations[ $theme_location ] ) ) {
// Get flat array of menu items with wp_get_nav_menu_items.
$menu = get_term( $locations[ $theme_location ], 'nav_menu' );
// If no menu object on theme location, abort.
if ( is_wp_error( $menu ) ) {
return;
}
$menu_id = $menu->term_id;
$array_menu = wp_get_nav_menu_items( $menu_id );
// Another layer of checking.
if ( empty( $array_menu ) ) {
return;
}
// Extract only values needed
// look up for all values with print($array_menu) ).
$menu = array();
foreach ( $array_menu as $m ) {
$menu[ $m->ID ] = array();
$menu[ $m->ID ]['ID'] = $m->ID;
$menu[ $m->ID ]['title'] = $m->title;
$menu[ $m->ID ]['url'] = $m->url;
$menu[ $m->ID ]['target'] = $m->target;
$menu[ $m->ID ]['xfn'] = $m->xfn;
$menu[ $m->ID ]['desc'] = $m->description;
$menu[ $m->ID ]['classes'] = $m->classes;
$menu[ $m->ID ]['attr_title'] = $m->attr_title;
$menu[ $m->ID ]['parent'] = $m->menu_item_parent;
$menu[ $m->ID ]['curr'] = $m->object_id;
$menu[ $m->ID ]['children'] = array();
$item_meta = get_post_meta( $m->ID );
$menu[ $m->ID ]['urlargs'] = isset( $item_meta['menu-item-urlargs'] ) ? $item_meta['menu-item-urlargs'][0] : '';
$menu[ $m->ID ]['mega'] = isset( $item_meta['menu-item-select-mega'] ) ? $item_meta['menu-item-select-mega'][0] : '';
$menu[ $m->ID ]['icon'] = isset( $item_meta['menu-item-select-icon'] ) ? $item_meta['menu-item-select-icon'][0] : '';
}
// MAKE MULTIDIMENSIONAL ARRAY FROM FLAT ARRAY / CREATE MENU TREE.
$menu_tree = my_theme_build_tree( $menu );
// if error in build_tree function, abort.
if ( empty( $menu_tree ) ) {
return;
}
// Offcanvas theme location css selector to menu.
$offc_css = '';
if ( 'offcanvas-menu' === $theme_location ) {
$offc_css = ' offcanvasopen';
}
// Start menu.
echo '<ul class="navigation ' . esc_attr( $theme_location . $offc_css ) . '" id="' . esc_attr( $theme_location ) . '">';
my_theme_build_menu( $menu_tree, $theme_location );
echo '</ul>';
}
}
add_action( 'my_theme_menu', 'my_theme_menu_f', 10, 1 );
if ( ! function_exists( 'my_theme_menuitem_elements' ) ) {
/**
* Output menu items
*
* @param array $item - menu item.
* @param string $theme_location - location in theme.
* @return void - echo $output html
*/
function my_theme_menuitem_elements( $item, $theme_location ) {
// Current page id.
$current_page_id = get_queried_object_id();
$title = ! empty( $item['title'] ) ? $item['title'] : '';
$attr_title = ! empty( $item['attr_title'] ) ? ' title="' . esc_attr( $item['attr_title'] ) . '"' : '';
$url = ! empty( $item['url'] ) ? $item['url'] : '#';
$target = ! empty( $item['target'] ) ? ' target="' . esc_attr( $item['target'] ) . '"' : '';
$xfn = ! empty( $item['xfn'] ) ? ' rel="' . esc_attr( $item['xfn'] ) . '"' : '';
$desc = ! empty( $item['desc'] ) ? $item['desc'] : '';
$classes = ! empty( $item['classes'] ) ? implode( ' ', $item['classes'] ) : '';
$current = ! empty( $item['curr'] ) ? intval( $item['curr'] ) : '';
$children = ! empty( $item['children'] ) ? $item['children'] : array();
// Custom meta for nav_menu_item CPT.
$urlargs = ! empty( $item['urlargs'] ) ? $item['urlargs'] : '';
$mega = ! empty( $item['mega'] ) ? $item['mega'] : '';
$icon = ! empty( $item['icon'] ) ? $item['icon'] : '';
// Theme locations (Offcanvas or Vertical) submenu arrow indicator.
$arr = '';
if ( 'offcanvas-menu' === $theme_location || 'vertical-menu' === $theme_location ) {
$arr = '<a href="#" class="sub"><i class="typcn typcn-chevron-right" aria-hidden="true"></i></a>';
}
// CSS classes for menu list item.
$item_class = '';
if ( $current_page_id === $current ) {
$item_class .= ' current';
}
$item_class .= my_theme_subs( $children, $mega );
// OUTPUT MENU ITEM ELEMENTS.
$output = '<li class="menu-item' . esc_attr( $item_class ) . '">';
// $urlargs var is custom meta defined.
$output .= '<a href="' . esc_url( $url . $urlargs ) . '" class="menu-link ' . esc_attr( $classes ) . '" ' . $attr_title . $target . $xfn . '>';
// $icon var is custom meta defined
$output .= ( $icon ? '<i class="item-icon typcn ' . esc_attr( $icon ) . '"></i>' : '' );
$output .= ( $title ? '<span class="title">' . esc_html( $title ) . '</span>' : '' );
$output .= ( $desc ? '<span class="desc">' . esc_html( $desc ) . '</span>' : '' );
// $mega var is custom meta defined
$output .= ( ( ! empty( $children ) || $mega ) ? '<span class="append-sub-arrow"></span>' : '' );
$output .= '</a>';
$output .= ( ! empty( $children ) ? wp_kses_post( $arr ) : '' );
echo wp_kses_post( $output );
}
}
if ( ! function_exists( 'my_theme_subs' ) ) {
/**
* CSS Class if there are children
*
* @param array $children - sub items of menu.
* @param string $mega - ID of megamenu (if any).
* @return $css
*/
function my_theme_subs( $children, $mega ) {
$css = '';
if ( ! empty( $children ) || $mega ) {
$css = ' dropdown';
}
return $css;
}
}
if ( ! function_exists( 'my_theme_build_tree' ) ) {
/**
* Build tree menu ( multidimensional array )
*
* @param array $elements - array of elements.
* @param integer $parent_id - ID of parent item.
* @return $branch
*/
function my_theme_build_tree( array &$elements, $parent_id = 0 ) {
$branch = array();
foreach ( $elements as $element ) {
if ( $element['parent'] == $parent_id ) {
$children = my_theme_build_tree( $elements, $element['ID'] );
if ( $children ) {
$element['children'] = $children;
}
$branch[ $element['ID'] ] = $element;
//unset($elements[$element['ID']]);
}
}
return $branch;
}
}
if ( ! function_exists( 'my_theme_build_menu' ) ) {
/**
* Build menu
*
* @param array $menu_tree
* @param string $theme_location
* @return html
* Recursive function to print out multidimensional array
* as menu in nested unordered list format
*/
function my_theme_build_menu( array &$menu_tree, $theme_location ) {
foreach ( $menu_tree as $id => $branch ) {
my_theme_menuitem_elements( $branch, $theme_location );
$children = ! empty( $branch['children'] ) ? true : false;
$mega = ! empty( $branch['mega'] ) ? $branch['mega'] : '';
if ( $children || isset( $mega ) ) {
// If megamenu is set in custom meta
// AND theme location is hor. menu, render mega menu.
if ( $mega && 'horizontal-menu' === $theme_location ) {
echo '<ul class="sub-menu mega-menu">';
echo apply_filters( 'my_theme_render_mega_menu', $mega );
} else {
echo '<ul class="sub-menu">';
my_theme_build_menu( $branch['children'], $theme_location );
}
echo '</ul>';
}
echo '</li>';
}
}
}
@Micemade
Copy link
Author

Micemade commented Mar 2, 2019

An alternative to WP menu walker. Use at your own risk, but this served well for Micemade themes.
Usage: do_action( 'my_theme_menu', 'my-menu-name' );
Remove unnecessarry vars or funcs ( custom meta - $icon $mega,$urlargs , my_theme_render_mega_menu action ... etc. )
Feel free to suggest a better solution(s) or improvements.

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