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

Require the package with Composer. The service provider and the Advertisements facade alias are auto-discovered. The Roundly packages it builds on — media-library, geolocation, sluggable, money, enums and package-toolkit — install as Composer dependencies, and their service providers are auto-discovered too:

composer require roundly-consulting/advertisements-for-laravel

php artisan vendor:publish --tag="advertisements-migrations"
php artisan migrate

The migrations are publish-only — the package never loads them itself, so php artisan migrate runs exactly the seven files you published, timestamped in dependency order: categories → placements → advertisements → the advertisement_placement pivot → advertisement_events → the targeting and country_code additions.

Sibling migrations

Creatives are stored in media-library-for-laravel’s media table, and its migrations are required even if you never upload one: render() checks the media table for a creative before it falls back to the text ad, so without it rendering any ad throws a QueryException. Slug history (off by default) needs sluggable-for-laravel’s slug_history table:

# Required — render() looks creatives up in media-library-for-laravel's media table
php artisan vendor:publish --tag="media-migrations"

# Only with advertisements.slugs.history on — sluggable-for-laravel's slug_history table
php artisan vendor:publish --tag="sluggable-migrations"

php artisan migrate

The price column comes from money-for-laravel’s $table->money() macro — a decimal(38,0) minor-unit amount plus a currency column sized by money.schema.currency_length — so money’s service provider must be registered when you migrate. Auto-discovery takes care of it.

Before you migrate

  • advertisements.key_type — set it to uuid or ulid when your author models use UUID/ULID keys. It decides the author morph column type and is read at migrate time, so every author model must share it; changing it later needs a migration of your own.
  • Supported locales — the advertisements migration creates one unique slug index per locale sluggable-for-laravel reports at migrate time (sluggable.locales.supported, else app.locale + app.fallback_locale). Set that list first.

Add a locale later and create its slug index with:

php artisan sluggable:indexes "RoundlyConsulting\Advertisements\Models\Advertisement"

Optional publishing

The config file is optional — every key has a default and the common ones are env-backed:

php artisan vendor:publish --tag="advertisements-config"

Publish the text-ad Blade view to restyle the fallback rendered when an ad has no image creative:

php artisan vendor:publish --tag="advertisements-views"
# → resources/views/vendor/advertisements/text-ad.blade.php
TagPublishes
advertisements-migrationsThe seven migrations, timestamped on publish.
advertisements-configconfig/advertisements.php.
advertisements-viewsresources/views/vendor/advertisements/text-ad.blade.php.

Storage and geolocation

Creatives are stored through media-library-for-laravel — configure its media.disk and an image driver (gd or imagick) as that package documents. Geo features resolve viewer IPs through geolocation-for-laravel — configure its provider pipeline (MaxMind, IPinfo, …) there.

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.