marcorieser/statamic-instagram
Fetch and display Instagram feeds in Statamic. This addon connects your site to the Instagram API, letting you pull posts, images, and captions into templates and use them in your Antlers views with simple tags.
This release (v2.6.1) is a small patch: the API token is now pulled from the environment rather than living in the package config. That changes your first-run setup slightly, so start here.
Install and publish the config
composer require marcorieser/<package>:^2.6
php artisan vendor:publish --tag=<package>-config
Set the token in .env — this is the headline change.
<PACKAGE>_API_TOKEN=your-token-here
The published config file should now only reference env('<PACKAGE>_API_TOKEN'); if you see a literal token string in config/<package>.php from an earlier version, that file is stale — re-publish or edit it so the value comes from env().
Clear cached config — mandatory, not optional:
php artisan config:clear
Where to look first: the published config file (confirm the env() key name matches what you put in .env), then the package's service provider for the container binding or facade alias. The token is almost certainly resolved once at container-boot time, which is why the config cache matters.
First use case: make one authenticated call and dump the result before wiring anything into your app.
$client = app(<Package>::class);
dump($client->ping()); // or whatever the cheapest read endpoint is
If this returns 401, the problem is environment/config resolution, not your integration code — verify with php artisan tinker that config('<package>.api_token') is non-null.
Migration note for existing installs: if you previously committed the token directly in config/<package>.php, move it to .env, rotate it if it was ever pushed to a shared repo, and add .env to your deployment secret store. Treat the old token as compromised if the config file was tracked in git history.
Resolve from the container, never new it up. Bind the client through the container (constructor injection or app()) so the token/config resolution path is identical everywhere, including queued jobs and artisan commands.
class SyncStats
{
public function __construct(private <Package> $client) {}
public function __invoke(): void
{
$this->client->stats(/* ... */);
}
}
Keep the token out of your own config. Don't copy the value into config/services.php or a custom config key. One env() call, one config file, one source of truth. If you need per-tenant tokens, pass them at runtime rather than reconfiguring the singleton:
$this->client->withToken($tenant->api_token)->stats(/* ... */);
If the package doesn't expose a withToken()-style setter, wrap it in a small factory that builds a fresh instance per tenant rather than mutating the shared binding — mutating a singleton is a classic cross-tenant leak.
Wrap external calls in jobs. API-backed packages belong behind a queue boundary so a slow or rate-limited upstream doesn't block a request. Add $tries, $backoff, and $timeout explicitly, and let the package's exceptions bubble so the job retries rather than silently swallowing failures.
Cache aggressively. These calls are usually for reporting/analytics data that doesn't need to be real-time. Cache the response, key it by the query parameters, and set a TTL that matches how fresh the data actually is.
$stats = Cache::remember("stats:{$site}:{$period}", now()->addMinutes(15), fn () =>
$this->client->stats($site, $period)
);
Test with Laravel's HTTP fake. Since the package sits on top of the HTTP client, you can stub the upstream instead of mocking the package itself — this keeps your tests honest about request shape and headers.
Http::fake(['api.example.com/*' => Http::response(['ok' => true], 200)]);
Deployment integration: set the env var in Forge/Vapor/CI secrets, then run php artisan config:cache as part of the deploy. Order matters — the env var must exist before the config cache is built, or you'll cache null.
config:cache is the #1 source of "my token isn't being picked up." Once cached, .env is never read again. Any env change requires php artisan config:clear && php artisan config:cache. Bake this into your deploy script.env() outside config files returns null when config is cached. If you're tempted to call env('<PACKAGE>_API_TOKEN') directly in a service or controller, don't — it will work locally and fail in production. Always go through config().config/<package>.php may still contain a hardcoded token, and the .env extraction effectively does nothing for you. Diff the vendor config against yours after upgrading..env. A token pasted with a trailing space or wrapped in quotes it doesn't expect produces a 401 that looks like an auth bug. php artisan tinker → strlen(config('<package>.api_token')) is a fast sanity check.queue:restart after rotating the token or changing config, otherwise long-running workers keep using the boot-time value.Authorization header. The package can't do that for you.Illuminate\Http\Client\Factory or exposes a ->client() accessor — that's preferable to forking. Failing that, a service-provider binding override in AppServiceProvider::register() is the supported seam.^2.6 is right for a patch like this; the .env extraction is behaviourally safe but config-shape-visible, so re-read the config diff on every 2.x minor.How can I help you explore Laravel packages today?