I had been using a plugin to create a table of contents on all my posts automatically.
I knew that this could be done with a code snippet, so I used an AI tool to create the function necessary to add a table of content to all my posts.
The AI tool also helped me with the CSS to style the table of content.
I have used this code and it works as expected. Feel free to use it if you like the result.
Code to Create a Table of Content
This code is a WordPress filter function that adds a table of contents to your WordPress posts.
The function does this by looking for all headings in the content (<h2>
, <h3>
, etc.) and then creating a list of links that point to those headings.
The resulting table of contents is then inserted into the content before the first heading.
I usually add this function to my mu-plugin folder
<?php
/*
Plugin Name: TOC
Plugin URI: https://ticolibre.com
Description: Add a Table of Content to all Posts Before the First Heading
Version: 1.0
Author: TicoLibre
Author URI: https://ticolibre.com
*/
function add_table_of_contents_before_first_heading($content) {
// check if the current post type is "post" and if the content contains at least one heading
if(get_post_type() == 'post' && preg_match('/<h[2-6]/', $content)) {
// Get language_picker custom field value
$language_picker_value = get_post_meta(get_the_ID(), 'language_pick', true);
// Set the table of contents title based on language_picker value
$toc_title = (strpos($language_picker_value, 'ES') !== false) ? '<p>Tabla de Contenidos</p>' : '<p>Table of Contents</p>';
// generate the table of contents
$table_of_contents = '<div class="table-of-contents">';
$table_of_contents .= $toc_title;
$table_of_contents .= '<ul>';
// find all headings in the content
preg_match_all('/<h([2-6])(.*?)>(.*?)<\/h[2-6]>/', $content, $matches);
foreach($matches[0] as $key => $heading) {
// extract the heading level and text
$heading_level = $matches[1][$key];
$heading_text = $matches[3][$key];
// add the heading to the table of contents
$table_of_contents .= '<li><a href="#'.sanitize_title($heading_text).'">'.$heading_text.'</a></li>';
// add an anchor to the heading
$content = str_replace($heading, '<a id="'.sanitize_title($heading_text).'"></a>'.$heading, $content);
}
$table_of_contents .= '</ul>';
$table_of_contents .= '</div>';
// Insert the table of contents before the first heading
$content = preg_replace('/<h[2-6]/', $table_of_contents.'<h2', $content, 1);
// Add a separator after the table of contents
$content = preg_replace('/<\/div><h2/', '</div><hr class="wp-block-separator has-alpha-channel-opacity" style=""><h2', $content, 1);
}
return $content;
}
add_filter('the_content', 'add_table_of_contents_before_first_heading');
CSS to Style the Table of Content
You can add this CSS via the theme customizer to make sure that the table of content generated by the function looks like the table of contents generated by popular TOC plugins.
.table-of-contents {
padding: 1em;
background-color: #f8f8f8;
border: 1px solid #ddd;
}
.table-of-contents h2 {
margin-top: 0;
margin-bottom: 0.5em;
}
.table-of-contents li {
margin-bottom: 0.5em;
}
.table-of-contents a {
color: #333;
text-decoration: none;
}
.table-of-contents a:hover {
text-decoration: underline;
}
In case you want to use the minified version of it, try this one:
/*TOC*/
.table-of-contents{padding:1em;background-color:#F7F9FF;border:1px solid #ddd;margin-bottom:25px}.table-of-contents p{font-weight:700;margin-top:0;margin-bottom:.5em}.table-of-contents li{margin-bottom:.3em}.table-of-contents a{color:#333;text-decoration:none}.table-of-contents a:hover{text-decoration:underline}
Once you like what you are seeing, you can keep the CSS in the theme customizer or you can inline in every page by style tags or you can add the CSS to your child them stylesheet.
Final Thoughts
A TOC allows users to quickly navigate to specific sections of a webpage or document, which can improve their overall experience.
As you can see creating and styling a table of content isn’t that complicated to implement.
Keep in mind that this custom plugin:
- Doesn’t add any scripts which is one less thing to worry about if you care about site speed, but you won’t find a way to show and hide the TOC content like some TOC plugins do.