On some occasions we need an output of a field and the formatter options are not what we require or we only need a custom output; Whatever the use for which we are going to need to use this form of implementation, we are going to see what we need to do it.
In this example we are going to render the output of a field of a content type to format it as a currency.
We create a new module for this example.
type: module
name: ex_twig_extension
description: 'Provides an example for a twig extension'
core: 8.x
In our module we are going to create a service which we will use to make our branch extension. so we create our /ex_twig_extension.services.yml file.
services:
twig.number_format:
class: Drupal\ex_twig_extension\NumberFormat
tags:
- { name: twig.extension }
Having our service, we are going to create the function that the service mentions, which will be our TWIG extension. In the /src/ path we are going to create the file with the class name NumberFormat.php.
new \Twig_Filter_Method($this, 'numberFormat')
);
}
public function numberFormat($string)
{
$re = '/([0-9]*)([0-9]{3})/';
$str = $string;
$subst = '$$1.$2,00';
$result = preg_replace($re, $subst, $str);
return $result;
}
}
In the definition of our function we find getName() which will be the function that returns the name of the service.
The getFilters() function will create an instance called number_format which will call our desired function, which will be in charge of doing the final processing. It is important to note that the name of the instance will be used to call itself as a function in TWIG.
Finally, the numberFormat($string) function expects a parameter that must be sent from the template as the data to be formatted. Within the function we find a regular expression, which takes the data, eg: 500000, and formats it to return it. ex: $500,000.00 in the case of currency.
If you ever need to use regular expressions to solve a problem, I recommend this page to create them: https://regex101.com
Now we have everything ready for our TWIG extension, what we need now is to focus on the main objective and that is our field. TWIG allows us to overwrite the output of views, pages, blocks and also between nodes, in this case we only need our field of a content type. In order to see the name of the template that we must use, we can enable the option in our services.yml file:
parameters:
twig.config:
debug: true
By inspecting element and selecting the desired field, we can see in order of priority the file names that we can use.
Another help we can have is the documentation that Drupal offers us on naming conventions: https://www.drupal.org/docs/8/theming/twig/twig-template-naming-conventions
For our case we will use this machine name, because it is a field, in the path: themes/custom/custom_theme/templates/field/field--node--field-name--content-type.html.twig
In our file we are going to take the options that this file would normally bring in the documentation https://api.drupal.org/api/drupal/core!modules!system!templates!field.html.twig/8.2.x and we are going to give some adjustments.
{% if label_hidden %}
{% if multiple %}
{% for item in items %}
{{ item.content }}
{% endfor %}
{% else %}
{% for item in items %}
{{ item.content }}
{% endfor %}
{% endif %}
{% else %}
{{ label }}
{% if multiple %}
{% endif %}
{% for item in items %}
{% set value = item.content | number_format %}
{{ value }}
{% endfor %}
{% if multiple %}
{% endif %}
{% endif %}
On line 20 we create a variable value which will have the formatted value, since if we observe the content which is our unformatted value it is called as a parameter in the number_format function which is our extension.
With this we can use PHP functions outside of TWIG used as services, it can be useful in some cases used as a formatter or according to a requirement.
I hope this helps.