Timber and Twig
Use Easy SVG Pro icons in a Timber theme: turn on the feature, draw icons from Twig, read them from fields, and keep templates safe when the feature is off.
Timber themes render their markup with Twig, and Twig cannot call PHP functions directly. Easy SVG Pro adds three things to Timber's Twig: the function easy_svg_icon(), a filter with the same name, and easy_svg_icon_exists(). This tutorial takes you from switching them on to a component library that keeps working even when somebody turns the feature off.
What you need
- Timber 1 (tested with 1.23.1) or Timber 2, from the plugin or through Composer in your theme.
- Easy SVG Support (the free plugin) and Easy SVG Pro, with an active licence.
- The features your collections need: Icon set editor for icon sets, Theme & folder sources for theme and drop-in folders. The free icon library needs neither.
Turn on Timber / Twig
Go to Icons → Features and switch on Timber / Twig in the Integrations group. The screen only shows it when a Timber class is loaded, so activate Timber (or load your theme with Timber) first.
Find an icon address
Every icon has an address collection/slug. Copy it from the Icon Sets tab, from the Packs tab, or list them with wp easy-svg icons list. A bare slug like phone means the free icon library.
Draw it
{{ easy_svg_icon( 'acme/phone' ) }}
Open the page. You should see an inline svg element, not text.
The three helpers
| Helper | Use it for | Returns |
|---|---|---|
easy_svg_icon( ref, args ) | Addresses you write in the template | Safe SVG markup or empty |
ref is easy_svg_icon(args) as a filter | Addresses from fields and loops | The same |
easy_svg_icon_exists( ref ) | Branching before you draw | true or false |
{{ easy_svg_icon( 'acme/phone' ) }}
{{ post.meta( 'easy_svg_icon' )|easy_svg_icon }}
{% if easy_svg_icon_exists( 'acme/award' ) %}...{% endif %}
All three call the free plugin's easy_svg_icon(). Twig, PHP templates, shortcodes and the Icon block draw the same markup.
Accessibility in one rule
An icon is decorative unless you give it a label.
{# Decorative: the text next to it says everything. #}
<a href="/contact">{{ easy_svg_icon( 'acme/mail' ) }} Contact</a>
{# Meaningful: the icon is the only content of the button. #}
<button>{{ easy_svg_icon( 'acme/search', { label: __( 'Search', 'acme' ) } ) }}</button>
Decorative icons get aria-hidden="true" focusable="false". Labelled icons get role="img" and aria-label. Pass decorative: false to keep an icon meaningful without your own label; it is then named after its stored title or its slug.
Icons from fields
Editors usually pick icons in a field, and the template draws whatever they picked. Every picker Easy SVG Pro integrates with stores the address as collection/slug:
- Block theme support registers the post meta
easy_svg_iconfor every post type. - The ACF icon picker tab, with ACF's default string return format, returns
collection/slug. - Meta Box, Lazy Blocks and WPBakery fields store the same address.
{% for service in services %}
<article class="service">
{{ service.meta( 'easy_svg_icon' )|easy_svg_icon( { class: 'service__icon' } ) }}
<h3>{{ service.title }}</h3>
</article>
{% endfor %}
A missing or empty field prints nothing, so you do not need an if for the icon itself. You only need one when you print wrapper markup around it.
A component that renders once
Checking with easy_svg_icon_exists() and then drawing with easy_svg_icon() renders the icon twice. In a loop of fifty cards that adds up. Capture the output instead:
{# templates/components/icon-badge.twig #}
{% set icon %}{{ easy_svg_icon( ref, { class: 'badge__icon', label: label|default( '' ) } ) }}{% endset %}
{% if icon|trim is not empty %}
<span class="badge">{{ icon }}</span>
{% endif %}
The set block keeps the markup marked as safe. The short form {% set icon = easy_svg_icon( ... ) %} does not: printing it shows SVG source as text unless you add |raw.
Keep templates safe when the feature is off
The Twig helpers exist only while the licence is active and Timber / Twig is on. When either goes away, they are not registered, and Twig fails to compile any template that calls them, with an "Unknown function" or "Unknown filter" error. On a client site that can mean a white page after a lapsed licence.
If you cannot guarantee the feature stays on, register your own wrapper under a different name. It calls the free plugin's public easy_svg_icon() directly and does not depend on the Pro Twig feature:
/**
* {{ acme_icon( 'acme/phone', { label: 'Call us' } ) }} in every template.
* Works with or without the Timber / Twig feature, and prints nothing
* when Easy SVG Support is missing.
*/
function acme_render_icon( $ref, $args = array() ) {
if ( ! function_exists( 'easy_svg_icon' ) || ! is_string( $ref ) || '' === trim( $ref ) ) {
return '';
}
return (string) easy_svg_icon( $ref, is_array( $args ) ? $args : array() );
}
function acme_twig_icon_helpers( $twig ) {
if ( ! is_object( $twig ) || ! method_exists( $twig, 'addFunction' ) || ! class_exists( '\Twig\TwigFunction' ) ) {
return $twig;
}
$safe = array( 'is_safe' => array( 'html' ) );
$twig->addFunction( new \Twig\TwigFunction( 'acme_icon', 'acme_render_icon', $safe ) );
if ( method_exists( $twig, 'addFilter' ) && class_exists( '\Twig\TwigFilter' ) ) {
$twig->addFilter( new \Twig\TwigFilter( 'acme_icon', 'acme_render_icon', $safe ) );
}
return $twig;
}
add_filter( 'timber/twig', 'acme_twig_icon_helpers' );
Two rules make this safe:
- Use your own name. Do not register a fallback called
easy_svg_icon. Twig refuses a second function with the same name, so a fallback that runs first would stop Easy SVG Pro's registration. - Escape on the way in, not out.
easy_svg_icon()returns stored markup that the free plugin has already sanitized and hardened, which is whyis_safeis fine here. Do not use the same wrapper for markup from anywhere else.
Pro icon sets and folder collections still need their own features (Icon set editor, Theme & folder sources). When those are off, the wrapper prints nothing for their addresses, and the page stays up.
Caching and performance
- Every call renders from the stored markup; there is no extra HTTP request and nothing is enqueued.
- If Styles & theme colors is on, templates and colour mapping are applied in the same call.
- If you cache rendered Twig with
Timber::render( $file, $context, $expires )or a page cache, a changed icon shows only after that cache expires. Clear it fromeasy_svg_pro_set_icons_writtenwhen a set changes.
Troubleshooting
| Symptom | Cause |
|---|---|
| "Unknown function easy_svg_icon" | Licence inactive or Timber / Twig off. Use the wrapper above. |
| SVG source appears as text | The value was assigned with {% set x = ... %} and printed later. Use the set block or ` |
| Nothing prints | Wrong address, a bare slug for a Pro icon, a draft set, or the collection's own feature is off. Try easy_svg_icon_exists() on the address. |
| Old drawing after an edit | A template or page cache. |
| The Timber / Twig switch is missing | No Timber class is loaded on that request. |