Creating Custom Filters
Filters are powerful tools for formatting and modifying data directly within Latte templates. They offer a clean
syntax using the pipe symbol (|
) to transform variables or expression results into the desired output format.
What are Filters?
Filters in Latte are essentially PHP functions designed specifically to transform an input value into an output value.
They are applied using the pipe (|
) notation within template expressions ({...}
).
Convenience: Filters allow you to encapsulate common formatting tasks (like date formatting, case conversion, truncation) or data manipulations into reusable units. Instead of repeating complex PHP code in your templates, you can simply apply a filter:
Readability: Using filters makes templates cleaner and more focused on presentation, moving the transformation logic into the filter's definition.
Context-Awareness: A key strength of Latte filters is their ability to be context-aware. This means a filter can understand the type of content it's operating on (HTML, JavaScript, plain text, etc.) and apply appropriate logic or escaping, which is crucial for security and correctness, especially when dealing with HTML generation.
Integration with Application Logic: Just like custom functions, the PHP callable behind a filter can be a closure, a static method, or an instance method. This allows filters to access application services or data if needed, though their primary purpose remains transforming the input value.
By default, Latte provides a rich set of standard filters. Custom filters allow you to extend this set with your project-specific formatting and transformation needs.
If you need to perform logic based on multiple inputs or don't have a primary value to transform, a custom function is likely a better fit. If you need to generate complex markup or control template flow, consider a custom tag.
Creating and Registering Filters
There are several ways to define and register custom filters in Latte.
Direct Registration via addFilter()
The simplest way to add a filter is using the addFilter()
method directly on the Latte\Engine
object.
You provide the filter name (how it will be used in the template) and the corresponding PHP callable.
Usage in Template:
Argument Passing:
The value on the left side of the pipe (|
) is always passed as the first argument to the filter function.
Any parameters specified after the colon (:
) in the template are passed as subsequent arguments.
Registration via Extension
For better organization, especially when creating reusable sets of filters or sharing them as packages, the recommended way is to register them within a Latte Extension:
This approach keeps your filter logic encapsulated and makes registration straightforward.
Using a Filter Loader
Latte allows registering a filter loader via addFilterLoader()
. This is a single callable that Latte asks for any
unknown filter name during compilation. The loader returns the filter's PHP callable or null
.
This method was primarily intended for lazy loading filters with very expensive initialization. However, modern dependency injection practices usually handle lazy services more effectively.
Filter loaders add complexity and are generally discouraged in favor of direct registration via addFilter()
or
within an Extension using getFilters()
. Use loaders only if you have a strong, specific reason related to performance
bottlenecks in filter initialization that cannot be addressed otherwise.
Filters Using a Class with Attributes
Another elegant way to define filters is by using methods within your template
parameters class. Simply add the #[Latte\Attributes\TemplateFilter]
attribute to the method.
Latte will automatically detect and register methods marked with this attribute when the TemplateParameters
object
is passed to the template. The filter name in the template will be the same as the method name (shortify
in
this case).
Contextual Filters
Sometimes, a filter needs more information than just the input value. It might need to know the content type of the string it's processing (e.g., HTML, JavaScript, plain text) or even modify it. This is where contextual filters come in.
A contextual filter is defined just like a regular filter, but its first parameter must be type-hinted as
Latte\Runtime\FilterInfo
. Latte automatically recognizes this signature and passes the FilterInfo
object
when calling the filter. Subsequent parameters receive the filter arguments as usual.
$info->contentType
is a string constant from Latte\ContentType
(e.g.,
ContentType::Html
, ContentType::Text
, ContentType::JavaScript
, etc.), or null
if the filter is applied to a variable ({$var|filter}
). You can read this to check the input context and
write to it to declare the output context type.
By setting the content type to HTML, you tell Latte that the string returned by your filter is safe HTML. Latte will then not perform its default auto-escaping on this result. This is crucial if your filter generates HTML markup.
If your filter generates HTML, you are responsible for correctly escaping any input data used within
that HTML (like in the htmlspecialchars($formatted)
call above). Failure to do so can create XSS vulnerabilities. If
your filter only returns plain text, you don't need to set $info->contentType
.
Filters on Blocks
All filters applied to blocks must be contextual. This is because the block's content has a defined content type (usually HTML), which the filter needs to be aware of.
Contextual filters provide powerful control over how data is processed based on its context, enabling advanced features and ensuring correct escaping behaviour, especially when generating HTML content.