1

Is it possible to display an entry field in search results if it contains the search query?

Context: I have an entry with a list of PDF assets. I want to show an asset in the search results if it contains the search query in the asset title. By default all the asset titles would display if any one contains the search query.

This is what I have in mind:

{% set searchQuery = craft.app.request.getParam('q') %}
{% set entries = craft.entries
  .section([
  'and', 'resources'
  ])
  .search(searchQuery)
  .orderBy('score')
  .all() %}
{% if entries|length %}
  <ul>
  {% for entry in entries %}
  <li><a href="{{ entry.url }}">{{ entry.title }}</a><br>
          {% set block = entry.downloads.all() %}   
          {% if block|length %}
                {% for file in block %}
                  {% for asset in file.file.all() %}
                  
                  {% if asset ***CONTAINS SEARCHQUERY*** %}
                      {{ asset.title }}
                  {% endif %}   
                  
                  {% endfor %}<br>
                {% endfor %}
          {% endif %}   
</li>
  {% endfor %}
  </ul>
{% endif %}

1 Answer 1

0

Like all relational fields, Assets fields return an ElementQuery instance (element queries are basically pre-baked query builders for fetching elements). You can use that ElementQuery's title() parameter to narrow down results based on assets' titles, including fuzzy searching. Here's how you could query for only assets with a title that contains the search query:

{% for asset in file.file.title('*' ~ searchQuery  ~ '*').all() %}
    {{ asset.title }}
{% endfor %}

Basically, the above appends * before and after the search query, which tells the ElementQuery returned by the Assets field (file.file, in your case) to only query for assets with titles that contain the search query somewhere.

There are other possible syntaxes available as well, depending on how you want to approach the title matching – see the official docs for more info.

6
  • This works perfectly for the example above. But I've tried to use the same code for a different Matrix block and I'm struggling to get it to work. The Matrix field is similar, but uses a different handle. The block handle is 'file' and the field handle is 'fileTitle', so I'm assuming it should be: {% for asset in file.fileTitle.title('' ~ searchQuery ~ '').all() %} {{ asset.title }} {% endfor %} - this doesn't work, so any help greatly appreciated!
    – Andrew
    Commented Jan 14, 2022 at 10:46
  • You’re missing the asterisks before and after the searchQuery, unless that was just a typo in your comment. Without the asterisks, Craft will query for assets with a filetitle exactly equal to the search query, which I assume is not what you want. Commented Jan 14, 2022 at 18:35
  • My mistake, the second version is a Matrix block with a text field. So I need the search query for a text field not an asset field. Unfortunately I cannot find any information on this anywhere. Once again any help would be fantastic!
    – Andrew
    Commented Jan 17, 2022 at 13:33
  • @Andrew If file.fileTitle is a plain text field, you should be able to simply do file.fileTitle('*' ~ searchQuery ~ '*') instead. Commented Jan 17, 2022 at 18:16
  • Many, many thanks for your help Mats. Unfortunately I'm a bit confused as the second version is not using a relational field. If I use {% for file in file.fileTitle('*' ~ searchQuery ~ '*').all() %}{{ file.fileTitle }} {% endfor %} - it doesn't work. So I've still got the syntax wrong.
    – Andrew
    Commented Jan 18, 2022 at 11:16

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.