# Extending Twig

## Twig Environment

Twig has a `\Twig\Environment` class that you can [use to extend Twig](https://twig.symfony.com/doc/3.x/advanced.html). One of the most common ways this is used is to add [functions](https://twig.symfony.com/doc/3.x/advanced.html#functions) and [filters](https://twig.symfony.com/doc/3.x/advanced.html#filters) to Twig. But it could also be used to add globals, extensions, and more.

Timber creates a `\Twig\Environment` object for you. You can use the `timber/twig` filter to access that object and extend Twig through it.

Timber further abstracts some of that functionality for you, so you can add functions or filters more easily.

## Functions

If you have functions that you use a lot and want to improve readability of your code, you can make them available in Twig.

By default, you’ll have to use `{{ fn('function_name') }}` to call a function in Twig. To use a function directly without using `fn()`, you can use the `timber/twig/functions` filter.

**functions.php**

```php
add_filter('timber/twig/functions', function ($functions) {
    $functions['wp_get_shortlink'] = [
        'callable' => 'wp_get_shortlink',
    ];

    return $functions;
});
```

The `$functions` variable is an array of functions that Timber already adds by default.

In the example above, we add a `wp_get_shortlink` function by defining an array with a `callable` key that contains the name of the PHP function we want to call. In this case: [`wp_get_shortlink()`](https://developer.wordpress.org/reference/functions/wp_get_shortlink/).

In Twig, we can then use it like this:

**single.twig**

```twig
{# Get shortlink for the current post #}
<a href="{{ wp_get_shortlink() }}">Short URL</a>

{# Get shortlink for a specific post #}
<a href="{{ wp_get_shortlink(post.id) }}">Short URL</a>
```

### Functions that Timber provides

Timber already comes with a list of functions it adds by default. You can read more about these functions in the [Functions Guide](https://timber.github.io/docs/v2/guides/functions/).

You can also var dump all filters directly by adding the following code to your `functions.php` file:

**functions.php**

```php
add_filter('timber/twig/functions', function ($functions) {
    var_dump($functions);

    return $functions;
});
```

### Changing functions

You can replace a function with your own function or even remove a function by updating the array items in `$functions`.

```php
add_filter('timber/twig/functions', function ($functions) {
    // Replace a function.
    $functions['get_image'] = [
        'callable' => 'custom_get_image',
    ];

    // Remove a function.
    unset($functions['get_image']);

    return $functions;
});
```

## Filters

Timber comes with a set of filters that you can use in your Twig templates. You can read more about these filters in the [Twig Filters Guide](https://timber.github.io/docs/v2/guides/twig-filters/).

To extend Twig with your own filters, you can use the `timber/twig/filters` filter in PHP. The benefit of filters is that they make your code somewhat more readable, because you chain filters with pipes (`|`) instead of nesting a value inside function calls.

Here’s an example where we add our own `|price` filter. We pass the name of the PHP that should be called – in this case it’s `format_price()` – with a `callable` key.

**functions.php**

```php
add_filter('timber/twig/filters', function ($filters) {
    // Add your own filters.
    $filters['price'] = [
        'callable' => 'format_price',
    ];

    $filters['slugify'] = [
        'callable' => 'sanitize_title',
    ];

    return $filters;
});
```

In Twig, we can then use it like this:

```twig
<h2 id="{{ post.title|slugify }}">{{ post.title }}</h2>

<span class="price">{{ post.meta('price')|price }}</span>
```

### Filters provided by Timber

You could use the same filter to dump a list of all available filters for debugging:

```php
add_filter('timber/twig/filters', function ($filters) {
    var_dump($filters);

    return $filters;
});
```

### Changing filters

You can replace a filter with your own function or even remove a filter by updating the array items in `$filters`.

```php
add_filter('timber/twig/filters', function ($filters) {
    // Replace a filter.
    $filters['list'] = [
        'callable' => 'custom_list_filter',
    ];

    // Remove a filter.
    unset($filters['list']);

    return $filters;
});
```

## Adding functionality with the Twig Environment filter

You can still extend the [Twig Environment](https://twig.symfony.com/doc/3.x/advanced.html) directly with the `timber/twig` filter. The only disadvantage of this is that once functions or filters are added to Twig, the can’t be removed anymore.

Here’s the same functions and filters that we add above. But instead of using `timber/twig/functions` and `timber/twig/filters`, we use `timber/twig` directly.

```php
add_filter( 'timber/twig', function( \Twig\Environment $twig ) {
    $twig->addFunction(
        new \Twig\TwigFunction( 'edit_post_link', 'edit_post_link' )
    );

    $twig->addFilter(
        new \Twig\TwigFilter( 'price', 'format_price' )
    );

    $twig->addFilter(
        new \Twig\TwigFilter( 'slugify', 'sanitize_title' )
    ];

    return $twig;
} );
```