kongondo Posted May 22, 2016 Author Share Posted May 22, 2016 De nada Link to comment Share on other sites More sharing options...
Ivan Gretsky Posted May 23, 2016 Share Posted May 23, 2016 I don't know if MSN can use a WireArray to build menus. It certainly can take a PageArray and build a menu out of that. The key here is that MSN relies on true/natural PW child-parent relationships (unless something has changed that I don't know about) to create menus. So, $page->children will make sense to it. You won't get $page->children in MB...at least not in that original sense. My bad. It is PageArray, not WireArray. Anyway, could you consider the scenario of somehow making it possible for MenuBuilder and MarkupSimpleNavigation to work together? Maybe providing PageArray output with some dynamically-made-up pages for external links? I really like the idea of separating concerns. It seems to me very handy to have one module to build menu markup from anywhere (MarkupSimpleNavigation) and one module to be able to generate contents for it from custom user input (MenuBuilder). So you do not have to learn two ways of doing the same thing on one site. What do you think? Could this be possible? Link to comment Share on other sites More sharing options...
kongondo Posted May 23, 2016 Author Share Posted May 23, 2016 OK...sigh...because you asked nicely... @note: Using this method, it makes no sense to create a menu with more than 1 level in Menu Builder. The levels will be built using natural child-parent relationship in MSN The CSS attritubes that can be set in MB have no meaning. I see no way of passing those to MSN This was a one-time exercise. Currently, I am not able to support more features for this technique Step 1: Create a 1-level menu in MB Step 2: Grab menu items from the menu created in MB in Step #1 $itemIDs = ''; $mb = $modules->get("MarkupMenuBuilder"); // options 1: get menu items as array $menuItemsArray = $mb->getMenuItems('Ivan Gretsky', 1); foreach($menuItemsArray as $m) $itemIDs .= $m['pages_id'] . '|'; $itemIDs = rtrim($itemIDs, '|'); #### OR #### //option 2: get menu items as object (WireArray) $menuItemsObj = $mb->getMenuItems('Ivan Gretsky'); // implode the WireArray the cool way (PW 2.4+) $itemIDs = $menuItemsObj->implode('|', 'pagesID'); // get a PageArray using menu item IDs $itemsPageArray = $pages->find('id=' . $itemIDs); Step 3: Output the menu using MSN // pass the PageArray to MSN (optionally passing it MSN $options) to output your menu $menu = $modules->get("MarkupSimpleNavigation"); echo $menu->render($options, null, $itemsPageArray); 3 Link to comment Share on other sites More sharing options...
dlen Posted May 31, 2016 Share Posted May 31, 2016 Hi, I got a problem, which makes me scratch my head a lot. I have a menu item with two children, which are 'hidden', but not 'unpublished'. (A newsletter opt in page with landing pages for the double-opt-in-process.) The menu generated looks like this (just the last 3 items): <li> <a href='/pw/de/impressum/'>Impressum</a> </li> <li> <a href='/pw/de/kontakt/'>Kontakt</a> </li> <li class="current"> <a href='/pw/de/newsletter/'>Newsletter</a> <ul class="submenu"> </ul> </li> As one can see, there is an empty ul in the last li. This causes some trouble with some jQuery - mobile - navigation generator. What is puzzling me is, that in a second menu, which just contains this last 3 items (a footer in the non-mobile version) this ul does not appear. I could not find any differences in the menu settings. FYI: runs otherwise smoohtly on pw 3.08 dev. Link to comment Share on other sites More sharing options...
kongondo Posted May 31, 2016 Author Share Posted May 31, 2016 Works fine here...(2.7.3)...How are you building and generating the menu? Using includeChildren? Anything else? Link to comment Share on other sites More sharing options...
dlen Posted June 1, 2016 Share Posted June 1, 2016 Thanks for your answer. I can indeed make the empty ul make disappear by setting 'include_children' => 0 in the options. But then, also those items, which shall have their submenu, don't have one. Also, i can switch on an unintended empty ul in another menu, when i set include_children to 1 there. Link to comment Share on other sites More sharing options...
kongondo Posted June 1, 2016 Author Share Posted June 1, 2016 (edited) My intent was not to suggest that you use include_children as a solution. What I needed is more information to reproduce this. I have been unable to replicate you issue so the more information I have the better ...How the menu is constructed, the options, your environment, etc...basically, the whole code if that is possible.... Edited June 1, 2016 by kongondo Link to comment Share on other sites More sharing options...
dlen Posted June 1, 2016 Share Posted June 1, 2016 Ah, ok. I'll attach all files i think could be relevant. if you want more, just drop a line. It's the "newsletter" item, which has the empty ul. Link to comment Share on other sites More sharing options...
dlen Posted June 1, 2016 Share Posted June 1, 2016 Hi, I found a possible cause for the issue when tampering with my own menu function and running into the very same problem. In line 351 of MarkupMenuBuilder.module if($p->numChildren) $hasNativeChildren = 1;// has children to add is the function numChildren used. This function counts in default mode also hidden children. To make it count only visible children, it has to be used with a parameter: if($p->numChildren(true)) $hasNativeChildren = 1;// has children to add I tried it and it seems to work! Link to comment Share on other sites More sharing options...
louisstephens Posted June 2, 2016 Share Posted June 2, 2016 Ok, this might just be a dumb question...But, has anyone had any success adding "<span class="caret"></span>" into a menu yet using bootstrap? My dropdown works great, save for the the fact that for the life of me I can not figure out how to get the dropdown li to have a caret. Link to comment Share on other sites More sharing options...
kongondo Posted June 2, 2016 Author Share Posted June 2, 2016 Hi, I found a possible cause for the issue when tampering with my own menu function and running into the very same problem. In line 351 of MarkupMenuBuilder.module if($p->numChildren) $hasNativeChildren = 1;// has children to add is the function numChildren used. This function counts in default mode also hidden children. To make it count only visible children, it has to be used with a parameter: if($p->numChildren(true)) $hasNativeChildren = 1;// has children to add I tried it and it seems to work! OK, I'll try and replicate. As for the files, seems I wasn't clear, sorry. I just needed to see how you were calling menubuilder methods + the options you were passing to it Ok, this might just be a dumb question...But, has anyone had any success adding "<span class="caret"></span>" into a menu yet using bootstrap? My dropdown works great, save for the the fact that for the life of me I can not figure out how to get the dropdown li to have a caret. Have a look here: https://processwire.com/talk/topic/4451-menu-builder/?p=120639 Link to comment Share on other sites More sharing options...
louisstephens Posted June 2, 2016 Share Posted June 2, 2016 Thanks Kongondo.. How in the world did I miss that ( I went through like 8 pages) Link to comment Share on other sites More sharing options...
kongondo Posted June 2, 2016 Author Share Posted June 2, 2016 Maybe 'coz it's on the 9th page? Link to comment Share on other sites More sharing options...
louisstephens Posted June 2, 2016 Share Posted June 2, 2016 Ha ha.. touche.. Well, I will get this all sorted out. I went with Example "1b", however, I am getting "Call to undefined function buildMenuFromObject()"... Any idea what could cause this? Link to comment Share on other sites More sharing options...
kongondo Posted June 2, 2016 Author Share Posted June 2, 2016 (edited) Example 1b is for buildMenuFromArray() actually...buildMenuFromObject() is for example 1a. Whichever you choose, you need to define the function first before you can call it...(i.e. the function code first, then echo it...) Edited June 2, 2016 by kongondo Link to comment Share on other sites More sharing options...
louisstephens Posted June 6, 2016 Share Posted June 6, 2016 Thank you so much (and sorry for my confusion). I thought I had it, but now I am just getting 6 errors: Error: Exception: Method MarkupMenuBuilder::getMenuItems does not exist or is not callable in this context (in Desktop/_Staging/test/wire/core/Wire.php line 409) #0 [internal function]: ProcessWire\Wire->___callUnknown('getMenuItems', Array)#1 Desktop/_Staging/test/wire/core/Wire.php(347): call_user_func_array(Array, Array)#2 Desktop/_Staging/test/wire/core/WireHooks.php(555): ProcessWire\Wire->_callMethod('___callUnknown', Array)#3 Desktop/_Staging/test/wire/core/Wire.php(370): ProcessWire\WireHooks->runHooks(Object(MarkupMenuBuilder), 'callUnknown', Array)#4 Desktop/_Staging/test/wire/core/Wire.php(371): ProcessWire\Wire->__call('callUnknown', Array)#5 Desktop/_Staging/test/site/templates/navTwo.inc(11): ProcessWire\Wire->__call('getMenuItems', Array)#6 /Desktop/_Staging/test/site/templates/head.inc(85): include('/Us I am a bit lost on this now, though I am trying to dig through them and understand what they mean. What I have thus far (all using example 1b): head.inc <div class="collapse navbar-collapse container" id="bs-example-navbar-collapse-1"> <?php //include('./navigation.inc');?> <?php include('./navTwo.inc');?> <?php echo buildMenuFromArray(0, $menuItems2); ?> </div><!-- /.navbar-collapse --> navTwo.inc <?php $mb = $modules->get('MarkupMenuBuilder');// get Menu Builder $jsonStr = $pages->get(1033)->menu_items; $arrayFromJSON = json_decode($jsonStr, true); #$menu = $arrayFromJSON;// pass an array $menu = 'main';// pass a title /** grab menu items as WireArray with Menu objects **/ // for examples 1a, 2 and 3 $menuItems = $mb->getMenuItems($menu, 2, $options);// called with options and 2nd argument = 2 {return Menu (WireArray object)} #$menuItems = $mb->getMenuItems($menu);// called without options; 2nd argument defaults to 2 /** grab menu items as Normal Array with Menu items **/ // only for example 1b below $menuItems2 = $mb->getMenuItems($menu, 1);// called without options; 2nd argument is 1 so return array /** * 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) { $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; } ?> Did I miss something crucial here? Link to comment Share on other sites More sharing options...
kongondo Posted June 6, 2016 Author Share Posted June 6, 2016 I see you copied and pasted more code than necessary. I have used your code and it works for me... First, you need to make sure you have the latest version of Menu Builder which has the method getMenuItems(), i.e. version 0.1.5 head.inc <div class="collapse navbar-collapse container" id="bs-example-navbar-collapse-1"> <?php include('./navTwo.inc');?> <?php echo buildMenuFromArray(0, $menuItems); ?> </div><!-- /.navbar-collapse --> navTwo.inc <?php $mb = $modules->get('MarkupMenuBuilder');// get Menu Builder $menu = 'Main';// pass a title of an existing menu (i.e. a menu already built and published in ProcessMenuBuilder) // grab menu items as Normal Array with Menu items (argument #2 = 1) $menuItems = $mb->getMenuItems($menu, 1); /** * 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) { $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; } ?> Link to comment Share on other sites More sharing options...
louisstephens Posted June 6, 2016 Share Posted June 6, 2016 Thanks again.. Finally starting to understand what is going on, but now it is time to figure out how to give the "second nested ul" a different class than the wrapper ul. I thought I could pass that through with $options, but that doesnt seem to work. (sorry to drag this thread out). Link to comment Share on other sites More sharing options...
kongondo Posted June 7, 2016 Author Share Posted June 7, 2016 Actually, my bad; the README and my post above wasn't very clear (have now updated them). Not all options apply to getMenuItems(). The reason is that if using MarkupMenuBuilder to output the menu for you, i..e using the method render(), the structuring of the menu (the <ul>, their CSS classes, etc) are taken care of by the method. In contrast, if using getMenuItems() what you get back are the menu items with all their relevant properties. The reasoning here is that you will use those properties as well as any other logic and/or options you want in your own custom recursive function (nested loops) where you have full control of the markup. That said, only 3 options (from the list of those applicable to render()) apply to getMenuItems(). These are default_title, default_class and current_class_level. default_class is applied to the item's property $m['ccss_itemclass']. Here is a revised navTwo.inc showing how you can pass custom options to the recursive function and applying the same as well as the 3 options that can be passed to getMenuItems(). head.inc is also slightly revised to pass $options to buildMenuFromArray() - @note: The new 4th argument in the function - @note: The custom options array - @note: Complete code for previous examples 1-3 can be found in these gists head.inc <div class="collapse navbar-collapse container" id="bs-example-navbar-collapse-1"> <?php include('./navTwo.inc'); // your CUSTOM options to pass to the recursive function buildMenuFromArray() $options = array ( 'submenu_css_class' => 'nested-ul-css-class',//CSS Class for sub-menus; you can use whatever index you want 'other_custom_option' => 'foo', 'first_class' => 'first', 'last_class' => 'last', 'current_class' => 'current', 'has_children_class' => 'parent', ); echo buildMenuFromArray(0, $menuItems, 0, $options); ?> </div><!-- /.navbar-collapse --> navTwo.inc <?php $mb = $modules->get('MarkupMenuBuilder');// get Menu Builder $menu = 'Main';// pass a title of an existing menu (i.e. a menu already built and published in ProcessMenuBuilder) // @note: only these 3 options will work with getMenuItems(); Only pass options if you need to; it is not mandatory $options4getMenuItems = array('default_title' => 1, 'default_class' => 'list-group', 'current_class_level' => 4); // grab menu items as Normal Array with Menu items (argument #2 = 1) #$menuItems = $mb->getMenuItems($menu, 1); OR $menuItems = $mb->getMenuItems($menu, 1, $options4getMenuItems);// if passing options /** * 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, $options = array()) { $out = ''; $has_child = false; $subMenuCSSClass = isset($options['submenu_css_class']) ? 'class="' . $options['submenu_css_class'] . '"' : ''; 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 ". $subMenuCSSClass .">\n"; } // item CSS $itemCSSID = isset($m['css_itemid'])? ' id="' . $m['css_itemid'] . '"' : ''; $itemCSSClass = isset($m['css_itemclass']) ? $m['css_itemclass'] . ' ' : ''; $itemFirst = isset($m['is_first']) && isset($options['first_class']) ? $options['first_class'] : ''; $itemHasChildren = isset($m['is_parent']) && isset($options['has_children_class']) ? $options['has_children_class'] . ' ' : ''; $itemLast = isset($m['is_last']) && isset($options['last_class']) ? $options['last_class'] . ' ' : ''; $itemCurrent = isset($m['is_current']) && isset($options['current_class']) ? $options['current_class'] . ' ' : ''; $classes = $itemCSSClass . $itemHasChildren . $itemLast . $itemCurrent . $itemFirst; $classes = trim(preg_replace('/\s+/', ' ', $classes)); $class = strlen($classes) ? ' class="' . $classes . '"' : ''; // a menu item $out .= '<li' . $itemCSSID . $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, $options); $out .= "</li>\n"; }// end if parent }// end foreach if ($has_child === true) $out .= "</ul>\n"; return $out; } ?> Link to comment Share on other sites More sharing options...
louisstephens Posted June 7, 2016 Share Posted June 7, 2016 Thanks again Kongondo! I appreciate all the help. I actually figured it out about 5 mins ago (forgot to check back on the forums). It feel good to have actually learned through your help and the various comments what actually is occurring and not blindly copying. Your module has made things so much easier (once I learned). Link to comment Share on other sites More sharing options...
pmichaelis Posted June 28, 2016 Share Posted June 28, 2016 Hey kongondo, thanks for thi great module again. A few days ago I figured out, that the output of the main menu builder header is not formated in html. Maybe it has to do with some other modules installed, because I never had the issue, that the output is not "rendered" as HTML. Does anyone else have this issue, too? Link to comment Share on other sites More sharing options...
kongondo Posted June 29, 2016 Author Share Posted June 29, 2016 Saw that once in a multilingual setup, IIRC.....What's your setup? PW version, etc... Link to comment Share on other sites More sharing options...
pmichaelis Posted June 29, 2016 Share Posted June 29, 2016 (edited) Hey, thanks for your fast reply. I attached a screenshot with my current setup. You are right, the page is multilingual. Maybe you cna give me a hint, how I can solve this? It seems, that the HTML is not rendered correctly. I tried to edit the HTML of the decription field and put Markdon tags in the description, which are displayed correct. Edited June 29, 2016 by pmichaelis Description Field HTML Link to comment Share on other sites More sharing options...
pmichaelis Posted July 4, 2016 Share Posted July 4, 2016 Sorry, I still can't figure it out. All the descriptions are not displayed as HTML. A can't update Menu Item, or anything else. Does anyone have a hint for me to solve this? Link to comment Share on other sites More sharing options...
kongondo Posted July 4, 2016 Author Share Posted July 4, 2016 I see you are using PW 3.x. Could you please try in a multilingual PW 2.7xx and let me know if it works? Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now