Contributed by
Jérôme Tamarelle
in
#52748
Twig extensions allow you to add new features to Twig templates using your
own logic. In Symfony applications, they are created by extending the
AbstractExtension
class and defining the custom filters and functions:
// src/Twig/AppExtension.php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class AppExtension extends AbstractExtension
{
public function getFilters(): array
{
return [
new TwigFilter('product_number', [$this, 'formatProductNumber']),
];
}
public function formatProductNumber(string $number): string
{
// ...
}
}
To improve performance, it's common to split the extension into two classes:
one to declare the filters/functions and another to contain the logic, which is
loaded only when the filter or function is actually used in a template:
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class AppExtension extends AbstractExtension
{
public function getFilters(): array
{
return [
new TwigFilter('product_number', [AppRuntime::class, 'formatProductNumber']),
];
}
}
use Twig\Extension\RuntimeExtensionInterface;
class AppRuntime implements RuntimeExtensionInterface
{
public function formatProductNumber(string $number): string
{
// ...
}
}
In Symfony 7.3, we're making custom Twig extensions even simpler and more
powerful thanks to PHP attributes. Here's what the same extension looks like now:
namespace App\Twig;
use Twig\Attribute\AsTwigFilter;
class AppExtension
{
#[AsTwigFilter('product_number')]
public function formatProductNumber(string $number): string
{
// ...
}
}
With this new approach:
- You no longer need to extend the
AbstractExtension
base class; - Your extensions are lazy-loaded by default, so you get the same
performance as before without having to split them into two classes; - You don't need to define
getFilters()
andgetFunctions()
methods;
just add the corresponding attribute (#[AsTwigFilter]
,#[AsTwigFunction]
)
directly to your methods.
The new attributes also allow you to fully configure each filter and function
using named arguments:
#[AsTwigFilter('...', needsEnvironment: true)]
#[AsTwigFilter('...', needsEnvironment: true, preEscape: true)]
#[AsTwigFunction('...', needsContext: true)]
#[AsTwigFunction('...', needsCharset: true, isSafe: ['html'])]
This new syntax makes your extensions cleaner, faster to write, and easier to
maintain while keeping the full power of the Twig integration.
Sponsor the Symfony project.