Overview
The MenuItem model represents individual items within navigation menus. It supports hierarchical menu structures through parent-child relationships, allowing you to create nested submenus.
Namespace: App\Models\MenuItem
File: app/Models/MenuItem.php:7
Properties
Fillable attributes
The ID of the parent menu
The display text for the menu item
The URL or route the menu item links to
The ID of the parent menu item (null for top-level items)
The sort order within the menu (lower numbers appear first)
Relationships
Belongs to relationship with the Menu model.
Returns: BelongsTo<Menu>
$menuItem = MenuItem :: find ( 1 );
$menu = $menuItem -> menu ;
parent()
Belongs to relationship for the parent menu item.
Returns: BelongsTo<MenuItem>
$menuItem = MenuItem :: find ( 5 );
$parent = $menuItem -> parent ; // null if top-level item
children()
Has many relationship for child menu items. Children are automatically ordered by their order field.
Returns: HasMany<MenuItem>
$menuItem = MenuItem :: find ( 1 );
$children = $menuItem -> children ; // Ordered by 'order' column
// Check if item has children
if ( $menuItem -> children -> count () > 0 ) {
// Has submenu
}
Usage examples
// Create top-level menu item
$homeItem = MenuItem :: create ([
'menu_id' => 1 ,
'label' => 'Home' ,
'url' => '/' ,
'parent_id' => null ,
'order' => 1
]);
// Create child menu item
$aboutTeamItem = MenuItem :: create ([
'menu_id' => 1 ,
'label' => 'Our Team' ,
'url' => '/about/team' ,
'parent_id' => $aboutItem -> id ,
'order' => 1
]);
// Get all top-level items with children
$menuItems = MenuItem :: where ( 'menu_id' , 1 )
-> whereNull ( 'parent_id' )
-> with ( 'children' )
-> orderBy ( 'order' )
-> get ();
// Recursive loading of all levels
$menuItems = MenuItem :: where ( 'menu_id' , 1 )
-> whereNull ( 'parent_id' )
-> with ( 'children.children' ) // Load grandchildren
-> orderBy ( 'order' )
-> get ();
// Update order for multiple items
$updates = [
[ 'id' => 1 , 'order' => 2 ],
[ 'id' => 2 , 'order' => 1 ],
[ 'id' => 3 , 'order' => 3 ]
];
foreach ( $updates as $update ) {
MenuItem :: where ( 'id' , $update [ 'id' ])
-> update ([ 'order' => $update [ 'order' ]]);
}
<!-- Recursive Blade component: resources/views/components/menu-items.blade.php -->
@foreach ( $items as $item )
< li >
< a href = " {{ $item -> url }} " class = "menu-link" >
{{ $item -> label }}
</ a >
@if ( $item -> children -> count () > 0 )
< ul class = "submenu" >
< x-menu-items :items = " $item -> children " />
</ ul >
@endif
</ li >
@endforeach
Breadcrumb generation
// Get breadcrumb trail for a menu item
function getBreadcrumbs ( MenuItem $item ) : array
{
$breadcrumbs = [ $item ];
$current = $item ;
while ( $current -> parent ) {
$current = $current -> parent ;
array_unshift ( $breadcrumbs , $current );
}
return $breadcrumbs ;
}
$breadcrumbs = getBreadcrumbs ( MenuItem :: find ( 10 ));
Database schema
Based on migration 2025_05_25_175649_create_menu_items_table.php, the menu_items table contains:
id - Primary key
menu_id - Foreign key to menus table
label - Display text (string)
url - Link URL (string)
parent_id - Foreign key to menu_items (nullable)
order - Sort order (integer)
created_at - Timestamp
updated_at - Timestamp
Additional fields
You can extend the MenuItem model to include:
icon - Icon class or name
target - Link target (_self, _blank)
css_class - Custom CSS classes
active - Enable/disable menu item
permission - Required permission to view
When adding new fields, remember to update the $fillable array and create a migration.
Best practices
When deleting menu items with children, decide whether to also delete children or reassign them. Consider using database cascading deletes or a model observer.
Be careful with deeply nested menus (more than 3 levels) as they can be difficult to navigate on mobile devices.
Menu model View Menu model documentation
Menu feature Learn about the menu management feature