Having a dynamic table of content for long articles is a really nice feature. And field collection module is just the module you need to get this feature implemented. To know how, check this tutorial.
Drupal’s field collection module is one of my favorite modules from drupal. What it does is lets you add a collection of fields as a single field to a content multiple times. For example, in my website I want to write a trip log which will be quite long and so its a good idea to divide it in days. Now, obviously I can have anchor tags in the body content and have a list on the top which will take the reader to the correct location, but what if these things are done automatically. I will have a set of fields as body and title. As and when I keep adding a new title and body field data, the toc will get updated automatically. Neat isn’t it?
So, that’s what we will be doing in this tutorial. The module that we will be using in this tutorial is “Field collection” which you can find here. And this module is dependent on Entity module which you can find here.
Ok, so once you have the module installed successfully, you will see “Field collection” as one of the options when you try to create a new field as shown in the screen shot below:
When adding you will come across two options: hidden and embedded. Make sure you select Embedded or else you will not be able to see the fields in add content field. The basic idea is to add the content from the admin section and then use internal functions and theme to display them inside the node.
Ok, make sure that the field has number of values set to more than 1 or else why would you even use this module :). Till now we have just added a container field. Now we have to add the sub fields which will be inside the container field. To do that you need to go inside Structure->Field collections and you will see that your field is listed there.
Inside manage fields, now I will add two fields – one for the title and the second for the body text. Mind it, I have set the number for these fields to just one because inside the container, there will be only one title and one body. But if you have a different requirement, then feel free to change accordingly. Check my screen shot:
Now that the fields are added, its time to add some content. Here is a snap shot of the content that I have added and how it looks by default.
The next step is to get rid of the content which is getting displayed below the body text by default and show it the way we like. Go to Structure->Content types->[Name of the content type]->manage display and hide the field from both teaser and default view. Well, if these are hidden how will the content get displayed?
So now let’s start the coding.
The module that I have create is “TOC”.
As you can see there are two tpl files. Although I highly recommend you having a separate folder for TPLs, JS, CSS used for a module, but this is just for demo so ?
Ok, let’s start with the hook_theme().
Two tpls are handleded here. One for the toc content and the second will be a list of the titles which will be displayed at the top of the body content.
Once that is done, let’s implement hook_node_load. Here is the code:
Here first we check if the node type is the one we want. In my case its the article content type. I assigned two new objects to the main node object while the node is getting loaded. $node->toccontent which will have all the body content from the field and $node->toclist which will have the main titles in the form of a list.
Toccontent uses an internal function call _nodeelements_generate_tocContent where I am passing the node object. Here is the function’s code:
No rocket science here, at first checking if the field data is not empty and then looping through all the fields and building array $tocBody. One important function call is “field_collection_item_load”. This is the field collection module’s function which gives the collection of the field and the data. It requires the field id for it to load the data. With the data loaded through this function, I added it to the $tocBody array and passed it to the tpl where I have taken care of the formatting.
The second object which is passed to the node is the toclist which again uses a similar function _nodeelements_generate_tocList where again I am passing the node object. The rest functionality is the same.
Once these functions are executed, the final thing to do is print the output in the node tpl so that the data can be seen. I am using the default drupal theme and here is the modified tpl screenshot:
The tpls which I have used does not have a lot of logic inside it. Here is the code for both of them:
The toccontent tpl
The toclist tpl