This Module allows you to easily create custom menus/navigation lists in the ProcessWire Admin Panel using drag and drop. In the backend, it uses the nestedSortable jQueryUI plugin by Manuele J Sarfatti.
The module has two components:
MarkupMenuBuilder has three methods available to users.
This method renders a menu/navigation list of a specified menu. The method accepts two arguments/parameters:
render($menu, $options);
The first argument is not optional and can be a Page object, a title, name or id of a menu or an array of menu items returned from a menu's menu_items field. Note that using titles or names in multi-lingual environments also works irrespective of the current user's language. The second argument is an optional array and will fall back to defaults if no user configurations are passed to the method.
The available render() options are. Please note the possible values for each.
$defaultOptions = array(
'wrapper_list_type' => 'ul',// ul, ol, nav, div, etc.
'list_type' => 'li',// li, a, span, etc.
'menu_css_id' => '',// a CSS ID for the menu
'menu_css_class' => '',// a CSS Class for the menu
'submenu_css_class' => '',// CSS Class for sub-menus
'has_children_class' => '',// CSS Class for any menu item that has children
'first_class'=>'',// CSS Class for the first item in
'last_class' => '',
'current_class' => '',
'default_title' => 0,// 0=show saved titles;1=show actual/current titles
'include_children' => 4, // whether to include natural/pw children of menu items in navigation; 0=never;1=in menu only;2=in breadcrumbs only;3=in both;4=do not show
'm_max_level' => 1,// how deep to fetch 'include_children'
'current_class_level' => 1,// how high up the ancestral tree to apply 'current_class'
'default_class' => '',// a CSS class to apply to all menu items
);
This method renders a breadcrumb navigation of a specified menu. The method also accepts two arguments/parameters:
renderBreadcrumbs($menu, $options);
Similar to render(), the first argument is not optional and can be a Page object, a title, name or id of a menu or an array of menu items returned from a menu's menu_items field. This means that you only have to retrieve a menu once and pass that to both render() and renderBreadcrumbs(). Note that using titles or names in multi-lingual environments also works irrespective of the current user's language. The second argument is an optional array and will fall back to defaults if no user configurations are passed to the method. The options are very similar to those of render(). Hence, as applicable, you can create one array of options and pass it to both render() and renderBreadcrumbs(). The methods will pick up what's of relevance to them.
The available renderBreadcrumbs() options are shown below. Please note the possible values for each.
$defaultOptions = array(
'wrapper_list_type' => 'ul',// ul, ol, nav, div, etc.
'list_type' => 'li',// li, a, span, etc.
'menu_css_id' => '',
'menu_css_class' => '',
'current_css_id' => '',
'current_class' => '',
'divider' => '»',// e.g. Home >> About Us >> Leadership
// prepend home page at the as topmost item even if it isn't part of the breadcrumb
'prepend_home' => 0,// 0=no;1=yes
'default_title' => 0,// 0=show saved titles;1=show actual/current titles
'include_children' => 4,// whether to include natural/pw children of menu items in navigation; 0=never;1=in menu only;2=in breadcrumbs only;3=in both;4=do not show
'b_max_level' => 1,// how deep to fetch 'include_children'
);
This is a new method since version 0.1.5. The method greatly simplifies the creation of custom complex menus. Use this method instead of render() if you wish to have total control over your menu logic and markup. Examples of how to use this method can be found in these gists as well as in this post in the support forum. The method accepts three arguments:
getMenuItems($menu, $type, $options);
Similar to render(), the first argument is not optional and can be a Page object, a title, name or id of a menu or an array of menu items returned from a menu's menu_items field.
The second argument determines the type of items that the method will return. A value of 1 will return an array and one of 2 (the default) will return a WireArray Menu Object.
The third argument is similar to the $options passed to render() but accepts slightly only a limited number of options as noted below.
Menu items returned via getMenuItems() have the following properties, as applicable. As previously mentioned, if $type=1 (see above), getMenuItems() will return an array. The array index equivalents of the menu items' properties are indicated in parentheses. Please note that if a propety is empty (including zero value), it will have no equivalent array index. For menu items returned as objects, the properties can be accessed using $menuItem->propertName. It is also possible to query menu items using their property names. For instance:
$items = $menu->find("parentID=10");
$item = $menu->get("id=5");
This option provides a powerful way to build complex navigation systems, for instance, mega menus, that provide more information to your web users than a simple menu. The option is only supported in getMenuItems(). To use it, pass an array to your $options as shown below.
The following Fieldtypes can be used in extra_fields:
The option extra_fields accepts an associative multi-dimensional array with named ProcessWire fields with options if applicable. Each inner array must have a name index whose value corresponds to the name of the ProcessWire field whose value to return for a given menu item.
getMenuItems() will return values of the named fields for each menu where applicable. For multi-lingual sites, the correct values for the current user's language are returned. For simpler fields, the single value is returned. For more complex fields (such as image fields), an array of items with values is returned.
Examples and options for all supported Fieldtypes are shown below.
FieldtypeDatetime fields can accept one string option, format. If this is not specified, the value of the field as returned by ProcessWire will be returned. This will be in accordance with the field's date output format. If specified, the value returned will be formatted as per the string in format, for instance d-m-Y.
Example
$options = array(
'extra_fields' =>array(
// example FieldtypeDatetime field
array('name'=>'date'),// e.g. $m->date
// example FieldtypeDatetime field with option
array('name'=>'date', 'format'=>'d/m/Y'),// e.g. ['date'] or $m->date
)
);
FieldtypeImage and FieldtypeFile fields will have their values returned as arrays irrespective of whether the fields are of type single or multiple files/images. The names (of the original image/file) and urls of images/files are always returned irrespective of the options below.
Available options (none need to be declared) for FieldtypeImage fields are:
Example
$options = array(
'extra_fields' =>array(
// example FieldtypeImage field with no options
array('name'=>'images'),// e.g. $m->images. (will return array with values for the first image)
// example FieldtypeImage field with options
array('name'=>'images','eq'=>2,'height'=>250),// returns the image at index 2 and sized at height 250px, width auto
// example FieldtypeImage field with options
array('name'=>'images','count'=>3,'height'=>200,'width'=>200),// returns the first 3 images and sized at height and width 200px
)
);
Available options (none need to be declared) for FieldtypeFile fields are:
Example
$options = array(
'extra_fields' =>array(
// example FieldtypeFile field (multi) with no options
array('name'=>'documents','count'=>5),// e.g. $m->documents. (will return array with values for the first 5 documents)
// example FieldtypeFile field (single) with options
array('name'=>'download','filesize_str'=>true,'description'=>1,'tags'=>true),// returns the file together with the file size, description and tags.
)
);
FieldtypePage will have their values returned as arrays irrespective of whether the fields are of type single or multiple pages. The titles and urls of pages are always returned irrespective of the options below.
Caution: Special attention should be paid to both the number of page items to return as well as the fields returned for those page items. The page items' fields may themselves be page reference fields. Failure to carefully consider the count of pages and/or the pages' fields can result in site performance issues (high memory usage, etc).
Available options (none need to be declared) for FieldtypePage fields are:
Example
$options = array(
'extra_fields' =>array(
// example FieldtypePage field (multi) without options
array('name'=>'countries'),// e.g. $m->countries (will return the first page)
// example FieldtypePage field (multi) with options
array(
'name'=>'countries',
'count' => 3,
// values of fields inside 'countries' pages to return
'fields' => array('population','gdp','summary'),
),// e.g. $m->countries (will return the first 3 pages values)
// example FieldtypePage field (single) without options
array('name'=>'city'),// e.g. ['city'] or $m->city
)
);
FieldtypeOptions will have their values returned as arrays irrespective of whether the fields are of type single or multiple options. The titles and ids of options are always returned irrespective of the options below.
Available options (none need to be declared) for FieldtypeOptions fields are:
Example
$options = array(
'extra_fields' =>array(
// example FieldtypeOptions field (single), no options
array('name'=>'option'),// e.g. $m->options (will return the id and the title of the selected option)
// example FieldtypeOptions field (multi) with option
array('name'=>'sizes', 'all_options'=>true, 'value'=>true),// e.g. $m->sizes (will return all selectable options as well as their value properties. The selected option will have an index [selected] with value 1)
)
);
FieldtypeTextLanguage, FieldtypeTextareaLanguage and FieldtypePageTitleLanguage fields will have their respective values returned according to the current user's langauge. Only the field names need to be specified. No other options are applicable. The values will be accessible as a property of a menu object (or an index in an array, see Properties above) in getMenuItems() as $m->nameOfField.
Example
$options = array(
'extra_fields' =>array(
// example FieldtypeTextLanguage field
array('name'=>'headline'),// e.g. $m->headline
// example FieldtypeTextareaLanguage field
array('name'=>'body'),// e.g. ['body'] or $m->body
)
);
Fields of type FieldtypeURL, FieldtypeCheckbox, FieldtypeEmail, FieldtypeInteger, FieldtypeFloat, FieldtypePageTitle, FieldtypeText and FieldtypeTextarea will have their values returned in their respective native formats.
Example
$options = array(
'extra_fields' =>array(
// example FieldtypeURL field
array('name'=>'web'),// e.g. $m->web
// example FieldtypeCheckbox field
array('name'=>'selected'),// e.g. ['selected'] or $m->selected
)
);
Below is an example countries trivia navigation using extra_fields in its $option. The output of the navigation is shown afterward.
$options = array(
'extra_fields' =>array(
// datetime
array('name'=>'visit','format'=>'d M Y'),
// checkbox
array('name'=>'safari'),
// float
array('name'=>'gdp'),
// image
array(
'name' => 'images',
'width' => 500,
'count' => 3,
'description' =>true,// or a truth value, e.g. 1
'tags' =>1,// or a truthy value, e.g. true
),
// page field
array(
'name'=>'cities',
'count'=>2,
'fields'=>array('summary','population','web')),
// options
array('name'=>'languages')
)
);
Below is the array output of the above example menu using extra_fields option.
(
[1] => Array
(
[pages_id] => 1279
[title] => South Africa
[url] => /mb-tests/country-facts/country-facts-countries/south-africa/
[is_first] => 1
[visit] => 16 Jan 2017
[safari] => 1
[gdp] => 6160.73
[images] => Array
(
[south_africa-1.jpg] => Array
(
[name] => south_africa-1.jpg
[description] => South Africa is a country on the southernmost tip of the African continent, marked by several distinct ecosystems. Inland safari destination Kruger National Park is populated by big game. The Western Cape offers beaches, lush winelands around Stellenbosch and Paarl, craggy cliffs at the Cape of Good Hope, forest and lagoons along the Garden Route, and the city of Cape Town, beneath flat-topped Table Mountain.
[tags] =>
[url] => /site-menubuilder/assets/files/1279/south_africa-1.500x0.jpg
)
[south_africa-2.jpg] => Array
(
[name] => south_africa-2.jpg
[description] =>
[tags] => Safari Delightful
[url] => /site-menubuilder/assets/files/1279/south_africa-2.500x0.jpg
)
[south_africa-3.jpg] => Array
(
[name] => south_africa-3.jpg
[description] =>
[tags] =>
[url] => /site-menubuilder/assets/files/1279/south_africa-3.500x0.jpg
)
)
[cities] => Array
(
[port-elizabeth] => Array
(
[title] => Port Elizabeth
[url] => /mb-tests/country-facts/country-facts-cities/port-elizabeth/
[population] => 312392
[web] => https://www.nmbt.co.za/
)
[soweto] => Array
(
[title] => Soweto
[url] => /mb-tests/country-facts/country-facts-cities/soweto/
[population] => 1271628
[web] => http://www.soweto.gov.za/
)
)
[languages] => Array
(
[1] => Array
(
[id] => 1
[title] => English
)
[2] => Array
(
[id] => 2
[title] => Tswana
)
[3] => Array
(
[id] => 3
[title] => Afrikaans
)
[4] => Array
(
[id] => 4
[title] => Zulu
)
[5] => Array
(
[id] => 5
[title] => Xhosa
)
[6] => Array
(
[id] => 6
[title] => Northern Sotho
)
[7] => Array
(
[id] => 7
[title] => Venda
)
[8] => Array
(
[id] => 8
[title] => Southern Sotho
)
[9] => Array
(
[id] => 9
[title] => Tsonga
)
[10] => Array
(
[id] => 10
[title] => Swati
)
[11] => Array
(
[id] => 11
[title] => Ndebele
)
)
)
[2] => Array
(
[pages_id] => 1262
[title] => China
[url] => /mb-tests/country-facts/country-facts-countries/china/
[visit] => 23 Sep 2021
[safari] => 1
[gdp] => 8826.99
[images] => Array
(
[china-1.jpg] => Array
(
[name] => china-1.jpg
[description] => China, officially the People's Republic of China, is a country in East Asia and is the world's most populous country, with a population of around 1.428 billion in 2017. Covering approximately 9,600,000 square kilometers, it is the third-largest or the fourth-largest country by area.
[tags] =>
[url] => /site-menubuilder/assets/files/1262/china-1.500x0.jpg
)
[china-2.jpg] => Array
(
[name] => china-2.jpg
[description] =>
[tags] =>
[url] => /site-menubuilder/assets/files/1262/china-2.500x0.jpg
)
[china-3.jpg] => Array
(
[name] => china-3.jpg
[description] =>
[tags] =>
[url] => /site-menubuilder/assets/files/1262/china-3.500x0.jpg
)
)
[cities] => Array
(
[wuhan] => Array
(
[title] => Wuhan
[url] => /mb-tests/country-facts/country-facts-cities/wuhan/
[population] => 11081000
[web] => http://www.wuhan.gov.cn/
)
[suzhou] => Array
(
[title] => Suzhou
[url] => /mb-tests/country-facts/country-facts-cities/suzhou/
[population] => 10721700
[web] => http://www.suzhou.gov.cn/
)
)
[languages] => Array
(
[12] => Array
(
[id] => 12
[title] => Mandarin
)
)
)
[3] => Array
(
[pages_id] => 1260
[title] => Canada
[url] => /mb-tests/country-facts/country-facts-countries/canada/
[visit] => 11 Jan 2020
[gdp] => 45032.1
[images] => Array
(
[canada-1.jpg] => Array
(
[name] => canada-1.jpg
[description] => The beauty that is Canada
[tags] =>
[url] => /site-menubuilder/assets/files/1260/canada-1.500x0.jpg
)
[canada-2.jpg] => Array
(
[name] => canada-2.jpg
[description] =>
[tags] =>
[url] => /site-menubuilder/assets/files/1260/canada-2.500x0.jpg
)
[canada-3.jpg] => Array
(
[name] => canada-3.jpg
[description] =>
[tags] => Travel Wow
[url] => /site-menubuilder/assets/files/1260/canada-3.500x0.jpg
)
)
[cities] => Array
(
[quebec-city] => Array
(
[title] => Quebec City
[url] => /mb-tests/country-facts/country-facts-cities/quebec-city/
[population] => 531902
[web] => https://www.ville.quebec.qc.ca/en/
)
[vancouver] => Array
(
[title] => Vancouver
[url] => /mb-tests/country-facts/country-facts-cities/vancouver/
[population] => 631486
[web] => https://vancouver.ca/
)
)
[languages] => Array
(
[1] => Array
(
[id] => 1
[title] => English
)
[13] => Array
(
[id] => 13
[title] => French
)
)
)
[4] => Array
(
[pages_id] => 1263
[title] => Switzerland
[url] => /mb-tests/country-facts/country-facts-countries/switzerland/
[gdp] => 80189.7
[images] => Array
(
[switzerland-2.jpg] => Array
(
[name] => switzerland-2.jpg
[description] =>
[tags] =>
[url] => /site-menubuilder/assets/files/1263/switzerland-2.500x0.jpg
)
[switzerland-3.jpg] => Array
(
[name] => switzerland-3.jpg
[description] =>
[tags] =>
[url] => /site-menubuilder/assets/files/1263/switzerland-3.500x0.jpg
)
[switzerland-1.jpg] => Array
(
[name] => switzerland-1.jpg
[description] => Switzerland is a mountainous Central European country, home to numerous lakes, villages and the high peaks of the Alps. Its cities contain medieval quarters, with landmarks like capital Bern’s Zytglogge clock tower and Lucerne’s wooden chapel bridge. The country is also known for its ski resorts and hiking trails. Banking and finance are key industries, and Swiss watches and chocolate are world renowned.
[tags] =>
[url] => /site-menubuilder/assets/files/1263/switzerland-1.500x0.jpg
)
)
[cities] => Array
(
[chur] => Array
(
[title] => Chur
[url] => /mb-tests/country-facts/country-facts-cities/chur/
[population] => 33373
[web] => http://www.chur.ch/
)
[st-gallen] => Array
(
[title] => St. Gallen
[url] => /mb-tests/country-facts/country-facts-cities/st-gallen/
[population] => 75806
[web] => http://www.stadt.sg.ch/
)
)
[languages] => Array
(
[13] => Array
(
[id] => 13
[title] => French
)
[14] => Array
(
[id] => 14
[title] => German
)
[15] => Array
(
[id] => 15
[title] => Italian
)
[16] => Array
(
[id] => 16
[title] => Romansh
)
)
)
[5] => Array
(
[pages_id] => 1261
[title] => USA
[url] => /mb-tests/country-facts/country-facts-countries/usa/
[is_last] => 1
[visit] => 08 Aug 2020
[gdp] => 59531.7
[images] => Array
(
[usa-1.jpg] => Array
(
[name] => usa-1.jpg
[description] => The U.S. is a country of 50 states covering a vast swath of North America, with Alaska in the northwest and Hawaii extending the nation’s presence into the Pacific Ocean.
[tags] =>
[url] => /site-menubuilder/assets/files/1261/usa-1.500x0.jpg
)
[usa-2.jpg] => Array
(
[name] => usa-2.jpg
[description] =>
[tags] =>
[url] => /site-menubuilder/assets/files/1261/usa-2.500x0.jpg
)
[usa-3.jpeg] => Array
(
[name] => usa-3.jpeg
[description] =>
[tags] => Mountains
[url] => /site-menubuilder/assets/files/1261/usa-3.500x0.jpeg
)
)
[cities] => Array
(
[seattle] => Array
(
[title] => Seattle
[url] => /mb-tests/country-facts/country-facts-cities/seattle/
[population] => 608660
[web] => http://www.seattle.gov/
)
[chicago] => Array
(
[title] => Chicago
[url] => /mb-tests/country-facts/country-facts-cities/chicago/
[population] => 2695598
[web] => http://chicago.gov/
)
)
[languages] => Array
(
[1] => Array
(
[id] => 1
[title] => English
)
)
)
)
The simplest way to render a menu is to use the method render(). It is straightforward and can be passed various options to customise your menu.
However, for the ultimate flexibility and total freedom, especially for complex menu structures, we recommend that you use the method getMenuItems(). Please note that the method getMenuItems() will not return a menu out of the box. Instead, it returns menu items that you can optionally manipulate, traverse using any recursive function (or for simpler menus, nested foreachs) and output within a HTML structure of your choosing. It means that you can apply logic within your chosen recursive function (or loop) to output extra details with your menu, for instance grab some data from a field within the pages that your menu items represent. Another example would be to show some parts of the menu only when a user is logged in, etc. If working with the Menu object, it means you can easily add properties to some or all of the menu items at runtime. It also means you have all the powerful WireArray methods at your disposal (don't touch sort though!).
// load the module
$menu = $modules->get('MarkupMenuBuilder');// $menu is an example
/**you can render by menu Page object, name, title, id or properly formatted array of menu items**/
// render by name, title or id
echo $menu->render('Title of Your Menu');// render the menu by title
echo $menu->render('name-of-your-menu');// render the menu by name
echo $menu->render('1234');//render by ID
// render by passing a Page object
$m = $pages->get(1234);
echo $menu->render($m);//render by Page object
// render by passing an array
// get the Menu Builder field menu_items for this menu. That is where your menu items JSON string is stored
$json = $pages->get(1234)->menu_items;
// convert the JSON string to an array. Here we assume the JSON string is not empty
$array = json_decode($json, true);
echo $menu->render($array);//render by array
You can render additional menus as well, e.g.
echo $menu->render('sidenav');
You can additionally pass CSS class/id options to the method. See above for available options.
$options = array(
'has_children_class' => 'has_children',
'current_class' => 'current',
'menu_css_id' => 'main',
'menu_css_class' => 'nav',
);
echo $menu->render('sidenav', $options);
Examples of more complex menus utilising the method getMenuItems() using various recursive menu functions can be seen at these gists.
Rendering breadcrumbs is quite similar to the above, the only difference being the method you use and some of the options that can be used to configure the output.
// load the module
$menu = $modules->get('MarkupMenuBuilder');// $menu is an example
/**you can render by menu Page object, name, title, id or properly formatted array of menu items**/
// render by name, title or id
echo $menu->renderBreadcrumbs('Title of Your Menu');// render the menu by title
echo $menu->renderBreadcrumbs('name-of-your-menu');// render the menu by name
echo $menu->renderBreadcrumbs('1234');// render by ID
// render by passing a Page object
$m = $pages->get(1234);
echo $menu->renderBreadcrumbs($m);
// render by passing an array
// get the Menu Builder field menu_items for this menu. That is where your menu items JSON string is stored
$json = $pages->get(1234)->menu_items;
// convert the JSON string to an array. Here we assume the JSON string is not empty
$array = json_decode($json, true);
echo $menu->renderBreadcrumbs($array);// render by array
Additionally, you can pass some options to the method. See above for available options.
$options = array(
'wrapper_list_type' => 'div',
'list_type' => 'span',
//'list_type' => '',// if empty, no tag will be applied + no CSS ID
'menu_css_id' => 'crumbs',
'menu_css_class' => 'trail',
'current_css_id' => 'current',
'divider' => '*',
'prepend_home' => 1
);
echo $menu->renderBreadcrumbs(1234, $options);
This is a flexible and powerful feature that you can leverage to produce all sorts of dynamic navigation for your ProcessWire website. With lots of power comes responsibility. The features should only be enabled (see relevant permission below) for users who know what they are doing. For example, a user could unknowingly use the feature to include descendant pages of a menu item that has hundreds of descendants, leading to undesirable effects.
At the global/menu/API-level, the following values can be passed with 'include_children'. This is useful if you want to override some item-level settings. The priority order of the settings and in comparison to item-level settings are explained further below.
At the local/admin/item-level, the following values can be saved with each navigation item either when creating or editing the menu item in the Menu Builder admin. This is useful when you want fine-grained control over 'include_children' output. The priority order of the settings and in comparison to menu-level settings are explained later below.
The combined (menu- and item-level) order of descending priority (i.e. a setting cannot override the setting above it) for these 'include_children' settings is as follows:
As a sanity check, in the Menu Builder admin, a navigation item made up of your ProcessWire 'homepage' cannot have its children included/excluded since it is the parent of all pages. In addition, you will only see 'include_children' inputs in the Menu Builder admin when both the feature is enabled and you have the permission menu-builder-include-children (or are a superuser; more below under Permissions). Finally, note that if a user without this permission edits a menu that was previously edited by a user with the permission, any 'include_children' item-level settings will be lost.
Note that you are not limited to using MarkupMenuBuilder. You can also use your own PHP (or even JavaScript) recursive function to display your menu by decoding the saved JSON string containing menu items and passing the resulting array to your function for traversal. The CSS is up to you, of course. Here's a nice example from a forum member. However, It is preferable to use getMenuItems() as shown above.
By default, if using AsmSelect or PageAutocomplete to select pages to add to your menu, the module will return a maximum of 50 pages. In that case, you might run into the 'not all my selectable pages are displayed issue'. You have two choices to resolve this. One, use PageListSelectMultiple instead. Alternatively, add a custom selector in the text field 'Pages selectable in menu' (main tab). For instance, limit=50. Or limit=50, sort=title or any other valid ProcessWire selector. You will either need to be logged in as a superuser or have the permission menu-builder-selectable in order to do this.
You can use the following permissions to control visibility and access to various advanced settings of Menu Builder by non-superusers. In ProcessWire, by default, Superusers inherit all permissions. Note that you will have to create and apply the permissions yourself using the normal ProcessWire way, i.e.
There are 9 permissions at your disposal for fine-grained access control of your Menu Builder admin.
menu-builder-lock This permission allows your non-superusers to lock and unlock menus using the 'Actions Panel' in Menu Builder's admin main page. Note two things: (i) This permission takes a whitelist approach. If this permission does not exist on your system (i.e. has not yet been created or is present but unpublished), by default, all users will be able to lock/unlock menus. (ii) The permission only kicks in if it is found. In that case, users without the permission will not be able to lock/unlock menus.
menu-builder-delete This permission allows your non-superusers to trash and delete menus using either the 'Actions Panel' in Menu Builder's admin main page or, when editing a single menu, via the 'Delete' tab. Note two things: (i) This permission takes a whitelist approach. If this permission does not exist on your system (i.e. has not yet been created or is present but unpublished), by default, all users will be able to trash and delete menus. (ii) The permission only kicks in if it is found. In that case, users without the permission will not be able to trash or delete menus.
menu-builder-selector This permission allows your non-superusers to add ProcessWire pages as menu items using a ProcessWire selector. This permission (and all the rest below) takes a blacklist approach. The permission does not need to exist in your system to kick in and by default all non-superusers are not able to add pages as menu items using selectors. This means that if you intend that only superusers will be allowed to use selectors in this manner, there is no need to create the permission. Only create and apply it if you wish to grant a particular non-superuser this feature. The same applies to all the following permissions.
menu-builder-selectable This permission allows non-superusers to specify ProcessWire pages that are selectable as menu items in either of two configurable page fields in Menu Builder, i.e. AsmSelect or PageAutocomplete (BUT not PageListSelectMultiple).
menu-builder-markup This permission allows your non-superusers to allow/disallow the use of markup/HTML in menu item titles/labels.
menu-builder-settings This permission allows non-superusers to edit nestedSortable settings, for instance set maxLevels (that controls number of nesting levels in a menu).
menu-builder-page-field This permission allows non-superusers to change the page field type used to select ProcessWire pages to add as menu items, i.e. toggle between AsmSelect [default], PageAutocomplete or PageListSelectMultiple.
menu-builder-include-children This permission allows non-superusers to set and use the include children feature.
menu-builder-disable-items This permission allows non-superusers to set and use the disable menu items feature.
menu-builder-multi-lingual-items This permission allows non-superusers to set and use the multi-lingual menu items feature (available only on multi-lingual sites).
Uninstall like any other ProcessWire module. Note that All your menus will be deleted on uninstall!. The associated fields and template above will also be deleted.
GPL2
Initial alpha release