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

Pexels Laravel Package

glooby/pexels

A Laravel wrapper for the Pexels API that lets you search and retrieve photos and videos with a simple, fluent syntax. Easily pull curated imagery into your app for galleries, backgrounds, or media libraries using your Pexels API key.

Deep Wiki
Context7

Getting Started

Install and configure

composer require glooby/pexels

Add your key (get one at https://www.pexels.com/api/) to .env:

PEXELS_API_KEY=your-key-here

Publish the config if the package ships one:

php artisan vendor:publish --provider="Glooby\Pexels\PexelsServiceProvider"

If you're on Laravel < 5.5 (or auto-discovery is disabled), register the provider and facade manually in config/app.php. Verify the exact class names in the package's composer.json extra.laravel block or its service provider — the repo is unmaintained, so don't assume the README matches the code.

Where to look first

  1. src/ — the client class and any facade. The package is a thin wrapper over the Pexels v1 REST API, so methods map almost 1:1 to endpoints: search, curated, popular, plus photo($id) / video($id).
  2. The service provider — tells you the binding key, config path, and whether the key is read from config('pexels.api_key') or PEXELS_API_KEY directly.
  3. The README examples — treat them as aspirational; check the actual signatures against src/.

First use case: a search in Tinker

php artisan tinker
>>> Pexels::search('office workspace', 10, 1);

If that returns an array of photo payloads, you're wired up. From there the natural first feature is a "pick a stock image" field in your admin.

Implementation Patterns

Inject the client, don't call the facade everywhere

Facades are fine for prototypes, but bind a small repository so you can swap/mock it:

namespace App\Services;

use Glooby\Pexels\Pexels; // confirm the real class name in src/

class StockPhotoService
{
    public function __construct(private Pexels $pexels) {}

    public function search(string $term, int $perPage = 20, int $page = 1): array
    {
        return $this->pexels->search($term, $perPage, $page);
    }
}

$this->app->bind(Pexels::class, fn () => new Pexels(config('pexels.api_key'))); in a service provider makes this testable.

Cache aggressively — the free tier is 200 req/hour, 20k/month

Search results change slowly. Cache by normalized query + page:

public function search(string $term, int $perPage = 20, int $page = 1): array
{
    $key = 'pexels:search:' . md5("{$term}|{$perPage}|{$page}");

    return Cache::remember($key, now()->addHours(12), function () use ($term, $perPage, $page) {
        return $this->pexels->search($term, $perPage, $page);
    });
}

Build a media picker, not a bulk mirror

Typical day-to-day pattern: an admin page that searches Pexels, shows a grid, and on select downloads the chosen size to your disk and stores the path + attribution on the model.

public function import(string $photoUrl, string $filename): string
{
    $contents = Http::timeout(15)->get($photoUrl)->throw()->body();

    Storage::disk('public')->put("stock/{$filename}", $contents);

    return "stock/{$filename}";
}

When selecting from the payload, prefer the ready-made variants (src->large, src->medium, src->tiny) over original — original is often 5–10 MB and will murder your page weight.

Pagination

Pexels uses page + per_page (max 80, default 15). Return page back to the UI and expose "load more" rather than trying to compute a total — the API returns next_page, not a reliable total count.

Queued ingestion

If you're seeding a demo catalogue, do the calls in a job with ->onQueue('media') and a rate limiter. Don't fan out 50 parallel requests from a synchronous request — you'll trip 429 and the package has no built-in backoff.

Testing

Mock at your own service boundary, not the package, and when you must test against the client, bind a fake:

$this->mock(StockPhotoService::class, fn ($m) => $m->shouldReceive('search')->andReturn([...]));

Use Http::fake() only if you're calling the Pexels endpoints directly; this package goes through its own HTTP layer.

Gotchas and Tips

  • It's effectively abandoned. Last release April 2019. The Pexels v1 API still exists, but nothing here is tested against current PHP/Laravel. Pin it, wrap it, and be ready to replace it with a 30-line Saloon or Guzzle client — that's roughly what the package is anyway.
  • Rate limits are the real constraint. 200/hour and 20k/month by default. Build the cache and a per-user throttle before you ship search to end users.
  • No retry/backoff. 429 and transient 5xx errors bubble up raw. Wrap calls in your service with retry(3, 250) or a Laravel RateLimiter, and handle 404s for deleted photos explicitly.
  • Attribute Pexels and the photographer. Store photographer, photographer_url, and url alongside the file and render a credit line. It's good practice and required by the API terms in many contexts; it also saves you a painful retroactive cleanup.
  • Hotlinking vs. storing. Pexels URLs are signed-ish but stable; hotlinking is fine for prototypes, but for anything production-facing download and serve locally so you control caching, dimensions, and don't depend on Pexels' CDN.
  • Image sizes. Use src->large (~940px) for cards, src->medium (~350px) for thumbs, original only for full-bleed hero downloads. The API gives you all variants; don't generate thumbnails yourself unless you need a specific crop.
  • Config cache caveat. If you read the key via env() inside the package's service provider, php artisan config:cache will break it — the package was written before that was universally flagged. Move the key into config/pexels.php with env('PEXELS_API_KEY') there, and reference config() everywhere else.
  • Array responses, not DTOs. Expect array all the way down; no typed objects, no IDE autocomplete. Define your own DTO/Data class (or a Spatie DataTransferObject) at the boundary so the rest of your app isn't coupled to untyped nested arrays.
  • No video handling nuance. Video payloads include multiple video_files at different resolutions and video_pictures for thumbnails. Pick by width/height rather than index — the ordering isn't guaranteed stable.
  • Extension points are thin. There's no driver/plugin system. Your extension point is the Laravel container: bind an interface (StockPhotoProvider) and either delegate to this package or swap in a direct HTTP implementation later without touching call sites.
  • Verify before you build. The repo isn't linked from the package metadata you have. Before writing anything non-trivial, grep -r "function " vendor/glooby/pexels/src/ to confirm method names, argument order, and whether it returns the raw Pexels envelope or just the photos array — the two differ and the README may be wrong.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
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