Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Update v2 caching docs #2797

Merged
merged 5 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
151 changes: 87 additions & 64 deletions docs/v2/guides/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,25 @@ You can still use plugins like [W3 Total Cache](https://wordpress.org/plugins/w3

## Cache the Entire Twig File and Data

When rendering, use the `$expires` argument in [`Timber::render`](https://timber.github.io/docs/v2/reference/timber-timber/#render). For example:
With Timber you can cache the full Timber render/compile calls. When you do this, the whole template you render and its data will be cached. This results in faster page rendering by skipping queries and Twig compilations. But here’s the cool part: Timber hashes the fields in the view context. This means that **as soon as the data changes, the cache is automatically invalidated**. Yay!

For Timber caching to take effect on your `Timber::render()` and `Timber::compile()` calls, you need to set the `$expires` argument. If the `$expires` argument is not set, Timber will not cache that particular template, even if the (global)cache mode is set.

Example:

```php
$context['posts'] = Timber::get_posts();

Timber::render('index.twig', $context, 600);
```

In this example, Timber will cache the template for 10 minutes (600 / 60 = 10). But here’s the cool part: Timber hashes the fields in the view context. This means that **as soon as the data changes, the cache is automatically invalidated**. Yay!

This method is very effective, but crude - the whole template is cached. So if you have any context dependent sub-views (eg. current user), this mode won’t do.

### Set cache mode
In this example, Timber will cache the template for 10 minutes (600 / 60 = 10) with the default cache mode which is "transient".
You can change the cache mode for Timber globally or on a per method basis. See [Timber cache modes](#timber-cache-modes) for more information.

As a fourth parameter for [Timber::render()](https://timber.github.io/docs/v2/reference/timber-timber/#render), you can set the `$cache_mode`.

```php
Timber::render($filenames, $data, $expires, $cache_mode);
```
This caching method is very effective, but crude - the whole template is cached. So if you have any context dependent sub-views (eg. current user), this mode won’t do.

The following cache modes are available:
### Timber cache modes
Timber has 5 cache modes that it can use for the Timber `Timber::render()` and `Timber::compile()` methods. The following cache modes are available:

| Mode | Description |
| --- | --- |
Expand All @@ -45,69 +43,28 @@ The following cache modes are available:
| `Timber\Loader::CACHE_SITE_TRANSIENT` | Network wide transients |
| `Timber\Loader::CACHE_USE_DEFAULT` | Use whatever caching mechanism is set as the default for `Timber\Loader`, the default is `CACHE_TRANSIENT`. |

## Cache _Parts_ of the Twig File and Data

If you want to use [`cache` tag](https://twig.symfony.com/doc/3.x/tags/cache.html) in Twig, you’ll have to install the `twig/cache-extra` package:

```bash
composer require twig/cache-extra
```

And register it in Timber like this:
By default the cache mode is set to transients. You can change the default cache mode globally by using a filter or on a per method basis. We will go over them both.

**functions.php**
#### Set Timber cache mode globally
The default cache mode can be changed by using the `timber/cache/mode` filter. For example:

```php
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Twig\Extra\Cache\CacheExtension;
use Twig\Extra\Cache\CacheRuntime;
use Twig\RuntimeLoader\RuntimeLoaderInterface;

class RunTimeLoader implements RuntimeLoaderInterface
{
public function load($class)
{
if (CacheRuntime::class === $class) {
return new CacheRuntime(new TagAwareAdapter(new FilesystemAdapter()));
}
}
}

add_filter('timber/twig', function ($twig) {
$twig->addExtension(new CacheExtension());
$twig->addRuntimeLoader(new RunTimeLoader());

return $twig;
apply_filters('timber/cache/mode', function () {
return Timber\Loader::CACHE_OBJECT;
});
```

You can then use it like this:
Sets the global/default cache mode to `CACHE_OBJECT`.

```twig
{% cache 'index;content' %}
{% for post in posts %}
{% include ['tease-' ~ post.post_type ~ '.twig', 'tease.twig'] %}
{% endfor %}
{% endcache %}
```

Read more about it in [Twig’s `cache` documentation](https://twig.symfony.com/doc/3.x/tags/cache.html).

If you want to use something meaningful for the cache key, you can also generate a cache key from the variables that you use. In the following example, we generate a cache key from `$posts` and then generate a key from it:
#### Set Timber cache mode per compile or render method
As a fourth parameter for [Timber::render()](https://timber.github.io/docs/v2/reference/timber-timber/#render) and [Timber::compile()](https://timber.github.io/docs/v2/reference/timber-timber/#compile), you can set the `$cache_mode`.

For example:
```php
$generator = new Timber\Cache\KeyGenerator();
$key = $generator->generateKey($posts);
Timber::render($filenames, $data, 600, Timber\Loader::CACHE_OBJECT);
```

### Extra: TimberKeyGeneratorInterface

Instead of hashing a whole object, you can specify the cache key in the object itself. If the object implements `TimberKeyGeneratorInterface`, it can pass a unique key through the method `get_cache_key`. That way a class can for example simply pass `'last_updated'` as the unique key.
If arrays contain the key `_cache_key`, that one is used as cache key.

This may save yet another few processor cycles.

## Cache the Twig File (but not the data)

Every time you render a `.twig` file, Twig compiles all the HTML tags and variables into a big, nasty blob of function calls and echo statements that actually gets run by PHP. In general, this is pretty efficient. However, you can cache the resulting PHP blob by turning on Twig’s cache via:
Expand Down Expand Up @@ -140,7 +97,7 @@ Thus, during development, you should enable the option for `auto_reload`:

```php
add_filter('timber/twig/environment/options', function ($options) {
$options['cache'] = true;
$options['cache'] = true;
$options['auto_reload'] = true;

return $options;
Expand All @@ -158,6 +115,69 @@ $loader = new Timber\Loader();
$loader->clear_cache_twig();
```


## Cache _Parts_ of the Twig File and Data

If you want to use [`cache` tag](https://twig.symfony.com/doc/3.x/tags/cache.html) in Twig, you’ll have to install the `twig/cache-extra` package:

```bash
composer require twig/cache-extra
```

And register it in Timber like this:

**functions.php**

```php
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Twig\Extra\Cache\CacheExtension;
use Twig\Extra\Cache\CacheRuntime;
use Twig\RuntimeLoader\RuntimeLoaderInterface;

add_filter('timber/twig', function ($twig) {
$twig->addRuntimeLoader(new class implements RuntimeLoaderInterface
{
public function load($class)
{
if (CacheRuntime::class === $class) {
return new CacheRuntime(new TagAwareAdapter(new FilesystemAdapter('', 0, TIMBER_LOC . '/cache/twig')));
}
}
});
$twig->addExtension(new CacheExtension());

return $twig;
});
```

You can then use it like this:

```twig
{% cache 'index;content' %}
{% for post in posts %}
{% include ['tease-' ~ post.post_type ~ '.twig', 'tease.twig'] %}
{% endfor %}
{% endcache %}
```

Read more about it in [Twig’s `cache` documentation](https://twig.symfony.com/doc/3.x/tags/cache.html).

If you want to use something meaningful for the cache key, you can also generate a cache key from the variables that you use. In the following example, we generate a cache key from `$posts` and then generate a key from it:

```php
$generator = new Timber\Cache\KeyGenerator();
$key = $generator->generateKey($posts);
```

### Extra: TimberKeyGeneratorInterface

Instead of hashing a whole object, you can specify the cache key in the object itself. If the object implements `TimberKeyGeneratorInterface`, it can pass a unique key through the method `get_cache_key()`. That way a class could for example pass a `'last_updated'` property as the unique key.
If arrays contain the key `_cache_key`, that one is used as cache key.

This may save yet another few processor cycles.


## Cache the PHP data

Sometimes the most expensive parts of the operations are generating the data needed to populate the twig template. You can of course use WordPress’s default [Transient API](http://codex.wordpress.org/Transients_API) to store this data.
Expand Down Expand Up @@ -213,3 +233,6 @@ Timber::render('single.twig', $context, 600);
// This reports the time diff by passing the $start time
echo Timber\Helper::stop_timer($start);
```
## Important notes

- Never use `{% spaceless %}` tags to minify your HTML output. These tags are only meant to control whitespace between html tags.
32 changes: 16 additions & 16 deletions src/Timber.php
Original file line number Diff line number Diff line change
Expand Up @@ -1308,15 +1308,15 @@ public static function context_global()
*
* $team_member = Timber::compile( 'team-member.twig', $data );
* ```
* @param array|string $filenames Name or full path of the Twig file to compile. If this is an array of file
* names or paths, Timber will compile the first file that exists.
* @param array $data Optional. An array of data to use in Twig template.
* @param bool|int $expires Optional. In seconds. Use false to disable cache altogether. When passed an
* array, the first value is used for non-logged in visitors, the second for users.
* Default false.
* @param string $cache_mode Optional. Any of the cache mode constants defined in Timber\Loader.
* @param bool $via_render Optional. Whether to apply optional render or compile filters. Default false.
* @return bool|string The returned output.
* @param array|string $filenames Name or full path of the Twig file to compile. If this is an array of file
* names or paths, Timber will compile the first file that exists.
* @param array $data Optional. An array of data to use in Twig template.
* @param bool|int|array $expires Optional. In seconds. Use false to disable cache altogether. When passed an
* array, the first value is used for non-logged in visitors, the second for users.
* Default false.
* @param string $cache_mode Optional. Any of the cache mode constants defined in Timber\Loader.
* @param bool $via_render Optional. Whether to apply optional render or compile filters. Default false.
* @return bool|string The returned output.
*/
public static function compile($filenames, $data = [], $expires = false, $cache_mode = Loader::CACHE_USE_DEFAULT, $via_render = false)
{
Expand Down Expand Up @@ -1566,13 +1566,13 @@ public static function fetch($filenames, $data = [], $expires = false, $cache_mo
*
* Timber::render( 'index.twig', $context );
* ```
* @param array|string $filenames Name or full path of the Twig file to render. If this is an array of file
* names or paths, Timber will render the first file that exists.
* @param array $data Optional. An array of data to use in Twig template.
* @param bool|int $expires Optional. In seconds. Use false to disable cache altogether. When passed an
* array, the first value is used for non-logged in visitors, the second for users.
* Default false.
* @param string $cache_mode Optional. Any of the cache mode constants defined in Timber\Loader.
* @param array|string $filenames Name or full path of the Twig file to render. If this is an array of file
* names or paths, Timber will render the first file that exists.
* @param array $data Optional. An array of data to use in Twig template.
* @param bool|int|array $expires Optional. In seconds. Use false to disable cache altogether. When passed an
* array, the first value is used for non-logged in visitors, the second for users.
* Default false.
* @param string $cache_mode Optional. Any of the cache mode constants defined in Timber\Loader.
*/
public static function render($filenames, $data = [], $expires = false, $cache_mode = Loader::CACHE_USE_DEFAULT)
{
Expand Down