Provides an interface to search a Funnelback collection

Installs: 167

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 1

Forks: 2

Open Issues: 1


1.1.0 2023-02-20 04:01 UTC

This package is auto-updated.

Last update: 2023-03-20 04:19:17 UTC


This module provides an interface to query a Funnelback collection.


Current features

  • Search a single Funnelback collection by one or more keywords
  • Present paginated search results to users
  • Has been tested and known to work with Funnelback version 15.

You can see this module in action on the Whaikaha - Ministry of Disabled People website.

Still to do

  • Identify a search result in the database and provide the most up-to-date content for the results page
  • Ability to filter or facet information (reliant on Funnelback supporting this)

What this module won't try to do


Install this module via Composer:

$ composer require madmatt/silverstripe-funnelback


You need to be using Silverstripe CMS 4.10 or newer, no other dependencies should matter.


Once you've installed the module, you'll need to do two things:

  1. Configure the necessary environment variables.
  2. Create & integrate your search form.

Step 1: Configuring the necessary environment variables

This module needs the following environment variables configured:

  • SS_FUNNELBACK_URL: The base URL to the Funnelback API endpoint, without any trailing slashes or path. For example,
  • SS_FUNNELBACK_USERNAME: The username provided by Funnelback.
  • SS_FUNNELBACK_PASSWORD: The password provided by Funnelback.
  • SS_FUNNELBACK_COLLECTION: The name of the collection (e.g. example-collection).

Once configured, the module can be used to perform search requests.

Step 2: Create & integrate your search form

You may already have some search infrastructure in place. If so, adapt these instructions as needed. This assumes you have nothing setup yet.

Create a new controller for your search page - app/src/Controllers/SearchController.php:

namespace App\Controllers;

use Madmatt\Funnelback\SearchService;

class SearchController extends \PageController
    private static $dependencies = [
        'searchService' => '%$' . SearchService::class

    public SearchService $searchService;

    public function index(HTTPRequest $request)
        $keyword = $request->getVar('q');
        $start = $request->getVar('start') ?? 0;

        // If a keyword has been supplied, perform a search and return the results.
        // Otherwise, don't bother performing an empty search.
        if ($keyword) {
            return [
                'Query' => DBField::create_field('Varchar', $keyword)
                'Results' => $this->searchService->search($keyword, $start),
        } else {
            return [];

Next, register your new controller via a Director route, for example in app/_config/routes.yml:

Name: app-routes
  - '#rootroutes'
  - '#coreroutes'
    'search': 'App\Controllers\SearchController'

Create your search results template (for example themes/<theme>/templates/App/Search/Layout/


    <% if $Results || $Query %>
        <h2>Results for "$Query"</h2>

        <% if $Results %>
            <h3>Displaying $Results.FirstItem - $Results.LastItem results of $Results.TotalItems</h3>

                <% loop $Results %>
                    <h3><a href="$Link">$Title</a></h3>
                <% end_loop %>

            <% if $Results.MoreThanOnePage %>
            <nav aria-label="pagination">
                    <% if $Results.NotFirstPage %>
                        <li><a href="$Results.PrevLink">Previous</a></li>
                    <% end_if %>

                    <% loop $Results.PaginationSummary %>
                        <% if $CurrentBool %>
                        <li>$PageNum <span class="sr-only">(current)</span></li>
                        <% else %>
                            <% if $Link %>
                                <li><a href="$Link">$PageNum</a></li>
                            <% else %>
                            <% end_if %>
                        <% end_if %>
                    <% end_loop %>

                    <% if $Results.NotLastPage %>
                        <li><a href="$Results.NextLink">Next</a></li>
                    <% end_if %>
            <% end_if %>
        <% else %>
            <h3>No search results found for "$Query"</h3>
        <% end_if %>
    <% end_if %>

Now, assuming that Funnelback has already crawled your website, you should be able to visit http://your-website/search?q=testing and have the website query Funnelback and return results for you.

On your PageController class, add the following SearchForm method so that you can output a search form on every page of your website:


use SilverStripe\CMS\Controllers\ContentController;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\TextField;

class PageController extends ContentController
    public function SearchForm(): Form
        $form = Form::create(
                TextField::create('q', 'Search query')

            ->setFormAction('/search') // Override the standard form action URL to always be /search
            ->setFormMethod('GET', true) // Ensure the form sends the search query in the URL so it can be bookmarked and cached etc
            ->disableSecurityToken(); // Turn off CSRF protection for this form, it's not required unless you have sensitive or private search results

        return $form;

Finally, add this into your template:


Provided everything is configured correctly, you should now have everything you need to get Funnelback search working on your website.

Optional configuration

Optional configuration options are listed below.

Code of Conduct

When having discussions about this module, please adhere to the Silverstripe Community Code of Conduct.