Of anchors and ToCs, part 1
A Table of Contents (ToC) gives readers a quick overview of the contents of a page and allows accessing specific parts quickly.
Prerequisites
Being familiar with registering extensions in Kirby and a basic understanding of PHP will be useful.
To follow along, install a Kirby Starterkit, create a /site/plugins/toc
folder with an index.php
inside and add some headlines in a textarea field, for example in one of the subpages of the /content/notes
page.
Note that the techniques described here only work for fields that are rendered using the kirbytext()
method, usually a textarea
field (or plugin fields derived from this), not with the Editor.
Plugin parts
To create a ToC, we need two things:
- Anchors in the text to which the ToC can link. While those could be added manually, it is much easier to auto-generate them from headlines. Anchors are useful even without a ToC, because you can link to these anchors from elsewhere.
- A navigation list of links to these anchors usually at the top of the page or the sidebar, the actual ToC.
Consequently, we have to implement two steps:
- Replace the headlines in the text with anchor headlines
- Add the ToC where we want it to appear
Let's start with replacing the headlines in our text with anchors.
Replace headlines with anchors
We can replace headlines automatically with a KirbyText
hook or manually using a field method. The actual code to replace the headlines is the same, but we hook into different Kirby extensions.
Let's start with a kirbytext:after
hook that converts all given headline levels into anchors whenever the kirbytext()
method is called. We make the headline levels we want to convert configurable via a config option and use h2
and h3
headlines as defaults.
Since we want to add a second hook of the same type in the next step, we use an array of functions after the kirbytext:after
key.
The important part here is the preg_replace_callback()
function. It needs three parameters…
- the search pattern (
$headlinesPattern
) - the callback function
- the input (
$text
)
…and returns the modified string.
To include more headlines levels, you can set the k-cookbook.toc.headlines
option in the config:
Result
If you now look at a page that contains headlines of the given level, you will see that the anchors were added.
Alternative: A field method to generate the anchors
This is an alternative to using the kirbytext
hook described above. Do not use the hook and this method in conjunction.
In your templates/snippets, you can now use the field method like this:
With a single headline level
With multiple headline levels
Instead of passing a string of options separated by |
, you can also pass an array of options:
If you don't pass an argument, the defaults will be used.
Generate the ToC
While the code we need to generate the ToCs from the headlines in a textarea field is the same, we can use different approaches to add them to the page.
- Use a placeholder that users can manually put into a textarea field where they want the ToC to appear
- Add a ToC in our template code using a field method
We will look into both options in this recipe.
To keep it simple, we will include only one headline level in our ToC. We will cover multiple levels in a future recipe.
Using a toc
placeholder
For the toc
placeholder, we use another kirbytext:after
hook, and a snippet that will contain the HTML for the ToC. We will reuse this snippet for the alternative field method approach below.
The code for the snippet goes into /site/plugins/toc/snippets/toc.php
:
Result
If you now add a (toc)
placeholder to a page that contains headlines of the given level, you should see a ToC appear where you added the placeholder.
Alternative: A field method to generate the ToC
The field method returns a collection of headline objects.
In your templates, you can now use the headlines()
field method in conjunction with the snippet we registered above.
Conclusion
In this recipe we explored different ways to add anchor headlines and a ToC to pages.
You can also mix the hook that auto-generates anchor headlines with the headlines
field method and the toc.php
snippet to create the ToC in your templates rather than through a placeholder users add manually.
If you vote for generating the ToC via the field method in your templates, you can still give editor control whether to show a ToC on a page by page basis using a toggle or checkbox field in your blueprints, for example:
You could also only show the ToC if there is at least a given number of headlines by slightly modifying the toc.php
snippet, for example, if there are at least 3 headlines:
Extra: ToC from blocks field
If you are using the blocks or layouts fields with separate blocks for your headings, you can filter the blocks by type heading
and heading level:
Then create the ToC snippet like this:
The last step is to overwrite the default heading block snippet and add an id
attribute: