Generating linked table of contents

I’m trying to generate a table contents based on the <h2> lines in my page. I’ve tried using the toc.php with a (toc) callout in the text file, but that isn’t working for me (and others seem to indicate that it isn’t linked anyway). Ideally, I want a list that links down to each <h2>, and then if you click the <h2> it will take you back to the top of the page. It seems like this should be easy (and it is in plain HTML), but I just cannot get it to work in Kirby.

Thanks for your help/patience!

With toc.php, I guess you are referring to this file?: https://github.com/getkirby/getkirby.com/blob/master/site/plugins/toc/toc.php

Correct, that’s the one I came across while looking through the forum for ideas.

Strange, that should work, at least in one direction. You’d have to add the toTop functionality, though. I just added the file to a new Starterkit and it does work without any problems. Are you rendering the content of the field with the kirbytext() method?

I thought I was rendering it properly with the kirbytext() method, but like another user, the page simply prints (toc) where the content list should appear. Is

Text:
(toc)
[...]

not correct?

Also, how would I add the toTop functionality?

Like this:

<?php
kirbytext::$post[] = function($kirbytext, $value) {
  $value = preg_replace_callback('!\(toc\)!', function($match) use($value) {
    preg_match_all('!<h2.*?>(.*?)</h2>!', $value, $matches);
    $ul = brick('ul');
    $ul->addClass('toc');
    $ul->attr('id', 'toc'); // add id
    foreach($matches[1] as $heading) {
      $li = brick('li', '<a href="#' . str::slug(str::unhtml($heading)) . '">' . $heading . '</a>');
      $ul->append($li);
    }
    return $ul;
  }, $value);
  $value = preg_replace_callback('!<h2>(.*?)</h2>!', function($match) {
    return '<h2 id="' . str::slug(str::unhtml($match[1])) . '"><a href="#toc">' . $match[1] . '</a></h2>'; // add link to toc id
  }, $value);
  return $value;
};

Or wherever you want to link to…

I think I see what I did…the <h2> elements that I want to appear in the contents list need to have the attribute id="toc", is that correct?

No, the h2 elements get an id through the code, the id is created from the text between the opening and closing heading tag: str::slug(str::unhtml($match[1]))

What post are you referring to?

Where have you put the toc.php?

I found the post Get markdown headline from $page->text() to genereate list of content. The toc.php is in site/plugins/toc.

I’ll send you a working Starterkit example in a minute via PM.