基于WordPress的Corcel/Laravel多级菜单生成问题
Hey there! Let's tackle this multi-level menu issue with Corcel together. That error you're seeing usually happens because you're trying to add items to a null collection—meaning you didn't initialize the child items container for your menu entries first. Let's walk through the correct implementation step by step.
Why the error happens
The official docs mention grouping items by parent ID, but they don't explicitly cover initializing the children collection for each menu item. When you try to push a child item to a parent that doesn't have a pre-defined children property (which defaults to null), you get the offsetSet() on null error.
Correct implementation code
Here's a complete, working example to build your multi-level menu:
// Fetch the main menu by location $menu = Menu::location('main')->first(); // Handle case where the menu doesn't exist if (!$menu) { return collect(); } // First, store all menu items in an array keyed by their ID for quick lookup $allMenuItems = []; foreach ($menu->items as $item) { // Initialize the children collection for each item to avoid null errors $item->children = collect(); $allMenuItems[$item->ID] = $item; } // Build the hierarchical menu structure $menuTree = collect(); foreach ($allMenuItems as $item) { if ((int)$item->menu_item_parent === 0) { // Top-level items (parent ID 0) go directly into the main tree $menuTree->push($item); } else { // Find the parent item and add this item to its children collection if (isset($allMenuItems[$item->menu_item_parent])) { $allMenuItems[$item->menu_item_parent]->children->push($item); } } } // Now $menuTree holds your multi-level menu structure!
Key fixes in this code:
- Initializing
childrencollection: We explicitly set$item->children = collect();for every menu item, so we never try to push to anullvalue. - Quick parent lookup: Storing items in an array keyed by ID makes finding parent items O(1) instead of looping through the collection every time, which is more efficient.
- Error handling: We check if the menu exists first to avoid unexpected issues if the menu location is misconfigured.
Rendering the menu (example with Blade)
Once you have $menuTree, you can render it recursively with a Blade template:
Main menu template
<ul class="main-menu"> @foreach($menuTree as $item) <li class="menu-item"> <a href="{{ $item->url }}">{{ $item->title }}</a> <!-- Render submenu if there are children --> @if($item->children->isNotEmpty()) @include('partials.submenu', ['items' => $item->children]) @endif </li> @endforeach </ul>
Submenu partial (resources/views/partials/submenu.blade.php)
<ul class="submenu"> @foreach($items as $item) <li class="submenu-item"> <a href="{{ $item->url }}">{{ $item->title }}</a> <!-- Recursively render nested submenus --> @if($item->children->isNotEmpty()) @include('partials.submenu', ['items' => $item->children]) @endif </li> @endforeach </ul>
This approach will handle any depth of nested menus, and you won't run into that offsetSet() error anymore.
内容的提问来源于stack exchange,提问作者Max

