В целом задача с неограниченно вложенностью решается рекурсией.
Вот сильно упрощенный и безбожно порезанный код, который собирает и выводит дерево. Использовать его в таком виде толку мало, но суть будет ясна.
class NavWidget extends Widget
{
public $items = [];
/**
* Renders the menu.
*/
public function run()
{
$items = $this->items;
if (!empty($items)) {
echo Html::tag('ul', $this->renderItems($items));
}
}
protected function renderItems($items)
{
$lines = [];
foreach ($items as $item) {
$menu = $this->renderItem($item);
if (!empty($item['items'])) {
$menu .= Html::tag('ul', $this->renderItems($item['items']));
}
$lines[] = Html::tag('li', $menu);
}
return implode("\n", $lines);
}
protected function renderItem($item)
{
$link = 'Тут собранная ссылка';
return $link;
}
}
P.S. А вообще, всё отлично видно и понятно в стандартных виджетах типа yii\widgets\Menu и в данном случае он всё это сделает прекрасно. Если что-то надо изменить, можно от него унаследоваться.