<p>You can use a <code>relatedTo</code> parameter to limit your query to all games that are related to one of multiple elements. This is assuming that both <code>specialsGame</code> and <code>genreGame</code> are <a href="https://craftcms.com/docs/4.x/entries.html" rel="nofollow noreferrer">entries fields</a> or another kind of element relation field (like tags or categories).</p>
<p>The following code assumes you're using element IDs for the values of your checkboxes.</p>
<pre class="lang-twig prettyprint-override"><code>{% set gamesQuery = craft.entries().section('games') %}

{% set genre = craft.app.request.getQueryParam('genre') %}
{% set specials = craft.app.request.getQueryParam('specials') %}
{% set selectedFilters = [genre, specials]|filter %}

{% if selectedFilters %}
    {% do gamesQuery.relatedTo({
        element: selectedFilters,
        field: ['genreGame', 'specialsGame']
    }) %}
{% endif %}
</code></pre>
<p>The <a href="https://craftcms.com/docs/4.x/relations.html" rel="nofollow noreferrer">documentation on relations</a> has more examples on how to narrow your query further. Note that <code>OR</code> logic is the default in this case (so the query is limited to all games that are limited to one of the specified elements).</p>
<p>If you want to support multiple selection for both filters, change your input names to use array syntax (<code>specials[]</code> and <code>genre[]</code>), this will cause PHP to parse those as arrays. Then merge those arrays together:</p>
<pre class="lang-twig prettyprint-override"><code>{% set genre = craft.app.request.getQueryParam('genre') ?? [] %}
{% set specials = craft.app.request.getQueryParam('specials') ?? [] %}
{% set selectedFilters = genre|merge(specials)|filter %}
</code></pre>

CC BY-SA 4.0
2022-11-21T11:16:54.923Z
thx for answer, but ... First. genreGame and specialsGame not entries fields! it is a checkboxes fields. I'm afraid your solution won't work (((( Second. URL from which I take the values looks like this: site.com/games?genre=action%2Crpg%2Chorror%2Cadventure&specials=single%2Cmultiplayer%2Cgamepad%2Ccards%2Cachievements therefore, to convert the received data, I use specialsGet|split(',')
Dimi
CC BY-SA 4.0
2022-11-21T11:26:48.107Z
@Dimi Yeah, that's why you need to include information on your fields as well as the template for your filter form in the question, without that we can only guess what kind of field you're working with ;) All the information on filtering checkboxes with multiple values can be found in the [documentation](https://craftcms.com/docs/4.x/checkboxes-fields.html#querying-elements-with-checkboxes-fields). For filtering across multiple fields with OR-logic, check out my answer here as a starting point: https://craftcms.stackexchange.com/a/38648/11705
MoritzLost
CC BY-SA 4.0
2022-11-21T11:27:17.473Z
@Dimi As a sidenote, you should only execute the query once, so use `{% do games.genreGame(genreGet|split(',')) %}` without the `all()` at the end.
MoritzLost
CC BY-SA 4.0
2022-11-21T17:29:38.677Z
i cant understand construction andWhere. my English is not very good))) Need good example. I try to do this: `{% set games = craft.entries().section('games').andWhere(['or',['=', '[[field_genreGame]]', ???WHAT_HERE??? ],['=', '[[field_specialsGame]]', ???WHAT_HERE???]]) %}`. What should I substitute instead `???WHAT_HERE???` And in general, am I moving in the right direction?
Dimi
CC BY-SA 4.0
2022-11-21T18:00:31.103Z
i try to do this: `{% set games = craft.entries().section('games').andWhere(['or',['=', '[[field_genreGame]]', ['horror'] ],['=', '[[field_specialsGame]]', ['multiplayer]']]) %}` but this not work. i get error "Undefined array key 1"
Dimi
CC BY-SA 4.0
2022-11-22T08:56:13.600Z
See the excellent answer by @MatsMikkelRummelhoff on how to solve this issue with your current content architecture. It's pretty involved, because the checkboxes field isn't really built for that type of heavy filtering. I would recommend you rethink your content architecture and use categories for genres and specials. Then you can use the solution provided in my answer, which makes it much easier. It also means you can add categories without touching the project config (which would require a pull request and a deployment in a development to live deployment scenario).
MoritzLost
CC BY-SA 4.0
2022-11-22T12:23:51.307Z
Yes, I listened to his advice. I decided that making fields of the entries type is better. Then it may come in handy if I want to expand the functionality of the site. For example, if I want to create a menu with icons for each genre
Dimi
CC BY-SA 4.0
2022-11-22T12:24:40.553Z
Here, I'm sitting redoing what I did)))
Dimi
CC BY-SA 4.0
2022-11-22T12:51:02.100Z
I have completed my question (Accidentally edited your answer)
Dimi
CC BY-SA 4.0
2022-11-19T18:32:23.800Z
2022-11-19T18:32:23.800Z
MoritzLost
<p>For multiple select/checkboxes fields, you can use the <a href="https://craftcms.com/docs/3.x/searching.html#supported-syntaxes" rel="nofollow noreferrer">search index</a>.</p>
<pre><code>{% set games = craft.entries().section('games').search('genreGame:horror OR specialsGame:multiplayer').all() %}
</code></pre>
<p>Note that you would need to enable searching on those fields in the CP first:
<a href="https://craftcms.com/docs/3.x/searching.html#configuring-custom-fields-for-search" rel="nofollow noreferrer">https://craftcms.com/docs/3.x/searching.html#configuring-custom-fields-for-search</a></p>

CC BY-SA 4.0
2022-11-21T10:15:56.440Z
No, using search is a very slow method. He won't do here. It's easier for me to redo the type of fields from checkboxes to entries and implement the solution that MoritzLost proposed
Dimi
CC BY-SA 4.0
2022-11-21T05:40:29.887Z
2022-11-21T05:46:51.970Z
2022-11-21T05:46:51.970Z
Matanya
<p><strong>Generally, and as @MoritzLost's answer suggest, using elements (i.e. entries or categories) and the <code>relatedTo</code> param instead of Checkboxes for categorisation, is definitely going to be a better idea in most cases, and the approach I'd recommend.</strong></p>
<p>That said, one option for using an OR operand to query entries on multiple, non-relational custom fields, is by creating a so-called <a href="https://craftcms.com/docs/4.x/element-queries.html#advanced-element-queries" rel="nofollow noreferrer">&quot;advanced&quot; element query</a>.</p>
<p>Essentially, an advanced element query is any element query that uses one or several methods from Craft's base query builder's – like <code>.where()</code>, <code>.join()</code>, <code>.distinct()</code> etc.</p>
<p>The biggest thing to know about advanced element queries is that unlike &quot;regular&quot; queries, you will usually have to specify the <em>full column name</em> for any custom field(s) used in their methods. For a custom field with the handle <code>genreGame</code>, the actual column name will look something like <code>field_genreGame_asfljksa</code>. That last part is a <em>random suffix</em> – this is possible to <a href="https://craftcms.stackexchange.com/questions/38471/get-array-of-titles-instead-of-whole-collection-of-entries-attributes/38473#38473">determine programmatically</a>, but it should also be fine to hard code it as it's not supposed to ever change between environments.</p>
<p>Essentially, here's how an advanced query that'll <em>almost</em> do what you need could look, using <code>.orWhere()</code> statements:</p>
<pre><code>{% set games = craft.entries().section('games') %}
...
{% do games.orWhere(['=', 'field_genreGame_asfljksa', '[&quot;horror&quot;]']) %}
...
{% do games.orWhere(['=', 'field_specialsGame_xsaoefasj', '[&quot;multiplayer&quot;]']) %}
</code></pre>
<p>The &quot;almost&quot; is due to the fact that since you're going to be querying on Checkboxes fields, you'll need to account for entries that have more than one value checked (i.e. selected) in those fields.</p>
<p>Additionally, Checkboxes fields store their selected values in the content database table as JSON (note the <code>[&quot;horror&quot;]</code> in the example query above, instead of just <code>horror</code>). This means that you can't actually use a simple <code>=</code> operator for the <code>.orWhere()</code> comparisons.</p>
<p>One option for adding support for multiple, serialized values is to create LIKE statements for all your possible matches found in the <code>genreGet</code> and <code>specialsGet</code> comma separated GET variables, i.e. something like this:</p>
<pre><code>...
{% for genre in genreGet|split(',') %}
    {% do games.orWhere(['like', 'field_genreGame_asfljksa', '&quot;' ~ genre ~ '&quot;']) %}
{% endfor %}
...
</code></pre>
<p>If that seems a bit squishy and/or verbose, I concur!</p>
<p>Another option is looking into the <code>JSON_EXTRACT()</code> and <code>JSON_CONTAINS()</code> SQL functions, but this stuff does get gnarly quite fast IMO.</p>

CC BY-SA 4.0
2022-11-22T09:05:19.960Z
Great answer! This is exactly why I avoid checkboxes fields for anything that might need to be searchable. Categories are much easier, especially since it allows editors to add categories without touching the project config. For what it's worth, storing all selected categories always struck me as a weird choice – it would make more sense to store the options in a separate table and use a junction table (or maybe even utilize the `relations` table) to store the selected options. Though maybe that would be difficult with the current architecture of the `content` table.
MoritzLost
CC BY-SA 4.0
2022-11-22T09:15:18.973Z
@MoritzLost 100%. Some other big drawbacks with using non-relational fields for this stuff is if you ever need to rename an option somewhere down the line, or if you need options translated for different sites.
Mats Mikkel Rummelhoff
CC BY-SA 4.0
2022-11-21T18:53:45.193Z
2022-11-22T09:09:44.167Z
2022-11-22T09:09:44.167Z
Mats Mikkel Rummelhoff
<p>I have a problem with filtering elements. I have a product catalog and have an item filter. The filter has a set of checkboxes. The number of products corresponding to the property is indicated in parentheses in the filter. Visually it looks like this:
<a href="https://i.sstatic.net/8vtff.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/8vtff.png" alt="enter image description here" /></a></p>
<p>It looks like everything is fine, but there is a problem. If I check the box in the &quot;genre&quot; section for &quot;horror&quot;, and in the &quot;specials&quot; section I check the box for &quot;multiplayer&quot;. That's what I see:</p>
<p><a href="https://i.sstatic.net/KHqIS.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/KHqIS.png" alt="enter image description here" /></a></p>
<p>This is the wrong logic. It displays a list of products that have genre = horror <strong>AND</strong> specials = multiplayer, while I'm looking to display products according to the logic of genre = horror <strong>OR</strong> specials = multiplayer. According to the logic I need, not one game should be displayed, but four games!</p>
<p>This is how the records I need are being pulled out now:</p>
<pre><code>{% set games = craft.entries().section('games') %}

{% set genreGet = craft.app.request.getQueryParam('genre') %}
{% if genreGet %}
    {% do games.genreGame(genreGet|split(',')).all() %}
{% endif %}

{% set specialsGet = craft.app.request.getQueryParam('specials') %}
{% if specialsGet %}
    {% do games.specialsGame(specialsGet|split(',')).all() %}
{% endif %}
</code></pre>
<p>Is there any way to make this work on the OR principle?</p>
<hr />
<hr />
<hr />
<hr />
<p>FINAL! Thanks to the guys Moritz Lost and Mats Mikkel Rummelhoff. They suggested how to do it better. Here is the final solution:</p>
<pre><code>{% set games = craft.entries().section('games') %}

{% set elements = [] %}
{% set fields = [] %}

{% set genres = craft.app.request.getQueryParam('genres') %}
{% if genres %}
    {% set elements = elements|merge(genres|split(','))%}
    {% set fields = fields|merge(['genreEntriesGame'])%}
{% endif %}

{% set specials = craft.app.request.getQueryParam('specials') %}
{% if specials %}
    {% set elements = elements|merge(specials|split(','))%}
    {% set fields = fields|merge(['specialsEntriesGame'])%}
{% endif %}

{% if elements|length &gt; 0 and fields|length &gt; 0 %}
    {% do games.relatedTo({
        element: elements,
        field: fields
    }) %}
{% endif %}

{% set games = games.all() %}
</code></pre>
<p>The only thing I did not use the <code>array syntax (genre[], specials[])</code> syntax as MoritzLost advised. When I use <code>array syntax (genre[], specials[])</code> in input fields, my URL becomes very long. The names of the parameters in the url are repeated very many times then. Therefore, I used JS to process the selected checkboxes, took their id and wrote them in a separate input field, thereby getting something like this <code>genre=4536,1457</code> in my URL. So I used <code>|split(',')</code></p>

CC BY-SA 4.0
2022-11-19T18:20:02.980Z
If you include the template code you're using to output the filters it's easier to provide an answer.
MoritzLost
CC BY-SA 4.0
2022-11-22T13:03:13.207Z
Get rid of the `split` and change your inputs as mentioned in my answer. The `|split` filter always returns an array, which will be empty if the query param doesn't exist. So `[genres, special]` will result in `[[], []]` – an array with two empty arrays. This is not falsy, so the `relatedTo` is always applied. So you're asking Craft for all games related to nothing, which matches nothing.
MoritzLost
CC BY-SA 4.0
2022-11-22T13:05:12.423Z
If you want to support multiple selection, adjust the inputs to use array syntax (`genre[]`, `specials[]`) and use the second code example in my answer.
MoritzLost
CC BY-SA 4.0
2022-11-22T13:08:29.523Z
@MoritzLost I have updated the question again (for the third time). Experienced a naked solution. Take a look
Dimi
CC BY-SA 4.0
2022-11-22T13:09:42.107Z
@MoritzLost Even with a bare solution, for some reason nothing is output((
Dimi
CC BY-SA 4.0
2022-11-22T13:10:14.687Z
You need `[36774, 36842, 36842]` instead of `[[36774], [36842,36842]]`. Take a look at the [documentation on relations](https://craftcms.com/docs/4.x/relations.html), there are multiple examples and all the supported parameters are listed there.
MoritzLost
CC BY-SA 4.0
2022-11-22T14:09:09.890Z
@MoritzLost iI have completed the question. You solution is best))) Thx.
Dimi
CC BY-SA 4.0
2022-11-22T14:11:12.190Z
Glad you got it working!
MoritzLost
<craft3>
How to make the directory filter work according to the OR principle?
# How to make the directory filter work according to the OR principle?

(Asked by: username_0 on 2022-11-17)

I have a problem with filtering elements. I have a product catalog and have an item filter. The filter has a set of checkboxes. The number of products corresponding to the property is indicated in parentheses in the filter. Visually it looks like this:

It looks like everything is fine, but there is a problem. If I check the box in the "genre" section for "horror", and in the "specials" section I check the box for "multiplayer". That's what I see:

This is the wrong logic. It displays a list of products that have genre = horror AND specials = multiplayer, while I'm looking to display products according to the logic of genre = horror OR specials = multiplayer. According to the logic I need, not one game should be displayed, but four games!
This is how the records I need are being pulled out now:
{% set games = craft.entries().section('games') %}

{% set genreGet = craft.app.request.getQueryParam('genre') %}
{% if genreGet %}
    {% do games.genreGame(genreGet|split(',')).all() %}
{% endif %}

{% set specialsGet = craft.app.request.getQueryParam('specials') %}
{% if specialsGet %}
    {% do games.specialsGame(specialsGet|split(',')).all() %}
{% endif %}

Is there any way to make this work on the OR principle?




FINAL! Thanks to the guys Moritz Lost and username_3. They suggested how to do it better. Here is the final solution:
{% set games = craft.entries().section('games') %}

{% set elements = [] %}
{% set fields = [] %}

{% set genres = craft.app.request.getQueryParam('genres') %}
{% if genres %}
    {% set elements = elements|merge(genres|split(','))%}
    {% set fields = fields|merge(['genreEntriesGame'])%}
{% endif %}

{% set specials = craft.app.request.getQueryParam('specials') %}
{% if specials %}
    {% set elements = elements|merge(specials|split(','))%}
    {% set fields = fields|merge(['specialsEntriesGame'])%}
{% endif %}

{% if elements|length > 0 and fields|length > 0 %}
    {% do games.relatedTo({
        element: elements,
        field: fields
    }) %}
{% endif %}

{% set games = games.all() %}

The only thing I did not use the array syntax (genre[], specials[]) syntax as username_1 advised. When I use array syntax (genre[], specials[]) in input fields, my URL becomes very long. The names of the parameters in the url are repeated very many times then. Therefore, I used JS to process the selected checkboxes, took their id and wrote them in a separate input field, thereby getting something like this genre=4536,1457 in my URL. So I used |split(',')

**Tags:** craft3

> **Comments:**
> **username_1**: If you include the template code you're using to output the filters it's easier to provide an answer.  
> **username_1**: Get rid of the `split` and change your inputs as mentioned in my answer. The `|split` filter always returns an array, which will be empty if the query param doesn't exist. So `[genres, special]` will result in `[[], []]` – an array with two empty arrays. This is not falsy, so the `relatedTo` is always applied. So you're asking Craft for all games related to nothing, which matches nothing.  
> **username_1**: If you want to support multiple selection, adjust the inputs to use array syntax (`genre[]`, `specials[]`) and use the second code example in my answer.  
> **username_0**: @username_1 I have updated the question again (for the third time). Experienced a naked solution. Take a look  
> **username_0**: @username_1 Even with a bare solution, for some reason nothing is output((  
> **username_1**: You need `[36774, 36842, 36842]` instead of `[[36774], [36842,36842]]`. Take a look at the [documentation on relations](https://craftcms.com/docs/4.x/relations.html), there are multiple examples and all the supported parameters are listed there.  
> **username_0**: @username_1 iI have completed the question. You solution is best))) Thx.  
> **username_1**: Glad you got it working!  

---

## 3 answers

### Answer by username_1 on 2022-11-19. Score: 4 | Accepted answer

You can use a relatedTo parameter to limit your query to all games that are related to one of multiple elements. This is assuming that both specialsGame and genreGame are entries fields or another kind of element relation field (like tags or categories).
The following code assumes you're using element IDs for the values of your checkboxes.
{% set gamesQuery = craft.entries().section('games') %}

{% set genre = craft.app.request.getQueryParam('genre') %}
{% set specials = craft.app.request.getQueryParam('specials') %}
{% set selectedFilters = [genre, specials]|filter %}

{% if selectedFilters %}
    {% do gamesQuery.relatedTo({
        element: selectedFilters,
        field: ['genreGame', 'specialsGame']
    }) %}
{% endif %}

The documentation on relations has more examples on how to narrow your query further. Note that OR logic is the default in this case (so the query is limited to all games that are limited to one of the specified elements).
If you want to support multiple selection for both filters, change your input names to use array syntax (specials[] and genre[]), this will cause PHP to parse those as arrays. Then merge those arrays together:
{% set genre = craft.app.request.getQueryParam('genre') ?? [] %}
{% set specials = craft.app.request.getQueryParam('specials') ?? [] %}
{% set selectedFilters = genre|merge(specials)|filter %}

> **Comments:**
> **username_0**: thx for answer, but ... First. genreGame and specialsGame not entries fields! it is a checkboxes fields. I'm afraid your solution won't work (((( Second. URL from which I take the values looks like this: site.com/games?genre=action%2Crpg%2Chorror%2Cadventure&specials=single%2Cmultiplayer%2Cgamepad%2Ccards%2Cachievements therefore, to convert the received data, I use specialsGet|split(',')  
> **username_1**: @username_0 Yeah, that's why you need to include information on your fields as well as the template for your filter form in the question, without that we can only guess what kind of field you're working with ;) All the information on filtering checkboxes with multiple values can be found in the [documentation](https://craftcms.com/docs/4.x/checkboxes-fields.html#querying-elements-with-checkboxes-fields). For filtering across multiple fields with OR-logic, check out my answer here as a starting point: https://craftcms.stackexchange.com/a/38648/11705  
> **username_1**: @username_0 As a sidenote, you should only execute the query once, so use `{% do games.genreGame(genreGet|split(',')) %}` without the `all()` at the end.  
> **username_0**: i cant understand construction andWhere. my English is not very good))) Need good example. I try to do this: `{% set games = craft.entries().section('games').andWhere(['or',['=', '[[field_genreGame]]', ???WHAT_HERE??? ],['=', '[[field_specialsGame]]', ???WHAT_HERE???]]) %}`. What should I substitute instead `???WHAT_HERE???` And in general, am I moving in the right direction?  
> **username_0**: i try to do this: `{% set games = craft.entries().section('games').andWhere(['or',['=', '[[field_genreGame]]', ['horror'] ],['=', '[[field_specialsGame]]', ['multiplayer]']]) %}` but this not work. i get error "Undefined array key 1"  
> **username_1**: See the excellent answer by @MatsMikkelRummelhoff on how to solve this issue with your current content architecture. It's pretty involved, because the checkboxes field isn't really built for that type of heavy filtering. I would recommend you rethink your content architecture and use categories for genres and specials. Then you can use the solution provided in my answer, which makes it much easier. It also means you can add categories without touching the project config (which would require a pull request and a deployment in a development to live deployment scenario).  
> **username_0**: Yes, I listened to his advice. I decided that making fields of the entries type is better. Then it may come in handy if I want to expand the functionality of the site. For example, if I want to create a menu with icons for each genre  
> **username_0**: Here, I'm sitting redoing what I did)))  
> **username_0**: I have completed my question (Accidentally edited your answer)  

---

### Answer by username_2 on 2022-11-21. Score: 1

For multiple select/checkboxes fields, you can use the search index.
{% set games = craft.entries().section('games').search('genreGame:horror OR specialsGame:multiplayer').all() %}

Note that you would need to enable searching on those fields in the CP first:
https://craftcms.com/docs/3.x/searching.html#configuring-custom-fields-for-search

> **Comments:**
> **username_0**: No, using search is a very slow method. He won't do here. It's easier for me to redo the type of fields from checkboxes to entries and implement the solution that username_1 proposed  

---

### Answer by username_3 on 2022-11-21. Score: 1

Generally, and as @username_1's answer suggest, using elements (i.e. entries or categories) and the relatedTo param instead of Checkboxes for categorisation, is definitely going to be a better idea in most cases, and the approach I'd recommend.
That said, one option for using an OR operand to query entries on multiple, non-relational custom fields, is by creating a so-called "advanced" element query.
Essentially, an advanced element query is any element query that uses one or several methods from Craft's base query builder's – like .where(), .join(), .distinct() etc.
The biggest thing to know about advanced element queries is that unlike "regular" queries, you will usually have to specify the full column name for any custom field(s) used in their methods. For a custom field with the handle genreGame, the actual column name will look something like field_genreGame_asfljksa. That last part is a random suffix – this is possible to determine programmatically, but it should also be fine to hard code it as it's not supposed to ever change between environments.
Essentially, here's how an advanced query that'll almost do what you need could look, using .orWhere() statements:
{% set games = craft.entries().section('games') %}
...
{% do games.orWhere(['=', 'field_genreGame_asfljksa', '["horror"]']) %}
...
{% do games.orWhere(['=', 'field_specialsGame_xsaoefasj', '["multiplayer"]']) %}

The "almost" is due to the fact that since you're going to be querying on Checkboxes fields, you'll need to account for entries that have more than one value checked (i.e. selected) in those fields.
Additionally, Checkboxes fields store their selected values in the content database table as JSON (note the ["horror"] in the example query above, instead of just horror). This means that you can't actually use a simple = operator for the .orWhere() comparisons.
One option for adding support for multiple, serialized values is to create LIKE statements for all your possible matches found in the genreGet and specialsGet comma separated GET variables, i.e. something like this:
...
{% for genre in genreGet|split(',') %}
    {% do games.orWhere(['like', 'field_genreGame_asfljksa', '"' ~ genre ~ '"']) %}
{% endfor %}
...

If that seems a bit squishy and/or verbose, I concur!
Another option is looking into the JSON_EXTRACT() and JSON_CONTAINS() SQL functions, but this stuff does get gnarly quite fast IMO.

> **Comments:**
> **username_1**: Great answer! This is exactly why I avoid checkboxes fields for anything that might need to be searchable. Categories are much easier, especially since it allows editors to add categories without touching the project config. For what it's worth, storing all selected categories always struck me as a weird choice – it would make more sense to store the options in a separate table and use a junction table (or maybe even utilize the `relations` table) to store the selected options. Though maybe that would be difficult with the current architecture of the `content` table.  
> **username_3**: @username_1 100%. Some other big drawbacks with using non-relational fields for this stuff is if you ever need to rename an option somewhere down the line, or if you need options translated for different sites.  

---

