Heading permalinks
HeadingPermalinkExtension gives headings stable slugs and adds configurable
permalink anchors. Duplicate headings receive deterministic numeric suffixes.
Install
This extension is bundled with alto/markdown.
composer require alto/markdownConfigure
<?php
use Alto\Markdown\Extension\HeadingPermalink\HeadingPermalinkExtension;
use Alto\Markdown\Markdown;
$markdown = Markdown::commonmark()->with(new HeadingPermalinkExtension());Markdown
# Hello, **world!**HTML
<h1><a id="content-hello-world" href="#content-hello-world" class="heading-permalink" aria-hidden="true" title="Permalink">¶</a>Hello, <strong>world!</strong></h1>
Options
Pass a HeadingPermalinkPolicy to control the generated anchor:
<?php
use Alto\Markdown\Extension\HeadingPermalink\HeadingPermalinkPolicy;
use Alto\Markdown\Extension\HeadingPermalink\HeadingPermalinkPosition;
$extension = new HeadingPermalinkExtension(new HeadingPermalinkPolicy(
minLevel: 2,
maxLevel: 4,
position: HeadingPermalinkPosition::After,
idPrefix: 'heading',
applyIdToHeading: true,
headingClass: 'anchored',
fragmentPrefix: 'heading',
htmlClass: 'permalink',
title: 'Link to this section',
symbol: '#',
ariaHidden: false,
));| Option | Default |
|---|---|
minLevel, maxLevel |
1, 6 |
position |
HeadingPermalinkPosition::Before |
idPrefix, fragmentPrefix |
content |
applyIdToHeading |
false |
headingClass |
Empty |
htmlClass |
heading-permalink |
title |
Permalink |
symbol |
¶ |
ariaHidden |
true |
Use HeadingPermalinkPosition::None to apply the configured heading ID and
class without rendering an anchor.
Both levels must be between 1 and 6, and minLevel cannot exceed maxLevel.
Security
Configured classes, titles, symbols, IDs, and fragments are escaped through the active HTML output context. Generated links remain subject to the active HTML policy.
Behavior
Slug allocation covers the complete document, including filtered headings, so partial node and section rendering keeps the same IDs. Renaming a heading invalidates the slug catalog. Rendering permalinks does not modify the source Markdown.