NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages

Open source

Advertisements for Laravel

Install
composer require roundly-consulting/advertisements-for-laravel
Requires: PHP ^8.4 · Laravel ^12.0|^13.0

Overview

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 crypto

By 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.