Statamic GraphQL Search Field

While the filter works well, we needed to use the site search to find records as we needed them and found this missing from the Statamic Search, I am going to put this in as a pull request to them however for now here is how you can add it to your installation.

in PHP, Statamic, Laravel

Add a new file : app\GraphQL\Queries\SearchableEntriesQuery.php

<?php
namespace App\GraphQL\Queries;

use Statamic\Support\Arr;
use Statamic\Support\Str;
use Statamic\Facades\Entry;
use Statamic\Facades\Search;
use Statamic\Facades\GraphQL;
use Statamic\GraphQL\Queries\EntriesQuery;

class SearchableEntriesQuery extends EntriesQuery
{
    public function args(): array
    {
	   //Extend the parent args adding an optional search and searchIndex argument
        return array_merge(
            parent::args(), [
            'search' => GraphQL::string(),
            'searchIndex' => GraphQL::string(),
            ]
        );
    }

    /**
	 * Overwrite the parent method to add in our search query
	 */
    public function resolve($root, $args)
    {
        $query = Entry::query();

        if ($collection = $args['collection'] ?? null) {
            $query->whereIn('collection', $collection);
        }

        $this->searchQuery($query, $args['search'] ?? null, $args['searchIndex'] ?? null);

        $this->filterQuery($query, $args['filter'] ?? []);

        $this->sortQuery($query, $args['sort'] ?? []);

        return $query->paginate($args['limit'] ?? 1000);
    }

   /**
    * This handles our search methodoloty
	* @param $query - the Entry Query
	* @param $filter - the filter value
	* @param $searchIndex - which index to search - defaults to the default one if not passed / empty / null
	*/
    private function searchQuery($query, $filter, $searchIndex)
    {
        if (empty($filter)) {
            return null;
        }

	  	// get the default index if not set.
        if (empty($searchIndex)) {
            $searchIndex = config('statamic.search.default');
        }

        $builder = Search::index($searchIndex)
            ->ensureExists()
            ->search($filter);

         $results = $builder->get('id')->map(fn($i) => $i->id());

         $this->queryCondition($query, 'id', 'in', $results->toArray());
    }

  /** Direct copy from parent -- due to being private **/
    private function filterQuery($query, $filters)
    {
        if (! isset($filters['status']) && ! isset($filters['published'])) {
            $filters['status'] = 'published';
        }

        foreach ($filters as $field => $definitions) {
            if (! is_array($definitions)) {
                $definitions = [['equals' => $definitions]];
            }

            if (Arr::assoc($definitions)) {
                $definitions = collect($definitions)->map(
                    function ($value, $key) {
                        return [$key => $value];
                    }
                )->values()->all();
            }

            foreach ($definitions as $definition) {
                $condition = array_keys($definition)[0];
                $value = array_values($definition)[0];
                $this->queryCondition($query, $field, $condition, $value);
            }
        }
    }

  /** direct copy from parent due to being private **/
    private function sortQuery($query, $sorts)
    {
        if (empty($sorts)) {
            $sorts = ['id'];
        }

        foreach ($sorts as $sort) {
            $order = 'asc';

            if (Str::contains($sort, ' ')) {
                [$sort, $order] = explode(' ', $sort);
            }

            $query->orderBy($sort, $order);
        }
    }
}

you can now add this query in to the config array or load it in your app service provider.