Create a Custom Table of Contents for Your WordPress Website

In this article, we will guide you through the process of creating an automatic table of contents for WordPress posts. This table of contents dynamically collects all the headings within a post and presents them in a list format.

The primary functionality of this table of contents is that when a user clicks on any of the headings listed, the page will smoothly scroll to the corresponding section. This ensures a seamless and user-friendly browsing experience, allowing readers to effortlessly navigate through the content by simply clicking on the desired heading.

By implementing this automatic table of contents, you can enhance the readability and accessibility of your WordPress posts, making it easier for users to locate specific sections within the content.

 * Table of Contents.
 * @return void
function toc_change_id( $content ) {
	$counter = 0;
	$content = preg_replace_callback( '/<h([1-6])(.*?)<\/h\1>/i', function( $matches ) use ( &$counter ) {
		return '<h' . $matches[1] . ' id="toc-heading-' . $counter . '"' . $matches[2] . '</h' . $matches[1] . '>';
	}, $content );
	return $content;
add_filter( 'the_content', 'toc_change_id' );

The code snippet is used to generate unique IDs for headings in a WordPress post, which can be utilized to create a table of contents.

By applying this code, the headings in your WordPress post will be updated with unique IDs in the format toc-heading-{counter}. These IDs can then be used to create a table of contents that allows users to navigate the post by clicking on the desired headings.

 * Table of Contents.
 * @return void
function custom_toc( $content ) {
	$dom     = new DOMDocument();
	$content = get_the_content();
	if ( ! $content ) {
	$dom->loadHTML( $content );
	$xpath    = new DOMXPath( $dom );
	$headings = $xpath->query( '//h2|//h3|//h4|//h5|//h6' );
	$counter  = 0;
	if ( 0 === count( $headings ) ) {
	<div class="toc-wrap" id="table-of-contents">

		<h2 class="toc-title">
			<?php echo esc_html_e( 'Table of Contents', 'text-domain' ); ?>
		<ul class="toc-content">
			foreach ( $headings as $heading ) {
				$heading_id = "toc-heading-$counter";
				<li class="toc-item toc-level-<?php echo esc_attr( $heading->tagName ); ?>">
					<a href="#<?php echo esc_attr( $heading_id ); ?>" rel="noopener">
						<?php echo esc_html( $heading->nodeValue ); ?>
	$toc = ob_get_clean();
	return $toc . $content;
add_filter( 'the_content', 'custom_toc' );

The code snippet defines a function custom_toc() that serves as a filter for the the_content hook.

This function generates a table of contents for the WordPress post as follow:

  1. It creates a DOMDocument object and loads the post content into it.
  2. A DOMXPath object is created for querying the DOMDocument.
  3. Using XPath, it queries for heading elements (h2 to h6) within the post content.
  4. If no headings are found, it returns the original content without modification.
  5. It initializes a counter variable to keep track of the headings.
  6. The function then generates the HTML for the table of contents by looping through each heading.
  7. For each heading, it increments the counter, generates a unique ID for the heading, and constructs an HTML list item with a link to the heading.
  8. Finally, the table of contents HTML is concatenated with the original post content and returned.
  9. The custom_toc function is added as a filter to the the_content hook, so it will be applied to the post content when it is displayed.
Table of content implementation for WordPress

Note: Each item in the list of headings has a corresponding class called toc-level-h*, where * represents the heading level. You can utilize these classes to apply custom styles to each heading level. For example, you can use these classes to shift child headings to the left or apply any other desired styles to differentiate the appearance of each heading level.

Now we might need to smooth scroll when click any item on table of content.

function enqueue_toc_scripts() {
	wp_enqueue_script( 'toc', get_template_directory_uri() . '/js/toc.js', array( 'jquery' ), '1.0', true );
add_action( 'wp_enqueue_scripts', 'enqueue_toc_scripts' );

And in toc.js file add the following.

	$(".toc-content a[href^='#']").on('click', function(e) {
		var target = $(this).attr("href");
		if ($(target).length) {
			$("html, body").animate({
				scrollTop: $(target).offset().top
			}, 500);

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top