(This module was tested on drupal 8.1.8)
Problem to solve
Sometimes working with Views can be a challenge, in some cases you want to modify the values or process the content of the field.
Many developers use the preprocess functions, or alter the query of the view, however there is another option: twig filters.
The Goals:
Being able to calculate the reading time of any given node (body field).
The field needs to output: "5 min read", "9 min read", depending on the word count of the node.
Twig Filters:
Twig filters give us the ability to modify variables on twig template.
{% set salutevariable = "Hello Friend" %}"
If we output the variable {{ salutevariable }}
is going to show: Hello Friend
If we want to make the variable lowercase, we use a filter.
{{ salutevariable | lower }}
the "|" indicates that we are going to use a filter in our case "lower"
, so the value "Hello Friend" is going to be parsed by the filter lower
.
The output will be: hello friend
Official Documentation:
Creating A Module:
Create a new module in: modules/custom/
Our module is going to have the following structure:
|readingtime/ |-- readingtime.info.yml |-- readingtime.services.yml |-- src/TwigExtension/ReadingTimeExtension.php
readingtime.info.yml
contains:
name: readingtime type: module description: Provides a Twig filter that calculates the time of reading for any given string. core: 8.x package: Custom
Create a services file: readingtime.services.yml
services: readingtime.twig_extension: class: Drupal\readingtime\TwigExtension\ReadingTimeExtension tags: - { name: twig.extension }
The ReadingTimeExtension.php
will contain the following:
<?php namespace Drupal\readingtime\TwigExtension; use Drupal\Core\Render\Markup; class ReadingTimeExtension extends \Twig_Extension { /** * Here is where we declare our new filter. * @return array */ public function getFilters() { return array( 'readingtime' => new \Twig_Filter_Function( array('Drupal\readingtime\TwigExtension\ReadingTimeExtension', 'readingTimeFilter') // Here we are self referencing the function we use to filter the string value. ) ); } /** * This is the same name we used on the services.yml file * @return string */ public function getName() { return "readingtime.twig_extension"; } /** * @param $string * @return float */ public static function readingTimeFilter($string) { if($string instanceof Markup) { // we check if the $string is an instance of Markup Object. // strip_tags help us to remove all the HTML markup. // if $string is an instance of Markup we use the method __toString() to convert it to string. $striped_markup = strip_tags($string->__toString()); // On avarage we read 130 words per minute. // the PHP function str_word_count counts the number of words of any given string. $wpm = str_word_count($striped_markup)/130; // $wpm = Words Per Minute. $reading_time = ceil($wpm); // Round the float number to an integer. return $reading_time; // we return an integer with the number of minutes we need to read something. } else { return $string; } } }
Testing our brand new filter:
Now we install our new module in admin/modules.
It's also helpful to generate dummy content with the devel module.
The View:
Then I proceed to create a simple view of articles:
View configuration:
FORMAT:
show: fields
FIELDS:
Content: Title
Content: Body ( this is the one we are going to apply our new twig filter )
Content: Body
We access the configuration of the second Content: Body
and under the REWRITE RESULTS option we are going to override the output of the field:
and the result is the following: