Some time ago I ported the wonderful Kirby 2 code from @jenstornell (PHP Table of Contents: https://forum.getkirby.com/t/table-of-contents-for-kirby-3/13780/11) to Kirby 3.
In the following I show the main parts. Because of the CSS code and the license file, I refer to the Kirby 2 code in the above link to @jenstornell’s code on GitHub.
Install
Create a new directory “site\plugins\jenstornell_toc_k3\
” with the file “site\plugins\jenstornell_toc_k3\index.php
” like:
<?php // site\plugins\jenstornell_toc_k3\index.php
// based on https://github.com/jenstornell/php-table-of-contents/blob/master/example/example.php, version 1.2
// adapted for K3 by HeinerEF - 07.-11.01.2020
@include_once __DIR__ . '/src/table-of-contents.php';
Kirby::plugin('jenstornell/php-table-of-contents', [
'hooks' => [
'kirbytext:after' => function ($text) {
$mypos = (stripos($text, '(toc: )') === FALSE);
if (!($mypos)) {
$toc = new PHPTableOfContents($text);
$text = preg_replace('#<p>\(toc: \)</p>#i', "\n" . ' <div class="toc">'
. "\n" . ' <p>Table of contents of the page:</p>'
. $toc->list() . ' </div>' . "\n", $toc->html());
};
return $text;
}
]
]);
Create a new directory “site\plugins\jenstornell_toc_k3\src\
” with the file “site\plugins\jenstornell_toc_k3\src\table-of-contents.php
” like:
<?php // site\plugins\jenstornell_toc_k3\src\table-of-contents.php
// based on https://github.com/jenstornell/php-table-of-contents/blob/master/src/table-of-contents.php, version 1.2
// some changes by HeinerEF for K3 - 07.-10.01.2020 (proper tag hierarchy from h2 to h6)
// use "Str::slug( )" from K3 by HeinerEF
class PHPTableOfContents {
private $headings;
private $html;
public function __construct($html) {
$this->html = $html;
$this->setHeadings();
}
// Html
public function html() {
$html = $this->html;
$matches = $this->headings;
foreach($matches[1] as $index => $item) {
$html = str_replace(
'>' . $item . '</h',
'><a id="' . $matches[2][$index] . '"></a>' . $item . ' </h', // 25.04.2020 by HeinerEF
$html
);
}
return $html;
}
// Generate table of content nested list
// 07.-10.01.2020 changes by HeinerEF (proper tag hierarchy from h2 to h6)
public function list() {
$out = '';
$old_depth = 0;
$matches = $this->headings;
foreach($matches[1] as $key => $item) {
$depth = substr($matches[0][$key], 2, 1) - 2;
if($old_depth > $depth) {
while ($old_depth > $depth) {
$old_depth--;
$out .= "\n </ol><!-- #".($old_depth+2)." -->";
};
} elseif($old_depth < $depth) {
$old_depth++;
$out .= "\n <li>\n";
$out .= " <ol><!-- #".($old_depth+1)." -->";
};
$out .= sprintf("
<li>
<span></span>
<a href='#%s'>%s</a>
</li>", $matches[2][$key], $item);
}
while ($old_depth > 0) {
$old_depth--;
$out .= "\n </ol><!-- #".($old_depth+2)." -->";
};
return "\n <ol><!-- #1 -->" . $out . "\n </ol><!-- #1 -->\n";
}
// Set headings
private function setHeadings() {
preg_match_all('|<h[^>]+>(.*)</h[^>]+>|iU', $this->html, $matches);
$slugs = [];
foreach($matches[1] as $item) {
$slugs[] = Str::slug($item); // changed by HeinerEF using K3
}
$this->headings = $matches;
$this->headings[2] = $slugs;
}
}
How to use
In the Panel field add three extra lines
(toc: )
where you want to have the TOC.
Remark:
Of course, with this technique it is necessary for all headings to be different in the text for the links to work.
Good luck!