{"componentChunkName":"component---src-templates-post-jsx","path":"/en/cache-api","result":{"data":{"markdownRemark":{"html":"<p>Drupal 8 arrived with several performance improvements — and performance means caching.</p>\n<p>In this article we will look in detail at the cache types provided by Drupal, and how to use them in our custom modules to ensure optimal performance for users.</p>\n<p>Before diving into the varieties of cache backends, I want to mention that Drupal 8 provides several modules installed by default:</p>\n<ul>\n<li><strong>Dynamic Page Cache</strong> and <strong>Internal Page Cache</strong>: require no configuration; they manage cache for authenticated and anonymous users respectively.</li>\n<li><strong>BigPipe</strong>: a technique introduced by Facebook and brought to the web, which improves performance by sending multiple chunks of a page one after another, allowing the browser to render ready parts while the rest loads.</li>\n</ul>\n<p>Below is a demonstration of how BigPipe works:</br></br>\n<img src=\"https://www.getopensocial.com/wp-content/uploads/2016/11/BigPipe-animation-02.gif\" alt=\"Alt Text\"></p>\n<p>Drupal's cache API uses several bins tied to cache tables in the database (prefixed with <code class=\"language-text\">cache_</code>). You must first request a specific cache bin to interact with the cache API.</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\"><span class=\"token variable\">$render_cache</span> <span class=\"token operator\">=</span> \\<span class=\"token package\">Drupal</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">cache</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'render'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>The <code class=\"language-text\">$render_cache</code> variable above represents a render cache bin object. Note that in this example the cache is called statically. When working within classes — as is standard in custom Drupal modules — it is recommended to use dependency injection by injecting the cache service (<code class=\"language-text\">cache.render</code> in our example).</p>\n<p>The cache API (backend) is based on three fundamental principles that must be well understood to use effectively in custom module development:</p>\n<ul>\n<li>Cache tags</li>\n<li>Cache contexts</li>\n<li>Cache max-age</li>\n</ul>\n<h2>Cache Tags</h2>\n<p>Cache tags work on a simple principle: they allow you to tag cached content and render elements with specific tags, which are later invalidated after a defined action.</p>\n<p>Example: Imagine a simple Article content type displayed on its own detail page, listing page, or other pages. If we don't manage the cache in the render array that displays content, items will be cached and we may end up showing stale content to users.\nWe can use the <code class=\"language-text\">node_list</code> tag on all render arrays that display content, ensuring that whenever content is modified, all render arrays tagged with <code class=\"language-text\">node_list</code> are invalidated and rebuilt with fresh content.</p>\n<ul>\n<li>By convention, cache tags use the format <code class=\"language-text\">&lt;entity type ID&gt;:&lt;entity ID&gt;</code> or <code class=\"language-text\">config:&lt;configuration name&gt;</code>. If the object only accepts one instance, use the object name as the tag.</li>\n<li>Cache tags are simply strings (e.g., <code class=\"language-text\">node_list</code>, <code class=\"language-text\">config:system.performance</code>).</li>\n<li>Multiple cache tags can be passed in a render array.</li>\n<li>The order of cache tags in a render array is not considered by Drupal.</li>\n</ul>\n<h3>( ! ) <strong>Note</strong></h3>\n<p>Cache tags in Drupal 8 do not support tags by bundle. This issue will be resolved in future versions. In the meantime, the <strong><a href=\"https://www.drupal.org/project/handy_cache_tags\">Handy Cache Tags</a></strong> module handles this limitation efficiently, allowing bundle-level tags (e.g., <code class=\"language-text\">handy_cache_tags:node:article</code>).</p>\n<hr/>\n<h2>Cache Contexts</h2>\n<p>As the name implies, a cache context is based on contexts defined by Drupal — in other words, cache contexts allow you to vary cache in a render array by path, user, language, theme, or other contexts.</p>\n<ul>\n<li>Multiple cache contexts can be added to a render array.</li>\n<li>The order of cache contexts in a render array is not considered by Drupal.</li>\n<li>There is a predefined hierarchy of contexts in Drupal; for example, when varying cache by user, there is no need to also vary it by permission since each user already has a default set of permissions.</li>\n</ul>\n<h2>Cache Max Age</h2>\n<p>Cache Max-Age lets you cache a render array for a specific duration. It takes a positive integer representing seconds (0, 60, 100, etc.).</p>\n<p>Example usage of cache in render arrays:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">  <span class=\"token comment\">//Case of render array</span>\n  <span class=\"token variable\">$build</span><span class=\"token punctuation\">[</span><span class=\"token single-quoted-string string\">'#cache'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token single-quoted-string string\">'max-age'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n\t\n  <span class=\"token comment\">//Case of plugin bloc (OOP way)</span>\n  <span class=\"token keyword\">public</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getCacheMaxAge</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<p>As mentioned at the beginning of this article, Drupal has the Internal Dynamic Page Cache (manages cache for authenticated users) and Internal Page Cache (manages cache for anonymous users). The latter does not recognize cache max-age — meaning that if you add a <code class=\"language-text\">max-age</code> in a render array, it will still be cached indefinitely for anonymous users due to Internal Page Cache ignoring max-age.</p>\n<p>It is therefore not recommended to use cache max-age in custom development. It is not used in Drupal Core source code either.</p>","excerpt":"Drupal 8 arrived with several performance improvements — and performance means caching. In this article we will look in detail at the cache types provided by…","frontmatter":{"date":"2020-01-20","metaDate":"2020-01-20","title":"Cache API","tags":["Cache","Performance","Module development","Drupal 8"],"path":"/cache-api","cover":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAgX/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQIE/9oADAMBAAIQAxAAAAHkUT61w4QI/8QAFxABAQEBAAAAAAAAAAAAAAAAABECAf/aAAgBAQABBQJitZvaqv/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABgQAAIDAAAAAAAAAAAAAAAAAAABIDEy/9oACAEBAAY/AizSh//EABoQAQACAwEAAAAAAAAAAAAAAAEAESFBUXH/2gAIAQEAAT8hK5AKqnsFXLvMsbg4pZ//2gAMAwEAAgADAAAAEMQ//8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAEDAQE/EELL/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAERIVH/2gAIAQIBAT8Qll6f/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARITFxkf/aAAgBAQABPxBLpfGogq/QokeJLcTYKxQ+2/ZaFn//2Q==","aspectRatio":1.5025484199796126,"src":"/static/ef64ba6bb722b02d93e341af50253a73/7b269/speed.jpg","srcSet":"/static/ef64ba6bb722b02d93e341af50253a73/0b320/speed.jpg 480w,\n/static/ef64ba6bb722b02d93e341af50253a73/60b32/speed.jpg 960w,\n/static/ef64ba6bb722b02d93e341af50253a73/7b269/speed.jpg 1474w","srcWebp":"/static/ef64ba6bb722b02d93e341af50253a73/a4c59/speed.webp","srcSetWebp":"/static/ef64ba6bb722b02d93e341af50253a73/bc3bf/speed.webp 480w,\n/static/ef64ba6bb722b02d93e341af50253a73/39337/speed.webp 960w,\n/static/ef64ba6bb722b02d93e341af50253a73/a4c59/speed.webp 1474w","sizes":"(max-width: 1474px) 100vw, 1474px"},"resize":{"src":"/static/ef64ba6bb722b02d93e341af50253a73/c4f3a/speed.jpg"}}}}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"pathSlug":"/cache-api","locale":"en","prev":{"fields":{"locale":"en"},"frontmatter":{"path":"/event-api","title":"Event API","tags":["Event API","Hooks","Drupal 8","Module development"]}},"next":{"fields":{"locale":"en"},"frontmatter":{"path":"/drupal-behaviors","title":"Drupal Behaviors","tags":["jQuery","JavaScript","Module development","Performance","Ajax"]}}}}}