<p>One workaround to problems like this is using string placeholders.</p>
<p>The basic idea is that instead of rendering the actual dynamic value inside <code>{% cache %}</code> tags, you can output a static string placeholder – and then wrap the cached content with the <a href="https://twig.symfony.com/doc/2.x/filters/replace.html" rel="nofollow noreferrer"><code>|replace</code></a> Twig filter to replace that placeholder with the dynamic value.</p>
<p>Here's a simple example:</p>
<p>__layout</p>
<pre><code>{% set randomColor = random(getenv('COLORS')|split(',')) %}
{% set randomColorPlaceholder = '%%%RANDOM_COLOR%%%' %}

{% apply replace(randomColorPlaceholder, randomColor)|raw %}
    {% block content %}{% endblock %}
{% endapply %}
</code></pre>
<p>__includes/banner</p>
<pre><code>&lt;div class=&quot;bg-{{ randomColorPlaceholder }}-light&quot;&gt;&lt;/div&gt;
</code></pre>
<p>In the above example, any occurrences of the <code>'%%%RANDOM_COLOR%%%'</code> string inside markup output in <code>{% block content %}</code>, would get replaced with the actual random color value whenever the page is rendered – regardless of whether that content is cached or not.</p>

CC BY-SA 4.0
2022-03-02T09:17:11.467Z
Excellent idea, I hadn't thought about it at all. In my case, it works perfectly ! Thanks for bringing up this solution ! :)
Elodie Grondin
CC BY-SA 4.0
2022-03-01T18:22:21.533Z
2022-03-02T08:54:17.477Z
2022-03-02T08:54:17.477Z
Mats Mikkel Rummelhoff
<p>Randomness and caching are always gonna be at odds. Before you jump at complicated solutions, I'd have a talk about precise requirements, including mentioning the trade-offs involved. Do you really need a (pseudo-)random class  for every page view, or would it be sufficient if the random result is cached for one day, giving you one new random value each day, allowing you to keep the cache around for 24 hours? Or maybe you don't need randomness at all? Another option would be to seed the selection with something – for example, using a division remainder based on the current day of the week or month. Then you still need to cycle your caches every day, but are guaranteed a new 'random' color every day.</p>
<p>If you really need a completely random result for every page view, moving the random selection to JavaScript is the way to go. You don't want such a tiny feature to prevent you from caching large parts of your site. You can still build this in a way that will work with your existing <code>.env</code> configuration for possible values. For example, you can output a <code>data-*</code> attribute with all possible values in your Twig template:</p>
<pre class="lang-twig prettyprint-override"><code>{% set randomColors = getenv('COLORS') %}
&lt;div data-random-classes=&quot;{{ randomColors }}&quot;&gt;&lt;/div&gt;
</code></pre>
<p>Then use JavaScript to find elements with that data attribute, split the possible values (using the comma as delimiters), and add a random class from the possible values to the element:</p>
<pre class="lang-javascript prettyprint-override"><code>const elementsWithRandomClass = Array.from(document.querySelectorAll('[data-random-classes]'));
elementsWithRandomClass.forEach(element =&gt; {
    const classes = element.dataset.randomClasses.split(',');
    const randomClass = classes[Math.floor(Math.random() * classes.length)];
    element.classList.add(randomClass);
})
</code></pre>

CC BY-SA 4.0
2022-03-02T09:16:43.087Z
I couldn't agree more, it's not worth giving up caches for such a small feature. Thanks for bringing up this solution ! :)
Elodie Grondin
CC BY-SA 4.0
2022-03-01T13:24:55.623Z
2022-03-01T15:20:35.133Z
2022-03-01T15:20:35.133Z
MoritzLost
<p>I recently started using tailwindcss and I generate random classes via the function random() and get &quot;text-nature&quot;, &quot;bg-nature&quot;, bg-nature-light&quot;, &quot;text-culture&quot;, &quot;bg-culture&quot;, bg-culture-light&quot;, etc.</p>
<p>Unfortunately, the ttempleton/craft-nocache plugin does not work. I would like the classes in my template to change each time the page is refreshed. When the caches are disabled, it works perfectly, otherwise it's always the first generated class that is displayed.</p>
<p>I guess I could generate random hex colors in a {% css %}{% endcss %} tag or maybe change the colors in JS but I'm curious if someone has another way to achieve that.</p>
<p><em>.env</em></p>
<pre><code>COLORS=&quot;nature,wooltz,culture,enjoy,adventure,family&quot;
</code></pre>
<p><em>_layout</em></p>
<pre><code>{% set randomColor = random(getenv('COLORS')|split(',')) %}
</code></pre>
<p><em>_entry</em></p>
<pre><code>{% cache globally using key '{tpl:{tpl}}{block:{block}}{path:{path}}'|t({
    tpl: _self,
    block: 'content',
    path: craft.app.request.getPathInfo()
}) for 1 week unless cacheExempt %}
    {% minify %}
        {% include &quot;_includes/banner&quot; %}
    {% endminify %}
{% endcache %}
</code></pre>
<p><em>_includes/banner</em></p>
<pre><code>&lt;div class=&quot;bg-{{randomColor}}-light&quot;&gt;&lt;/div&gt;
</code></pre>

<craft3><cache><classes>
How do you deal with random class and cache?
# How do you deal with random class and cache?

(Asked by: username_0 on 2022-03-01)

I recently started using tailwindcss and I generate random classes via the function random() and get "text-nature", "bg-nature", bg-nature-light", "text-culture", "bg-culture", bg-culture-light", etc.
Unfortunately, the ttempleton/craft-nocache plugin does not work. I would like the classes in my template to change each time the page is refreshed. When the caches are disabled, it works perfectly, otherwise it's always the first generated class that is displayed.
I guess I could generate random hex colors in a {% css %}{% endcss %} tag or maybe change the colors in JS but I'm curious if someone has another way to achieve that.
.env
COLORS="nature,wooltz,culture,enjoy,adventure,family"

_layout
{% set randomColor = random(getenv('COLORS')|split(',')) %}

_entry
{% cache globally using key '{tpl:{tpl}}{block:{block}}{path:{path}}'|t({
    tpl: _self,
    block: 'content',
    path: craft.app.request.getPathInfo()
}) for 1 week unless cacheExempt %}
    {% minify %}
        {% include "_includes/banner" %}
    {% endminify %}
{% endcache %}

_includes/banner

**Tags:** craft3, cache, classes


---

## 2 answers

### Answer by username_1 on 2022-03-01. Score: 3 | Accepted answer

One workaround to problems like this is using string placeholders.
The basic idea is that instead of rendering the actual dynamic value inside {% cache %} tags, you can output a static string placeholder – and then wrap the cached content with the |replace Twig filter to replace that placeholder with the dynamic value.
Here's a simple example:
__layout
{% set randomColor = random(getenv('COLORS')|split(',')) %}
{% set randomColorPlaceholder = '%%%RANDOM_COLOR%%%' %}

{% apply replace(randomColorPlaceholder, randomColor)|raw %}
    {% block content %}{% endblock %}
{% endapply %}

__includes/banner


In the above example, any occurrences of the '%%%RANDOM_COLOR%%%' string inside markup output in {% block content %}, would get replaced with the actual random color value whenever the page is rendered – regardless of whether that content is cached or not.

> **Comments:**
> **username_0**: Excellent idea, I hadn't thought about it at all. In my case, it works perfectly ! Thanks for bringing up this solution ! :)  

---

### Answer by username_2 on 2022-03-01. Score: 3

Randomness and caching are always gonna be at odds. Before you jump at complicated solutions, I'd have a talk about precise requirements, including mentioning the trade-offs involved. Do you really need a (pseudo-)random class  for every page view, or would it be sufficient if the random result is cached for one day, giving you one new random value each day, allowing you to keep the cache around for 24 hours? Or maybe you don't need randomness at all? Another option would be to seed the selection with something – for example, using a division remainder based on the current day of the week or month. Then you still need to cycle your caches every day, but are guaranteed a new 'random' color every day.
If you really need a completely random result for every page view, moving the random selection to JavaScript is the way to go. You don't want such a tiny feature to prevent you from caching large parts of your site. You can still build this in a way that will work with your existing .env configuration for possible values. For example, you can output a data-* attribute with all possible values in your Twig template:
{% set randomColors = getenv('COLORS') %}


Then use JavaScript to find elements with that data attribute, split the possible values (using the comma as delimiters), and add a random class from the possible values to the element:
const elementsWithRandomClass = Array.from(document.querySelectorAll('[data-random-classes]'));
elementsWithRandomClass.forEach(element => {
    const classes = element.dataset.randomClasses.split(',');
    const randomClass = classes[Math.floor(Math.random() * classes.length)];
    element.classList.add(randomClass);
})

> **Comments:**
> **username_0**: I couldn't agree more, it's not worth giving up caches for such a small feature. Thanks for bringing up this solution ! :)  

---

