(.*?)<\/\1>/'; function getContent($page) { if ($page->intendedTemplate() == 'grid') return $page->body()->toBlocks(); if ($page->intendedTemplate() == 'linear') { if ($page->isBlockMode()->isTrue()) return $page->bodyBlocks()->toBlocks(); if ($page->isBlockMode()->isFalse()) return $page->body(); } return null; } function getTocContent($page) { if (!$page->parent()?->parent()?->is('textes')) return null; $content = (string) getContent($page); return $content ?: null; } Kirby::plugin('actuel-inactuel/toc', [ 'pageMethods' => [ 'hasToc' => function(): bool { return count($this->tocItems()) > 0; }, 'tocItems' => function(): array { $content = getTocContent($this); if (!$content) return []; preg_match_all(HEADING_PATTERN, $content, $matches, PREG_SET_ORDER); $items = []; foreach ($matches as $m) { $entry = ['title' => $m[3], 'slug' => Str::slug($m[3])]; if ($m[1] === 'h3') { $entry['children'] = []; $items[] = $entry; } elseif ($m[1] === 'h4' && count($items) > 0) { $items[count($items) - 1]['children'][] = $entry; } } return $items; }, 'bodyWithAnchors' => function(): string { $content = getTocContent($this); if (!$content) return ''; return preg_replace_callback( HEADING_PATTERN, fn($m) => '<' . $m[1] . ' id="' . Str::slug($m[3]) . '"' . $m[2] . '>' . $m[3] . '', $content ); } ] ]);