5

I think I am not fully understanding how caching works.

Based on this answer I thought I could cache my query and then shuffle the resulting array items.

So I ended up with this code:

{% cache %}
  {% set categoryProducts = craft.entries.section('products').relatedTo(category) %}
{% endcache %}

{% set categoryProducts = shuffle(categoryProducts) %}
{% for entry in categoryProducts %}
  ...
{% endfor %}

But that does give me a "categoryProducts" does not exist error.

Could someone shed some light as to why caching the query doesn't work? I thought caching tags help to reduce the amount of queries being made and I've been studying the documentation, but I don't seem to fully grasp the concept.

2
  • I reached out to carlcs (author of the answer you linked to)... That answer contained some misinformation, and he has since deleted it. Caching is a complex and confusing subject, so you'll occasionally see it described inaccurately. But khalwat is correct, the cache tag needs to contain HTML output. If your query was included within the cached segment, then it will be recorded for cache-busting purposes, and not run again unless the data changes.
    – Lindsey D
    Commented Nov 18, 2015 at 18:02
  • Sorry Katrin, I actually did think you can cache a criteria model like so and get around that problem. But you can't.
    – carlcs
    Commented Nov 18, 2015 at 18:08

1 Answer 1

8

The {% cache %} tag only caches the HTML output. That's it.

In your example above, nothing is cached, and categoryProducts will be an empty set.

One thing you could do is to cache each entry individually:

{% set categoryProducts = craft.entries.section('products').relatedTo(category) %}
{% set categoryProducts = shuffle(categoryProducts) %}

{% for entry in categoryProducts %}
    {% cache globally using key 'product-' ~ entry.id %}
        ...
    {% endcache %}
{% endfor %}
7
  • 2
    I hope you didn't mind me messing around with your answer. But I felt sorry and wanted to give Katrin an answer to her caching problem, without adding an answer myself.
    – carlcs
    Commented Nov 18, 2015 at 18:14
  • Khalwat, that looks very insightful; makes me wonder, though, if the SQL execution of the query is avoided, since the caching is within the results loop. And, would the shuffle be active; wouldn't you get the same ordering of results each next time? I may be missing the logic... Commented Nov 18, 2015 at 20:06
  • 2
    @narration_sd no, the criteria models SQL will still run for each request. But each entry's queries don't fire if they are cached, and those queries can be really expensive. Imagine you loop 80 categoryProducts and there's three relation queries for each entry, a product category, a product tag and also a product assets query; this would add up to 240 not very small additional queries that you could avoid with this technique.
    – carlcs
    Commented Nov 19, 2015 at 8:48
  • Brilliant explanations, thank you all! So, you can cache entry data queries but not ElementCriteriaModel queries - got it! :)
    – Katrin
    Commented Nov 19, 2015 at 14:42
  • Not exactly. The key take-away here is you can ONLY cache HTML output. Commented Nov 19, 2015 at 18:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.