Skip to content

Internal API Reference

Jonathan Bossenger edited this page Nov 10, 2026 · 2 revisions

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.

Overview

 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

Functions for plugins

register_channel( $name, $args = array() ): Built

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.

unregister_channel( $name ): Built

Unregisters a channel. Returns the removed Model\Channel, or false if it wasn't registered.

notify( $channel_name, $args = array() ): Planned

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: Built

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

Models: Built

The models are simple value objects with getters. Each implements JsonSerializable, and dates are serialised as ISO 8601 strings in UTC.

Model\Channel

Property Type Required
name string Yes
title string Yes
context ?string No
description ?string No
icon ?string No

Model\Message

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.

Model\Notification

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

Model\Subscription

Property Type Notes
channel_name ?string Required.
user_id ?int Required.
created_at ?DateTime
snoozed_until ?DateTime Notifications are snoozed until this time.

Factories: Built

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.

Statuses: Built

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: Placeholder

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_Error and stores nothing.
  • It is all or nothing: if any part fails, it returns a WP_Error and nothing from that call is stored.

REST API: mostly placeholder

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.

JavaScript store: Built

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.

Known inconsistencies

  • The channel query parameter on GET /notifications expects integer IDs, but channels are identified by their string names.
  • GET /notifications accepts orderby values of dismissed_at and displayed_at, but the repository only supports created_at.
  • The context query parameter on GET /channels reuses WordPress's reserved REST context parameter (view/edit/embed) for a display-context filter. The 0.3.0 plan renames it to display_context.
  • GET /channels and GET /notifications describe their context field as only adminbar or dashboard, but the JS store accepts any context.

Historical: original proposed API

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.

Clone this wiki locally