bit-mx / statamic-toc
Reusable TOC extraction and anchor injection for Statamic Bard and Markdown fields.
Requires
- php: ^8.4
- illuminate/support: ^12.0
- statamic/cms: ^6.0
Requires (Dev)
- larastan/larastan: ^3.9
- laravel/pint: ^1.27
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.0
- phpstan/extension-installer: ^1.4
- phpunit/phpunit: ^11.0
- tomasvotruba/type-coverage: ^2.1
This package is auto-updated.
Last update: 2026-03-06 18:44:29 UTC
README
A reusable Table of Contents package for Statamic that extracts headings from HTML, Markdown, and Bard content, generates stable anchors, and optionally injects heading IDs into rendered HTML.
Requirements
- PHP 8.3+
- Laravel 12
- Statamic 6
Installation
composer require bit-mx/statamic-toc
Publish Configuration
php artisan vendor:publish --tag=statamic-toc-config
This publishes config/statamic-toc.php.
Configuration
return [ 'min_level' => 1, 'max_level' => 6, 'preserve_existing_ids' => true, 'default_source' => 'html', 'default_tree' => true, 'cache' => [ 'enabled' => false, 'ttl' => 600, 'store' => null, 'prefix' => 'statamic_toc', ], ];
Key Options
min_level,max_level: Heading level range included in TOC.preserve_existing_ids: Keep existing heading IDs when injecting anchors.cache.enabled: Enable caching for tag output.cache.ttl: Cache lifetime in seconds.
Usage
Blade Tag Compatibility (<s:toc>)
This package is compatible with Statamic Blade tag usage like:
<s:toc :content="$content" :is_flat="false" depth="3" from="h1"> @isset($toc_id) <a href="#{{ $toc_id }}">{{ $toc_title }}</a> @if($has_children) @foreach($children as $child) <a href="#{{ $child['toc_id'] }}">{{ $child['toc_title'] }}</a> @endforeach @endif @endisset </s:toc>
Supported legacy params:
contentfield(default:article)depth(default:3)from(default:h1)is_flat(default:false)
Legacy output keys are provided for drop-in compatibility:
toc_titletoc_idtoc_levelchildrenhas_childrentotal_childrentotal_resultsno_results
Tag Usage (Antlers / Blade context)
Use the toc tag to extract TOC items.
{{ toc:items source="html" :content="content" min_level="2" max_level="4" }}
<li><a href="#{{ id }}">{{ text }}</a></li>
{{ /toc:items }}
Parameters:
source:html,markdown, orbard.content: The input payload to parse.min_level/max_level: Optional level limits.tree:true/falseto return hierarchical or flat output.
Modifier Usage
Inject heading IDs into rendered HTML:
{{ content | toc }}
Optional params:
{{ content | toc:2:4:true }}
Meaning:
- min level
- max level
- preserve existing IDs
Service / Facade Usage (PHP)
use BitMx\StatamicToc\Facades\Toc; $items = Toc::extractAsArray('markdown', $markdown, 1, 6, true);
Or via DI:
use BitMx\StatamicToc\Toc\TocService; public function show(TocService $tocService): array { return $tocService->extractAsArray('html', $html, 2, 4, true); }
Output Shape
Each item includes:
textlevelidurl(for example,#installation)children(whentree=true)
Bard Integration Notes
The Bard extractor walks nested node structures and set values, so headings inside nested/complex Bard content are included.
Caching
When cache.enabled=true, tag results are cached using a key that includes source, content, level range, and tree mode.
Migration from In-App TOC Logic
If you already have custom parser/tag/modifier classes in your project:
- Install this package.
- Replace custom TOC tag calls with package tag usage.
- Replace custom heading-id injection with
| tocmodifier. - Keep your front-end template markup, only swap data source.
- Remove legacy TOC classes after parity verification.
Troubleshooting
IDs are not added to headings
- Ensure content passed to modifier is rendered HTML.
- Confirm heading levels are within configured min/max.
Duplicate anchors
- Duplicate heading text is expected to produce suffixes (
-2,-3, ...).
Missing Bard headings
- Verify the field content passed to source
bardis raw Bard data (array structure).
Cache not updating
- Disable cache during development.
- Check cache store and TTL settings.
Testing
composer test
License
MIT