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

Plug Php Laravel Package

croct/plug-php

Croct PHP SDK brings dynamic, personalized content natively into your applications. Install via Composer and connect your Laravel or PHP app to Croct's headless CMS for content management, A/B testing, and personalization without complex integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the SDK directly or via the Laravel bridge:

# Framework-agnostic
composer require croct/plug-php

# Laravel (recommended for Laravel apps — adds config, facade, middleware)
composer require croct/plug-laravel

For plain PHP, configure once during bootstrap:

use Croct\Plug\Croct;

Croct::configure([
    'appId' => getenv('CROCT_APP_ID'),
    'token' => getenv('CROCT_API_KEY'), // server-side only
]);

For Laravel, publish the config and set env vars instead:

php artisan vendor:publish --tag=croct

then set CRO CT_APP_ID and CROCT_APP_ID / CROCT_API_KEY in .env. The facade Croct is auto-registered.

Where to look first

  1. The Quick start linked from the README (docs.croct.com/reference/sdk/php/integration) — it walks through the app ID, token, and first slot.
  2. config/croct.php (Laravel) — the only place you should be flipping options like defaultTimeout, test, and storage/cache drivers.
  3. The Croct\Plug\Croct class itself — configure(), personalize(), evaluate(), track(), identify() are the whole surface you'll touch day to day.

First use case — personalize a single slot and render a fallback:

$hero = Croct::personalize('home-hero', [
    'timeout' => 300,
    'fallback' => ['title' => 'Welcome', 'cta' => '/signup'],
]);

This one call is the canonical "hello world": app configured, slot defined in the Croct dashboard, fallback in place so a network blip never breaks the page.

Implementation Patterns

Configure in one place, use the facade everywhere. Put Croct::configure() in a singleton/service provider (or rely on plug-laravel's provider) and call the static facade from controllers, Blade components, and API resources. Never configure inside a request handler — it's meant to be idempotent bootstrap.

Slot-based personalization for SSR. The typical workflow is: define a slot in the Croct dashboard → call personalize($slotId, $options) in the controller → pass the returned array into a Blade view → ship a fallback object so the page renders if the API times out. Keep slot IDs in a constant/enum class rather than string literals scattered across templates.

Identify early, personalize later. Resolve the user once in middleware (Croct::identify($userId)) then reuse it:

$user = Croct::identify($user->id)
    ->withAttributes(['plan' => $user->plan, 'returning' => $user->isReturning()]);

$content = Croct::withUser($user)->personalize('dashboard-banner');

identify() gives Croct a stable audience key; withAttributes() lets your audience rules (plan, tenure, region) actually match. Do this in middleware so every downstream personalize()/evaluate() inherits the same user.

Evaluate expressions for flags and branches. For simple conditionals — feature flags, A/B gates — Croct::evaluate('user is returning') or Croct::evaluateExpression($expr) returns a scalar/bool. This avoids full slot round-trips when you just need a yes/no.

Track events alongside personalization. Conversions and CTA clicks should be Croct::track('cta_clicked', ['slot' => 'home-hero']). Fire-and-forget is fine; track() returns a promise you can ignore unless you need to await it. Keep event names snake_case and stable — they're the basis for audience rules.

Cache personalized payloads. In a high-traffic SSR app, wrap personalize() results in a PSR-16 cache keyed by a cacheKey that includes user audience + slot ID. Pass the cache option (and cacheKey) so Croct can skip the API when nothing has changed. This is the single biggest lever for latency in production.

Preview mode for content editors. Set previewToken (from the dashboard) on a staging environment so editors see unpublished variants. Keep it out of production config entirely.

Test mode / mocking. Use 'test' => true in non-production to avoid burning evaluation quota, and inject a fake plug (or wrap Croct behind a small interface) in unit tests so tests don't hit the network.

Gotchas and Tips

  • The token is server-side only. The app ID can live in the browser, but the API token must never be shipped to the frontend. If you're using plug-php from a controller, that's fine; don't proxy it through JS.
  • Timeouts are the silent killer. The default timeout is generous for a request/response cycle; set defaultTimeout globally and a shorter per-call timeout for above-the-fold slots. Always provide a fallback — a personalization miss should degrade, not 500.
  • Attributes must exist before they match. Audience rules are evaluated on the attributes you actually pass. Forgetting withAttributes() (or typoing a key) doesn't error — it just quietly never matches, so an empty {} response looks like a Croct bug. Log the attributes you send in staging.
  • Cache keys need user context. Caching by slot ID alone will serve one user's variant to another. Include the user ID or a stable audience hash in cacheKey. Also be wary of preview mode polluting the production cache.
  • Default storage is per-request. The plug's user storage is in-memory by default; if you need the identified user to survive across requests in plain PHP, wire in a session-backed storage (the Laravel bridge handles this via middleware). Without it, identify() is effectively re-run every request.
  • Preview token ≠ production token. Using a preview token in prod bypasses published-state rules and can show drafts to real users. Gate it on app()->environment('local', 'staging').
  • Logging is your debugging lifeline. The package accepts a PSR-3 logger option. Inject Laravel's logger (or Monolog) and set debug level while integrating — timeouts, auth failures, and schema mismatches all surface there but are otherwise swallowed as fallbacks.
  • Extension points are the options array. logger, clock, storage, cache, previewToken, defaultTimeout, and test are all injected via configure(). If you need to mock time or swap the cache, this is the seam — subclass/inject there rather than wrapping the facade.
  • Tiny ecosystem — pin and read the changelog. With very few dependents and a recent release cadence, the API can shift between minors. Lock a version in composer.json, and treat upgrades as a review item (especially around the personalize() options schema, which has evolved).
  • Empty response ≠ error. A personalize() call can return null/empty when no audience matches; that's not an exception, it's "you haven't defined a variant for this user." Handle it with the same fallback path as a timeout.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums