How to add pagination to your custom relationship fieldtype in Statamic

Usually when building a custom relationship fieldtype you want to work with data from somewhere else than Statamic.

In this example we extended the relationship fieldtype in order to provide a list of imported tags. Thanks to the Statamic docs, this is pretty easy.

class Tags extends Relationship
{
    protected array | string $tags;

    // Fetch tags from api. 
    // Using a facade makes it nice to read and easier to test.
    public function __construct()
    {
        $this->tags = Api::tags();
    }

    
    // Define columns.
    protected function getColumns()
    {
        return [
            Column::make('title'),
        ];
    }

    // Take search requests into account. 
    // Just comparing strings. Nothing fancy.
    public function getIndexItems($request)
    {
        return collect($this->tags)
          ->filter(function ($tag) use ($request) {
            if (! $request->search) {
                return true;
            }

            return Str::contains($tag['title'], $request->search);
        });
    }
}

In many cases this would already be it. But what if you have a huge amount of tags or items that need to be loaded into Statamics selector stack? I found that loading about 16000 tags at once into the selector stack would either cause unbearable loading times or even make the browser freeze.

This issue could be solved by enabling pagination. But unfortunately the relationship fieldtype does not automatically enable pagination when loading a specific number of items.

In order to do so and show pagination at the bottom of the selector stack you need to return an instance of the \Statamic\Extensions\Pagination\LengthAwarePaginator instead of a collection in the getIndexItems method.

This could be done like this:

public function getIndexItems($request)
    {
        $tags = collect($this->tags)->filter(function ($tag) use ($request) {
            if (! $request->search) {
                return true;
            }

            return Str::contains($tag['title'], $request->search);
        });

        return $this->paginate($tags);
    }


    protected function paginate($tags): LengthAwarePaginator
    {
        $currentPage = Paginator::resolveCurrentPage();
        $perPage = 50;
        $total = $tags->count();
        $result = $total ? $tags->forPage($currentPage, $perPage) : collect();

        return new LengthAwarePaginator($result, $total, $perPage, $currentPage, []);
    }

Curios about the LengthAwarePaginator? Read more in the Laravel Docs

Et voilà - a custom relationship fieldtype with added pagination:

A custom relationship fieldtype with added pagination in Statamic

Julia Lange

Access Current Entry in Custom Validation Rule

Sometimes, when writing a custom validation rule for a Statamic project, I find myself in a position...

Discover full article

Lakkes

Create an entry approval workflow with Statamic Revisions

When managing entries in your Statamic application that gather external data, such as from APIs, you...

Discover full article

Yamen Hadla

Effortless Language Redirection - TYPO3 Extension

Introduction Hello fellow TYPO3 enthusiasts! I had the pleasure of cooperating with my...

Discover full article
View all articles