Problem/Motivation
It seems that, in general, renderable components and/or plugins like blocks and field items are generally limited regarding reusing instances of them on the same page multiple times, due to the behavior of the caching system. All objects holding renderable data and implementing CacheableDependencyInterface
seem to be affected by this. I'm trying to describe the limitation with the following simplified example:
A given render array (element) represents an HTML tag with a unique HTML id being randomly generated.
The only requirement of the element is, that it must have a unique HTML id when it's being rendered.
The element will be returned by a block plugin, i.e. a class which implements BlockPluginInterface
.
The block plugin does not depend or relate on any data / configuration of the system, i.e. no users, no nodes, no URL etc - it's just there to output the element.
The only requirement of the block plugin is, that an instance of it must be globally reusable.
An instance of the block has been created and placed via the block layout.
A node of a certain type has an entity reference field to blocks. The teaser mode of the node outputs the entity reference field.
There are now multiple nodes which reference to the same block instance. A view on a page lists these nodes in teaser view mode.
In the list, the block outputs the element multiple times, but cached. As a result, the HTML id is not unique and thus doesn't meet its corresponding requirement.
A way to meet both requirements (from element and block plugin) is to set the block plugin's max-age
cache to 0. This means that the block doesn't allow any caching. Because of the render cache's "bubbling" behavior, this would imply that all parent render elements won't be cacheable. This means, when an instance of the block plugin is getting rendered inside a field item, all the field items, the whole teaser view, the whole list view, the region where this list view is getting rendered and its further parents won't be cacheable in the render cache.
For block plugins, you could use hook_block_build_alter() to remove its generated cache key for "passing through" the render array. This can be useful e.g. for blocks which
- are cheap to render and
- most likely have invalid cache records when their parent elements have invalid cache records
Proposed resolution
Enable objects implementing CacheableDependencyInterface
to deliver some sort of cache passthrough, i.e. they just take the bubbled caching metadata from their child elements and pass them through (or say "bubble up") to their parent elements. This way, these objects are just further parts of the whole render structure, but their parent elements (in the above example the field items, teaser view mode, list views and regions etc.) may be still cacheable.
I'm not sure whether it's clear what I've written here. Feel free to ask for more details. Of course it's also possible that I miss or misunderstood an important part of the caching system here.