Open source
Advertisements for Laravel
composer require roundly-consulting/advertisements-for-laravelOverview
A native advertisement engine for Laravel. It ships an Advertisement model with a draft → scheduled → published → expired → archived lifecycle, nestable categories and placements (ad zones), per-locale names, and impression and click tracking with click-through rate — written inline or buffered to the queue. Four sibling Roundly packages supply the rest: image creatives per placement with a text-ad fallback, geo-targeting and per-country reports, per-locale slugs with 301 history, and exact Money prices. MIT-licensed, with no third-party dependencies beyond Laravel and Roundly’s own packages.
What you get
Full ad lifecycle
Draft, schedule, publish, expire and archive with one call each — every transition fires an event and status is recomputed from the dates on every read.
Placements & serving
Model ad zones, attach ads by model, id or slug, and fetch the active or a random ad for a zone in one call.
Impression & click tracking
Denormalized counters and click-through rate, request context on every event row, written inline or buffered to the queue.
Creatives with a text-ad fallback
A responsive image creative sized to each placement, falling back to a restylable text ad so no slot stays empty.
Geo-targeting & reports
Allow or block countries, target a radius around a point, and break impressions and clicks down by country.
Exact Money prices
Minor-unit Money in a decimal(38,0) column — no floats, currency-safe writes and numeric ordering.
Facade, DI or actions
One Advertisements facade, an injectable manager and single-purpose actions — plus a recording fake with an assertion per operation.
Documentation
Installation
Install via Composer, publish and run the migrations (plus media-library’s, always, and sluggable’s for slug history), then optionally the config and view.
Configuration
Every config key with its default and env variable — models, author key type, currency, locale, slug history, tracking, creatives and geo.
Quick start
Create an ad, give it a placement, publish it, then serve, render and track it — the whole flow through the Advertisements facade.
The Advertisements facade
The whole API on one facade — lifecycle verbs, serving queries, rendering, and a for($ad) handle for placements and tracking.
DI and actions
Inject AdvertisementManager for the same API without static calls, or call the single-purpose action behind each facade method.
Creating & updating ads
Build ads from the AdvertisementData DTO or its exact fromMinor() / fromDecimal() factories, straight from requests, and update only the fields you pass.
Lifecycle & status
Publish now or on a schedule, unpublish, expire, archive and soft-delete — each transition fires an event; status is recomputed on every read.
Query scopes
Chain published, active, scheduled, expired, draft, archived, author, placement, category and geo scopes — or start from the facade.
Prices
Prices are exact Money values in a decimal(38,0) minor-unit column — no floats, currency-safe writes, numeric ordering and API resources.
Placements
Model ad zones such as a sidebar or in-feed slot, attach ads by model, id or slug, and fetch the active or a random ad for a zone in one call.
Impression & click tracking
Record impressions and clicks of live ads inline or via the queue, with transactional counters, CTR, request context and per-country reports.
Creatives
Attach an image creative per placement, get a display variant sized to the zone, and render a responsive <img> or the text-ad fallback.
Geo-targeting
Restrict ads to allowed or blocked countries or a radius around a point, and serve each viewer only the ads their location matches.
Translations
Name, description and slug are per-locale JSON maps with active-locale reads, a configurable fallback and no third-party dependency.
Categories
Organise ads into a nestable category tree and filter by one category alone or together with every category nested beneath it.
Slugs & routing
Per-locale ad slugs with database-enforced uniqueness, any-locale route binding, optional 301s from retired slugs and validation rules.
Events
Every create, update and lifecycle transition dispatches an event with the ad; impressions and clicks dispatch one with the tracking row.
Custom models
Point the four model config keys at your own subclasses to add fields and logic while keeping every scope, relation and cast.
Artisan commands
Prune expired ads with model:prune, inspect the setup with about, and add per-locale slug indexes with sluggable:indexes.
Testing
Advertisements::fake() records every lifecycle, placement and tracking call with an assertion for each, plus factories and geolocation fakes.
Exceptions
The package’s exception base, InvalidTargeting, AdvertisementNotActive and AdvertisementNotInPlacement, plus money, sluggable and toolkit errors.
Requirements
PHP 8.4+ with ext-bcmath, Laravel 12 or 13, and six Roundly packages Composer installs for you; gd or imagick for creative variants.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.