Auto-placeholdering
Drupal 8's Render API automatically creates placeholders of highly dynamic parts of a page, to have the best possible cacheability (i.e. the fewest possible contexts to vary by) for those pages.
Why?
- Some cache contexts have a high cardinality and are thus very costly because they cause many, many variations. A good example is the
'user'
cache context. - Some cache tags have a high invalidation rate: they're known to be invalidated very frequently, which makes caching anything that has this cache tag (i.e. depends on the data this cache tag describes) not very worthwhile.
- Caching something with max-age zero is completely useless because it can not be cached at all. But, for some sites, some content is/needs to be updated with a very high frequency, say every second (
max-age=1
) or every few seconds (max-age=5
). Depending on your site's server infrastructure and needs, it may also not be worth caching things with such a low max-age.
In other words, for all three cacheability metadata properties, some values cause poor cacheability and due to bubbling, they will infect the rest of the page too.
(All ancestors inherit the cacheability metadata so all ancestors will be poorly cacheable, will therefore not be cached, including the containing page.)
What?
The process of detecting poorly cacheable (highly dynamic) parts of a page and rendering them later is called auto-placeholdering.
If a certain render array is built lazily (using a #lazy_builder
callback) and has the 'user'
cache context, Drupal is able to postpone the rendering until the very last moment. The place in the page where that very dynamic content would appear is first assigned a placeholder, and only at the very last moment, it is replaced with the actual content.
This allows Drupal to still:
- render cache fragments (blocks, entities …) despite parts of them being too dynamic to be worth caching.
- cache the overall page in the Dynamic Page Cache.
Auto-placeholdering is performed according to the auto-placeholder conditions specified in the renderer.config
container parameter:
renderer.config:
auto_placeholder_conditions:
max-age: 0
contexts: ['session', 'user']
tags: []
This can be customized to match your site's needs, but as you can tell, by default Drupal will automatically placeholder fragments of the page that have a max-age of zero, or vary by session or by the current user. No high-invalidation rate cache tags are specified — because that requires site-specific knowledge.
How?
An HTML page served by Drupal can be considered one big render tree, with the root of the tree being the entire page, the first level being the regions, the second level the blocks, the third level being the block contents, and so on.
Therefore, any subtree will be auto-placeholdered, if:
- it is defined by a
#lazy_builder
(and not by a render array) - it meets the auto-placeholder conditions, which can happen in one of two ways:
- it has a
#cache
value whose properties meet at least one of the auto-placeholder conditions - its
#lazy_builder
callback, when executed and rendered, results in the bubbling of cacheability metadata that meet at least one of the auto-placeholder conditions. The first time this happens, the bubbled cacheability metadata will be cached (seePlaceholderingRenderCache
) so that future hits won't have to first execute and render the#lazy_builder
to know it should be auto-placeholdered
Note: auto-placeholdering based on a bubbled max-age does not yet work in 8.0.x, that's postponed to at least 9.5.0: https://www.drupal.org/node/2559847. Auto-placeholdering for #lazy_builder with bubbling of max-age.
- it has a
Please be aware that for the moment the lazy builder callback should not return a render array based on the #type
property. Instead, it should be one of the other ones, such as #theme
, #markup
or #plain_text
. If you need to return a #type
, wrap it into an array as a child. This issue is known and currently still debated in https://www.drupal.org/project/drupal/issues/2609250.
Examples
See CommentDefaultFormatter
(comment form), BlockViewBuilder
(blocks), NodeViewBuilder
(node links), StatusMessages
(status messages).
See also
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion