/**
  * @param Page[]|MenuItem[] $items
  * @param int $parentPageId
  * @param int $level
  * @param int $subLevels
  * @return string
  */
 protected static function _buildMenu($items, $parentPageId, $level = 1, $subLevels = 0)
 {
     // convert page models to menu items and remove non-live pages
     foreach ($items as $k => $item) {
         if (is_a($item, Page::class)) {
             $pageId = $item->id;
             $items[$k] = new MenuItem();
             $items[$k]->page_id = $item->id;
             $items[$k]->sub_levels = 0;
             $items[$k]->custom_name = '';
         } else {
             $pageId = $item->page_id;
         }
         $pageId = Path::unParsePageId($pageId);
         $page = Page::preload($pageId);
         if (!$page->exists || !$page->is_live()) {
             unset($items[$k]);
         }
     }
     $pageParents = [];
     $pageLevels = PageBuilder::getData('pageLevels') ?: [];
     foreach ($pageLevels as $k => $parentPage) {
         if ($k > 0) {
             $pageParents[] = $parentPage->page_id;
         }
     }
     $currentPage = PageBuilder::getData('page') ?: new Page();
     $total = count($items);
     $menuItems = '';
     $defaultSubLevels = $subLevels;
     if (is_a($items, Collection::class)) {
         $items = $items->all();
     }
     $items = array_values($items);
     foreach ($items as $count => $item) {
         $isFirst = $count == 0;
         $isLast = $count == $total - 1;
         $pageId = Path::unParsePageId($item->page_id);
         $active = $currentPage->id == $pageId || in_array($pageId, $pageParents);
         $itemData = new MenuItemDetails($item, $active, $parentPageId, self::$_canonicals);
         $subMenu = '';
         $subLevels = $item->sub_levels > 0 ? $item->sub_levels : $defaultSubLevels;
         if ($subLevels > 0) {
             if ($subPages = Page::category_pages($pageId)) {
                 $subMenu = self::_buildMenu($subPages, $pageId, $level + 1, $subLevels - 1);
             }
         }
         if (!empty($subMenu)) {
             $menuItems .= self::_getRenderedView('submenu_' . $level, ['item' => $itemData, 'items' => $subMenu, 'is_first' => $isFirst, 'is_last' => $isLast, 'count' => $count + 1, 'total' => $total, 'level' => $level, 'further_levels' => $subLevels]);
         } else {
             $menuItems .= self::_getRenderedView('item', ['item' => $itemData, 'is_first' => $isFirst, 'is_last' => $isLast, 'count' => $count, 'total' => $total, 'level' => $level]);
         }
     }
     if ($level == 1) {
         return self::_getRenderedView('menu', ['items' => $menuItems]);
     } else {
         return $menuItems;
     }
 }
 /**
  * @param string|array $blockName
  * @param string|array $search
  * @param array $options
  * @return string
  */
 public function categoryFilter($blockName, $search, $options = [])
 {
     $pageId = !empty($options['page_id']) ? $options['page_id'] : $this->pageId();
     if ($pageId) {
         $options['fromPageIds'] = [];
         $categoryPages = Page::category_pages($pageId, true);
         foreach ($categoryPages as $categoryPage) {
             $options['fromPageIds'][] = $categoryPage->id;
         }
         return $this->filter($blockName, $search, $options);
     }
     return '';
 }