Unlimited page depth to array

This code work but is really messy:

foreach( $children as  $item ) {
    $data = array(
        'title' => $item->title()->value(),
        'template' => $item->template()
    );

    if( $item->depth() == 2) {
        $this->data[$item->uri()] = $data;
    } elseif( $item->depth() == 3) {
        $this->data[$item->parent()->uri()][$item->uri()] = $data;
    } elseif( $item->depth() == 4) {
        $this->data[$item->parent()->parent()->uri()][$item->uri()] = $data;
    }
}

I’ve tried many times to make this a kind of recursive function to create an unlimited hierachy array. I gave up. How is it done?

Result

My result from above, it has 2 levels but in a perfect scenario it should have unlimited levels.

    [categories/custom] => Array
        (
            [title] => title
            [template] => category-custom
        )

    [categories/leggings] => Array
        (
            [title] => another title
            [template] => category
            [categories/leggings/undersida] => Array
                (
                    [title] => subtitle
                    [template] => sub-category
                )

        )

Unlimited might be the wrong word because it’s still limited by the page depth.

I think a function like this require more brain power than I have. So if you want a challange…

Absolutely not sure about this but I think you can use some sort of recursive function.

function checkChildren($initialPage) {
    if (!$initialPage->hasChildren()) :
        // Do Something if you reached the end of the tree
    else :
        foreach ($initialPage->children() as $subPage) :
            checkChildren($subPage);
        endforeach;
    endif;
}

foreach ($site->children() as $entry) {
   checkChildren($entry);
}
1 Like

I am unsure if this answer actually answered the OP, but it did help me with a similar question:

How to iterate through a pages tree of unknown depth ?

So thank you @manuelmoreale !

I’d like to add that the final foreach may be redundant. If I understand it correctly, every page is a subpage of $site isn’t it ?

Then wouldn’t it give the same results to start iterating $site directly using your function, instead of using a foreach to get $site’s children, then iterate each children using your function? I mean:

checkChildren($site);

…instead of:

foreach ($site->children() as $entry) {
  checkChildren($entry);
}
1 Like

If i remember correctly in kirby core there is class Children that does recursive indexing (index() is defined there i think).

Maybe you should look how kirby is doing it.

You’re welcome. As @krisa pointed out, there are probably some native functionalities in kirby that you can use. Mine was just a generic answer :wink:

Because I did not reply to this I probably went for a different solution. Nowdays I’m much better at recursive functions and snippets as I need it in my plugin that I’m developing right now.

Anyway, it looks alot like @manuelmoreale suggestion, but like @plagasul said, no loop before the function call is needed if done well.

1 Like

Just for completeness, I believe this is the code @krisa refers to, found at kirby’s github core/children.php class file, where ‘index()’ is defined.

   /**
   * Creates a clean one-level collection with all
   * pages, subpages, subsubpages, etc.
   *
   * @param object Pages object for recursive indexing
   * @return Children
   */
  public function index(Children $obj = null) {
    if(is_null($obj)) {
      if(isset($this->cache['index'])) return $this->cache['index'];
      $this->cache['index'] = new Children($this->page);
      $obj = $this;
    }
    foreach($obj->data as $key => $page) {
      $this->cache['index']->data[$page->uri()] = $page;
      $this->index($page->children());
    }
    return $this->cache['index'];
  }

More complex than expected :smiley: