EN / ZH
Adding a Table of Contents to WordPress Posts Without Plugins

In my previous post about adding breadcrumb navigation to WordPress blogs, I covered how it helps search engines index your site. Today, I’d like to introduce a method for adding a table of contents to your articles. What is a table of contents? If you frequently visit Baidu Zhidao, you’ll notice the article sidebar features a table of contents. Denis’s blog also has table of contents in articles. So what purpose does it serve? Simply put: first, clicking on a heading jumps you to the corresponding section; second, it makes the article’s structure and flow much clearer.

There are only a handful of WordPress table of contents plugins. The free ones are cumbersome to use and overly complex with their configurations. Denis offers a paid plugin, but I still hold to my original principle — use as few plugins as possible and integrate functionality directly into the theme.

Here’s how to do it:

1. Add the Code

As usual, add the following code to your theme’s functions.php file:

// Article Table of Contents
function article_index($content) {
    $matches = array();
    $ul_li = '';

    $r = "/<h3>([^<]+)<\/h3>/im";

    if (preg_match_all($r, $content, $matches)) {
        foreach($matches[1] as $num = >$title) {
            $content = str_replace($matches[0][$num], '<h2 id="title-'.$num.'">'.$title.'</h2>', $content);
            $ul_li. = '<li><a href="#title-'.$num.'" title="'.$title.'">'.$title."</a></li>\n";
        }

        $content = "\n<div id=\"article-index\">
                <b>[Table of Contents]</b>
                <ul id=\"index-ul\">\n".$ul_li."</ul>
            </div>\n".$content;
    }

    return $content;
}

add_filter("the_content", "article_index");

2. Add CSS:

With the code in place, styling is equally important. You can write your own CSS or use the styles provided below:

#article-index {background:#F7F7F7;-moz-border-radius: 6px 6px 6px 6px;border: 1px solid #DEDFE1;float: right;margin: 5px 0 5px 15px;padding: 0 6px;width: 280px;line-height: 24px;}
#article-index b {border-bottom: 1px dashed #DDDDDD;display: block;line-height: 30px;padding: 0 4px;}
#index-ul {margin: 0;padding-bottom: 5px;}
#index-ul li {background: none repeat scroll 0 0 transparent;list-style-type: disc;padding: 0;margin-top: 5px;margin-bottom: 5px;margin-left: 20px;}
#index-ul a{text-decoration:none;}

3. How to Use:

I recall that Denis’s plugin cascades from H1 through H6 tags, which I don’t think works very well. So I changed it to use the </h3> tag, which corresponds to “Heading 3” in the editor. When writing an article, simply add a heading with the </h3> tag for each section. If you don’t want a table of contents for a particular article, just don’t use the </h3> tag. A small note: if you want to customize your heading styles, modify the h2 in your theme’s stylesheet, not h3.

4. Limitations and Suggestions

  • Cannot generate multi-level nested table of contents
  • If your theme has article pagination, the table of contents won’t be able to extract headings from the second page onward
  • If you need multi-level nesting, you might want to try a plugin. I’ll write some articles later specifically recommending such plugins