Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Statamic Enhanced Graphql Laravel Package

legrisch/statamic-enhanced-graphql

Statamic Enhanced GraphQL is a Statamic CMS addon that extends the built-in GraphQL API with additional querying capabilities, helping developers expose and retrieve content through more flexible, developer-friendly GraphQL endpoints for headless or decoupled sites.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirements and install

composer require legrisch/statamic-enhanced-graphql

Check composer.json in the package for its Statamic constraint before installing — the last release is July 2023, so verify it against your Statamic 4/5 install rather than assuming compatibility. Then clear everything:

php artisan optimize:clear
php artisan statamic:stache:clear   # blueprint/collection schema is cached here

Wire up the endpoint first, the addon second. The package adds queries to Statamic's existing GraphQL schema, so nothing works until core GraphQL does:

  1. Confirm GraphQL is enabled (see config/statamic/graphql.php in your app) and that POST /graphql returns a schema error rather than a 404.
  2. Open Statamic's GraphiQL playground (or point Altair/GraphiQL at /graphql) and introspect. The package's queries appear as siblings of Statamic's built-in entries, entry, collection, globalSet, etc.

Where to look first

  • The README examples — for a package this small, they are the documentation. Treat the exact argument shapes there as authoritative and confirm each one in GraphiQL before writing frontend code.
  • src/ query classes — the package implements Statamic GraphQL query objects and registers them in its service provider. That service provider and one query class are the best template you'll get for your own custom queries.
  • The generated schema (npm-free introspection dump) — the fastest way to see which arguments each enhanced query actually accepts.

First use case

A headless frontend (Next/Nuxt/Inertia) that needs to fetch entries with filtering or sorting the stock entries query can't express — e.g. "published news posts in the blog collection, filtered on a custom topic field and a date range, sorted, paginated, in one round trip." Build that single query first; if the addon can't express it, you've learned that before you architected around it.

Sanity check the shape before building anything:

query SmokeTest {
  entries(collection: "blog", limit: 1) {
    data { id title slug }
  }
}

Then swap in the enhanced query named in the README and diff the response shape against the built-in one.

Implementation Patterns

Use it as an addition, not a replacement. The stock Statamic queries remain valid. Keep one canonical selection set per content type and reuse it via fragments across both the built-in and enhanced queries:

fragment EntryCard on Entry {
  id
  title
  slug
  url
  date
  ... on Entry_Blog_BlogPost {
    topic
    hero_image { url }
  }
}

query BlogIndex {
  # built-in query — works fine where it fits
  entries(collection: "blog", sort: "date:desc", limit: 12) {
    data { ...EntryCard }
  }

  # enhanced query — where you need the extra filtering
  enhancedEntries(collection: "blog", limit: 12) {
    data { ...EntryCard }
  }
}

The ... on Entry_<Collection>_<Blueprint> inline fragment is the piece people forget: fields are not on the base Entry type, so a flat selection silently fails or is rejected.

Pattern: move filtering server-side. The main win is expressing conditions the built-in filter argument (a JSON-ish string with field:operator:value entries) handles poorly — multi-field ORs, ranges, custom-field sorting. Build a small PHP-side QueryBuilder wrapper that maps your app's filter state to GraphQL variables rather than concatenating filter strings in JavaScript:

// app/GraphQL/EntryQuery.php
final class EntryQuery
{
    public function __construct(
        private string $collection,
        private array $filters = [],
        private string $sort = 'date:desc',
        private int $limit = 12,
        private int $page = 1,
    ) {}

    public function toGraphQL(): array
    {
        return [
            'query' => 'query ($collection: String!, $limit: Int, $page: Int) {
                enhancedEntries(collection: $collection, limit: $limit, page: $page) {
                    data { ...EntryCard }
                    total
                    current_page
                    last_page
                }
            }',
            'variables' => [
                'collection' => $this->collection,
                'limit' => $this->limit,
                'page' => $this->page,
            ],
        ];
    }
}

Push filters into the variables object too — never interpolate user input into the query string. (Variable names and accepted argument types must match the package's schema; introspect before assuming the above compiles.)

Pattern: global sets in one document. If the package adds a multi-globalset query, use it to hydrate your layout — footer, header nav, site settings — in one request instead of one query per set. Pair it with the collection queries in a single persisted query so the frontend has one document to cache.

Pattern: cache the resolved response, not the SQL. GraphQL is POST-only, so Statamic's static caching won't help you. Cache at the Laravel layer keyed on query + variables + site:

$key = 'gql:' . md5($query->toGraphQL()['query'] . serialize($variables) . $site);

return Cache::remember($key, now()->addMinutes(5), fn () => $client->post('/graphql', $payload));

Invalidate on entry save via Entry::saved / Entry::deleted listeners, or keep the TTL short. Statamic's stache makes the underlying reads cheap; the cache is mostly about network round trips.

Custom query extension. Add your own query in a service provider the same way the package does, then copy one of its classes as a template. This is the highest-leverage move with a 2-star package: anything too specific to your domain should live in your app, not in a dependency you can't patch upstream.

Gotchas and Tips

Pin it, and assume you'll fork it. Two stars, zero dependents, last release July 2023. That's not a knock on the code — it's a maintenance risk assessment. Require an exact version ("legrisch/statamic-enhanced-graphql": "1.0.0"), and if a core Statamic upgrade breaks it, plan on vendoring the src/ directory into app/GraphQL/ and adjusting the service provider rather than waiting for a release.

Argument shapes are not the same as the core queries. The enhanced queries exist because they take different (richer) arguments. The most common bug is copy-pasting a core entries selection onto an enhanced query, or assuming filter: "{...}" works identically. Introspect each query individually; don't infer from the built-in docs.

Multi-site defaults silently pick a site. Omitting site yields the default site's entry, and the response looks valid — you just get the wrong content. Always pass site explicitly, derived from the request locale, and add an assertion in your query wrapper that it's set.

Drafts, future-dated entries, and permissions. Verify the addon's queries respect the same visibility rules as core (status, published, current-user permissions). If they don't, you can leak unpublished content through a public endpoint. Test with an unpublished entry before shipping. Guard the /graphql route with your own middleware if the endpoint shouldn't be world-readable.

"Cannot query field" almost always means a stale schema. After changing a blueprint, adding a field, or toggling a collection, run:

php artisan statamic:stache:clear
php artisan optimize:clear

and reload GraphiQL. If the field is genuinely missing, check that the fieldtype is exposed to GraphQL at all — some addon fieldtypes aren't, and no query layer can fix that.

Depth and N+1. The enhanced filtering doesn't change how nested relationship fields resolve. A deeply nested query over a large collection will issue a query per relationship. Keep limit low, always paginate list fields, and profile with the Laravel query log (DB::listen) or Laravel Telescope during development rather than guessing.

Field name collisions. If the addon adds fields to shared types like Entry, a future Statamic release may add the same name and cause a schema build error. Keep a note of the type extensions in your service provider so a schema failure at boot points you at the right place.

Escape hatches to know: Statamic's type extension points (extending the entry/collection/global-set types with fields) and the query registry in the package's service provider. Between those two, anything the addon doesn't do, you can add in your own app without touching vendor code — which is exactly what you want from a package this small.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin