CMS Framework - v2.2.2
Notifications — Notification Preferences
This guide explains how users can control which notifications they receive and whether to receive email notifications.
What are Notification Preferences?
Notification preferences allow users to:
- Opt out of specific notification types entirely
- Disable email notifications while keeping in-app notifications
- Maintain granular control over what they receive
Preferences are stored in the notification_preferences table with two boolean flags:
- is_enabled — Whether to receive in-app notifications for this type
- email_enabled — Whether to receive email notifications for this type
Default Behavior
If a user has no preference for a notification type, the system defaults to enabled:
// No preference exists for 'post.published'
$user->shouldReceiveNotification('post.published'); // true
$user->shouldReceiveNotificationEmail('post.published'); // true
This ensures users receive notifications by default and must explicitly opt out.
Checking User Preferences
Using User Model Methods
The HasNotifications trait provides convenience methods:
$user = auth()->user();
// Check if user should receive in-app notification
if ($user->shouldReceiveNotification('post.published')) {
// Send notification
}
// Check if user should receive email
if ($user->shouldReceiveNotificationEmail('post.published')) {
// Send email
}
// Get the preference object
$preference = $user->getNotificationPreference('post.published');
if ($preference) {
echo $preference->is_enabled; // true/false
echo $preference->email_enabled; // true/false
}
Retrieving All Preferences
$user = auth()->user();
$preferences = $user->notificationPreferences;
foreach ($preferences as $preference) {
echo $preference->notification_type; // e.g., 'post.published'
echo $preference->is_enabled; // true/false
echo $preference->email_enabled; // true/false
}
Creating and Updating Preferences
Create a Preference
use ArtisanPackUI\CMSFramework\Modules\Notifications\Models\NotificationPreference;
NotificationPreference::create([
'user_id' => $userId,
'notification_type' => 'post.published',
'is_enabled' => false, // Disable in-app notifications
'email_enabled' => false // Disable email notifications
]);
Update a Preference
$preference = $user->getNotificationPreference('post.published');
if ($preference) {
$preference->update([
'is_enabled' => true,
'email_enabled' => false // Keep in-app, disable email
]);
} else {
// Create if doesn't exist
NotificationPreference::create([
'user_id' => $user->id,
'notification_type' => 'post.published',
'is_enabled' => true,
'email_enabled' => false
]);
}
Update or Create
NotificationPreference::updateOrCreate(
[
'user_id' => $userId,
'notification_type' => 'post.published'
],
[
'is_enabled' => true,
'email_enabled' => false
]
);
Automatic Filtering
When sending notifications, the system automatically filters recipients based on preferences:
// Only users who haven't disabled 'newsletter.weekly' will receive it
apSendNotification('newsletter.weekly', [1, 2, 3, 4, 5]);
The filtering happens in NotificationManager:
- Check each user's preference for the notification type
- Exclude users where
is_enabled = false - Send to remaining users
- If
send_emailis true, filter again foremail_enabled = false - Queue emails only for users with email enabled
Building a Preferences UI
Display All Registered Notifications
use function apGetRegisteredNotifications;
$registered = apGetRegisteredNotifications();
$user = auth()->user();
foreach ($registered as $key => $data) {
$preference = $user->getNotificationPreference($key);
$isEnabled = $preference ? $preference->is_enabled : true;
$emailEnabled = $preference ? $preference->email_enabled : true;
// Display checkboxes for $key
}
Blade Template
<form method="POST" action="{{ route('preferences.update') }}">
@csrf
<h2>Notification Preferences</h2>
@php
$registered = apGetRegisteredNotifications();
$user = auth()->user();
@endphp
@foreach($registered as $key => $data)
@php
$preference = $user->getNotificationPreference($key);
$isEnabled = $preference ? $preference->is_enabled : true;
$emailEnabled = $preference ? $preference->email_enabled : true;
@endphp
<div class="preference-row">
<div class="notification-info">
<strong>{{ $data['title'] }}</strong>
<p>{{ $data['content'] }}</p>
<span class="badge {{ $data['type']->colorClass() }}">
{{ $data['type']->label() }}
</span>
</div>
<div class="preference-controls">
<label>
<input
type="checkbox"
name="preferences[{{ $key }}][is_enabled]"
value="1"
{{ $isEnabled ? 'checked' : '' }}
>
In-App Notifications
</label>
<label>
<input
type="checkbox"
name="preferences[{{ $key }}][email_enabled]"
value="1"
{{ $emailEnabled ? 'checked' : '' }}
>
Email Notifications
</label>
</div>
</div>
@endforeach
<button type="submit">Save Preferences</button>
</form>
Controller to Handle Updates
use Illuminate\Http\Request;
use ArtisanPackUI\CMSFramework\Modules\Notifications\Models\NotificationPreference;
class NotificationPreferenceController extends Controller
{
public function update(Request $request)
{
$user = auth()->user();
$preferences = $request->input('preferences', []);
// Get all registered notification keys
$registered = apGetRegisteredNotifications();
foreach ($registered as $key => $data) {
$isEnabled = isset($preferences[$key]['is_enabled']);
$emailEnabled = isset($preferences[$key]['email_enabled']);
NotificationPreference::updateOrCreate(
[
'user_id' => $user->id,
'notification_type' => $key
],
[
'is_enabled' => $isEnabled,
'email_enabled' => $emailEnabled
]
);
}
return redirect()->back()->with('success', 'Preferences updated successfully');
}
}
Livewire Component
use Livewire\Component;
use ArtisanPackUI\CMSFramework\Modules\Notifications\Models\NotificationPreference;
class NotificationPreferences extends Component
{
public $preferences = [];
public function mount()
{
$user = auth()->user();
$registered = apGetRegisteredNotifications();
foreach ($registered as $key => $data) {
$preference = $user->getNotificationPreference($key);
$this->preferences[$key] = [
'title' => $data['title'],
'content' => $data['content'],
'type' => $data['type'],
'is_enabled' => $preference ? $preference->is_enabled : true,
'email_enabled' => $preference ? $preference->email_enabled : true,
];
}
}
public function toggleInApp($key)
{
$this->preferences[$key]['is_enabled'] = !$this->preferences[$key]['is_enabled'];
$this->save($key);
}
public function toggleEmail($key)
{
$this->preferences[$key]['email_enabled'] = !$this->preferences[$key]['email_enabled'];
$this->save($key);
}
protected function save($key)
{
NotificationPreference::updateOrCreate(
[
'user_id' => auth()->id(),
'notification_type' => $key
],
[
'is_enabled' => $this->preferences[$key]['is_enabled'],
'email_enabled' => $this->preferences[$key]['email_enabled']
]
);
$this->dispatch('preference-updated');
}
public function render()
{
return view('livewire.notification-preferences');
}
}
{{-- resources/views/livewire/notification-preferences.blade.php --}}
<div>
<h2>Notification Preferences</h2>
@foreach($preferences as $key => $pref)
<div class="preference-item">
<div>
<strong>{{ $pref['title'] }}</strong>
<p class="text-sm text-gray-600">{{ $pref['content'] }}</p>
</div>
<div class="controls">
<label>
<input
type="checkbox"
wire:change="toggleInApp('{{ $key }}')"
{{ $pref['is_enabled'] ? 'checked' : '' }}
>
In-App
</label>
<label>
<input
type="checkbox"
wire:change="toggleEmail('{{ $key }}')"
{{ $pref['email_enabled'] ? 'checked' : '' }}
>
Email
</label>
</div>
</div>
@endforeach
</div>
API Endpoints
Get User Preferences
Route::get('/api/user/notification-preferences', function () {
$user = auth()->user();
$registered = apGetRegisteredNotifications();
$preferences = [];
foreach ($registered as $key => $data) {
$preference = $user->getNotificationPreference($key);
$preferences[$key] = [
'title' => $data['title'],
'content' => $data['content'],
'type' => $data['type']->value,
'is_enabled' => $preference ? $preference->is_enabled : true,
'email_enabled' => $preference ? $preference->email_enabled : true,
];
}
return response()->json($preferences);
});
Update Preference
Route::post('/api/user/notification-preferences/{key}', function (Request $request, string $key) {
$request->validate([
'is_enabled' => 'required|boolean',
'email_enabled' => 'required|boolean',
]);
NotificationPreference::updateOrCreate(
[
'user_id' => auth()->id(),
'notification_type' => $key
],
[
'is_enabled' => $request->boolean('is_enabled'),
'email_enabled' => $request->boolean('email_enabled')
]
);
return response()->json(['success' => true]);
});
Practical Examples
Opt-Out of All Emails
Allow users to disable all email notifications at once:
public function disableAllEmails()
{
$user = auth()->user();
$registered = apGetRegisteredNotifications();
foreach (array_keys($registered) as $key) {
NotificationPreference::updateOrCreate(
[
'user_id' => $user->id,
'notification_type' => $key
],
[
'is_enabled' => true, // Keep in-app
'email_enabled' => false // Disable email
]
);
}
}
Reset to Defaults
public function resetToDefaults()
{
auth()->user()->notificationPreferences()->delete();
}
Preference Groups
Group related notifications for easier management:
$groups = [
'Content Updates' => ['post.published', 'post.comment', 'post.liked'],
'Account' => ['user.password_changed', 'user.email_verified'],
'System' => ['system.maintenance', 'system.update'],
];
foreach ($groups as $groupName => $keys) {
// Display group with toggle all functionality
}
Best Practices
Provide Sensible Defaults
Register notification types with appropriate default email settings:
// High priority - email by default
apRegisterNotification(
key: 'payment.failed',
title: 'Payment Failed',
content: '...',
sendEmail: true
);
// Low priority - in-app only by default
apRegisterNotification(
key: 'post.liked',
title: 'Post Liked',
content: '...',
sendEmail: false
);
Respect User Choices
Always check preferences before sending:
if (!$user->shouldReceiveNotification('post.comment')) {
// User opted out, don't send
return;
}
apSendNotification('post.comment', [$user->id]);
The helper functions handle this automatically, but custom implementations should check.
Offer Granular Control
Allow users to configure both in-app and email separately:
// User can choose:
// - In-app: Yes, Email: Yes (both)
// - In-app: Yes, Email: No (in-app only)
// - In-app: No, Email: No (fully disabled)
Document Notification Purposes
In your preferences UI, clearly explain what each notification type does:
<div class="notification-description">
<strong>Post Published</strong>
<p>Notifies you when a new post is published in categories you follow.</p>
</div>
Warn Before Disabling Critical Notifications
@if($key === 'security.alert')
<div class="warning">
⚠️ This is a security notification. We recommend keeping it enabled.
</div>
@endif
Next Steps
- Learn about Hooks and Events to extend preference functionality
- Review Database and Migrations for schema details
- Use the API Reference for complete method documentation
- Explore Sending Notifications to understand how preferences affect delivery