Skip to content

Instantly share code, notes, and snippets.

@kongondo
Last active August 30, 2023 08:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kongondo/a478e2a9274fc29f5d7cdb93a8166989 to your computer and use it in GitHub Desktop.
Save kongondo/a478e2a9274fc29f5d7cdb93a8166989 to your computer and use it in GitHub Desktop.
Menu Builder getMenuItems() Examples
<?php
/**
* Builds a nested list (menu items) of a single menu.
*
* A recursive function to display nested list of menu items.
*
* @access private
* @param Int $parent ID of menu item.
* @param Array $menu Object of menu items to display.
* @param Int $first Helper variable to designate first menu item.
* @return string $out.
*
*/
function buildMenuFromObject($parent = 0, $menu, $first = 0) {
if(!is_object($menu)) return;
$out = '';
$has_child = false;
foreach ($menu as $m) {
$newtab = $m->newtab ? " target='_blank'" : '';
// if this menu item is a parent; create the sub-items/child-menu-items
if ($m->parentID == $parent) {// if this menu item is a parent; create the inner-items/child-menu-items
// if this is the first child
if ($has_child === false) {
$has_child = true;// This is a parent
if ($first == 0){
$out .= "<ul class='main-menu cf'>\n";
$first = 1;
}
else $out .= "\n<ul class='sub-menu'>\n";
}
$class = $m->isCurrent ? ' class="current"' : '';
// a menu item
$out .= '<li' . $class . '><a href="' . $m->url . '"' . $newtab . '>' . $m->title;
// if menu item has children
if ($m->isParent) {
$out .= '<span class="drop-icon">▼</span>' .
'<label title="Toggle Drop-down" class="drop-icon" for="' . wire('sanitizer')->pageName($m->title) . '" onclick>▼</label>' .
'</a>' .
'<input type="checkbox" id="' . wire('sanitizer')->pageName($m->title) . '">';
}
else $out .= '</a>';
// call function again to generate nested list for sub-menu items belonging to this menu item.
$out .= buildMenuFromObject($m->id, $menu, $first);
$out .= "</li>\n";
}// end if parent
}// end foreach
if ($has_child === true) $out .= "</ul>\n";
return $out;
}
##################################
/* grab menu items using MarkupMenuBuilder */
$mb = $modules->get('MarkupMenuBuilder');// get Menu Builder
/* get menu the menu we want (i.e. a menu created and published using ProcessMenuBuilder) */
// we can pass the menu's Page, page ID, title, name or its menu items string to getMenuItems()
#$menu = $pages->get(1299);// pass a Page
#$menu = 1299;// pass an ID
#$menu = 'main';// pass a name
// passing an array
#$jsonStr = $pages->get(1299)->menu_items;
#$arrayFromJSON = json_decode($jsonStr, true);
#$menu = $arrayFromJSON;// pass an array
$menu = 'Main';// pass a title
/* only these 3 options apply to getMenuItems() */
$options = array('default_title'=> 1, 'default_class'=> 'cool_menu_class', 'current_class_level' => 4);
/* grab menu items as a WireArray with Menu objects */
$menuItems = $mb->getMenuItems($menu, 2, $options);// called with options and 2nd argument = 2 {return Menu (WireArray object)}
#$menuItems = $mb->getMenuItems($menu);// if calling without without options; 2nd argument defaults to 2
?>
<div id="content">
<nav id="mainMenu">
<label for='tm' id='toggle-menu' onclick>Navigation <span class='drop-icon'>▼</span></label>
<input id='tm' type='checkbox'>
<?php
// build menu from array (example 1b only)
echo buildMenuFromObject(0, $menuItems);
?>
</nav>
</div>
<?php
/**
* Builds a nested list (menu items) of a single menu from an Array of menu items.
*
* A recursive function to display nested list of menu items.
*
* @access private
* @param Int $parent ID of menu item.
* @param Array $menu Array of menu items to display.
* @param Int $first Helper variable to designate first menu item.
* @return string $out.
*
*/
function buildMenuFromArray($parent = 0, $menu, $first = 0) {
if(!is_array($menu)) return;
$out = '';
$has_child = false;
foreach ($menu as $id => $m) {
$parentID = isset($m['parent_id']) ? $m['parent_id'] : 0;
$newtab = isset($m['newtab']) && $m['newtab'] ? " target='_blank'" : '';
// if this menu item is a parent; create the sub-items/child-menu-items
if ($parentID == $parent) {// if this menu item is a parent; create the inner-items/child-menu-items
// if this is the first child
if ($has_child === false) {
$has_child = true;// This is a parent
if ($first == 0){
$out .= "<ul class='main-menu cf'>\n";
$first = 1;
}
else $out .= "\n<ul class='sub-menu'>\n";
}
$class = isset($m['is_current']) && $m['is_current'] ? ' class="current"' : '';
// a menu item
$out .= '<li' . $class . '><a href="' . $m['url'] . '"' . $newtab . '>' . $m['title'];
// if menu item has children
if (isset($m['is_parent']) && $m['is_parent']) {
$out .= '<span class="drop-icon">▼</span>' .
'<label title="Toggle Drop-down" class="drop-icon" for="' . wire('sanitizer')->pageName($m['title']) . '" onclick>▼</label>' .
'</a>' .
'<input type="checkbox" id="' . wire('sanitizer')->pageName($m['title']) . '">';
}
else $out .= '</a>';
// call function again to generate nested list for sub-menu items belonging to this menu item.
$out .= buildMenuFromArray($id, $menu, $first);
$out .= "</li>\n";
}// end if parent
}// end foreach
if ($has_child === true) $out .= "</ul>\n";
return $out;
}
##################################
/* grab menu items using MarkupMenuBuilder */
$mb = $modules->get('MarkupMenuBuilder');// get Menu Builder
/* get menu the menu we want (i.e. a menu created and published using ProcessMenuBuilder) */
// we can pass the menu's Page, page ID, title, name or its menu items string to getMenuItems()
#$menu = $pages->get(1299);// pass a Page
#$menu = 1299;// pass an ID
#$menu = 'main';// pass a name
// passing an array
#$jsonStr = $pages->get(1299)->menu_items;
#$arrayFromJSON = json_decode($jsonStr, true);
#$menu = $arrayFromJSON;// pass an array
$menu = 'Main';// pass a title
/* only these 3 options apply to getMenuItems() */
$options = array('default_title' => 0, 'default_class' => 'cool_menu_class', 'current_class_level' => 3);
/* grab menu items as Normal PHP Array with Menu items */
// only for example 1b
$menuItems = $mb->getMenuItems($menu, 1, $options);// called without options; 2nd argument is 1 so return array
#$menuItems = $mb->getMenuItems($menu, 1);// if calling without options; 2nd argument is 1 so return array
?>
<div id="content">
<nav id="mainMenu">
<label for='tm' id='toggle-menu' onclick>Navigation <span class='drop-icon'>▼</span></label>
<input id='tm' type='checkbox'>
<?php
// build menu from array (example 1b only)
echo buildMenuFromArray(0, $menuItems);
?>
</nav>
</div>
<?php
/**
* Recursively traverse and visit every child item in an array|object of Menu items.
*
* @param Menu item parent ID $parent to start traversal from.
* @param callable $enter function to call upon visiting a child menu item.
* @param callable|null $exit function to call after visiting a child menu item (and all of its children).
* @param Menu Object|Array $menuItems to traverse.
*
* @see Modified From mindplay.dk https://processwire.com/talk/topic/110-recursive-navigation/#entry28241
*/
function visit($parent, $enter, $exit=null, $menuItems) {
if(!is_object($menuItems)) return;
foreach ($menuItems as $m) {
if ($m->parentID == $parent) {
call_user_func($enter, $m);
if ($m->isParent) visit($m->id, $enter, $exit, $menuItems);
if ($exit) call_user_func($exit, $m);
}
}
}
#############################
/* grab menu items using MarkupMenuBuilder */
$mb = $modules->get('MarkupMenuBuilder');// get Menu Builder
/* get menu the menu we want (i.e. a menu created and published using ProcessMenuBuilder) */
// we can pass the menu's Page, page ID, title, name or its menu items string to getMenuItems()
#$menu = $pages->get(1299);// pass a Page
#$menu = 1299;// pass an ID
#$menu = 'main';// pass a name
// passing an array
#$jsonStr = $pages->get(1299)->menu_items;
#$arrayFromJSON = json_decode($jsonStr, true);
#$menu = $arrayFromJSON;// pass an array
$menu = 'Main';// pass a title
/* only these 3 options apply to getMenuItems() */
$options = array('default_title'=> 1, 'default_class'=> 'cool_menu_class', 'current_class_level' => 4);
/* grab menu items as a WireArray with Menu objects */
#$menuItems = $mb->getMenuItems($menu, 2, $options);// called with options and 2nd argument = 2 {return Menu (WireArray object)}
$menuItems = $mb->getMenuItems($menu);// if calling without without options; 2nd argument defaults to 2
?>
<div id="content">
<nav id="mainMenu">
<label for='tm' id='toggle-menu' onclick>Navigation <span class='drop-icon'>▼</span></label>
<input id='tm' type='checkbox'>
<?php
echo "<ul class='main-menu cf'>";
visit(
0// start from the top items
,
// function $enter: <li> for a single menu item
function($menuItem) {
echo '<li><a href="' . $menuItem->url . '">' . $menuItem->title;
if ($menuItem->isParent) {
echo '<span class="drop-icon">▼</span>' .
#'<label title="Toggle Drop-down" class="drop-icon" for="' . wire('sanitizer')->pageName($menuItem->title) . '" onclick>▼</label>' .
'<label title="Toggle Drop-down" class="drop-icon" for="sm' . $menuItem->id . '" onclick>▼</label>' .
'</a>' .
#'<input type="checkbox" id="' . wire('sanitizer')->pageName($menuItem->title) . '"><ul class="sub-menu">' .
'<input type="checkbox" id="sm' . $menuItem->id . '"><ul class="sub-menu">';
}
else echo '</a>';
}// end function 1 ($enter)
,
#function $exit: close menu item <li> and sub-menu <ul> tags
function($menuItem) {
if ($menuItem->isParent) echo '</ul>';
echo '</li>';
},
$menuItems// the menu items (Menu objects in this example)
);
?>
</nav>
</div>
<?php
/**
* Recursively traverse and visit every child item in an array|object of Menu items.
*
* @param Menu Object|Array $menuItems to traverse.
* @param Int $parent ID to start traversal from.
* @param Int $depth Depth of sub-menus.
* @param Int $first Helper variable to designate first menu item.
* @see Modified From @slkwrm https://processwire.com/talk/topic/563-page-level-and-sub-navigation/?p=4490
* @return string $out.
*/
function treeMenu($menuItems, $parent, $depth = 1, $first = 0) {
if(!is_object($menuItems)) return;
$depth -= 1;
if ($first == 0){
$out = "\n<ul class='main-menu cf'>";
$first = 1;
}
else $out = "\n<ul class='sub-menu'>";
foreach($menuItems as $m) {
if ($m->parentID == $parent) {
$sub = '';
$out .= "\n\t<li>\n\t\t<a href='" . $m->url . "'>" . $m->title;
if($m->isParent && $depth > 0 ) {
$sub = str_replace("\n", "\n\t\t", treeMenu($menuItems, $m->id, $depth, $first));
$out .= '<span class="drop-icon">▼</span>' .
'<label title="Toggle Drop-down" class="drop-icon" for="sm' . $m->id . '" onclick>▼</label>' .
'</a>' .
'<input type="checkbox" id="sm' . $m->id . '">' .
$sub . "\n\t";
}
else $out .= "</a>\n\t";
$out .="\n\t</li>";
}
}// end foreach
$out .= "\n</ul>";
return $out;
}
#############################
/* grab menu items using MarkupMenuBuilder */
$mb = $modules->get('MarkupMenuBuilder');// get Menu Builder
/* get menu the menu we want (i.e. a menu created and published using ProcessMenuBuilder) */
// we can pass the menu's Page, page ID, title, name or its menu items string to getMenuItems()
#$menu = $pages->get(1299);// pass a Page
#$menu = 1299;// pass an ID
#$menu = 'main';// pass a name
// passing an array
#$jsonStr = $pages->get(1299)->menu_items;
#$arrayFromJSON = json_decode($jsonStr, true);
#$menu = $arrayFromJSON;// pass an array
$menu = 'Main';// pass a title
/* only these 3 options apply to getMenuItems() */
$options = array('default_title'=> 1, 'default_class'=> 'cool_menu_class', 'current_class_level' => 5);
/* grab menu items as a WireArray with Menu objects */
$menuItems = $mb->getMenuItems($menu, 2, $options);// called with options and 2nd argument = 2 {return Menu (WireArray object)}
#$menuItems = $mb->getMenuItems($menu);// if calling without without options; 2nd argument defaults to 2
?>
<div id="content">
<nav id="mainMenu">
<label for='tm' id='toggle-menu' onclick>Navigation <span class='drop-icon'>▼</span></label>
<input id='tm' type='checkbox'>
<?php
//parameters: menu items, menu item parent ID, depth, first (helper variable; @note: defaults to 0 - only shown here for completeness)
echo treeMenu($menuItems, 0, 4, 0);
?>
</nav>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment