Automatically generate a content table in WordPress

A content table is what you can use in some big and small documents to reference all the titles so as to give quick access to certain part of the document.

You see that often on FAQs pages for example or other long page where inner navigation is needed.

The point here is to automate the process of creating a content table in WordPress. We are going to produce a list of a certain type of headers at the top of the page/post and link them with anchors to the document. Something similar to this:

[content_table tag=”h2″]

Sounds good but there is a limitation. We are not going to support nested titles list for now. It is possible but it would make the code much more complex.

The code is pretty simple and will consist of one function hooked to the filter “the_content” available in WordPress. Using a shortcode like content_table tag=”h2″  between [] will tell the function to generate the table.

Let’s get started

Here is the full code. I’ll go in more details below.

[snippet-content_table_full]

So, what have we got there.

[snippet-filter]

The function add_filter is a built function in WordPress which link functions to a particular trigger. In this case we use the filter the_content, which is called just before WordPress prints out the content of a post/page. The filter will pass the content of the post/page to each functions hooked to it. Now all we need is work on the content using the function get_content_table we’ve just hooked.

The get_content_table function.

[snippet-preg_match]

First we need to find out if the content table is requested so we search for the string content_table (parameters) (between []). If we find one then we carry on, if not we just return the content untouched.

[snippet-find_titles]

If the shortcode is there we need to get which tag needs to be used to build the table. WordPress provides a function to do that in the shortcode api. Once we have the targeted tag we can do a search for it in the content and put the results in an array.

Now the interesting stuff:

[snippet-create_table]

If the right type of titles are present then we start building the  content_table. First we find out how many elements we’ve got then create a div container to hold everything and start the first unordered list.

When we reach half of the elements we close the first ul and open a new one to create to list. This will help if you want to split the content table in two columns. Note: we have to slug the titles to use them as anchor links and keep the code valid.

The next is to add the back to top link to the existing titles:

[snippet-back_to_top]

We use the power of regular expressions and callback function to get that sorted. I think this was the trickiest bit of the code.

If you place this code in you function folder and add a the content_table tag=”X” (between [], don’t forget the double quotes around the tag) shortcode (where X is the tag used for your titles) then you should get a nice content table where you have added the shortcode. Add some simple styling and you’re done!

18 thoughts on “Automatically generate a content table in WordPress”

  1. Thanks for your comment Amanda and great job on getting it working in the sidebar! That’s something I was thinking about but never got the time to get around it, thanks a lot.

  2. Nevermind, I was able to piece something together by modifying this a bit and using the shortcode in a text widget.

    What I ended up with is a bit specific to my site, and I’m sure there’s a better way to go about it, but here it is if someone wants to play with it:
    http://pastie.org/852611

    I’m going to always use h3’s, so I removed the need for the “tag” attribute (so the shortcode is just [content_table]), and since it’s in the sidebar, I’ll never need to divide it in half, so I removed that bit too, along with some slight markup changes, etc.

  3. Is there a way to do this outside of the loop? For example, to put the contents table in the sidebar?

  4. Sorry but it still doesn´t work. My shortcode IS between tags but they where stripped out in my last comment.

    The “echo” doesn´t seem to work but I´m not so much a PHP guy and not sure where exactly to put it.

    Maybe something went wrong when I copy&paste the code for the functions file. Is it possible you send it to me via email in a txt file?

  5. If there is no p tags around the shortcode then try to change the line $content = str_replace('<p>'.$m[0].'</p>', $content_table, $content);

    by

    $content = str_replace($m[0], $content_table, $content);

    By echo I meant using the echo function in php to print out some variable like $content_table before doing the replace. Just to double check that the function acually works.

  6. Ok let’s try something else. Is you shortcode between p tags? The function only replaces the string <p>[content_table tag="xx"]</p>. (check spaces as well)

    If still no luck try to echo at various stage of the function to see where it fails.

  7. That’s my bad, you have to enclose the tag in double quotes. So the shortcode should look like: [content_table tag=”h3″] in your case.

    I’ve corrected that in the article as well.

  8. Needed to set some backslashes in front of some doublequotes and now the error is gone. I´m Running PHP 5.

    But it still does not wor properly. When I type in

    [content_table tag=h3]

    in order to get the h3 headings in a list the output is just the shortcode as plain text. D I make any mistake?

  9. Works for me when I tried you line of code for the ‘back to top’ bit. Could be a problem with php. Some early versions (before 4.0.4) do not allow you to use the $n in the second parameter of preg_replace.

  10. Cool stuff but i get an error:

    Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING in /PATH-TO-FILE/functions.php on line 190

    In line 190 is the part for the “back to top” links:

    $content = preg_replace("|(.*)|e", "''.ucfirst('$1').'Back to top'", $content);

    Any idea what´s happened?

Leave a Reply

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