6

I'll do my best to explain this.

I have a Portfolio of companies, which I have as a structure, that I need to be able to filter/search through by using up to four different parameters.

  1. Keyword - a basic search field that a user can type into
  2. Industry - a category field
  3. Company Status - a dropdown field
  4. Board Members - a relation to a different structure

I know how to search these individually but I'm not quite sure how to use any combo of these all at once. Whether that be using a keyword and industry to search, all four items to search, maybe just by industry and board members, or maybe just by industry.

Below is what I have so far. Hoping someone will be able to point me in the right direction or help me piece this together.

This handles the search

{# What is being searched #}
{% set portfolio = craft.entries.section('portfolio') %}

{# Potential Query Strings #}
{% set query = craft.request.getParam('q') %}
{% set industryParam = craft.request.getParam('industry') %}
{% set statusParam = craft.request.getParam('status') %}
{% set boardMemberParam = craft.request.getParam('boardMember') %}

{# Related to Industry and/or Board Member #}
{% set industry = craft.categories.group('industries').slug(industryParam).first %}

{# Here's where I'm not sure how to combine the relatedTo for the industry, status, and/or board members #}
{% set relationParam = industryParam ? {targetElement: industry} : '' %}

{% set entries = portfolio.relatedTo(relationParam).search(query) %}

{# Probably best to not use search, as it's slower than relatedTo, so I commented this out. #}
{# .search('companyStatus::"' ~ statusParam ~ '"') #}

{# Spit out the entries #}
{% if entries|length %}

  {% for entry in entries %}
    <article class="portfolio-item grid-3">
      <a class="portfolio-item-content" href="{{ entry.url }}">
        <h3 class="portfolio-item-title">{{ entry.title }}</h3>
      </a>
    </article>
  {% endfor %}

{% else %} {# If nothing matches the search criteria #}

  <p>Sorry, no results.</p>

{% endif %}

Stripped down version of where the user sets the parameters

<form action="{{ url('portfolio') }}">
  <h3 class="sidebar-title">Filter by Keyword</h3>
  <input type="search" name="q" placeholder="Search">

  <h3 class="sidebar-title">Filter by Industry</h3>
  <select class="fancy" name="industry">
    <option value="">All Industries</option>

    {# Only get categories that are being used. #}
    {# This will definitely need some cache tags. #}
    {% set categories = craft.categories.group('industries').order('title asc') %}
    {% set entriesWithCategories = craft.entries.relatedTo(categories) %}
    {% set categoriesInUse = craft.categories.relatedTo(entriesWithCategories) %}

    {% for category in categoriesInUse %}
      <option value="{{ category.slug }}">{{ category.title }}</option>
    {% endfor %}
  </select>

  <h3 class="sidebar-title">Filter by Status</h3>
  <select class="fancy" name="status">
    <option value="">All Statuses</option>
    <option value="active">Active</option>
    <option value="past">Past</option>
  </select>

  <h3 class="sidebar-title">Filter by Board Member</h3>
  <select class="fancy" name="boardMember">
    <option value="">All Board Memebers</option>
    {% set team = craft.entries.section('team') %}
    {% for member in team %}
      <option value="{{ member.slug }}">{{ member.title }}</option>
    {% endfor %}
  </select>

  <input type="submit" value="Go">
</form>

And if possible, how would I do this with AJAX? This can come later, initial search function is 100% okay. I know I could do the the AJAX filter completely on the Front-End but there's potential that the client will want to eventually add pagination if they start adding a bunch of companies to their portfolio.

Thanks in advance.

  • Hey Zack - I'll take a look at the search in a bit, but as for the AJAX, you'll be able to do that using Routes and the built in pagination template tag. Separate that into a new question once this one is resolved to give it some room to be answered :) – Aaron Berkowitz Feb 3 '15 at 0:55
  • Awesome, thanks @aberkie. And separating the AJAX is definitely a good idea. I'll see if I can take a shot at it once the "basic" search is taken care of. Looking forward to seeing what you come up with. – zackspear Feb 3 '15 at 1:41
8

One method is to build your params before performing the search.

{# set base params #}
{% set params = {
    section: 'portfolio',
    limit: null
} %}
{% set relatedParams = ['and'] %}

{# status #}
{% if craft.request.getParam('status') %}
    {% set status = craft.request.getParam('status') %}
    {% set params = params|merge({'companyStatus':status}) %}
{% endif %}

{# industry #}
{% if craft.request.getParam('industry') %}
    {% set category = craft.categories.group('industries').slug(craft.request.getParam('industry')).first %}
    {% set relatedParams = relatedParams|merge([{ targetElement:category }]) %}
{% endif %}

{# board member #}
{% if craft.request.getParam('boardMember') %}
    {% set boardMember = craft.entries.section('team').slug(craft.request.getParam('boardMember')).first %}
    {% set relatedParams = relatedParams|merge([{ targetElement:boardMember }]) %}
{% endif %}

{# add relatedParams to params #}
{% if relatedParams|length > 1 %}
    {% set params = params|merge({'relatedTo':relatedParams}) %}
{% endif %}

{# perform search #}
{% set searchParams = craft.request.getParam('q') %}
{% set entries = craft.entries(params).search(searchParams|trim) %}

{# display results #}
{% for entry in entries %}
    {{ entry.title }}
    ...
{% endfor %}

To AJAX load results you would place this in another template and load it dynamically with jquery. See this answer for an example.

To paginate the results you will need to submit your form as "GET" and append the query to your nextPage and prevPage links. See this answer for an example.

  • 1
    You should avoid passing a single ['and'] to the relatedTo param (→ "Users relatedTo multiple categories"). – carlcs Feb 3 '15 at 8:20
  • @DouglasMcDonald appreciate the response. This method definitely makes sense to me. Unfortunately it's throwing a template error at: {% set params = params|merge(['status':status]) %} and {% set params = params|merge(['relatedTo':relatedParams]) %} "An array element must be followed by a comma. Unexpected token "punctuation" of value ":" ("punctuation" expected with value ",")" A comma there doesn't make sense to me. I also tried it for the hell of it and the search doesn't work with commas there. So I'm not sure what I should do to fix the template error. – zackspear Feb 3 '15 at 17:06
  • 1
    Try {% set params = params|merge({'relatedTo':relatedParams}) %}. I'll update the answer. – Douglas McDonald Feb 3 '15 at 18:55
  • Awesome, that fixed the template error. The only thing not working now is the status param. It doesn't throw an error or anything it just doesn't filter anything. Seeing if I can fix it. I'll update this comment if I get it. – zackspear Feb 3 '15 at 23:03
  • 1
    I think that the reason 'status' is not working is that there is a craft parameter called status. Possible values are 'live', 'pending', 'expired', 'disabled', and null. You may need to rename that variable. – Douglas McDonald Feb 3 '15 at 23:12

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.