Repository navigation
Internal API Reference
This page describes the PHP, REST and JavaScript APIs on the develop branch, as of commit ec95a15. All PHP code is in the WP\Notifications namespace.
Each section is marked with its status:
- Built: works today.
- Placeholder: the interface or route exists, but returns empty results or an error.
- Planned: designed in the 0.3.0 release plan, not yet in the code.
Related pages: Channels explains the channel model, and Database Schema describes the tables.
register_channel() ─────► Channel_Registry (in memory, per request)
│
notify() [planned] ──────────────┤ look up channel
│ ▼
│ Factory\Message ──► Model\Message
▼
Persistence\Notification_Repository::add() [placeholder]
│
▼
notifications_messages + notifications_queue
│
▼
REST /wp-notifications/v1/notifications [placeholder]
│
▼
JS store core/wp-notifications ──► admin bar hub / dashboard area
Registers a notification channel. Call it on init. Returns the Model\Channel, or false if the name is invalid or already registered.
WP\Notifications\register_channel(
'my-plugin/order-shipped',
array(
'title' => __( 'Order Shipped', 'my-plugin' ), // Required.
'description' => __( 'Order shipping events.', 'my-plugin' ),
'icon' => 'cart',
'context' => 'adminbar',
)
);See Channels for the naming rules and the list of core/* channels.
Unregisters a channel. Returns the removed Model\Channel, or false if it wasn't registered.
Sends a notification on a registered channel. It will return the stored message ID, or a WP_Error.
WP\Notifications\notify(
'my-plugin/order-shipped',
array(
'title' => __( 'Order #123 shipped', 'my-plugin' ),
'message' => __( 'The order is on its way.', 'my-plugin' ),
'severity' => 'info',
)
);Model\Channel::emit( $args ) is planned as a shorthand for the same call. See Channels for how recipients will be chosen.
Channel_Registry holds every registered channel for the current request. Get it with Channel_Registry::get_instance().
| Method | Returns |
|---|---|
register( $name, $args = array() ) |
Model\Channel or false. $name can also be a Model\Channel. |
unregister( $name ) |
The removed Model\Channel, or false. |
get_registered( $name ) |
Model\Channel or null. |
get_all_registered() |
Array of Model\Channel, keyed by name. |
is_registered( $name ) |
bool |
The models are simple value objects with getters. Each implements JsonSerializable, and dates are serialised as ISO 8601 strings in UTC.
| Property | Type | Required |
|---|---|---|
name |
string |
Yes |
title |
string |
Yes |
context |
?string |
No |
description |
?string |
No |
icon |
?string |
No |
The content of a notification, stored once in notifications_messages.
| Property | Type | Notes |
|---|---|---|
message |
?string |
Required. Text content, at most 255 bytes. |
title |
?string |
|
id |
?int |
Database ID. |
created_at |
?DateTime |
|
expires_at |
?DateTime |
|
severity |
?string |
alert, info, warning or success (per the REST schema). |
accept_label |
?string |
Label of the accept action. |
accept_link |
?string |
URL of the accept action. |
dismiss_label |
?string |
Label of the dismiss action. |
is_dismissible |
?bool |
Default true. |
icon |
?string |
|
channel_title |
?string |
Copy of the channel title. Planned for removal (#372). |
encode_meta() returns the JSON stored in the meta column. It holds the non-null values of accept_label, accept_link, channel_title, dismiss_label, expires_at, icon, is_dismissible and severity.
One user's copy of a message, stored as a row in notifications_queue.
| Property | Type | Notes |
|---|---|---|
channel_name |
?string |
Required. |
message_id |
?int |
Required. |
user_id |
?int |
Required. |
context |
?string |
Where it is displayed. Default adminbar. |
created_at |
?DateTime |
|
displayed_at |
?DateTime |
When the user first saw it. |
dismissed_at |
?DateTime |
When the user dismissed it. |
expires_at |
?DateTime |
| Property | Type | Notes |
|---|---|---|
channel_name |
?string |
Required. |
user_id |
?int |
Required. |
created_at |
?DateTime |
|
snoozed_until |
?DateTime |
Notifications are snoozed until this time. |
Each model has a factory that builds it from an array, such as a database row or request arguments. MySQL datetime strings in the array are converted to DateTime objects in UTC.
$message = WP\Notifications\Factory\Message::get_instance()->make(
array(
'message' => 'The order is on its way.',
'created_at' => '2026-11-10 09:00:00',
)
);| Factory | Builds |
|---|---|
Factory\Message |
Model\Message. title defaults to '', is_dismissible to true. |
Factory\Notification |
Model\Notification. context defaults to adminbar. |
Factory\Subscription |
Model\Subscription. |
All factories extend Framework\Factory, whose get_instance() returns one shared instance per factory class.
Status_Interface defines a notification's status. It is worked out from the displayed_at and dismissed_at times; there is no status column.
| Constant | Value | Meaning |
|---|---|---|
NEW |
new |
Arrived during the current session. Server-side, treated the same as undisplayed. |
UNDISPLAYED |
undisplayed |
Not displayed and not dismissed. |
DISPLAYED |
displayed |
Displayed, not dismissed. |
DISMISSED |
dismissed |
Dismissed, whether or not it was displayed. |
Persistence\Notification_Repository defines how notifications are stored and read. Every read and write is scoped to a single user, so a message ID only ever reaches the user it was sent to. Results are pairs of array{ notification: Model\Notification, message: Model\Message }.
Persistence\Wpdb_Notification_Repository is the $wpdb implementation. It is not written yet: every method returns an empty result, and add() returns a not_implemented WP_Error. Nothing in the plugin creates an instance yet.
| Method | Returns | Description |
|---|---|---|
find_by_id( int $message_id, int $user_id ) |
?array |
One pair, or null if this user doesn't have it. |
find_by_user( int $user_id, array $args = array() ) |
array |
The user's notifications, filtered (see below). |
count_by_user( int $user_id, array $args = array() ) |
int |
Count for the same filters, ignoring pagination. For X-WP-Total. |
find_by_date_range( int $user_id, DateTimeInterface $start, DateTimeInterface $end, $order = 'desc', $pagination = 10, $offset = 0 ) |
array |
The user's notifications in a date range. |
find_latest( int $user_id, DateInterval $interval, $pagination = 10, $offset = 0 ) |
array |
The user's notifications from the last $interval. Implemented in Abstract_Notification_Repository using find_by_date_range(). |
add( Model\Message $message, string $channel_name, array $user_ids, string $context = 'adminbar' ) |
int|WP_Error |
Store a message and add it to each user's queue. See the rules below. |
dismiss( int $message_id, int $user_id ) |
bool |
Set dismissed_at. |
mark_displayed( int $message_id, int $user_id ) |
bool |
Set displayed_at. |
remove( int $message_id, int $user_id ) |
bool |
Remove the user's copy of the message. |
purge_orphans() |
int |
Delete messages that no user still has. Returns the number removed. |
find_by_user() arguments:
| Argument | Description |
|---|---|
status |
new, undisplayed, displayed or dismissed. Omit for all statuses. |
channel_name |
Only this channel. |
context |
Only this display context. |
after / before
|
Exclusive bounds on created_at, as ISO 8601 in UTC, e.g. 2026-10-17T09:00:00Z. after is used for polling. |
include_expired |
Include expired notifications. Default false. |
order |
Order::ASCENDING (asc) or Order::DESCENDING (desc). Default desc. |
orderby |
Only created_at is supported. |
per_page / offset
|
Default 10 / 0. |
add() rules:
- Duplicate user IDs count as one recipient.
- An empty recipient list, or any user ID that doesn't exist, returns a
WP_Errorand stores nothing. - It is all or nothing: if any part fails, it returns a
WP_Errorand nothing from that call is stored.
All routes are under /wp-notifications/v1 and require a logged-in user, except where noted. Only GET routes exist.
| Route | Status | Returns |
|---|---|---|
GET /channels |
Built | All registered channels: name, title, description, icon, context. Not filtered by permission yet. |
GET /notifications |
Placeholder | Always an empty array. |
GET /subscriptions |
Placeholder | Always an empty array. Its logged-in check is commented out, so logged-out users can call it. |
Notification fields: id, user_id, channel_name, channel_title, context (adminbar or dashboard), status, severity, title, message, icon, accept_label, accept_link, dismiss_label, is_dismissible, created_at, displayed_at, dismissed_at and expires_at.
Notification query parameters: channel, status (default undisplayed), order (default desc), orderby (default created_at), offset.
Subscription fields: channel_name, user_id, created_at, snoozed_until.
The planned routes are listed in the 0.3.0 release plan: write routes for dismissing and marking notifications displayed, and get/update/delete routes for single subscriptions.
The front end registers a @wordpress/data store named core/wp-notifications. It loads notifications from /wp-notifications/v1/notifications/ and keeps them grouped by display context.
| Context | Where it renders |
|---|---|
adminbar |
The notification hub in the admin bar (#wp-admin-bar-wp-notifications-hub). Default. |
dashboard |
#wp-notifications-dashboard |
Any other context renders into an element with ID wp-notifications-{context}, if the page has one.
Actions:
| Action | Description |
|---|---|
hydrate( notices ) |
Add an array of notices, each to its own context (default adminbar). |
addNotice( notice ) |
Add a notice. |
updateNotice( notice ) |
Merge the given fields into the notice with the same id. |
removeNotice( id ) |
Remove a notice by ID. |
clear( context ) |
Remove all notices in a context. |
Selectors:
| Selector | Description |
|---|---|
getNotices( context ) |
The notices in a context. |
findNotice( idOrTerm, args ) |
Find a notice by ID, or search by a field. |
const { addNotice } = wp.data.dispatch( 'core/wp-notifications' );
const notices = wp.data.select( 'core/wp-notifications' ).getNotices( 'adminbar' );Because GET /notifications returns nothing yet, the store is only filled by notices added in JavaScript.
- The
channelquery parameter onGET /notificationsexpects integer IDs, but channels are identified by their string names. -
GET /notificationsacceptsorderbyvalues ofdismissed_atanddisplayed_at, but the repository only supportscreated_at. - The
contextquery parameter onGET /channelsreuses WordPress's reserved RESTcontextparameter (view/edit/embed) for a display-context filter. The 0.3.0 plan renames it todisplay_context. -
GET /channelsandGET /notificationsdescribe theircontextfield as onlyadminbarordashboard, but the JS store accepts any context.
This was the original proposal. It was never built, and it predates channels. The 0.3.0 release plan replaces it with
notify( $channel_name, $args ). It is kept here for reference.
wp_notify( $recipients, $message )
$recipients can be a user ID, a role string, an array of user IDs or role strings, or an instance of an object implementing the WP_Notification_Recipient interface.
$message can be string or an instance of an object implementing the WP_Notification_Message interface.