Skip to content
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Kirby Anchor-Headings by @wottpal

Release MIT Tweet

(Disclaimer: This is a pre-release.)

A field-method for the Kirby CMS which automagically enumerates your headings, generates IDs for them and inserts matching anchor links. Customizable to it's core. 🤘

Demo of Kirby Anchor-Headings

Note: Please dive into this advanced use case if you want to build something like the GIF above.



Use Kirby's CLI and install the plugin via: kirby plugin:install wottpal/kirby-anchor-headings or place the repo manually under site/plugins.

🎉 That's it.


This is a kirby field-method, so you can basically just do:

<?= $page->text()->kirbytext()->headingAnchors() ?>


The following options can be set globally in your config.php with c::set($key, $value = null). You can also set multiple keys with c::set([$key => $value, ..]). 🤓

Please prefix every key with anchorheadings.!

key default description
toplevel.only true Nested headings are ignored.
heading.min 2 The <h>-level to begin enumeration.
heading.max 3 The <h>-level to end enumeration.
enum.start 1 Integer to start enumeration on each level.
enum.seperator '.' Seperator for enumeration-levels.
id.prefix false A string all IDs get prefixed with (before the enumeration).
id.prepend.enum true If the enumeration should be part of the generated ID.
id.rules (see below) A dictionary of reg. expressions and their respective replacements. (They will be applied in the given order.)
markup (see below) A template-string which defines the new inner-markup of each heading-element

Set id.prefix

Even if id.prefix defaults to false I encourage you to set it to something like section- to prevent namespace-conflicts all over your site.

Default of id.rules

You can either pass a regular expression as the replacement or a callback-function. They will be used with preg_replace_callback or preg_replace, respectively.

  // characters to replace with an hyphen
  '/[_ ~\/,.]/' => '-',
  // replace German umlauts (YES, even the large ß)
  '/ä/' => 'ae', '/ö/' => 'oe', '/ü/' => 'ue',
  '/Ä/' => 'Ae', '/Ö/' => 'Oe', '/Ü/' => 'Ue',
  '/ß/' => 'ss', '/ẞ/' => 'SS',
  // remove all remaining characters that are not letters/digits
  '/[^A-Za-z0-9\-]/' => '',
  // remove trailing hyphens and squash multiple occurences
  '/-+$/' => '',
  '/-{2,}/' => '-',
  // convert everything to lowercase (using a callback-function)
  '/([A-Z]+)/' => function($x) { return strtolower($x[1]); }

Default of markup

<a href='#{id}'>{enum}.</a> {heading}

You can use the following template-literals in your markup: {id}, {enum} and {heading}. I think they are self-explanatory, but feel free to reach out if you need further guidance.

Advanced Markup & Styling


Have a look at the releases page.


  • Add an example with advanced markup & styling to the
  • Improve ID generation by collapsing consecutive '-' to one
  • Allow non integer values for enum.start like A or i and conitnue enumeration with this style.

💰‍ Pricing

Just kidding. This plugin is totally free. Please consider following me on Twitter if it saved your day.

Twitter Follow

You can also check out one of my other Kirby-plugins:

  • Lightbox-Gallery - Easily inline beautifully aligned galleries with lightbox-support powered by PhotoSwipe.
  • HTML5-Video Kirbytag - Adds a kirbytag for embedding HTML5-videos with a variety of features.


A kirby field-method which enumerates heading-elements, generates IDs for anchor-links and inserts custom markup based on your options.




No packages published


You can’t perform that action at this time.