*/ class RecursiveMenuIterator implements RecursiveIterator { public $items; private $current = 0; /** * Create a new RecursiveMenuIterator instance. * * @param string $menu menu to get items of */ public function __construct($menu) { if (is_string($menu)) { $menu = wp_get_nav_menu_object(get_nav_menu_locations()[$menu]); // Wordpress is nice and will always place children below parents so we can easily create a tree out of it $items = collect(wp_get_nav_menu_items($menu))->keyBy('ID')->reverse(); $itemsArray = $items->all(); foreach ($itemsArray as $id => $item) { $itemsArray[$id]->children = $items->where('menu_item_parent', $id)->values(); } // only have nodes without a parent at the top level of the tree $this->items = collect($itemsArray)->filter(function ($item) { return $item->menu_item_parent === 0 || $item->menu_item_parent === '0'; })->reverse()->values(); } else { $this->items = $menu; } } /** * Return the current element. * * @link http://php.net/manual/en/iterator.current.php * * @return \WP_Post Can return any type. * * @since 5.0.0 */ public function current() { return $this->items[$this->current]; } /** * Move forward to next element. * * @link http://php.net/manual/en/iterator.next.php * * @return void Any returned value is ignored. * * @since 5.0.0 */ public function next() { $this->current++; } /** * Return the key of the current element. * * @link http://php.net/manual/en/iterator.key.php * * @return mixed scalar on success, or null on failure. * * @since 5.0.0 */ public function key() { return $this->current; } /** * Checks if current position is valid. * * @link http://php.net/manual/en/iterator.valid.php * * @return bool The return value will be casted to boolean and then evaluated. * Returns true on success or false on failure. * * @since 5.0.0 */ public function valid() { return isset($this->items[$this->current]); } /** * Rewind the Iterator to the first element. * * @link http://php.net/manual/en/iterator.rewind.php * * @return void Any returned value is ignored. * * @since 5.0.0 */ public function rewind() { $this->current = 0; } /** * Returns if an iterator can be created for the current entry. * * @link http://php.net/manual/en/recursiveiterator.haschildren.php * * @return bool true if the current entry can be iterated over, otherwise returns false. * * @since 5.1.0 */ public function hasChildren() { return !$this->current()->children->isEmpty(); } /** * Returns an iterator for the current entry. * * @link http://php.net/manual/en/recursiveiterator.getchildren.php * * @return RecursiveIterator An iterator for the current entry. * * @since 5.1.0 */ public function getChildren() { return new static($this->current()->children); } }