How to create a table of contents in WordPress without using plugins

Last updated 13-08-2019.

For my cryptocurrency mining guide I wanted to create a table of contents. There are plenty of WordPress plugins available for this, but if you want to use plugins with WordPress as a blog host, you have to pay extra. Not particularly pleased with this, I set out to build my own HTML-based table of contents. The final result will be shared in this article. I’ve split the information into a copy-paste part and two explanation parts, so you can choose how much detail you want.

Contents

1. Copy-paste is the only explanation I need
2. So… how do I use this?
3. A detailed explanation would be nice
3.1. Wait.
3.2. Images complicate things?
4. Troubleshooting

Copy-paste is the only explanation I need

This is a template for your table of contents (used in this article):

<h2>Contents</h2>
<a href="#Copy-paste is the only explanation I need">1. Copy-paste is the only explanation I need</a>
<a href="#So... how do I use this?">2. So... how do I use this?</a> 
<a href="#A detailed explanation would be nice">3. A detailed explanation would be nice</a> 
<a style="margin-left: 2rem;" href="#Wait.">3.1. Wait.</a> 
<a style="margin-left: 2rem;" href="#Images complicate things?">3.2. Images complicate things?</a> 
<a href="#Troubleshooting">4. Troubleshooting</a>

If the table of contents’ rows do not show up on separate lines, just insert <br> tags between them (this seems to vary, probably depending on your HTML-editor or your page CSS).

This is a template for your headings (used for the heading of this section):

<h2><a style="position: relative; top: -30px;" name="Copy-paste is the only explanation I need"></a>Copy-paste is the only explanation I need</h2>

So… how do I use this?

You can see how these templates are used in this article by looking at the source code of the web page (press the F12 key with the page selected in your browser). Basically, all you need to do is to switch to the HTML editing mode of your WordPress site (previously called “Text” editing mode) and copy-paste the template code above into your article at suitable locations. You should also change all instances of heading names to match the headings of your article, to avoid confusing your readers and the HTML code.

If you need more indentation for sub-headings, change margin-left from 2rem to 3rem or 4rem or higher.

If you need more headings, just follow the same pattern as the entries already in the table of contents. So for each heading in your article, copy-paste the heading template above and change all instances of “Copy-paste is the only explanation I need” to whatever your heading is. Make sure that the corresponding href entry in the table of contents is exactly the same as “# + the name attribute of your heading anchor tag <a>” (like you see in the table of contents template above), otherwise the table of contents anchor will not find the heading anchor.

In the visual editing mode of WordPress you will see the anchor tags <a> as small grey blocks with an anchor symbol inside. There will also be an indent of each heading to make space for the anchor symbol. This indent will not be seen once the article is published or previewed.

Note that the name attribute in the heading anchor tag will be part of the URL if someone links to your heading from another site. Also note that the h2 tag can be changed to whatever heading size you wish.

A detailed explanation would be nice

I thought you’d never ask! Let’s start by taking a closer look at the anchor code. As you know by now you can instruct a web browser how it should display a web page via HTML tags. The anchor tag “<a>” is actually the same as is used for external links, so what we are actually doing with the method above is creating hyperlinks to other parts of the webpage.

The simplest way to write the code for an anchor is actually a bit different from what I wrote in the template above. It would look like this:

<a name="Copy-paste is the only explanation I need"></a><h2>Copy-paste is the only explanation I need</h2>

Note the shift in anchor position within the code and the lack of style attribute. However, at least with the theme I use on my blog I found that images will not work well with this approach.

Wait.

Alexas_Fotos, cat-2806957_1920

Images complicate things?

Yes. I encountered two problems. First, an additional space was created after an image when it was directly followed by a heading. Then, when trying to fix this problem for my cryptocurrency mining guide I noticed that when clicking on a link in the table of contents while logged into WordPress, the black WordPress menu bar at the top makes it so that the start of the linked section will not be visible. Our feline friend above demonstrates this latter problem.

Fortunately, the solution to these problems is quite simple once you know it. First the anchor tag should be moved inside the heading tag <h2>. This removes the additional space after images. Then style="position: relative; top: -30px;" should be added to the anchor tag. This moves the anchor up by 30px units relative to its original position. So even a reader which is logged into WordPress while browsing your blog will see the intended text section when clicking on a link in the table of contents, since there is a margin for the black WordPress menu bar at the top. Thus you end up with headings in the familiar form: <h2><a style="position: relative; top: -30px;" name="Copy-paste is the only explanation I need"></a>Copy-paste is the only explanation I need</h2>

Since this seems to solve all problems mentioned above, I recommend that you use this version of the heading anchor code.

Indentation of the table of contents is done via the style="margin-left: 2rem;" attribute. E.g. <a style="margin-left: 2rem;" href="#Images complicate things?">3.2. Images complicate things?</a>. This just changes the left margin of the text, but it is worth noting that the rem unit can be replaced with many other units (rem (= root em), em and px being the most common ones). Using the rem unit in this particular case is better than using px since rem scales with the text size of the page, while px is (vaguely) designed to always look the same. Using the px unit could thus cause the relative position of things in the table of contents to change depending on font size. When moving the heading anchor with the style="position: relative; top: -30px;" code we use the px unit since we always want to move the anchor a constant distance. The distance would otherwise depend on the font size of the heading (using em) or the the font size of the root page (using rem). In general, the rem unit is recommended nowadays.

Troubleshooting

You may want to center align images in your posts so that the images won’t look out of place if a user flips their mobile device while browsing your post.

If the anchor tag tries to create an extra new line before the heading, you may want to switch to the visual editing mode of WordPress and delete this new line manually.

Add some <br> tags (newline) if you need more space between images and text.

Just in case the above heading code template does not work for you I will mention another anchor version here. Note that it seems to look off when using Microsoft’s Edge browser. As before, replace “Copy-paste is the only explanation I need” with whatever heading you use:

<h2><a style="margin-top: -30px; padding-top: 30px;" name="Copy-paste is the only explanation I need"></a>Copy-paste is the only explanation I need</h2>
Advertisement

13 comments

  1. Thank you… You have solved my problem.

    1. You’re welcome!

  2. Thank you for this! I copied the code, but my content list comes out as below (ie.. all on the one line – everything else works) – any ideas?
    Contents
    1. National Parks Road Trip 2. East Africa 3. New Zealand – South Island Road Trip 4. Uluru Road Trip

    1. Hi booked91!
      Glad it helps. The solution to your problem would be to add br tags after each list item. I’ll update the example with this in a day or so when I have more time. Thank you for bringing the issue to my attention!

      1. Thank you again, that worked! I need to do some more reading to remind myself of basic code.

  3. The instructions worked perfectly, wow…thank you so much for writing this post! 😀

    1. No problem!

  4. Bless your soul! I learned so much 🙂 Thank you!

    1. Thank you!

  5. Thank you so much! This will save any extra plugin sluggishness I was about to install on my sites. You are da bomb!

    1. Many thanks!

  6. You are a life saver! So glad I found this thank you so much!

    1. Happy to help!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: