How to Customize Grav Gantry 5 Helium theme to show reading time
Well, it finally happened. My journey into managing this blog site with Grav has reached a new step. To date I have done everything with this site using nothing more than the Grav Admin Panel web interface. My goal was to see how long I could manage everything this way. That is, I have not had to resort to "going under the hood" to modify any files, etc. But this time I hit a wall.
Grav has a very nice Admin Panel. And Gantry 5 is quite powerful and offers a nice web-based UI plugin for managing your site's theme, also from within Grav Admin. Unfortunately, when it comes to adjusting a theme to the level I was after, it turns out you have to go lower.
Using Grav Admin, I added the readingtime plugin to my site in hopes of showing, as many blog sites do, how long a given post would take (on average) to read. This is that line which says "X minutes" or "X minutes to read", typically shown under a blog title along with the date and other such info. If you look at this post, for example, you will see it shown nestled between the date and the tags of the post just under the title. Unfortunately, it does not do so automatically but rather requires adding a line of code to be added.
Now it is possible that I could have used the Gantry 5 web-based UI to drop this line of code within a blog post manually. But it would require using TWIG (a template engine for PHP), meaning I would have to enable TWIG in the configuration for blog posts, and then I would have to remember to add the code in each post. What I wanted was to have this readingtime feature automatically appear just as the publish date and tag information do.
Digging around, I eventually found where the date and tag information were generated. Unfortunately, Gantry 5 offers no way via its web UI to tweak themes for this. This meant modifying the theme template files directly. So I read about customizing Gantry 5 theme files.
Generally speaking, when it comes to modifying things in Grav, you should only work with files in the <grav_root>/user/data/...
subtree. The idea is that anything users create is stored there, and anything you have installed from Grav that lies outside that should look for a similar (though as you will see not identical) path within that subtree, and, if found, use that copy as a sort of override for the installed default. The general thinking is that you do not modify any files installed by Grav or its plugins, but rather maintain overrides in a parallel subtree. This way updates will not be inadvertently impacted by you mucking about, nor will your overrides be overwritten by such updates. It is a design used in various software. The one thing you DO need to be cognizant of is that if you copy over a default file and modify it, after any updates to that app/plugin/theme/etc., you may need to check if your copy requires any adjustments relevant to the new default file.
Now in this instance, I am using the Gantry 5 theme framework and specifically its Helium theme. So what I wanted to modify was the Helium template files specifically related to blog_item
pages. The template files are located under
<grav_root>/user/plugins/gantry5/engines/nucleus/templates
To override any such files, according to the Gantry documentation, you place them in
<grav_root>/user/data/gantry5/themes/g5_helium/engine/templates
The particular file I found that I needed to modify (which contained the TWIG code for generating the date and tag information for a blog post)--blog_item.html.twig
--is actually a partial file, as in one that is included within another file. It is located at
<grav_root>/user/plugins/gantry5/engines/nucleus/templates/partials/blog_item.html.twig
So to achieve my goal, I first had to first create the necessary subtree and copy over the default file as follows:
# Create directories under <grav_root>/user/data
sudo mkdir -p <grav_root>/user/data/gantry5/themes/g5_helium/engine/templates/partials
# Copy over default file used for blog_item posts
sudo cp <grav_root>/user/plugins/gantry5/engines/nucleus/templates/partials/blog_item.html.twig <grav_root>/user/data/gantry5/themes/g5_helium/engine/templates/partials
# Set ownership of all files and subdirectories to the webserver account
sudo chown -R www-data:www-data <grav_root>/user/data/gantry5
# Edit file
sudo nano <grav_root>/user/data/gantry5/themes/g5_helium/engine/templates/partials/blog_item.html.twig
Next I added the line below just after the date code:
...
<span class="separator">/</span> {{ page.content|readingtime({'format': '{minutes_short_count} {minutes_text}'}) }}
...
To see this in context...
...
{% if page.taxonomy.tag or show_date %}
<div class="list-blog-meta">
{% if show_date %}
<i class="fa fa-clock-o" aria-hidden="true"></i>
<time class="dt-published" datetime="{{ page.date|date("c") }}">
{{ page.date|date('jS M Y') }}
</time>
{% endif %}
<span class="separator">/</span> {{ page.content|readingtime({'format': '{minutes_short_count} {minutes_text}'}) }}
{% if page.taxonomy.tag %} <span class="separator">/</span> {% endif %}
...
With that done, I reloaded the blog pages, and they now show the reading time for each post.