Nested list of every page

Hello,

I’m quite new with Kirby and PHP, but I want to create a nested HTML list of every page on my site. The problem is that the nested list I find here, is only generating a list of pages and its subpages.

I’m looking for a way to create a list that goes as deep as it has to. So in case there are 10 levels depth of sub sub sub sub sub pages etc, it will work anyway. Kirby’s nested menu code only goes 2 levels deep.

How can I achieve this?

Thanks

Use the treemenu instead: https://getkirby.com/docs/cookbook/templating/menus#tree-menu

Thanks for your response.

While your response did answer my questions, it doesn’t work in my case.

I need my list to be output as similar to:

  <li><a href="#">± Book 1</a><ul style="display: none;">
      <li><a href="someHref">Chapter 1</a></li>
      <li><a href="someHref">Chapter 2</a></li>
      <li><a href="someHref">Chapter 3</a></li>
      <li><a href="someHref">Chapter 4</a></li>
    </ul>
  </li>
  <li><a href="#">± Book 2</a><ul style="display: none;">
      <li><a href="someHref">Chapter 1</a></li>
      <li><a href="someHref">Chapter 2</a></li>
      <li><a href="#">± Chapter 3</a><ul style="display: none;">
          <li><a href="listCollapseExample.html">Ex 1</a></li>
          <li><a href="someHref">Ex 2</a></li>
        </ul>
      </li>
      <li><a href="javascript:notA();">Chapter 4</a></li>
    </ul>
  </li>
  <li><a href="#">± Book 3</a><ul style="display: none;">
      <li><a href="someHref">Chapter 1</a></li>
      <li><a href="someHref">Chapter 2</a></li>
      <li><a href="someHref">Chapter 3</a></li>
      <li><a href="someHref">Chapter 4</a></li>
    </ul>
  </li>

The tree menu returns:

It’s important since I’m using another script that takes an html list (like the first one I wrote) and turns it into a collapsible list. So essentially now I’m not receiving the right format from the tree menu, possibly because it’s recursive (?).

Any ways to get the format of the list right?

Thanks

There’s something wrong with your snippet, why would you get all these script tags and multiple nav elements? That’s not what the treemenu creates… You are probably using it wrong?

Also, your HTML is missing a ul wrapper, what you posted above is not valid HTML…

Thanks for your response.

My HTML was just the console output from writing the .innerHTML of the main UL. Sorry if that was unclear. The point was this format of a list anyway, the way it’s structured.

Regarding the image I embedded, which showed the result from me using the tree menu. Here’s the full code from my treemenu.php that outputs that image (it doesn’t really matter if I output innerHTML of ID “theTree” or ID “someID”, still doesn’t output a clean format):

<nav class="nav" id="theTree">
<?php if(!isset($subpages)) $subpages = $site->children() ?>
<ul class="collapsibleList" id="someID">
  <?php foreach($subpages->listed() as $p): ?>
  <li class="depth-<?= $p->depth() ?>">
    <a<?php e($p->isActive(), ' class="active"') ?> href="<?= $p->url() ?>"><?= $p->title()->html() ?></a>
    <?php if($p->hasChildren()): ?>
    <?php snippet('treemenu', ['subpages' => $p->children()]) ?>
    <?php endif ?>
  </li>
  <?php endforeach ?>
</ul>
</nav>


<script type="text/javascript">
    var theSomeID = document.getElementById('theTree');
    
window.onload = function () {
    compactMenu('someID',false,'&plusmn; ');
    stateToFromStr('someID',retrieveCookie('menuState'));
    setTimeout(writeID,1000);
}
window.onunload = function () {
    setCookie('menuState',stateToFromStr('someID'));
}

function writeID(){
    console.log(""+theSomeID.innerHTML);
}
</script>

As I said, the nav element and the script should definitely not be part. of your snippet, otherwise they are also called recursively which doesn’t make sense at all.

This is the HTML produced by the treemenu when used correctly:

<ul>
    <li class="depth-1">
    <a href="http://mmm.test/en/photography">Photography</a>
        <ul>
    <li class="depth-2">
    <a href="http://mmm.test/en/photography/desert">desert</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/photography/mountains">Mountains</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/photography/ocean">Ocean</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/photography/plants">Plants</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/photography/sky">Sky</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/photography/trees">Trees</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/photography/waterfall">Waterfall</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/photography/landscape">Landscape</a>
      </li>
  </ul>      </li>
    <li class="depth-1">
    <a href="http://mmm.test/en/notes">Notes</a>
        <ul>
    <li class="depth-2">
    <a href="http://mmm.test/en/notes/across-the-ocean">Across the ocean</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/notes/a-night-in-the-forest">A night in the forest</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/notes/in-the-jungle-of-sumatra">In the jungle of Sumatra</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/notes/through-the-desert">Through the desert</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/notes/himalaya-and-back">Himalaya and back</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/notes/chasing-waterfalls">Chasing waterfalls</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/notes/exploring-the-universe">Exploring the universe</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/notes/test-me">Test me</a>
      </li>
  </ul>      </li>
    <li class="depth-1">
    <a href="http://mmm.test/en/about">About us</a>
      </li>
    <li class="depth-1">
    <a href="http://mmm.test/en/tag-manager">Tag Manager</a>
      </li>
    <li class="depth-1">
    <a href="http://mmm.test/en/comments">comments</a>
        <ul>
    <li class="depth-2">
    <a href="http://mmm.test/en/comments/testcomment1">New comment</a>
      </li>
    <li class="depth-2">
    <a href="http://mmm.test/en/comments/testcomment2">New comment</a>
      </li>
  </ul>      </li>
  </ul>

Thanks for your help. I got this part working.

I’m aware we are heading away from my initial question, but I have noticed that I now have a problem which is that LI items that contain subpages still has a link. For my collapsing script to work it needs the following format:

> <ul id="someID">
>   <li>Book 1
>     <ul>
>       <li><a href="someHref">Chapter 2</a></li>
>       <li><a href="someHref">Chapter 3</a></li>
>       <li><a href="someHref">Chapter 4</a></li>
>     </ul>
>   </li>
> </ul>

In my output, every LI item has a link to its page, which breaks the script. Only the final level of each branch should have the link. So essentially, LI items either will act as a “folder” (with no link) if it contains sub levels, or as “content” with a link to its page if it has no sub levels.

Any way to achieve this? Thanks a lot

Then you have to check if a page has subpages first and only add a link if not, otherwise use a li without a link.

<?php if(!isset($subpages)) $subpages = $site->children() ?>
<ul>
  <?php foreach($subpages->listed() as $p): ?>
  <li class="depth-<?= $p->depth() ?>">
     <?php if($p->hasChildren() === false): ?>
    <a<?php e($p->isActive(), ' class="active"') ?> href="<?= $p->url() ?>"><?= $p->title()->html() ?></a>
     <?php else: ?>
        <?= $p->title()->html() ?>
     <?php endif ?>
    <?php if($p->hasChildren()): ?>
    <?php snippet('treemenu', ['subpages' => $p->children()]) ?>
    <?php endif ?>
  </li>
  <?php endforeach ?>
</ul>
1 Like

Nice! It works as it should now I believe :-). And I learned a bit of php on the way. Thanks a lot for your support.

There’s still unfortunately a problem so this is hopefully the final question.

<?php if(!isset($subpages)) $subpages = $site->children() ?>
<ul class="collapsibleList" id="someID">
  <?php foreach($subpages->listed() as $p): ?>
  <li class="depth-<?= $p->depth() ?>">
     <?php if($p->hasChildren() === false): ?>
    <a<?php e($p->isActive(), ' class="active"') ?> href="<?= $p->url() ?>"><?= $p->title()->html() ?></a>
     <?php else: ?>
        <?= $p->title()->html() ?>
     <?php endif ?>
    <?php if($p->hasChildren()): ?>
    <?php snippet('treemenu', ['subpages' => $p->children()]) ?>
    <?php endif ?>
  </li>
  <?php endforeach ?>
</ul>

Since it’s recursive, the class and ID of

<ul class="collapsibleList" id="someID">

gets repeated which mess up the script.

There needs to be a single base UL with the class and ID just like here:

> <ul id="someID">
>   <li>Book 1
>     <ul>
>       <li><a href="someHref">Chapter 2</a></li>
>       <li><a href="someHref">Chapter 3</a></li>
>       <li><a href="someHref">Chapter 4</a></li>
>     </ul>
>   </li>
> </ul>

I tried embedding the treemenu.php inside of a UL element but it doesn’t work. Any clues?

Thanks

Try:

<?php 
$attrs = null;
if(!isset($subpages)) $attrs = 'class="collapsibleList" id="someID"';
if(!isset($subpages)) $subpages = $site->children() ?>

<ul <?= $attrs ?>>

  <?php foreach($subpages->listed() as $p): ?>
  <li class="depth-<?= $p->depth() ?>">
    <a<?php e($p->isActive(), ' class="active"') ?> href="<?= $p->url() ?>"><?= $p->title()->html() ?></a>
    <?php if($p->hasChildren()): ?>
    <?php snippet('treemenu', ['subpages' => $p->children()]) ?>
    <?php endif ?>
  </li>
  <?php endforeach ?>
</ul>
1 Like