prismic/php-sdk
The prismic/php-sdk is a PHP client for Prismic’s content API, enabling developers to query repositories, fetch documents by type or ID, apply predicates, handle pagination, and integrate headless CMS content into PHP or Laravel applications.
Install the SDK and wire it into Laravel’s container once:
composer require prismic/php-sdk
// config/services.php
'prismic' => [
'endpoint' => env('PRISMIC_ENDPOINT'), // https://your-repo.cdn.prismic.io/api/v2
'token' => env('PRISMIC_TOKEN'), // only for private repositories
],
// app/Providers/AppServiceProvider.php
use Prismic\Api;
public function register(): void
{
$this->app->singleton(Api::class, fn () => Api::get(
config('services.prismic.endpoint'),
config('services.prismic.token') ?: null
));
}
Start by reading these classes in the package: Prismic\Api for entry points (get, query, getByID, getByUID, getSingle), Prismic\Predicates for query filters, and Prismic\Fragment\* for rendering rich text, links, images, and slices. Skip anything bookmark-related — see the deprecation note below.
First use case: fetch a singleton document, such as a homepage, and render its title:
use Prismic\Api;
$homepage = app(Api::class)->getSingle('homepage');
$title = $homepage?->getData()->title?->asText();
In a real Laravel app, don’t call Api directly from controllers. Put it behind a small repository class so query predicates, caching, preview handling, and fragment rendering stay in one place.
Note for 5.4.0: bookmarks were removed from the Prismic API in February 2025 and are now marked deprecated in the SDK. If you are upgrading from 5.3.0, this is the only behavioral surface that changed — see Gotchas. Nothing else in the public query/rendering API moved.
Repository wrapper. Bind a PrismicRepository that owns all predicates and response shaping:
use Prismic\Api;
use Prismic\Predicates;
use Prismic\Response;
class PrismicRepository
{
public function __construct(private Api $api) {}
public function homepage(): ?\Prismic\Document
{
return $this->api->getSingle('homepage');
}
public function posts(int $page = 1): Response
{
return $this->api->query(
Predicates::at('document.type', 'post'),
[
'page' => $page,
'pageSize' => 10,
'orderings' => '[my.post.date desc]',
]
);
}
}
Cache at the repository boundary. Prismic’s CDN helps, but Laravel cache gives you control over invalidation and preview bypassing:
public function posts(int $page = 1): Response
{
return Cache::remember(
"prismic:posts:page:{$page}",
now()->addMinutes(10),
fn () => $this->api->query(
Predicates::at('document.type', 'post'),
['page' => $page, 'pageSize' => 10, 'orderings' => '[my.post.date desc]']
)
);
}
Blade integration. Convert fragments at the edge of your application instead of passing SDK objects deep into views:
@foreach ($response->getResults() as $post)
<h2>{{ $post->getData()->title?->asText() }}</h2>
{!! $post->getData()->excerpt?->asHtml() !!}
@endforeach
For slices, loop over $document->getData()->body->getSlices() and render a partial per getSliceType(). Keep slice partials in resources/views/prismic/slices/.
Preview workflow. Prismic previews pass a ref query parameter. Read it from the request, pass it to queries, and bypass cache:
$ref = request('ref');
$options = $ref ? ['ref' => $ref] : [];
if ($ref) {
return $this->api->query($predicates, $options);
}
return Cache::remember($key, $ttl, fn () => $this->api->query($predicates, $options));
Webhook-driven invalidation. Add a CSRF-exempt route for Prismic webhooks and clear relevant cache keys or tags when documents are published:
Route::post('/webhooks/prismic', PrismicWebhookController::class)
->withoutMiddleware(\App\Http\Middleware\VerifyCsrfToken::class);
Navigation without bookmarks. Prior to the API removal, bookmarks were the idiomatic way to define a menu or "featured" set. Replace them with explicit Predicates::at('document.type', ...) / Predicates::any('document.tags', [...]) queries, or a single navigation singleton document with a content-relationship group. Anything you previously read via a bookmark lookup now needs a real predicate and a cache key.
Testing. Bind a fake PrismicRepository in tests rather than mocking the SDK’s HTTP layer. If you must test the SDK itself, use Guzzle mock handlers or an in-memory fake behind your repository interface.
getBookmarks() / bookmark-name-keyed lookup code is dead weight — delete it, and check composer why if an old service class still references it. Expect the methods to disappear in the next major.composer.lock, and if you are on 5.3.0 the upgrade is safe but buys you nothing beyond the deprecation notice — skip it unless you want the deprecation warnings surfaced.Api as a singleton. Api::get() resolves the repository endpoint and can make an HTTP call. Creating it per request or per query adds avoidable latency.getData()->title may not exist for empty fields. Use nullsafe access (?->asText()) and guard in Blade.asHtml() returns raw HTML. Do not render untrusted rich text without sanitization. Use a purifier or explicitly allow expected tags.my.post.date or an invalid ordering string often returns empty results rather than an exception. Log predicates and response totals when debugging.ref selects a draft version. Keep them separate, include ref in cache keys, and never cache preview responses.NOASSERTION. The 5.4.0 changelog did not clarify licensing. Confirm the actual license before commercial use.How can I help you explore Laravel packages today?