Weave Code
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

Posters Laravel Package

baks-dev/posters

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use

  1. Installation:

    composer require baks-dev/posters
    

    Publish the package configuration and migrations:

    php artisan vendor:publish --provider="BaksDev\Posters\PostersServiceProvider" --tag="config"
    php artisan vendor:publish --provider="BaksDev\Posters\PostersServiceProvider" --tag="migrations"
    php artisan migrate
    
  2. Configure Ad Slots: Define ad slots in config/posters.php:

    'slots' => [
        'header' => [
            'positions' => ['top', 'bottom'],
            'weight' => 70,
        ],
        'sidebar' => [
            'positions' => ['left', 'right'],
            'weight' => 30,
        ],
    ],
    
  3. Create an Ad Campaign: Use Tinker or a seed class to create a campaign:

    php artisan tinker
    
    $campaign = \BaksDev\Posters\Models\AdCampaign::create([
        'name' => 'Summer Sale',
        'impression_limit' => 1000,
        'click_limit' => 200,
    ]);
    $campaign->ads()->create([
        'url' => 'https://example.com/sale',
        'image_url' => 'https://example.com/banner.jpg',
        'alt_text' => 'Summer Sale Banner',
    ]);
    
  4. Render an Ad Slot in Blade: Add the Blade directive to your view (e.g., resources/views/layouts/app.blade.php):

    @adSlot('header')
    
  5. Test Locally: Visit a page with the ad slot to verify the banner renders. Check Laravel logs for tracking events:

    tail -f storage/logs/laravel.log
    

Implementation Patterns

Core Workflows

1. Ad Slot Management

  • Dynamic Placement: Use Blade directives (@adSlot('slot_name')) or a helper method (Posters::render('slot_name')) to insert ads into views.
  • Position-Based Rotation: Configure slot positions in config/posters.php to control ad rotation order (e.g., ['top', 'bottom']).
  • Weighted Distribution: Assign weights to slots/campaigns to influence ad frequency (e.g., header slot with weight: 70 appears 70% of the time).

2. Campaign Creation and Assignment

  • Bulk Campaigns: Use a seed class or Laravel Forge to pre-populate campaigns:
    // database/seeders/AdCampaignSeeder.php
    public function run()
    {
        \BaksDev\Posters\Models\AdCampaign::factory()->count(5)->create()->each(function ($campaign) {
            $campaign->ads()->saveMany(\BaksDev\Posters\Models\Ad::factory()->count(3)->make());
        });
    }
    
  • Slot-Campaign Mapping: Assign campaigns to slots via a pivot table or config:
    // config/posters.php
    'slot_campaigns' => [
        'header' => [1, 2], // Campaign IDs
        'sidebar' => [3],
    ],
    

3. Tracking and Analytics

  • Event Listeners: Extend tracking logic by listening to AdImpression and AdClick events:
    // app/Listeners/LogAdEvents.php
    public function handle(AdEvent $event)
    {
        Log::channel('ad_tracking')->info($event->toArray());
    }
    
    Register the listener in EventServiceProvider:
    protected $listen = [
        \BaksDev\Posters\Events\AdImpression::class => [
            \App\Listeners\LogAdEvents::class,
        ],
    ];
    
  • Custom Metrics: Integrate with third-party analytics (e.g., Google Analytics) by extending the AdService:
    // app/Services/ExtendedAdService.php
    public function logImpression(Ad $ad, Request $request)
    {
        parent::logImpression($ad, $request);
        // Custom logic (e.g., GA4 event)
        Analytics::event('ad_impression', [
            'ad_id' => $ad->id,
            'slot' => $request->route('slot'),
        ]);
    }
    

4. Dynamic Targeting

  • User-Based Rules: Filter ads by user attributes (e.g., role, location) using a custom resolver:
    // app/Providers/PostersServiceProvider.php
    public function boot()
    {
        Posters::resolver(function ($slot, $request) {
            if ($request->user()->role === 'premium') {
                return Posters::slot('premium_header')->getAd();
            }
            return Posters::slot('header')->getAd();
        });
    }
    
  • Content-Based Targeting: Pass contextual data (e.g., article category) to the slot:
    @adSlot('sidebar', ['category' => $article->category])
    

5. API Integration (Optional)

  • Headless Ad Serving: Expose an API endpoint to serve ads dynamically:
    // routes/api.php
    Route::get('/ads/{slot}', [AdController::class, 'serve']);
    
    // app/Http/Controllers/AdController.php
    public function serve($slot, Request $request)
    {
        $ad = Posters::slot($slot)->getAd();
        return response()->json([
            'url' => $ad->url,
            'image' => $ad->image_url,
        ]);
    }
    
  • Third-Party Ad Networks: Fetch ads from external sources (e.g., Google AdSense) and merge with local ads:
    // app/Services/HybridAdService.php
    public function getAd($slot)
    {
        $localAd = Posters::slot($slot)->getAd();
        if ($localAd) return $localAd;
    
        return $this->fetchFromAdSense($slot);
    }
    

Integration Tips

  1. Queue Workers for Tracking: Configure a queue worker to process ad events asynchronously:

    php artisan queue:work --queue=ad_tracking
    

    Ensure the PostersServiceProvider binds the queue connection:

    $this->app->bind(\Illuminate\Contracts\Queue\Queue::class, function ($app) {
        return Queue::connection('ad_tracking');
    });
    
  2. Caching Ad Slots: Cache frequently accessed slots to reduce database load:

    // app/Providers/AppServiceProvider.php
    public function boot()
    {
        Posters::extend(function ($app) {
            $app->singleton(\BaksDev\Posters\Contracts\SlotRepository::class, function ($app) {
                return new CachedSlotRepository(
                    new EloquentSlotRepository,
                    Cache::store('redis')
                );
            });
        });
    }
    
  3. Blade Component Upgrade: Replace Blade directives with modern Laravel components for better maintainability:

    <x-ad-slot name="header" />
    

    Register the component in AppServiceProvider:

    Blade::component('ad-slot', \BaksDev\Posters\View\Components\AdSlot::class);
    
  4. Testing Strategy:

    • Unit Tests: Mock the SlotRepository and AdService to test ad selection logic:
      $repository = Mockery::mock(\BaksDev\Posters\Contracts\SlotRepository::class);
      $repository->shouldReceive('findByName')->andReturn($slot);
      $this->app->instance(\BaksDev\Posters\Contracts\SlotRepository::class, $repository);
      
    • Feature Tests: Test ad rendering in a live environment:
      $response = $this->get('/');
      $response->assertSeeInOrder([
          'Ad Slot: header',
          'https://example.com/banner.jpg',
      ]);
      
  5. Deployment Checklist:

    • Run migrations and seeders:
      php artisan migrate --seed
      
    • Configure queue workers and caching:
      php artisan config:cache
      php artisan queue:work --daemon
      
    • Monitor ad performance post-deployment:
      php artisan posters:stats
      

Gotchas and Tips

Pitfalls

  1. Database Schema Mismatches:
    • The package may assume specific table names (e.g., ad_campaigns, ad_slots). If you’ve customized your schema, override the Eloquent models:
      // app/Models/CustomAdCampaign.php
      class CustomAdCampaign extends \BaksDev\Posters\Models\AdCampaign
      {
          protected $table = 'custom_ad_campaigns';
      }
      
    • Fix: Check `database/migrations
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor