Adding search to blog

I am struggling to add search to my blog controller. I do not want to use a separate page to display the results. I have a dynamic title at the top of the blog page that changes depending on wether you you are looking at the blog, or of you are filtering with tags or categories. That bit works.

It should also change when search results are returned. When i try to add the search facility based on the cookbook guide, it breaks. The search results must end up in $posts i think so i can use the same for each loop on blog template.

Where am i going wrong? How can i change the title and get the search results displayed?

Heres my controller:

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

  // Import Global Controller
  require_once kirby()->roots()->controllers() . '/shared/global.php';

  // Template Code
  // fetch the basic set of pages
  $posts = $site->index()->find('blog')->children()->visible()->unscheduled()->sortBy('created','desc');

  $resultsTitle = 'Latest Posts';

  // add the tag filter
  if($tag = param('tag')) {
    $posts = $posts->filterBy('tags', $tag, ',');
    $resultsTitle = 'Tag: '.$tag;
  }

  // fetch all tags
  $tags = $posts->pluck('tags', ',', true);
  asort($tags);

  // add the category filter
  if($category = param('category')) {
    $posts = $posts->filterBy('categories', $category, ',');
    $resultsTitle = 'Category: '.$category;
  }

  // fetch all categories
  $categories = $posts->pluck('categories', ',', true);
  asort($categories);

  // Search Results
  if($query = get('q')) {
    // if we are searching
    $posts = $posts->search($query, 'title|pagetext');
      if($posts == '') {
        $resultsTitle = 'No results found for: "'.$query.'"';
      }
      else {
        $resultsTitle = 'Search results for: "'.$query.'"';

        return array(
          'query' => $query,
          'posts' => $posts
        );

      }

    } else {

    // if we are not searching
    $posts = $posts;

  }

  // apply pagination
  $posts = $posts->paginate(c::get('pagination'));
  $pagination = $posts->pagination();


  // Pass these off to the template
  return compact('resultsTitle', 'posts', 'tags', 'tag', 'category', 'categories', 'pagination', 'articleimage', 'articleimgsrc');

};

Never mind… think i solved it…

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

  // Import Global Controller
  require_once kirby()->roots()->controllers() . '/shared/global.php';

  // Template Code
  // fetch the basic set of pages
  $posts = $site->index()->find('blog')->children()->visible()->unscheduled()->sortBy('created','desc');

  $resultsTitle = 'Latest Posts';

  // add the tag filter
  if($tag = param('tag')) {
    $posts = $posts->filterBy('tags', $tag, ',');
    $resultsTitle = 'Tag: '.$tag;
  }

  // fetch all tags
  $tags = $posts->pluck('tags', ',', true);
  asort($tags);

  // add the category filter
  if($category = param('category')) {
    $posts = $posts->filterBy('categories', $category, ',');
    $resultsTitle = 'Category: '.$category;
  }

  // fetch all categories
  $categories = $posts->pluck('categories', ',', true);
  asort($categories);

  // Search Results
  $query = get('q');
  $posts = $posts->search($query, 'title|pagetext');

  if($query = get('q')) {
    if($posts == '') {
      $resultsTitle = 'No results found for: "'.$query.'"';
    }
    else {
      $resultsTitle = 'Search results for: "'.$query.'"';
    }
  }

  // apply pagination
  $posts = $posts->paginate(c::get('pagination'));
  $pagination = $posts->pagination();


  // Pass these off to the template
  return compact('query', 'resultsTitle', 'posts', 'tags', 'tag', 'category', 'categories', 'pagination', 'articleimage', 'articleimgsrc');

};

The return array within the if-else statement is not what you want, you want to return everything at the end of your controller.

The if($posts = '')statement doesn’t make sense either, because an empty collection is not an empty string. Use if(!$posts->count()) instead. Also, the else part in the query if statement is superfluous.

If you want to get all categories and tags, move you pluck statements up to right after you first define your posts. Otherwise you will only end up with the tags/categories of the filtered collection.

Do you really need to search the complete index for the blog page?

So, we finally end up with this:

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

  // Import Global Controller
  require_once kirby()->roots()->controllers() . '/shared/global.php';

  // Template Code
  // fetch the basic set of pages
  $posts = $site->index()->find('blog')->children()->visible()->unscheduled()->sortBy('created','desc');
 
  // fetch all tags
  $tags = $posts->pluck('tags', ',', true);
  asort($tags);

  // fetch all categories
  $categories = $posts->pluck('categories', ',', true);
  asort($categories);

  $resultsTitle = 'Latest Posts';

  // add the tag filter
  if($tag = param('tag')) {
    $posts = $posts->filterBy('tags', $tag, ',');
    $resultsTitle = 'Tag: '.$tag;
  }



  // add the category filter
  if($category = param('category')) {
    $posts = $posts->filterBy('categories', $category, ',');
    $resultsTitle = 'Category: '.$category;
  }


  // Search Results
  if($query = get('q')) {
    // if we are searching
    $posts = $posts->search($query, 'title|pagetext');
      if($posts->count()) {
        $resultsTitle = 'Search results for: "'.$query.'"';
      } else {
        $resultsTitle = 'No results found for: "'.$query.'"';
      }

  } 

  // apply pagination
  $posts = $posts->paginate(c::get('pagination'));
  $pagination = $posts->pagination();


  // Pass these off to the template
  return compact('resultsTitle', 'posts', 'tags', 'tag', 'category', 'categories', 'pagination', 'articleimage', 'articleimgsrc', 'query');

};

Awesome… i kind of solved it at the same time as you posting, but thanks for the tips on improving the code. I will add those :slight_smile: