Answers.Body: <p>Not sure i understand well, but to be sure: you want to be able to filter for (let's say you sell shirts) a Red AND Large shirt, so it filters only the shirts which contain the color red and that are available in large?</p>
  
  <p>On that note, have you tried setting <code>relatedToParam</code> to <code>and</code> instead of <code>or</code>?</p>
  
  <p>The <a href="https://craftcms.stackexchange.com/questions/18447/how-to-filter-entries-based-on-tags">answer</a> you linked seems to work for multiple selections that are not related. For example: i want the website to show me all the red shirts and all the large shirts, but not necessarily just the red large shirts.</p>
  
  <p>Following that logic, changing <code>relatedToParam</code> to <code>and</code> should do the trick?</p>
  
  <p><br></p>
  
  <p><strong>EDIT (2019-02-07):</strong></p>
  
  <p>So, i tried quite a few solutions and that seems to be working, please read the comments.</p>
  
  <p><strong>EDIT 2:</strong></p>
  
  <p>There was an issue! 
  For example, if no size was selected, the loop simply won't do nothing. You could switch the loop to start with types, but then again, if no type is selected, same problem. 
  Now it's working but still really NOT versatile. 
  Feel free to edit or comment with a better solution!</p>
  
  <pre><code>{% set sizes = craft.tags.group('size').all() %}
  {% set types = craft.tags.group('type').all() %}
  
  {# You'll need to separate tags inside the query itself #}
  {# ?size=......&amp;type=...... #}
  
  {# The split filter doesn't work directly on getParam #}
  
  {# Error when getParam is empty #}
  {# Because it is set to [] and we can't split on an array #}
  {# You will need to find a little condition to make it bulletproof #}
  
  {% set selectedSizesIds = craft.app.request.getParam('size') ?? [] %}
  {% set selectedSizesIds = selectedSizesIds|split(',') %}
  
  {% set selectedTypesIds = craft.app.request.getParam('type') ?? [] %}
  {% set selectedTypesIds = selectedTypesIds|split(',') %}
  
  {# You can actually use a if inside a print statement #}
  {# Take a look at the "checked" print condition #}
  
  {% for size in sizes %}
      &lt;input type="checkbox" name="tags[]" value="{{ size.id }}" {{ (size.id in selectedSizesIds) ? 'checked' : '' }}&gt;{{ size.title }}&lt;/input&gt;
  {% endfor %}
  
  {% for type in types %}
      &lt;input type="checkbox" name="tags[]" value="{{ type.id }}" {{ (type.id in selectedTypesIds) ? 'checked' : '' }}&gt;{{ type.title }}&lt;/input&gt;
  {% endfor %}
  
  {# Where it gets tricky #}
  {% set relatedToParam = ['and'] %}
  
  {# Loop through the second set of tags while looping through the first set of tags #}
  {# Still not quite sure that's the best way to go but it works well #}
  
  {% if selectedSizesIds|length &gt; 0 %}
      {% for size in selectedSizesIds %}
          {% if selectedTypesIds|length &gt; 0 %}
              {% for type in selectedTypesIds %}
                  {% set relatedToParam = relatedToParam|merge([
                      { targetElement : [size,type] }
                  ]) %}
              {% endfor %}
          {% else %}
              {% set relatedToParam = relatedToParam|merge([
                  { targetElement : size }
              ]) %}
          {% endif %}
      {% endfor %}
  {% elseif selectedTypesIds|length &gt; 0 %}
      {% for type in selectedTypesIds %}
          {% set relatedToParam = relatedToParam|merge([
              { targetElement : type }
          ]) %}
      {% endfor %}
  {% endif %}
  
  {% set relatedToParam = relatedToParam|length &gt; 1 ? relatedToParam : null %}
  
  {% set entries = craft.products.type('accommodation').relatedTo(
      relatedToParam
  ).all() %}
  
  {% for product in entries %}
     {{ product.title }}
  {% endfor %}
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-06T09:12:49.200Z
Answers.Text: I think what I need is a combination of both 'and' and 'or'. As an example, If the user were to select 'L' and 'XL' from sizes, and 'Tops' from type, I'd like it to show all L and XL tops. Putting 'and' will make that search show nothing. Not sure how I'd go about it, but I think I'd need to merge each filter on its own first with the 'or' param, and then combine those together with an 'and'.
Answers.UserDisplayName: Amy
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-06T23:28:10.823Z
Answers.Text: Can the user search for XL + L + TOPS + BOTTOMS?
  Anyway, i guess you could loop through the first set of tags (size) and inside that loop, you could loop through the second set of tags (type). When doing this, you build an array for each possible filter, giving you something like that:
  (XL AND TOPS) OR (XL AND BOTTOMS) OR (L AND TOPS) OR (L AND BOTTOMS)
  Does that make sense?
  Sorry i can't give you a real code snippet right now! (tell me if you don't get it and i'll try to make one later)
Answers.UserDisplayName: Cryptomothy
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-07T11:07:07.830Z
Answers.Text: I understand the process, i'm not not quite sure how to go about it. If you could update your answer with a code snippet later it would be much appreciated!
Answers.UserDisplayName: Amy
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-07T21:15:50.817Z
Answers.Text: @Amy, done! Feel free to use it and ask questions :)
Answers.UserDisplayName: Cryptomothy
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-08T11:15:09.783Z
Answers.Text: I'm currently getting a 'explode() expects parameter 2 to be string, array given' error when I submit a search form no matter how many filters are selected. I've made the condition to do nothing if the array is empty, but as soon as the array is populated I get the error. Not sure if it would have something to do with how the URL is outputted, currently being '?size%5B%5D=475&type%5B%5D=478' or if it's something else. Have you come across this?
Answers.UserDisplayName: Amy
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-08T14:41:06.370Z
Answers.Text: Considering you are using size[] and type[] in your url, the output may already be an array, so doing a split on it will not work. Reading the error, it seems that is the problem. You can probably remove the line where we split the `selectedTypesIds` and `selectedSizesIds` !
Answers.UserDisplayName: Cryptomothy
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-05T19:29:37.617Z
Answers.LastActivityDate: 2019-02-08T00:02:45.920Z
Answers.LastEditDate: 2019-02-08T00:02:45.920Z
Answers.UserDisplayName: Cryptomothy
Body: <p>I've built a product filtering system using tags and currently have 2 available tag groups under different fields. <code>Size</code> and <code>Type</code></p>
  
  <p>Currently if I select 1 tag from both size and type, it shows all products with either selected, however I want it to only show if the product contains both tags.</p>
  
  <pre><code>{% set query = craft.request.getQuery() %}
  {% set selectedTagsIds = query.tags ?? [] %}
  
  {% for tag in craft.tags.group('size').all() %}
      {% set checkedAttr = tag.id in selectedTagsIds ? 'checked' : '' %}
      &lt;input type="checkbox" name="tags[]" value="{{ tag.id }}" {{ checkedAttr }}&gt;{{ tag.title }}&lt;/input&gt;
  {% endfor %}
  
  {% for tag in craft.tags.group('type').all() %}
      {% set checkedAttr = tag.id in selectedTagsIds ? 'checked' : '' %}
      &lt;input type="checkbox" name="tags[]" value="{{ tag.id }}" {{ checkedAttr }}&gt;{{ tag.title }}&lt;/input&gt;
  {% endfor %}
  
  {% set relatedToParam = ['or'] %}
  
  {% for id in selectedTagsIds %}
      {% set relatedToParam = relatedToParam|merge([{
          targetElement: id
      }]) %}
  {% endfor %}
  
  {% set relatedToParam = relatedToParam|length &gt; 1 ? relatedToParam : null %}
  
  {% set entries = craft.products.type('accommodation').relatedTo(relatedToParam) %}
  
  {% for product in entries %}
      // Product content here
  {% endfor %}
  </code></pre>
  
  <p>Is there a way I can modify what I have above to make it so that if user selects an option from each tag group, that it only shows products with both selected tags? And if more than 1 of each group are selected to show those too?</p>
  
  <p>I've based my current code based off <a href="https://craftcms.stackexchange.com/questions/18447/how-to-filter-entries-based-on-tags">this</a> answer.</p>
  
Tags: <craft3><tags><plugin-craftcommerce2><filtering>
Title: Product Filtering with Tags
ThreadText: # Product Filtering with Tags
  
  (Asked by: username_0 on 2019-02-05)
  
  I've built a product filtering system using tags and currently have 2 available tag groups under different fields. `Size` and `Type`
  
  Currently if I select 1 tag from both size and type, it shows all products with either selected, however I want it to only show if the product contains both tags.
  
  ```
  {% set query = craft.request.getQuery() %}
  {% set selectedTagsIds = query.tags ?? [] %}
  
  {% for tag in craft.tags.group('size').all() %}
      {% set checkedAttr = tag.id in selectedTagsIds ? 'checked' : '' %}
      <input type="checkbox" name="tags[]" value="{{ tag.id }}" {{ checkedAttr }}>{{ tag.title }}</input>
  {% endfor %}
  
  {% for tag in craft.tags.group('type').all() %}
      {% set checkedAttr = tag.id in selectedTagsIds ? 'checked' : '' %}
      <input type="checkbox" name="tags[]" value="{{ tag.id }}" {{ checkedAttr }}>{{ tag.title }}</input>
  {% endfor %}
  
  {% set relatedToParam = ['or'] %}
  
  {% for id in selectedTagsIds %}
      {% set relatedToParam = relatedToParam|merge([{
          targetElement: id
      }]) %}
  {% endfor %}
  
  {% set relatedToParam = relatedToParam|length > 1 ? relatedToParam : null %}
  
  {% set entries = craft.products.type('accommodation').relatedTo(relatedToParam) %}
  
  {% for product in entries %}
      // Product content here
  {% endfor %}
  
  ```
  
  Is there a way I can modify what I have above to make it so that if user selects an option from each tag group, that it only shows products with both selected tags? And if more than 1 of each group are selected to show those too?
  
  I've based my current code based off [this](https://craftcms.stackexchange.com/questions/18447/how-to-filter-entries-based-on-tags) answer.
  
  **Tags:** craft3, tags, plugin-craftcommerce2, filtering
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2019-02-05. Score: 2 | Accepted answer
  
  Not sure i understand well, but to be sure: you want to be able to filter for (let's say you sell shirts) a Red AND Large shirt, so it filters only the shirts which contain the color red and that are available in large?
  
  On that note, have you tried setting `relatedToParam` to `and` instead of `or`?
  
  The [answer](https://craftcms.stackexchange.com/questions/18447/how-to-filter-entries-based-on-tags) you linked seems to work for multiple selections that are not related. For example: i want the website to show me all the red shirts and all the large shirts, but not necessarily just the red large shirts.
  
  Following that logic, changing `relatedToParam` to `and` should do the trick?
  
  **EDIT (2019-02-07):**
  
  So, i tried quite a few solutions and that seems to be working, please read the comments.
  
  **EDIT 2:**
  
  There was an issue!
  For example, if no size was selected, the loop simply won't do nothing. You could switch the loop to start with types, but then again, if no type is selected, same problem.
  Now it's working but still really NOT versatile.
  Feel free to edit or comment with a better solution!
  
  ```
  {% set sizes = craft.tags.group('size').all() %}
  {% set types = craft.tags.group('type').all() %}
  
  {# You'll need to separate tags inside the query itself #}
  {# ?size=......&type=...... #}
  
  {# The split filter doesn't work directly on getParam #}
  
  {# Error when getParam is empty #}
  {# Because it is set to [] and we can't split on an array #}
  {# You will need to find a little condition to make it bulletproof #}
  
  {% set selectedSizesIds = craft.app.request.getParam('size') ?? [] %}
  {% set selectedSizesIds = selectedSizesIds|split(',') %}
  
  {% set selectedTypesIds = craft.app.request.getParam('type') ?? [] %}
  {% set selectedTypesIds = selectedTypesIds|split(',') %}
  
  {# You can actually use a if inside a print statement #}
  {# Take a look at the "checked" print condition #}
  
  {% for size in sizes %}
      <input type="checkbox" name="tags[]" value="{{ size.id }}" {{ (size.id in selectedSizesIds) ? 'checked' : '' }}>{{ size.title }}</input>
  {% endfor %}
  
  {% for type in types %}
      <input type="checkbox" name="tags[]" value="{{ type.id }}" {{ (type.id in selectedTypesIds) ? 'checked' : '' }}>{{ type.title }}</input>
  {% endfor %}
  
  {# Where it gets tricky #}
  {% set relatedToParam = ['and'] %}
  
  {# Loop through the second set of tags while looping through the first set of tags #}
  {# Still not quite sure that's the best way to go but it works well #}
  
  {% if selectedSizesIds|length > 0 %}
      {% for size in selectedSizesIds %}
          {% if selectedTypesIds|length > 0 %}
              {% for type in selectedTypesIds %}
                  {% set relatedToParam = relatedToParam|merge([
                      { targetElement : [size,type] }
                  ]) %}
              {% endfor %}
          {% else %}
              {% set relatedToParam = relatedToParam|merge([
                  { targetElement : size }
              ]) %}
          {% endif %}
      {% endfor %}
  {% elseif selectedTypesIds|length > 0 %}
      {% for type in selectedTypesIds %}
          {% set relatedToParam = relatedToParam|merge([
              { targetElement : type }
          ]) %}
      {% endfor %}
  {% endif %}
  
  {% set relatedToParam = relatedToParam|length > 1 ? relatedToParam : null %}
  
  {% set entries = craft.products.type('accommodation').relatedTo(
      relatedToParam
  ).all() %}
  
  {% for product in entries %}
     {{ product.title }}
  {% endfor %}
  
  ```
  
  > **Comments:**
  > **username_0**: I think what I need is a combination of both 'and' and 'or'. As an example, If the user were to select 'L' and 'XL' from sizes, and 'Tops' from type, I'd like it to show all L and XL tops. Putting 'and' will make that search show nothing. Not sure how I'd go about it, but I think I'd need to merge each filter on its own first with the 'or' param, and then combine those together with an 'and'.  
  > **username_1**: Can the user search for XL + L + TOPS + BOTTOMS? Anyway, i guess you could loop through the first set of tags (size) and inside that loop, you could loop through the second set of tags (type). When doing this, you build an array for each possible filter, giving you something like that: (XL AND TOPS) OR (XL AND BOTTOMS) OR (L AND TOPS) OR (L AND BOTTOMS) Does that make sense? Sorry i can't give you a real code snippet right now! (tell me if you don't get it and i'll try to make one later)  
  > **username_0**: I understand the process, i'm not not quite sure how to go about it. If you could update your answer with a code snippet later it would be much appreciated!  
  > **username_1**: @username_0, done! Feel free to use it and ask questions :)  
  > **username_0**: I'm currently getting a 'explode() expects parameter 2 to be string, array given' error when I submit a search form no matter how many filters are selected. I've made the condition to do nothing if the array is empty, but as soon as the array is populated I get the error. Not sure if it would have something to do with how the URL is outputted, currently being '?size%5B%5D=475&type%5B%5D=478' or if it's something else. Have you come across this?  
  > **username_1**: Considering you are using size[] and type[] in your url, the output may already be an array, so doing a split on it will not work. Reading the error, it seems that is the problem. You can probably remove the line where we split the `selectedTypesIds` and `selectedSizesIds` !  
  
  ---
  
  