PHPackages                             toastnz/opensearch - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. toastnz/opensearch

ActiveSilverstripe-vendormodule[Search &amp; Filtering](/categories/search)

toastnz/opensearch
==================

A simple OpenSearch wrapper for SilverStripe, built on top of the official OpenSearch PHP client.

1.0.3(4w ago)0123↓50%BSD-3-ClausePHP

Since Apr 17Pushed 6d agoCompare

[ Source](https://github.com/toastnz/silverstripe-opensearch)[ Packagist](https://packagist.org/packages/toastnz/opensearch)[ RSS](/packages/toastnz-opensearch/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (3)Versions (5)Used By (0)

OpenSearch for SilverStripe
===========================

[](#opensearch-for-silverstripe)

A wrapper around the OpenSearch PHP client.

Requirements
------------

[](#requirements)

See the root `composer.json`.

Installation
------------

[](#installation)

```
composer require toastnz/opensearch
```

Helper Configuration
--------------------

[](#helper-configuration)

Configure the helper through Injector properties:

```
SilverStripe\Core\Injector\Injector:
  Toast\OpenSearch\Helpers\OpenSearch:
    properties:
      client_host: '`OPENSEARCH_HOST`'
      client_username: '`OPENSEARCH_USERNAME`'
      client_password: '`OPENSEARCH_PASSWORD`'
      client_verify: false
      index_class: App\Search\SiteSearchIndex
      record_operation_fail_silently: true
```

Supported helper properties:

- `client_host`
- `client_username`
- `client_password`
- `client_verify`
- `index_class`
- `default_search_index`
- `record_operation_fail_silently`

`record_operation_fail_silently` defaults to `true`. It only affects automatic record-driven indexing through `Toast\OpenSearch\Extensions\DataObjectExtension`, where insert, update, delete, publish, and unpublish operations fail quietly if the index is missing, not configured, or unreachable. It does not apply to direct index operations such as `OpenSearchManagerTask`, `OpenSearchReindexTask`, `initIndex()`, `clearIndex()`, or `deleteIndex()`.

Defining an Index
-----------------

[](#defining-an-index)

Create a subclass of `Toast\OpenSearch\Search\OpenSearchIndex` and override protected properties before calling `parent::__construct()`.

```
use SilverStripe\Assets\File;
use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Model\VirtualPage;
use SilverStripe\ErrorPage\ErrorPage;
use Toast\OpenSearch\Search\OpenSearchIndex;

class SiteSearchIndex extends OpenSearchIndex
{
    public function __construct(?string $indexName = null)
    {
        $this->indexName = $indexName ?? 'default_index';
        $this->fields = [
            'Title' => ['type' => 'text'],
            'Content' => ['type' => 'text'],
            'PublishDate' => 'Datetime',
        ];
        $this->searchFields = [
            'Title^2',
            'Content',
            'SearchContent',
            'ElementalArea.Elements.Title',
        ];
        $this->filters = [
            'SubsiteID' => ['type' => 'integer'],
            'PublishDate' => 'Datetime',
        ];
        $this->includedClasses = [SiteTree::class, File::class];
        $this->excludedClasses = [
            ErrorPage::class,
            RedirectorPage::class,
            VirtualPage::class,
        ];
        $this->filterField = 'ShowInSearch';

        parent::__construct($indexName);
    }
}
```

Important: the base constructor only accepts an optional index name. It does not accept named arguments such as `fields`, `searchFields`, or `filters`.

Querying
--------

[](#querying)

```
use Toast\OpenSearch\Helpers\OpenSearch;

$results = OpenSearch::singleton()->search('annual report', null, [
    'filters' => [
        'SubsiteID' => 2,
        'PublishDate' => ['gte' => '2026-01-01'],
    ],
]);
```

The second argument can be:

- an `OpenSearchIndex` instance
- an index-definition class name
- a literal OpenSearch index name
- `null` for the configured default

SiteConfig Search Tuning
------------------------

[](#siteconfig-search-tuning)

The bundled `SiteConfigExtension` adds four CMS tabs under `Root.OpenSearch`:

- `Weights` for per-field search weights
- `FineTune` for search-time query behaviour
- `Synonyms` for runtime query expansion rules
- `More` for running a search and reviewing per-result OpenSearch explanations

When `silverstripe/subsites` is installed and the active index declares `SubsiteID` as a filter, the `More` explanation search automatically scopes results to the current CMS subsite from `SubsiteState`, while still including records with `SubsiteID` 0 or no `SubsiteID`.

`FineTune` stores non-default values in `OpenSearchFineTuneSettings` and applies them to generated searches at runtime. The available controls are:

- `type` (`multi_match.type`)
- `operator`
- `minimum_should_match`
- `fuzziness`
- `min_score`

Defaults preserve the module's existing behaviour:

- `type`: omitted, which matches the current `multi_match` default behaviour
- `operator`: omitted, which matches the current `multi_match` default behaviour
- `minimum_should_match`: omitted
- `fuzziness`: omitted
- `min_score`: omitted

When `type` is `cross_fields`, `phrase`, or `phrase_prefix`, configured `fuzziness` is ignored because OpenSearch does not allow that combination.

`min_score` is only added to generated request bodies when a search term is present or an explicit `query` option is supplied, so empty filter-only searches continue to behave as they do today.

`Synonyms` stores rules as related `OpenSearchSynonym` records on the current `SiteConfig` and applies them to generated searches at runtime, so changes take effect without reindexing or recreating the index.

In the CMS, editors manage synonyms with a GridField under `Root.OpenSearch.Synonyms`. Each row has two simple lists:

- `When searching for these`
- `Also search for these`

Search Form
-----------

[](#search-form)

The module ships with:

- `Toast\OpenSearch\Forms\SearchForm`
- `Toast\OpenSearch\Extensions\ContentControllerExtension`

The controller extension adds `SearchForm()` and `searchResults()` to `ContentController`. The form reads the `Search` query parameter, runs the helper query, and hydrates matches back into `DataObject` records when possible.

Search form pagination config:

```
Toast\OpenSearch\Forms\SearchForm:
  enable_pagination: true
  results_per_page: 10
```

Tasks
-----

[](#tasks)

Index manager:

```
/dev/tasks/OpenSearchManagerTask?action=status

```

Supported actions:

- `init`
- `reset`
- `clear`
- `delete`
- `status`

Full reindex:

```
/dev/tasks/OpenSearchReindexTask

```

Notes
-----

[](#notes)

- `searchFields` entries not declared in `fields` are mapped as `text`
- `filters` are both mapped and included in indexed documents
- `ID` and `ClassName` are always indexed
- versioned classes are reindexed from `Live`
- undeclared runtime filters are ignored
- `Toast\OpenSearch\Extensions\DataObjectExtension` only performs automatic indexing for records included by the active `OpenSearchIndex`, while still reindexing dependent parent records for declared relation chains and respecting `excludedClasses`

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance97

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity37

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~8 days

Total

4

Last Release

28d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/49888163?v=4)[Leandro Palmieri](/maintainers/leandro-toastnz)[@leandro-toastnz](https://github.com/leandro-toastnz)

---

Top Contributors

[![beetpix](https://avatars.githubusercontent.com/u/66008824?v=4)](https://github.com/beetpix "beetpix (6 commits)")

---

Tags

searchsilverstripefulltextsimilarityrankingfuzzyboosting

### Embed Badge

![Health badge](/badges/toastnz-opensearch/health.svg)

```
[![Health](https://phpackages.com/badges/toastnz-opensearch/health.svg)](https://phpackages.com/packages/toastnz-opensearch)
```

###  Alternatives

[silverstripe/solr

Solr integration for SilverStripe. Note that this is NOT related to the silverstripe/fulltext package.

1914.0k](/packages/silverstripe-solr)[heyday/silverstripe-elastica

Provides Elastic Search integration for SilverStripe DataObjects using Elastica

1137.9k2](/packages/heyday-silverstripe-elastica)[g4b0/searchable-dataobjects

This module adds DataObjects to frontend search

254.9k](/packages/g4b0-searchable-dataobjects)[silverstripe-terraformers/gridfield-rich-filter-header

Rich filter header component for GridField

1326.1k1](/packages/silverstripe-terraformers-gridfield-rich-filter-header)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
