Showing the Paragraph of a Search result

Hi there!

I am building a more or less simply search function in a website and the basics work fine. If I type in a search term the corresponding page is listed as a link in my results! My goal is to display not only the link to the page (containing the found search term) but also the paragraph in which the search term was found.

As I understand it so far:

  • The outcome ($result) gives me the page
  • On that page I need to initiate a search again (in my tamplate) with the search term ($query)
  • then I need to get the paragraph / parent / field of that search result
  • then render that paragraph / parent / field into text

Here is my code:

Search Controller

<?php
return function($site, $pages, $page) {

  $query   = get('q');
  $results = $site->search($query);

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

};

Search Tamplate

      <?php if ($results->isNotEmpty()): ?>
        <h3>Searchresult:</h3>
        <ul>
          <?php foreach ($results as $result): ?>
            <li>
              <a href="<?= $result->url() ?>">
                <?= $result->title() ?>
              </a>
              <?= $result->search($query)->tofield()->kirbytext() ?>
            </li>
          <?php endforeach ?>
        </ul>
      <?php endif ?>

Thats the line wich is not working and wich I am strugling with

<?= $result->search($query)->tofield()->kirbytext() ?>

Thank you for any help!

I posted this solution a long while ago, maybe it helps as a starting point: Live Search in Kirby 3 - #6 by texnixe

Thanks for the link! That would be a nice option too. I am new to php and Kirby and don’t really get it integrated in my code. I guess I put your snipped into the search controller? if I do that I get an error in the search tamplate about the Undefined variable “$text”…

In the example where I used it at the time, my search was limited to title and text field. And I limited highlighting to the text field.

The code snippet is a function that can go into the controller or into a plugin index.php, then has to be called on the text field:

 <?php foreach ($results as $result) : ?>
  <li>
    <h2><a href="<?= $result->url() ?>"><?= $result->title() ?></a></h2>
    <?= getResultText($result->text(), $query) ?>
  </li>
<?php endforeach ?>

If you search through all possible fields, you would have to approach this differently.

Thank’s a lot! It works perfectly with the function in the controller and the code you provided for the template!

Indeed I need a solution wich works even when my search is extended to different content fields. In my Search controller I use 3 different searches. First of all to define different search parameters and second to display search results in different sections.

I all ready tried to adapt the function for example the declaration field. This works fine but would mean that I need to write a lot of functions… If thats the only way – I of course will do it but I was wondering if there is a more light solution. I want to archive the displayed text for the search in general pages (fields: text) and in the position section (fields: declaration, implementation, references, notes) but not in the participants search.

Controler Code (without the mentioned function)

<?php
return function($site, $kirby) {

  $query = get('q');
  // Searching general pages 
  $results = $site->index()->find('info','howtodo','contact')->search($query);
  // Searching positions
  $resultsPos = $site->index()->listed()->search($query,'title|declaration|implementation|references|notes');
  // Searching participants
  $resultsPart = $kirby->users()->role('participants')->search($query,'name');
  
  return [
    'query'   => $query,
    'results' => $results,
    'resultsPos' => $resultsPos,
    'resultsPart' => $resultsPart,
  ];
};

Tamplate Code (without the resultText)

        <!-- Searchresults general pages  -->
        <?php if ($results->isNotEmpty()): ?>
          <h3>Allgemein</h3>
          <ul>
            <?php foreach ($results as $result): ?>
              <li>
                <a href="<?= $result->url() ?>">
                  <?= $result->title() ?>
                </a>
              </li>
            <?php endforeach ?>
          </ul>
        <?php endif ?>

        <!-- Searchresults in positions  -->
        <?php if ($resultsPos->isNotEmpty()): ?>
          <h3>Positionen</h3>
          <ul>
            <?php foreach ($resultsPos as $result): ?>
              <li>
                <a href="<?= $result->url() ?>">
                  <?= $result->title() ?>
                </a><br>
              </li>
            <?php endforeach ?>
          </ul>
        <?php endif ?>

        <!-- Searchresults in Participants  -->
        <?php if ($resultsPart->isNotEmpty()): ?>
          <h3>Teilnehmende</h3>
          <ul>
            <?php foreach ($resultsPart as $result): ?>
              <li>
                <a href="<?= $result->url() ?>">
                  <?= $result->name() ?>
                </a>
              </li>
            <?php endforeach ?>
          </ul>
        <?php endif ?>

What you could do is get the text for all relevant fields and apply the method on this combined text.

$text = '';
$fields = ['field1', 'field2'];
foreach($fields as $field) {
  $text .= $result->{$field}()->value();
}
$field = new Field($result, $text, 'mixfield');

echo getResultText($field, $query);

(not tested)

There’s probably a better way to achieve this, but something like this should work.