offload-project/laravel-notification-preferences

Manage and display user notification preferences in Laravel

Installs: 22

Dependents: 1

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/offload-project/laravel-notification-preferences

v1.0.0 2025-12-16 18:44 UTC

This package is auto-updated.

Last update: 2025-12-16 18:51:07 UTC


README

Latest Version on Packagist GitHub Tests Action Status Total Downloads

Laravel Notification Preferences

A Laravel package for managing user notification preferences with support for multiple channels, notification groups, and automatic channel filtering — perfect for building notification settings UIs.

Features

  • Automatic Filtering — All notifications respect user preferences without code changes
  • Multiple Channels — Support for mail, database, broadcast, SMS, or custom channels
  • Notification Grouping — Organize notifications into logical groups (system, marketing, etc.)
  • Forced Channels — Critical notifications that users cannot disable
  • Bulk Operations — Disable all emails, mute a group, or toggle notification types
  • Structured Output — UI-ready table structure for building preference pages
  • Opt-in/Opt-out Defaults — Configure default behavior at global, group, or notification level
  • Event Dispatching — Listen for preference changes for audit logging or sync
  • Input Validation — Prevents setting preferences for unregistered notifications/channels

Requirements

  • PHP 8.3+
  • Laravel 11+

Installation

composer require offload-project/laravel-notification-preferences

Publish the config and migrations:

php artisan vendor:publish --tag=notification-preferences-config
php artisan vendor:publish --tag=notification-preferences-migrations
php artisan migrate

Quick Start

1. Add the trait to your User model:

use OffloadProject\NotificationPreferences\Concerns\HasNotificationPreferences;

class User extends Authenticatable
{
    use HasNotificationPreferences;
}

2. Register your notifications in config/notification-preferences.php:

return [
    'channels' => [
        'mail' => ['label' => 'Email', 'enabled' => true],
        'database' => ['label' => 'In-App', 'enabled' => true],
    ],

    'groups' => [
        'system' => [
            'label' => 'System Notifications',
            'description' => 'Important system updates',
            'default_preference' => 'opt_in',
            'order' => 1,
        ],
    ],

    'notifications' => [
        \App\Notifications\OrderShipped::class => [
            'group' => 'system',
            'label' => 'Order Shipped',
            'description' => 'When your order ships',
            'order' => 1,
        ],
    ],
];

3. Send notifications normally — preferences are applied automatically:

$user->notify(new OrderShipped($order));

Managing Preferences

// Set a preference
$user->setNotificationPreference(OrderShipped::class, 'mail', false);

// Check a preference
$enabled = $user->getNotificationPreference(OrderShipped::class, 'mail');

// Get all preferences
$preferences = $user->getNotificationPreferences();

// Get structured table for UI
$table = $user->getNotificationPreferencesTable();

Bulk Operations

Convenient methods for "disable all emails" or "mute marketing" features:

// Disable all emails
$user->setChannelPreferenceForAll('mail', false);

// Mute all marketing notifications for email
$user->setGroupChannelPreference('marketing', 'mail', false);

// Disable all channels for a notification type
$user->setAllChannelsForNotification(OrderShipped::class, false);

All bulk methods return the count of updated preferences and automatically skip forced channels.

Explicit Control with Trait

For granular control, use the ChecksNotificationPreferences trait in your notification:

use OffloadProject\NotificationPreferences\Concerns\ChecksNotificationPreferences;

class OrderShipped extends Notification
{
    use ChecksNotificationPreferences;

    public function via($notifiable)
    {
        return $this->allowedChannels($notifiable, ['mail', 'database', 'broadcast']);
    }
}

Forced Channels

Prevent users from disabling critical notifications:

'notifications' => [
    SecurityAlert::class => [
        'group' => 'security',
        'label' => 'Security Alerts',
        'force_channels' => ['mail', 'database'],
    ],
],

Per-Channel Defaults

Set specific channels enabled by default:

'notifications' => [
    OrderShipped::class => [
        'group' => 'system',
        'label' => 'Order Shipped',
        'default_channels' => ['mail', 'database'], // Only these enabled by default
    ],
],

Events

The package dispatches events when preferences change:

use OffloadProject\NotificationPreferences\Events\NotificationPreferenceChanged;

Event::listen(NotificationPreferenceChanged::class, function ($event) {
    // $event->preference - The NotificationPreference model
    // $event->user - The user who changed the preference
    // $event->wasCreated - Whether this was a new preference or update
});

Using the Interface

For dependency injection and testing, use the interface:

use OffloadProject\NotificationPreferences\Contracts\NotificationPreferenceManagerInterface;

class NotificationPreferenceController
{
    public function __construct(
        private NotificationPreferenceManagerInterface $manager
    ) {}

    public function update(Request $request)
    {
        $this->manager->setPreference(
            $request->user(),
            $request->notification_type,
            $request->channel,
            $request->enabled
        );
    }
}

Table Structure Output

The getNotificationPreferencesTable() method returns UI-ready data:

[
    [
        'group' => 'system',
        'label' => 'System Notifications',
        'description' => 'Important system updates',
        'notifications' => [
            [
                'type' => 'App\Notifications\OrderShipped',
                'label' => 'Order Shipped',
                'description' => 'When your order ships',
                'channels' => [
                    'mail' => ['enabled' => true, 'forced' => false],
                    'database' => ['enabled' => true, 'forced' => false],
                ],
            ],
        ],
    ],
]

Inertia.js Integration

Share preferences via middleware:

// app/Http/Middleware/HandleInertiaRequests.php
public function share(Request $request): array
{
    return [
        ...parent::share($request),
        'notificationPreferences' => fn () => $request->user()?->getNotificationPreferencesTable(),
    ];
}

Cache Management

Preferences are cached for 24 hours. Clear when needed:

use OffloadProject\NotificationPreferences\NotificationPreferenceManager;

app(NotificationPreferenceManager::class)->clearUserCache($userId);

Uninstalling

php artisan notification-preferences:uninstall --force
composer remove offload-project/laravel-notification-preferences
rm config/notification-preferences.php

Configuration Reference

Channels

Option Type Description
label string Display name for UI
enabled bool Whether channel is available (default: true)

Groups

Option Type Description
label string Display name for UI
description string Optional description for UI
default_preference string opt_in or opt_out (overrides global)
order int Sort order in UI

Notifications

Option Type Description
group string Group key this notification belongs to
label string Display name for UI
description string Optional description for UI
default_preference string opt_in or opt_out (overrides group)
default_channels array Specific channels enabled by default
force_channels array Channels that cannot be disabled
order int Sort order within group

Testing

./vendor/bin/pest

License

The MIT License (MIT). Please see License File for more information.