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

Malte Riechmann

New git guidelines: We have switched to Conventional Commits

Giving teams as much autonomy as possible is a good idea, but having some company-wide guidelines can...

Discover full article

Cleo Pelte

One year of coding – recommendations for beginners from a beginner

This month one year ago I started my three year long journey as a web development trainee/apprentice...

Discover full article

Malte Riechmann

Our tech stack in 2022

Preface Reading about our tech stack from one year ago gives me confidence for the future....

Discover full article
View all articles

Right on the intersection of communication, marketing and digital product development »visuellverstehen« offers innovative solutions and concepts for all areas of corporate communication. No matter if you are a mid tier business, an established brand, a cultural institution, an industrial corporation or a successful trading company we advice and accompany you holistically and honestly.