This shortcode dynamically generates a table of contents with proper parent-child nesting based on heading levels (h2, h3, etc.) within a specified container, enhancing content navigation for your WordPress posts or pages.
shortcode: [custom_tableofcontents class_name=”.your-custom-content-container”]
// [custom_tableofcontents class_name=".your-custom-container"] shortcode
function custom_table_of_contents_shortcode($atts) {
// Set default class as '.post-contents' if not provided in the shortcode
$atts = shortcode_atts(
array(
'class_name' => '.post-contents', // default container class
),
$atts,
'custom_tableofcontents'
);
// Output the div for the TOC and the JavaScript
ob_start();
?>
<div id="table-of-contents"></div>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Get the container element based on the class_name attribute
var contentContainer = document.querySelector("<?php echo esc_attr($atts['class_name']); ?>");
if (!contentContainer) return; // Exit if the container isn't found
var headings = contentContainer.querySelectorAll("h2, h3, h4, h5, h6");
var tocContainer = document.getElementById("table-of-contents");
var tocList = document.createElement("ul");
var currentLevel = 2; // Start from h2
var currentList = tocList; // Main list is the root level list
headings.forEach(function(heading, index) {
var level = parseInt(heading.tagName.substring(1)); // Get the heading level (2, 3, 4, etc.)
var anchorId = "toc-heading-" + index;
heading.setAttribute("id", anchorId); // Add unique ID to the heading
var listItem = document.createElement("li");
var link = document.createElement("a");
link.setAttribute("href", "#" + anchorId);
link.textContent = heading.textContent;
listItem.appendChild(link);
// Adjust list levels based on heading level
if (level > currentLevel) {
// Create a new nested list
var nestedList = document.createElement("ul");
currentList.lastElementChild.appendChild(nestedList); // Nest it in the previous item
currentList = nestedList;
} else if (level < currentLevel) {
// Go back up to the correct level
while (level < currentLevel) {
currentList = currentList.parentElement.parentElement;
currentLevel--;
}
}
currentLevel = level; // Update the current level
currentList.appendChild(listItem); // Add the item to the current list
});
tocContainer.appendChild(tocList); // Append the final TOC list to the container
});
</script>
<?php
return ob_get_clean(); // Output the HTML and JavaScript
}
// Register the shortcode
add_shortcode('custom_tableofcontents', 'custom_table_of_contents_shortcode');