MenuAPI Module
This module provides an abstraction layer for getting and setting menu items. Default menu trees are in Config/menu_trees.php. This module gets loaded first (see module.json priority) and creates a new MenuRepository as a singleton in the service provider. Other modules and app can then get/set/add to menu trees in a dedicated definition file under Plugins/MenuLinks.
NOTE: If your module has a priority lower than -1000 (this module priority), you won't be able to access the default menu_trees provided by this module.
Menu trees
The following trees are available:
- frontend_main
- frontend_footer
- dash
Menu definitions
Menu definitions should:
- Be located under
app/Plugins/MenuLinksorModules/[ModuleName]/Plugins/MenuLinks - Extend
Modules/MenuApi/Plugins/MenuLinks/BaseMenuDefinitionthat implementsModules/MenuApi/Contracts/MenuDefinitionInterface - Define links in their constructor by calling
$this->menu()->...
Examples
Anatomy of a menu link
$link = [
'label' => 'Link label',
'href' => 'Url for link (only used if route unavailable)',
'route' => 'a.route.name',
'params' => ['params' => 'if', 'route' => 'used'],
'icon' => 'a-district-icon-code',
'children' => ['array of child links'],
'permission' => 'can do permission',
'addToChildren' => false, // VerticalMenu: Prepend parent to children it has any, default is true.
];
Adding a link to a menu via a menu definition.
class MenuDefinition extends \Modules\MenuApi\Plugins\MenuLinks\BaseMenuDefinition
{
public function __construct() {
// Add a link to the end of the `dash` tree.
$this->menu()->addToMenuTree(MenuService::TREE_NAME_DASH, [
'route' => 'dashboard.example_module.index',
'icon' => 'icon-name',
'title' => 'Example',
]);
// Add breadcrumbs.
}
}
Updating a tree via via a menu definition..
class MenuDefinition extends \Modules\MenuApi\Plugins\MenuLinks\BaseMenuDefinition
{
public function __construct() {
// Remove first link in the `dash` tree.
$tree = $menuProvider->getMenuTreeCurrentState('dash');
unset($tree[0]);
$this->menu()->setMenuTree('dash', $tree);
}
}
Config overrides
Possible to override the menu_trees config at app level that will override the starter menus and menu list.
Breadcrumbs
Breadcrumbs are defined in a very similar way to menu links. A repository is used to cache all breadcrumb definitions and the current matching breadcrumbs are added to the page props so they can be rendered by the frontend.
Anatomy of the breadcrumb map
Breadcrumb map is keyed by the uri pattern that should match the current page with the value being an array of links (see menu link structure above).
[
'path/that/matches/current/uri' => [$breadcrumbLink, $breadcrumbLink, $breadcrumbLink],
'path/with/exact/{model}/uri/match' => [$breadcrumbLink, $breadcrumbLink, $breadcrumbLink],
'path/with/wildcard/*/uri/match' => [$breadcrumbLink, $breadcrumbLink, $breadcrumbLink],
]
Matching uris
- A full uri match is first the preference. See
php artisan route:listorrequest()->route()->uri()for what this might look like for a given page. Egdash/pages/{page}will match on that route exactly. - A fallback is a wildcard match, this is useful when many pages have the same breadcrumbs. Eg.
dash/pages/*will matchdash/page/1,dash/page/1/edit, etc
To get the current crumbs for the given url you can:
MenuService::getBreadcrumbsForUri(request()->route()->uri())
Getting current breadcrumbs in the frontend
The current matching breadcrumbs are passed to the frontend via global props and can be accessed with
this.$page.props.district.Breadcrumbs
If no breadcrumbs are found, this prop should still exist but be an empty array.
Defining breadcrumbs in your module
Breadcrumbs are defined in a MenuDefinition plugin (along with menu links as described above). An example of defining breadcrumbs for a path is
class MenuDefinition extends \Modules\MenuApi\Plugins\MenuLinks\BaseMenuDefinition
{
public function __construct() {
// Define breadcrumbs for `path/to/*/content/*`
$this->breadcrumbs()->setBreadcrumbs('path/to/*/content/*', [
[
'route' => 'dashboard.example_module.index',
'title' => 'Crumb 1',
],
[
'route' => 'dashboard.example_module.index',
'title' => 'Crumb 2',
],
]);
// Add menu links.
}
}
There are many more helpers other than setBreadcrumbs, see BreadcrumbProvider for docs.
Using context in breadcrumbs
Often breadcrumbs need to have context, eg showing the current model/url or the current models parent.
Eg. If you are on a survey that has a parent, you probably want Parents > parent > surveys. In this case parent will be dynamic and need context.
To use context, add a key to the link type with value of context, then for the title and href of the link, add the Json path to get that value from this.$page.props.
Example of defining breadcrumbs that have a dynamic context
class MenuDefinition extends \Modules\MenuApi\Plugins\MenuLinks\BaseMenuDefinition
{
public function __construct() {
// Define breadcrumbs for `path/to/*/content/*`
$this->breadcrumbs()->setBreadcrumbs('path/to/*/content/*', [
// Default static crumb.
[
'route' => 'dashboard.example_module.index',
'title' => 'Crumb 1',
],
// The below crumb will populate from the page props.
[
'type' => 'context',
'title' => 'parentableModel.title',
'href' => 'parentableModel.action_urls.show',
],
]);
// Add menu links.
}
}
This should result in something like below when on path/to/*/content/*
this.$page.props.district.Breadcrumbs === [
{title: 'Crumb 1', route: 'dashboard.example_module.index'},
{title: 'Parentable model title', href: `parentable/model/url`}
]