Channels
A channel carries events to every browser subscribed to it. Your server publishes to it (publishing), and browsers may send each other events on it (client events).
Names and kinds
Channel names follow Pusher's rules, which many developers already know: up to 200 characters of A-Z a-z 0-9 _ - = @ , . ;.
| Name | Kind | Who may subscribe |
|---|---|---|
orders | public | anyone with the site's key: put nothing private here |
private-orders-42 | private | whoever your callback lets in |
presence-room-7 | presence | whoever your callback lets in, listed to everyone on it (presence) |
- Each site's channels are its own. Two sites'
ordersnever meet. - They are separate from the Pusher-compatible API's. A Pusher client can't join them, and the same name on both is two different channels.
private-encrypted-…names are not taken.
Owning channels
A plugin owns the channels whose names start with its prefix, and decides who may join them:
add_action( 'plugins_loaded', function () {
wordplus_realtime()->channel( 'private-orders-', function ( $user_id, $channel ) {
$order = (int) substr( $channel, strlen( 'private-orders-' ) );
return $user_id > 0 && my_shop_customer_of( $order ) === $user_id;
} );
} );
$user_idis the signed-in user, or 0 for a visitor.- The answer is
false,true, or an array. For a presence channel the array may carryinfo, which everyone on the channel sees, andidfor a member who isn't a WordPress user (presence). - The longest prefix wins: register
private-orders-vip-besideprivate-orders-and the first decides for its channels. - A private or presence channel nobody owns is refused to everyone.
Subscribing in the browser
Your script depends on the SDK's handle, and the page gets its settings in window.wordplusRealtimeConfig:
wp_enqueue_script( 'my-shop', plugins_url( 'shop.js', __FILE__ ), array( wordplus_realtime()->script() ), '1.0.0', true );
if ( window.wordplusRealtimeConfig ) {
const rt = wordplusRealtimeClient.channels( window.wordplusRealtimeConfig );
const order = rt.subscribe( 'private-orders-42' );
order.on( 'updated', ( data ) => showStatus( data.status ) );
order.on( 'realtime:subscribed', () => console.log( 'listening' ) );
order.on( 'realtime:error', ( e ) => console.warn( e.code ) ); // forbidden, expired, bad_token, auth_failed …
// Later:
order.unsubscribe(); // or rt.unsubscribe( 'private-orders-42' )
}
subscribe()returns the same subscription for the same name, and works before the connection is up.- An event's listener gets
( data, meta ).meta.user_idis set for a client event, naming the user who sent it. once( event, fn )listens once.off( event, fn )stops listening.rt.on( 'error', fn )hears the connection refused, with{ code }:not_included,not_licensed,wrong_origin… (errors).rt.on( 'connected' | 'disconnected' | 'moved', fn )follow the connection.rt.close()leaves every channel. The browser's other tabs keep the connection.
The page's own events
The SDK's own events are named realtime:…. Your server can't publish such a name (bad_request), and the page drops one sent by a browser, so neither can be faked.
| Event | Gets | When |
|---|---|---|
realtime:subscribed | the members, for presence | the subscription is in place, again after each reconnect |
realtime:error | { code } | the subscription was refused |
realtime:member_added | { id, info } | someone joined a presence channel |
realtime:member_removed | { id } | someone left it |
realtime:unopened | { event, label } | an event came sealed with a key the site won't give this user (encryption) |
Sealed
What your server publishes to a private or presence channel, what browsers send each other on it, and its members' info travel sealed with the channel's key, which comes with the channel's token. The page opens them before your listener sees them, in the order they came. You write nothing for it; see encryption.
Tokens
A private or presence channel needs a token, which the site signs and nobody else can make:
- The page asks the site's auth route,
POST /wp-json/wordplus/v1/realtime/authwith{ channels: [...] }. The channels subscribed in the same moment go in one request. - Each channel's owner answers. The route returns one token for the channels allowed, and the reason for each refused (
denied). - The token is kept and renewed ten minutes before it runs out, so a move to another server or a reconnect never asks the site again.
- Tokens live 6 hours by default (the filter
wordplus_realtime_token_ttl, at most 24 hours). - A function in place of the route: pass
authorize: ( channels ) => Promise<{ token, exp, denied }>tochannels()to sign elsewhere.
Moves and reconnects
The connection moves to another realtime server without a drop when one restarts. The page subscribes every channel again on the new connection, with the tokens it holds, before switching over. After a reconnect it does the same. Presence counts each user's connections, so a move never shows anyone leaving.
One connection for the whole browser
Every tab and every plugin of a browser rides one connection to the site's channels. A tab hears only the events of its own subscriptions. An event a tab caused itself, a client event or a publish with except naming that tab, doesn't come back to it.
Limits
See limits: 1,000 channels a connection, events of up to 10 KB, and 1,000 members a presence channel.