search ]

Table of Contents for Posts : WordPress Plugin for UX & SEO

The “Efficient TOC Widget” is a custom WordPress plugin designed to add Table of Contents (TOC) to single posts on your WordPress blog. The plugin helps your readers quickly navigate through long-form content while improving the user experience on your site.

I currently use the plugin on this website (check out the Table of Contents in the sidebar, visible on desktop only).

TOC Plugin Overview

This TOC widget plugin dynamically generates a Table of Contents by capturing all <h2> headings within the post content. Each heading is given a unique ID and an anchor link, allowing users to jump to each section.

Adding a Table of Contents to your posts can enhance visibility in search engines. Google may recognize the TOC structure and display links to specific sections directly in the search engine results pages (SERPs), offering users quick navigation to relevant content.

This can improve click-through rates as users see clearly organized sections, which makes your content more accessible and appealing in search results. It looks like this in google search results:

TOC in Google Search Results

Providing users with a Table of Contents improves user experience by making long content easier to navigate, which can also positively impact your SEO.

Let’s dive into the code and understand how it works…

Code Breakdown

To use this plugin, create a new PHP file (e.g., efficient-toc-widget.php), add the code to it, and save it in the wp-content/plugins folder. This will make the plugin available for activation in your WordPress dashboard.

Here’s the full code for the plugin:

<?php 
/**
* Plugin Name: Efficient TOC Widget
* Description: Add a table of contents widget to single posts.
* Version: 1.3
* Author: Roee Yossef
* Text Domain: efficient-toc-widget
* Domain Path: /languages
*/

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}
class Efficient_TOC_Widget {

    private $headings = [];

    public function __construct() {
        add_action( 'XXXXXX', [ $this, 'show_toc' ] ); // Replace 'XXX' with the desired action hook
        add_filter( 'the_content', [ $this, 'build_toc' ] );
    }

    public function build_toc( $content ) {
        if ( ! is_singular( 'post' ) ) {
            return $content;
        }
        $this->headings = [];
        $content = preg_replace_callback( '/<h2>(.*?)</h2>/i', [ $this, 'extract_headings' ], $content );

        return $content;
    }

    public function extract_headings( $matches ) {
        static $counter = 0;

        $id = 'title_' . $counter++;
        $this->headings[] = [
            'id'    => $id,
            'title' => strip_tags( $matches[1] )
        ];

        return sprintf(
            '<h2 id="%s" class="copy-heading" data-clipboard-text="%s">%s</h2>',
            esc_attr( $id ),
            esc_url( get_permalink() . '#' . $id ),
            esc_html( $matches[1] )
        );
    }

    public function generate_toc() {
        if ( empty( $this->headings ) || count( $this->headings ) < 2 ) { // Change '2' to adjust TOC generation 
            return false; 
        }
    
        $html = '<div id="toc" class="toc_wrapper">';
        $title = esc_html__( 'Table of Contents', 'efficient-toc-widget' );
        $html .= '<p class="toc-title">' . $title . '</p>';
        $html .= '<ul>'; // Track the index of the iteration $first = true;

        foreach ( $this->headings as $heading ) {
            $class = $first ? ' class="current"' : '';  // Apply 'current' class only to the first item
        
            $html .= sprintf(
                '<li%s><a href="#%s">%s</a></li>',
                $class,
                esc_attr( $heading['id'] ),
                esc_html( $heading['title'] )
            );
            $first = false; // After the first iteration, set this to false
        }

        $html .= '</ul>';
        $html .= '</div>';

        return $html;
    }

    public function show_toc() {
        if ( is_singular( 'post' ) ) {
            $toc = $this->generate_toc();
            if ( $toc ) {
                echo $toc; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            }
        }
    }
}

new Efficient_TOC_Widget();

To customize the appearance of the Table of Contents, you’ll need to add CSS styles. By applying your own CSS, you can control elements like fonts, colors, and spacing to seamlessly match the TOC with your website’s design.

Choosing a Custom Hook for Displaying the TOC

Since the plugin uses the XXXXXX hook (a placeholder), you need to replace it with an actual action hook in your theme, depending on where you want the Table of Contents to appear. For instance, if you want it displayed at the end of a post, you could add a custom hook in your theme.

Adding a Custom Hook in Your Theme

In your theme’s single.php or a template file, you can create a hook like so:

do_action( 'custom_toc_hook' );

Then, in the plugin, replace XXX with custom_toc_hook:

add_action( 'custom_toc_hook', [ $this, 'show_toc' ] );

By adding this line to your template, you control where the TOC will appear, giving you flexibility to integrate it into your site layout effectively.

Using custom hooks is a great way to add specific functionality precisely where you need it in your theme.

Adjusting TOC Display Based on Heading Count

The TOC will generate only if there are more than two <h2> headings. To change this, modify the line:

if ( empty( $this->headings ) || count( $this->headings ) < 2 ) { // Change '2' to adjust TOC generation

By setting a different number, you can control when the TOC is displayed based on the minimum number of sections you want in the content.

Conclusion

The “Efficient TOC Widget” plugin enhances post navigation and readability by offering a flexible, user-friendly Table of Contents. By using customizable hooks and adjusting the minimum heading count, this plugin can be seamlessly integrated with any theme for improved usability and SEO.

Feel free to ask any questions in the comments—I’ll be happy to help! 😊

0 Comments...

Leave a Comment

To add code, use the buttons below. For instance, click the PHP button to insert PHP code within the shortcode. If you notice any typos, please let us know!

Savvy WordPress Development