2

I'm trying to get the number of entries that have selected checkboxes.

This works successfully (where genreGames is a checkbox field):

{{ games.genreGames('action').all()|length }}

Is there a way that I can do the same thing, except the field name is set dynamically? Like this:

{% set games = craft.entries().section('games') %}
{% set field = 'genreGames' %}
{{ games.field('action').all()|length }}

Obviously that won't work, but I need something similar.


The reason I need this is I'm building a solution for displaying the number of entries where a certain checkbox is checked. As you can see from the screenshot below, I want to set some parameters first and then use them below in my actual "template". It would also be nice to create a function to pass these variables in to and then output the template, but I do not know if this is possible in Twig.

1

2
  • This is possible, but a bit involved. It's very likely there's a better solution. Why do you need to add a filter based on a variable field? Please include the context, then it's easier to suggest a better solution.
    – MoritzLost
    Commented Nov 14, 2022 at 16:07
  • @MoritzLost, Made adjustments to the question
    – Dimi
    Commented Nov 14, 2022 at 17:25

2 Answers 2

2

To query on variable field names, you can use object notation; i.e. an object passed to craft.entries():

{% set field = 'genreGames' %}

{% set games = craft.entries({ (field): 'action' }).section('games').all() %}

Note the paranthesis around the field variable attribute; this is necessary to let Twig know that it should be parsed as a variable, and not interpreted literally as a field handle "field".

It's possible to add multiple variable parameters (i.e. fields) using the object notation:

{% set fieldA = 'genreGames' %}
{% set fieldB = 'somethingElse' %}

{% set games = craft.entries({ (fieldA): 'action', (fieldB): 'foo' }).section('games').all() %}

...but I'd recommend sticking with the common dot notation for any fields/parameters that doesn't have to be variables (i.e. .section(), in the above examples).

Object notation also works for relational fields (e.g. Entries fields), for example if you had an Entries field called relatedGames you could do this:

{% set relatedGames = entry.relatedGames({ (field): 'action' }).all()

Aside from this, Jalen's suggestion for using include to create a re-usable "query template" partial (i.e. to act as a "function" to pass variables into and render the final template), is solid, and commonly the way situations like this are solved in Twig. You might also want to look into Twig macros, which are even more "function-like" than includes or embeds, but essentially these will just behave like a less flexible include.

3
  • Your solution is the best! But I don't understand how to correctly specify the path to the template in the construction {% include .... with {} %}
    – Dimi
    Commented Nov 16, 2022 at 18:09
  • {% include 'filter/checkboxes.twig' with { .. } %} - This is my code that is written in index.twig (/templates/games/index.twig). File checkboxes.twig i put to the /templates/games/. It gives an error that it cannot find the template «filter/checkboxes.twig» in "games" at line 81
    – Dimi
    Commented Nov 16, 2022 at 18:41
  • @Dimi Sounds like you just have the wrong path for the template you're trying to include. Twig includes are always relative to your templates folder, not to the template with the {% include %} tag. That means you always have to give it the full file path (albeit without templates). If the template you're trying to include exists at templates/games/checkboxes.twig, the include code should read {% include 'games/checkboxes.twig' with { ... } %}. The code {% include 'filter/checkboxes.twig' with { ... } %} would look for a file templates/filter/checkboxes.twig; hence the error. Commented Nov 16, 2022 at 23:33
2

To answer your initial question, I think you could use the attribute function here to solve your problem:

{% set field = 'genreGames' %}
{{ attribute(games, field, 'action').all()|length }}

FYI, there is also the .count() method, which could be a better fit here than .all()|length - works the same in this instance, but is shorter and more clear 🙃


To answer your question/wish about the function thingy in Twig, I think what you might be looking for is something like this:

  1. Move your template code (i.e. what you highlighted as template code in your screenshot) into its own Twig file somewhere in your templates folder.
  2. Then, you'll want to include that template, and you can pass it your parameters (you don't even need the different sets you're currently doing):
{% include 'path/to/your/template/partial.twig' with {
    'name': 'genre',
    'type': 'checkbox',
    'field': 'genreGame',
    'fields': craft.app.fields.getFieldByHandle('genreGame')
} %}

There are some other things you could tinker with there, like the inclusion of only in the include function if you don't want the whole Twig context passed, or its possible an embed might fit your use case more than the include.


Hopefully that helps!

2
  • When i use function argument i get error: craft\helpers\Template::attribute(): Argument #5 ($arguments) must be of type array, string given, called in /home/c/cf74574/mysite.com/storage/runtime/compiled_templates/0b/0b03a02d1223f07326227307d9f56f99afe2eb4c689d0c27fa6ccc336a931e9b.php on line 192. My code looks like this: {{ attribute(games, 'genreGame', 'action').all()|length }} varible games is array/ What i doing wrong?
    – Dimi
    Commented Nov 15, 2022 at 22:35
  • PS. Just in case, I corrected the question and showed how I get the games variable
    – Dimi
    Commented Nov 15, 2022 at 23:13

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.