3

I am trying to set up a form with checkboxes that allows users to filter entries by selecting multiple categories, but I am not quite getting it right.

Currently this is my form:

{% set subcategoryParam = craft.request.getParam('subcategory') %}
{% set subcategories = craft.categories.group('partnerAreas').find() %}

<form action="{{ craft.request.url }}">

  {% for subcategory in subcategories %}
    <input type="checkbox" value="{{ subcategory.slug }}" id="{{ subcategory.slug }}" name="subcategory" {{ subcategory.slug in subcategoryParam ? 'checked'}}>
    <label class="label__checkbox" for="{{ subcategory.slug }}">
      {{ subcategory.title }}
    </label>
  {% endfor %}

  <button type="submit">
    Search
  </button>
</form>

Submitting this form gets me URL query strings like this:

?subcategory=sourcing-local-products&subcategory=communication

When I am using craft.request.getParam('subcategory'), only the last selected subcategory gets picked up (as you would expect).

I've tried setting the name on the checkbox field to subcategory[], but that gets me an array to string conversion template error and the URL query string then looks like this:

?subcategory%5B%5D=sourcing-local-products&subcategory%5B%5D=communication

What do I need to do to get a comma separated list for the subcategory parameter like this:

?subcategory=sourcing-local-products,communication

And once that is working, how do I then get all the entries that have any of the selected categories assigned via a Matrix field?

This is what I've currently got:

{% set subcategoryParam = craft.request.getParam('subcategory') %}
{% set selectedSubcategories = craft.categories.slug(subcategoryParam) %}
{% set entries = craft.entries({
  section: listingType,
  relatedTo: {
    targetElement: selectedSubcategories,
    field: 'involvementAreas.area'
  }
}) %}

But I imagine that's not quite right if I want to account for an array of selected categories...

4

I had to get this working just the other day. Here is what I did:

{# Get the relevant entries #}
{% set categoryQuery = craft.request.getParam('category') %}
{% set categories = craft.categories.group('sectionName').slug(categoryQuery) %}

{# Set the search parameters #} 
{% set searchParams = {
    relatedTo: categories,
    section: 'sectionName'
} %}

{# Get the relevant entries #}
{% set relevantEntries = craft.entries(searchParams) %}

In the form I have:

<form action="">

{% for category in craft.categories.group('services') %}
    <input id="{{category.slug}}" type="checkbox" name="category[]"  value="{{ category.slug }}" {{ category.slug in categoryQuery or categoryQuery == null  ? 'checked'}}>
    <label for="{{ category.slug }}" >{{ category.title }}</label>
{% endfor %}

</form>

This seems to work for me.

  • Thank you Dave, that's very helpful. Good to see that getting the categories and entries based on the query is as easy as that. It appears that the crux of my problem lies with the fact that I am unable to get the form to submit a comma separated list of categories. I have copied your code and that gives me a query string that looks like this: ?category%5B%5D=managing-waste-recycling&category%5B%5D=working-with-communities. And that's just not right. No idea why that is and how to fix it. Stuck on this one. – Katrin Apr 30 '15 at 10:16
  • Turns out my knowledge about query strings was non-existent and what I was getting in the URL was correct. I just needed to fix up a couple of array to string conversion template errors somewhere else and all is now working as expected. – Katrin Apr 30 '15 at 11:28
2

If multiple are passed subcategoryParam should be an array. So I believe you will need to process the data differently to get the categories. If you pass the id instead of the slug you could do this:

targetElement: subcategoryParam|join(',')
  • Thanks Aran. For this I would have to have a comma separated list in the URL query string, like ?subcategory=11,12, yes? How do I get to that stage in the first place? – Katrin Apr 29 '15 at 9:27
  • Change the value of subcategory.slug to subcategory.id. Then just use the code I posted earlier which will join each of those categories together. {% set entries = craft.entries({ section: listingType, relatedTo: { targetElement: subcategoryParam|join(','), field: 'involvementAreas.area' } }) %} – aran Apr 29 '15 at 14:52
  • That doesn't solve the main issue, which is that I am not getting a comma separated list for the subcategory parameter, which is what I need for this to work. – Katrin Apr 29 '15 at 15:15
  • Sorry I had another look at your code. You need to add a name to your checkbox with brackets name="subcategory[]" this will submit the checkboxes as an array. – aran Apr 29 '15 at 15:38
  • Nope, it doesn't. I have tried that. I have detailed what I am getting instead in the question. – Katrin Apr 29 '15 at 15:58
0

I hijacked the form submission and generated the URL based on all the checkboxes they checked.

Creating a URL like: /results?category=green,red,blue&number=one,two,three

The input names were not category[], but category and number.

Then in the results template, I grabbed the parameters (just displaying one in this example):

{% set number = craft.request.getParam('number') %}

{% if number %}
    {% for item in mealType|split(',') %}
        {% set numberCategories = craft.categories.group('number').slug(item) %}
        {% set relationParam = relationParam|merge([{ targetElement: numberCategories }]) %}
    {% endfor %}
{% endif %}

{# setup your search parameters #}
{% set searchParams = {
    section: 'news',
    relatedTo: relationParam
} %}

{# Find your entries #}
{# {% set entries = craft.entries(searchParams).order('score') %} #}
{% if relationParam|length > 1 %}
    {% paginate craft.entries(searchParams).order('score').limit(12) as pageInfo, pageEntries %}
{% endif %}

The JS for getting the values from each checkbox, I set the checkboxes all to have the same class. I looped thru those checkboxes and built an array to of checkbox input names and the values.

$("#news-form").submit(function(e) {
    e.preventDefault();
    var query_string = '';
    var categories = [];
    var i = 0;

    $('.category-checkbox').each(function (index, value) {
        var checkboxName = $(this).attr('name');
        var checkboxValue = $(this).val();

        // if checkbox is checked
        if ($(this).is(':checked'))
        {
            categories[checkboxName] = categories[checkboxName] || [];
            categories[checkboxName].push(checkboxValue);
        }

    });

    var cat_index = 0;

    for(var key in categories)
    {
        console.log(key);

        if(cat_index > 0)
        {
            query_string += '&' + key + '=' + categories[key];
        } else {
            query_string += key + '=' + categories[key];
        }

        cat_index++;
    }

    if( query_string != '')
    {
        window.location = '/news/results?' + query_string;
    }
});

Hopefully this helps someone out.

  • "hijacked the form submission". I assume this means this approach wouldn't work when JS fails/isn't enabled? – Katrin Apr 13 '16 at 18:36
  • Correct. I think most users have JS enabled. As long as you can get it to go to a URL like: project.com/news/filtered?category1=green,blue&category2=up,down then you're good to go w/ the rest of the code. – Brad Apr 13 '16 at 20:02
  • You are certainly not alone with that approach to web development, but I would urge you to reconsider. – Katrin Apr 14 '16 at 12:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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