contentpulseio / laravel
Laravel integration for ContentPulse.io — webhook ingestion, local content storage, and rendering.
Requires
- php: ^8.2
- contentpulse/contentpulse-php: ^0.1
- illuminate/console: ^10.0|^11.0|^12.0
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/routing: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- laravel/pint: ^1.0
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
README
Laravel integration for ContentPulse.io. Receives content webhooks, stores a local copy of the published content, and renders it through your own layout. Once content is delivered, your app serves it from its own database with no runtime dependency on ContentPulse.
Requirements
- PHP
^8.2 - Laravel
^10 | ^11 | ^12
Installation
composer require contentpulseio/laravel php artisan contentpulse:install php artisan migrate
The package is published on Packagist,
so the command above works out of the box. contentpulse:install publishes the
config and migration; the service provider is auto-discovered.
If you install from a private fork instead of Packagist, add the repository to
your composer.json before requiring:
"repositories": [ { "type": "vcs", "url": "https://github.com/contentpulseio/laravel" } ]
Set your credentials in .env:
CONTENTPULSE_API_KEY=your-api-key CONTENTPULSE_WEBHOOK_SECRET=your-webhook-secret # optional CONTENTPULSE_BASE_URL=https://contentpulse.io CONTENTPULSE_TIMEOUT=30
How it works
- Register the webhook endpoint (
webhooks/contentpulse) in your ContentPulse dashboard. Incoming requests are verified againstCONTENTPULSE_WEBHOOK_SECRET. - On
content.*events the package fetches the item and upserts it into thecontentpulse_contentstable. - Published content is served from the local store via the bundled routes:
GET /resources— indexGET /resources/{slug}— single item
Set your layout so rendered content slots into your site chrome:
CONTENTPULSE_LAYOUT=layouts.app
Webhooks
The package ships a ready-to-use webhook receiver — no controller or middleware to write in your app.
- Endpoint:
POST /webhooks/contentpulse(override withCONTENTPULSE_WEBHOOK_PATH). - Signature: every request is verified by the
VerifyContentPulseSignaturemiddleware. It computeshash_hmac('sha256', <raw request body>, CONTENTPULSE_WEBHOOK_SECRET)and compares it (constant-time) to theX-Webhook-Signatureheader.- Secret not set →
503 - Missing/invalid signature →
401 - Valid →
200 {"status":"ok"}
- Secret not set →
- Handled events (from the
eventfield orX-Webhook-Eventheader, withdata.content_idas the ContentPulse ULID):content.created,content.updated,content.published→ fetch the item from the API and upsert it intocontentpulse_contentscontent.deleted→ remove the local row
Register the endpoint in your ContentPulse dashboard (Webhooks) pointing at
https://your-app.test/webhooks/contentpulse, subscribe to the content.*
events, and set the signing secret to match CONTENTPULSE_WEBHOOK_SECRET.
Published content then syncs automatically; contentpulse:sync is only needed
for the initial backfill.
Rendering in your own views
Query the local model directly:
use ContentPulse\Laravel\Models\Content; $content = Content::published()->where('slug', $slug)->firstOrFail(); echo $content->rendered_html;
Customizing the design
The bundled Blade views are fully overridable. Publish them into your app to own the markup and styling:
php artisan vendor:publish --tag=contentpulse-views
This copies the views to resources/views/vendor/contentpulse/:
index.blade.php— list pageshow.blade.php— single itempartials/head.blade.php— SEO meta tags / JSON-LDpartials/styles.blade.php— base CSS
Laravel automatically loads the published copies instead of the package defaults, so edit them freely. Delete a file to fall back to the package version. Package updates never overwrite your published views.
Artisan
php artisan contentpulse:sync --locale=en
Backfills the local store from the API (useful for the initial import).
License
MIT