Show/group parents results in search page

Hi,

I’m trying to show in the search results page, all parents of results items.

Search controller:

<?php

return function ($site) {

  $query   = get('q');
  $results = $site->index()->filterBy('template', 'items')->children()->listed()->search($query, 'title|text')->sortBy('title');


  return [
    'query'   => $query,
    'results' => $results
    

  ];

};

Search template:

 <?php if($results->count()): ?>
  <ul class="categoriesItems">
    <?php foreach ($results as $result): ?>

    <li  class="ResultCategoriesItems <?= $result->parent()->title()->slug() ?>-style">
      <span><?= $result->parent()->title() ?> </span>
      <a href="<?= $result->url() ?>">
        <?= $result->title() ?> 
      </a>


    </li>
    <?php endforeach ?>
  </ul>

  <?php else : ?>

  <div>
    <p>No post matching with: <?= html($query) ?>.</p>
    
  </div>


  <?php endif ?>

Result parent is correctly shown in the loop, but I would like to add an other one showing only parent results:

 <?php if($results->count()): ?>

<ul>
 <li><a href="parent1">parent title 1</a></li>
 <li><a href="parent2">parent title 2</a></li>
 <li><a href="parent3">parent title 3</a></li>
</ul>

<hr>

  <ul class="categoriesItems">
    <?php foreach ($results as $result): ?>

    <li  class="ResultCategoriesItems <?= $result->parent()->title()->slug() ?>-style">      
      <a href="<?= $result->url() ?>">
        <?= $result->title() ?> 
      </a>


    </li>
    <?php endforeach ?>
  </ul>

  <?php else : ?>

  <div>
    <p>No post matching with: <?= html($query) ?>.</p>
    
  </div>


  <?php endif ?>

I tried to follow some older post: Group Search Results By Parents and also with Pluck in template but no result :frowning:

Thank you for any tips.

$parents = $results->pluck('parent', null, true);
foreach($parents as $parent) {
  echo $parent->title();
}

This will only get you the parents.

If you want to group by parents, you can use the group() method with a callback. But from what you wrote above, you only want the parents, right?

1 Like

Yes excatly. Only parents needed, thank you for your help. I’m quite sur to have tried your solution before but with no result :confused: Anyway, it works perfectly now.
Grouping by parents will certainly give a more polished/finished work. I’ll try some tests and get back to you if needed :slight_smile:

Grouping the results can be achieved like this:

$groupedResults = $results->group(function($item) {
  return $item->parent();
}

Then you need two looks to render the lists (leaving out the HTML here)

<?php
foreach ($groupedResults as $parent => $resultList) {
  echo $parent->title();
  foreach ($resultList as $result) {
    echo $result->title();
  }
}

I haven’t tested how this behaves if there is no parent (i.e. if the site is the parent).

Yes! Result is really better and more clear for the visitor! the final code to group search results with parent pages is:

search controllers:

<?php

return function ($site) {

  $query   = get('q');
  $results = $site->index()->filterBy('template', 'items')->children()->listed()->search($query, 'title|text')->sortBy('title');


  $groupedResults = $results->group(function($item) {
    return $item->parent();
  });


  return [
    'query'   => $query,
    'results' => $results,
    'groupedResults' => $groupedResults


  ];

};

and the search template:

  <?php if($results->count()): ?>
  <?php foreach ($groupedResults as $parent => $resultList) : ?>
  <h3 style="color:white"><a href="<?= page($parent)->url() ?>"><?= page($parent)->title() ?></a></h3>
  <ul class="categoriesItems itemsResults">
    <?php foreach ($resultList as $result) : ?>
    <li class="ResultCategoriesItems <?= page($parent)->title()->slug() ?>-style">
      <a href="<?= $result->url(); ?>"><?= $result->title(); ?></a>
    </li>
    <?php endforeach?>    
  </ul>
  <?php endforeach?>
  <?php else : ?>
  <div class="noResult">
    <p>No post matching with: <?= html($query) ?>.</p>
  </div>
  <?php endif ?>

Thank you Sonja.

Edit: for people who would use this code, structure folder is:

site
- all items
  - categories
    - category 1
    - category 2
    (...)

Not tested if the site is the parent.