Notifications – Notification Class & No-Code Rules
The Notification class raises in-app notifications — the little messages that light up the bell in your generated app's navbar. It creates its own table, self-heals its schema, colour-codes messages by severity, and ships targeting helpers so you can notify one user, a role, a group, everyone, or the record's owner in a single line.
There are two ways to send notifications:
- No-code rules — the Notifications module (project sidebar 🔔). Point-and-click: “When a record is added / edited / deleted, notify these people with this message.” Compiled into event hooks at build time. Recommended for most cases.
- Code — call the
NotificationAPI from any Event (afterAdd / afterEdit / …) or custom page when you need full control.
Contents
- Severity types (colour & icon)
- No-code Notification Rules
- Sending from code —
Add() - Targeting helpers (role / group / everyone / owner)
- Reading, counting & marking read
- The bell — badge, animation & toast
- Enabling the table
- Real-world examples
Severity types
Every notification has a type. It sets the icon and accent colour automatically — you never
pick an icon unless you want to override it.
type | Auto icon | Accent | Use for |
|---|---|---|---|
info (default) | info-circle | Blue | General FYI, mentions, assignments |
success | check-circle | Green | Created / approved / completed |
warning | exclamation-triangle | Amber | Needs attention, nearing a limit |
error | x-circle | Red | Failed / rejected / overdue |
Pass 'icon' => 'bi-cart' to override the auto icon. Any Bootstrap-Icons name works.
No-code Notification Rules
Open the Notifications page in the project sidebar (🔔). Click a one-click template or New rule, then fill in four steps:
| Step | Choose |
|---|---|
| 1. When | A table + trigger — record added, edited, or deleted. |
| 2. Notify | Audience — Everyone, a Role, a Group, specific Users, the record owner, or the actor (who did it). |
| 3. Message | Title + message + type. Insert live field values with {field} chips. |
| 4. Link | Where clicking the notification goes — the record, nothing, or a custom URL. |
Placeholders: put any column of the saved row in curly braces and it is substituted at
send time. For an orders rule:
Title: New order #{id}
Message: {customer_name} placed an order for {total}
Rules are stored per-project and compiled into the table's afterAdd / afterEdit / afterDelete event hooks at build time — no runtime overhead, and they sit alongside any hand-written event code (they never overwrite it). Enabling any rule automatically provisions the notification bell, its API endpoint, and the table in the generated app.
Sending from code — Add()
$id = Notification::Add([
'user_id' => 5, // recipient (null = everyone)
'title' => 'Orders',
'message' => 'New order #1234 has been placed.',
'type' => 'success', // info | success | warning | error
'url' => '/generated/orders/view.php?id=1234',
'icon' => 'bi-cart', // optional — overrides the type icon
'expire' => '2026-12-31 23:59:59', // optional auto-expiry
]);
| Key | Meaning |
|---|---|
user_id | Recipient user id. null / omitted = broadcast to all. (userId also accepted.) |
title | Bold heading shown above the message. |
message | The notification body. Required. |
type | Severity — drives colour + icon. Defaults to info. |
url | Where clicking navigates. (link also accepted.) |
icon | Override the auto icon (Bootstrap-Icons name). |
expire | Auto-hide after this timestamp. |
You don't have to enable anything first — Add() creates the table on demand and
self-heals its columns, so the rich fields (title / icon / url / type) work even if a
leaner feature (e.g. the Calendar reminders) created the table earlier.
Targeting helpers
Skip the “look up the user ids” boilerplate — these do it for you and return how many were sent:
| Helper | Sends to |
|---|---|
AddForUsers(array $ids, array $data) | Each id in the list (deduped). |
AddForRole(string $role, array $data) | Every user whose role matches. |
AddForGroup(int $groupId, array $data) | Every member of the group. |
AddForEveryone(array $data) | All users (one broadcast row). |
AddForRecordOwner(array $row, string $ownerField, array $data) | Whoever created the record (reads the id from $ownerField). |
// Alert every admin, green tick, links to the record
Notification::AddForRole('admin', [
'title' => 'New order',
'message' => 'Order #' . $id . ' was placed',
'type' => 'success',
'url' => '/generated/orders/view.php?id=' . $id,
]);
// Tell the person who created the ticket it was answered
Notification::AddForRecordOwner($data, 'created_by', [
'title' => 'Ticket updated',
'message' => 'Your ticket "' . $data['subject'] . '" was answered',
'type' => 'info',
]);
// Broadcast an announcement to everyone
Notification::AddForEveryone([
'title' => 'Maintenance tonight',
'message' => 'The app will be read-only from 10–11pm.',
'type' => 'warning',
]);
Reading, counting & marking read
// 20 most recent for the current user
$items = Notification::Get(Security::CurrentUserData()['id'], 20);
// Only unread
$unread = Notification::Get($userId, 10, true);
// Unread badge count
$count = Notification::Count($userId);
// Mark one / all read
Notification::MarkRead(12);
Notification::MarkAllRead($userId);
// Housekeeping — drop anything older than 60 days
Notification::DeleteOld(60);
The bell — badge, animation & toast
The generated app's navbar bell is wired automatically whenever notifications are in use. It:
- Shows a red badge with the unread count.
- Wiggles when a new message arrives (respects reduced-motion).
- Pops a toast for the newest unread message, colour-matched to its
type. - Polls every 30s and refreshes instantly when the tab regains focus.
- Colour-codes each row and shows an accent bar on unread items.
Need to refresh the bell after your own AJAX action? Call window.ppNotifyRefresh() on the page.
Enabling the table
Usually you don't — a Notification rule, a Notification::Add() call, or the Calendar's
in-app reminders each provision everything on their own. To turn it on explicitly, use
Misc → Advanced → Notifications (set the table name, default notifications),
or programmatically:
Notification::Enable('notifications'); // create + self-heal the table
Notification::SetTableName('notifications');
Real-world examples
afterAdd — notify admins a customer signed up
Notification::AddForRole('admin', [
'title' => 'New customer',
'message' => "'{$data['name']}' just registered",
'type' => 'success',
'url' => '/generated/customers/view.php?id=' . $id,
]);
afterEdit — warn the owner their order shipped
if (($data['status'] ?? '') === 'shipped') {
Notification::AddForRecordOwner($data, 'created_by', [
'title' => 'Order shipped',
'message' => 'Order #' . $id . ' is on its way',
'type' => 'info',
'url' => '/generated/orders/view.php?id=' . $id,
]);
}
Approaching a limit — a warning to managers
if ((int)$data['stock'] < 5) {
Notification::AddForRole('manager', [
'title' => 'Low stock',
'message' => $data['name'] . ' is down to ' . $data['stock'],
'type' => 'warning',
]);
}