
How to add a table of contents to WordPress posts?
The easiest way to add a table of contents to WordPress posts is with a plugin such as Easy Table of Contents, LuckyWP Table of Contents, or the table of contents block included in Yoast SEO and Rank Math. These tools scan your headings and generate a clickable list of links automatically. If you prefer not to use a plugin, you can build one manually in the block editor with HTML anchors, or add a small piece of code that creates one for every post.
A table of contents (TOC) helps readers understand what a long article covers and jump straight to the section they need. It's especially useful for tutorials, guides, and reference posts. This article walks through why a TOC is worth adding, three different ways to add one, how to style it, and common problems to watch for.
Why Add a Table of Contents to Your Posts?
A table of contents is a small addition that improves long-form content in several ways:
- Easier navigation: Readers can jump to the exact section they care about instead of scrolling.
- Better first impression: A visible outline shows visitors at a glance that the post covers what they're looking for.
- Longer engagement: When people can find the answer quickly, they're less likely to leave and more likely to keep reading.
- Accessibility: A clear list of in-page links helps keyboard and screen reader users move through long pages.
- Search features: Search engines sometimes display "jump to" links to sections of a page in results. A TOC with clear headings makes your structure easy to understand.
- Better writing discipline: Seeing your headings listed together quickly reveals if your structure is confusing or repetitive.
When a TOC Makes Sense
Not every post needs one. A table of contents works best on:
- Posts longer than roughly 1,500 words
- Step-by-step tutorials and how-to guides
- Reference articles, glossaries, and documentation
- Comparison and "best of" posts with many sections
For short news posts or quick updates, a TOC mostly adds clutter.
Start With a Good Heading Structure
Every method in this article relies on your headings, so get them right first:
- Use one H1 per post, which is usually your post title (your theme outputs it automatically).
- Use H2 headings for main sections.
- Use H3 headings for subsections within an H2, and H4 only when needed.
- Don't skip levels, such as jumping from H2 straight to H4.
- Write descriptive headings. "Step 3: Configure Your Settings" is much more helpful in a TOC than "Next Up".
In the block editor, you can check your structure by clicking the Document Overview icon (the three stacked lines) in the top toolbar and choosing the Outline tab. It lists all headings and warns you about skipped levels.
Method 1: Add a Table of Contents With a Plugin
Plugins are the most practical option for most sites because they generate the TOC automatically and update it when you change headings.
Popular Table of Contents Plugins
- Easy Table of Contents: One of the most widely used TOC plugins. It can insert a TOC automatically based on rules, and offers a shortcode and block.
- LuckyWP Table of Contents: Flexible automatic insertion, plus a block and shortcode, with good styling options.
- Yoast SEO: Includes a Yoast Table of Contents block in the block editor (available in Yoast SEO Premium).
- Rank Math: Includes a Table of Contents by Rank Math block in its free version.
- Heroic Table of Contents: A lightweight, block-based option.
If you already use an SEO plugin with a TOC block, try that first before adding another plugin.
Setting Up Easy Table of Contents
Here's how to configure a typical automatic TOC plugin:
- Install the plugin: Go to Plugins > Add New Plugin, search for "Easy Table of Contents", click Install Now, then Activate.
- Open the settings: Go to Settings > Table of Contents.
- Enable post types: Under Enable Support, tick Posts (and Pages if you want).
- Choose auto insertion: Under Auto Insert, select the post types where the TOC should appear automatically.
- Set the position: Choose where the TOC appears, such as Before first heading.
- Set a minimum: Use Show when to only display the TOC when a post has at least a certain number of headings, such as 4.
- Choose headings: Under the advanced settings, pick which heading levels to include. Including H2 and H3 is usually enough.
- Save changes and view a long post to check the result.
Most TOC plugins also let you disable the TOC on specific posts through a setting in the post editor sidebar, which is handy for exceptions.
Adding a TOC Block Manually
If you'd rather decide post by post:
- Open a post in the block editor.
- Click the + inserter and search for "table of contents".
- Insert your plugin's TOC block, usually after the introduction.
- Adjust the block settings, such as which headings to include or whether it starts collapsed.
The block updates itself as you add or edit headings.
Method 2: Create a Table of Contents Manually in the Block Editor
You can build a TOC without any plugin using HTML anchors. This takes a bit more effort but adds no extra code to your site.
Step 1: Add Anchors to Your Headings
- Select a heading block in your post.
- In the block settings sidebar, open the Advanced panel.
- In the HTML anchor field, enter a short, unique ID with no spaces, such as
choose-a-plugin. - Repeat for each heading you want to include.
WordPress may already generate anchors automatically for headings in recent versions, but setting them yourself gives you short, predictable IDs.
Step 2: Create the List of Links
- After your introduction, add a Heading block (for example, "In This Article") and a List block.
- Type the name of each section as a list item.
- Select the text of each item, click the Link button, and enter
#followed by the anchor, such as#choose-a-plugin. - Use nested list items for H3 subsections if you want a hierarchy.
Step 3: Save It as a Pattern (Optional)
If you use the same layout often, wrap the heading and list in a Group block, then save it as an unsynced pattern so you can insert it quickly next time. See our guide to block patterns for how that works.
The downside of this method is maintenance: if you rename a section or add a new one, you need to update the TOC by hand.
Method 3: Generate a Table of Contents Automatically With Code
If you're a developer and want a lightweight, automatic TOC without a plugin, you can filter the post content. The code below:
- Finds H2 and H3 headings in single posts.
- Adds an
idto each heading that doesn't have one. - Builds a nested list of links and inserts it before the first heading.
Add it to your child theme's functions.php or a small custom plugin. Back up your site and test on a staging copy first.
function sajjad_add_table_of_contents( $content ) {
if ( ! is_singular( 'post' ) || ! in_the_loop() || ! is_main_query() ) {
return $content;
}
$pattern = '/<h([23])([^>]*)>(.*?)<\/h\1>/is';
if ( ! preg_match_all( $pattern, $content, $matches, PREG_SET_ORDER ) ) {
return $content;
}
// Only show a TOC when there are at least 3 headings.
if ( count( $matches ) < 3 ) {
return $content;
}
$used_ids = array();
$toc = '<nav class="sajjad-toc" aria-label="' . esc_attr__( 'Table of contents', 'sajjad' ) . '">';
$toc .= '<p class="sajjad-toc__title">' . esc_html__( 'Table of Contents', 'sajjad' ) . '</p><ul>';
$in_sub = false;
foreach ( $matches as $heading ) {
$level = (int) $heading[1];
$attrs = $heading[2];
$text = wp_strip_all_tags( $heading[3] );
if ( preg_match( '/\sid=["\']([^"\']+)["\']/i', $attrs, $id_match ) ) {
$id = $id_match[1];
} else {
$id = sanitize_title( $text );
$base = $id;
$i = 2;
while ( in_array( $id, $used_ids, true ) ) {
$id = $base . '-' . $i;
$i++;
}
$new_heading = '<h' . $level . $attrs . ' id="' . esc_attr( $id ) . '">' . $heading[3] . '</h' . $level . '>';
$content = preg_replace( '/' . preg_quote( $heading[0], '/' ) . '/', $new_heading, $content, 1 );
}
$used_ids[] = $id;
if ( 3 === $level && ! $in_sub ) {
$toc .= '<ul>';
$in_sub = true;
} elseif ( 2 === $level && $in_sub ) {
$toc .= '</ul>';
$in_sub = false;
}
$toc .= '<li><a href="#' . esc_attr( $id ) . '">' . esc_html( $text ) . '</a></li>';
}
if ( $in_sub ) {
$toc .= '</ul>';
}
$toc .= '</ul></nav>';
// Insert the TOC before the first H2 or H3 heading.
$position = stripos( $content, '<h' . $matches[0][1] );
if ( false === $position ) {
return $toc . $content;
}
return substr( $content, 0, $position ) . $toc . substr( $content, $position );
}
add_filter( 'the_content', 'sajjad_add_table_of_contents', 20 );
A few notes about this snippet:
- It runs at priority 20, after WordPress has rendered blocks, so it sees the final heading HTML.
- It respects anchors you've already set in the block editor.
- The list nests H3 items under the preceding H2 as a sub-list. For strictly valid HTML, sub-lists would sit inside the parent
<li>; browsers render this fine, but you can refine the structure if you need to. - Parsing HTML with regular expressions works well for predictable post content, but for complex markup a plugin or a DOM-based approach is more robust.
Smooth Scrolling
To make jumping between sections feel smoother and prevent a sticky header from covering the heading, add this CSS through Appearance > Editor > Styles > Additional CSS (block themes) or Appearance > Customize > Additional CSS (classic themes):
html {
scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
}
h2[id],
h3[id] {
scroll-margin-top: 90px;
}
Adjust 90px to match the height of your sticky header. The reduced-motion rule respects visitors who prefer less animation.
Styling Your Table of Contents
A TOC should be easy to spot but not overpower your content. Here's simple CSS for the code-based TOC above, which you can adapt for plugin output by changing the class names:
.sajjad-toc {
background: #f7f7f9;
border: 1px solid #e2e4e7;
border-radius: 8px;
padding: 1rem 1.25rem;
margin: 1.5rem 0 2rem;
}
.sajjad-toc__title {
font-weight: 700;
margin: 0 0 0.5rem;
}
.sajjad-toc ul {
margin: 0;
padding-left: 1.25rem;
}
.sajjad-toc ul ul {
margin-top: 0.25rem;
}
.sajjad-toc li {
margin: 0.25rem 0;
}
.sajjad-toc a {
text-decoration: none;
}
.sajjad-toc a:hover,
.sajjad-toc a:focus {
text-decoration: underline;
}
Most TOC plugins also provide built-in themes, colors, and options for collapsible or sticky TOCs in their settings.
Where to Place the Table of Contents
- After the introduction: The most common placement. Readers get context first, then the outline.
- In a sidebar: A sticky sidebar TOC works well for long documentation, but it's usually hidden or moved on mobile.
- Collapsed by default: Useful if your TOC is long, but make sure the toggle is obvious.
Avoid placing the TOC above your introduction, since the first thing readers should see is a clear answer or summary.
Common Table of Contents Problems and Fixes
The TOC doesn't appear: Check that the post type is enabled in the plugin settings and that the post meets the minimum number of headings.
Links jump to the wrong place or behind the header: Add scroll-margin-top to your headings as shown above.
Links don't work at all: Two headings may have the same anchor, or a caching or optimization plugin is modifying the HTML. Clear your cache and check for duplicate IDs.
The TOC shows on pages where you don't want it: Use the plugin's per-post disable option or restrict it to certain post types.
Headings created by a page builder aren't detected: Some builders render headings in ways a TOC plugin can't read. Check whether your builder has its own TOC widget.
FAQ: Table of Contents in WordPress
WordPress core does not include a finished table of contents block yet. A TOC block has been developed in the Gutenberg plugin, but most sites use a plugin or an SEO plugin's TOC block.
Easy Table of Contents and LuckyWP Table of Contents are popular, reliable choices. If you use Rank Math or Yoast SEO Premium, their built-in TOC blocks may be all you need.
It can help indirectly by improving navigation and engagement, and search engines may show section links in results. It isn't a direct ranking factor on its own.
Yes. Add HTML anchors to your headings in the Advanced panel of each heading block, then create a list of links pointing to those anchors. Developers can also generate one automatically with the_content filter.
H2 and H3 headings are usually enough. Including every H4 and H5 makes the list long and harder to scan.
A sticky header covers the top of the page. Add scroll-margin-top to your headings in CSS so the browser leaves space above them when jumping.
Conclusion
Adding a table of contents is one of the easiest ways to make long WordPress posts more readable. For most people, a plugin like Easy Table of Contents or the TOC block in your SEO plugin is the fastest route, since it builds and updates the list automatically. If you want zero extra plugins, HTML anchors and a simple list do the job, and developers can generate a TOC with a small the_content filter.
Whichever method you choose, the quality of your TOC depends on your headings. Keep them clear, descriptive, and properly nested, then add a little CSS for smooth scrolling and spacing. Your readers will find what they need faster, and your long-form content will feel far more approachable.


