Riff is built the way a feature plugin is: one track shape everywhere, read through WordPress's own APIs. Everything here is public and keeps working within a major version; anything that has to go is deprecated for a release first.
Hooks
Every filter and action has a page of its own, generated from the docblock above the line it fires on. All hooks, PHP and JavaScript, are searchable in one list.
Filters
| Filter | Description |
|---|---|
| riff_about_sections | Filters the sections of the About panel, Riff's own included: track, the cover, the title and the artist and album, and credits, what the file's tags say about who made it. |
| riff_can_play | Filters whether the current visitor may play a track. |
| riff_enabled | Filters whether Riff's player loads on the current front-end request. |
| riff_extensions | Filters the extensions Riff loads, by name: a host can leave one out, or name another plugin it has placed in Riff's extensions/ folder. |
| riff_protect_storage | Filters whether the storage a file is kept in elsewhere was made private, when it is protected, or public again, when it isn't. A plugin that keeps uploads in object storage or on a CDN answers for its own files: true once the copy there is private (or public again), or a WP_Error to say why it couldn't be, which the Media Library shows. Without an answer, a file only on this server is moved into the protected folder, and one kept elsewhere is not protected, as moving it would leave it public there. Riff can't send a file it doesn't have, so a plugin that protects its files signs their addresses through riff_protected_url too. |
| riff_protected_send | Filters how a protected file is handed over: 'php' sends it from PHP; 'x-sendfile' asks Apache's mod_xsendfile or LiteSpeed to send it; 'x-accel-redirect' asks Nginx, which then needs an internal location for the protected folder (see the readme). |
| riff_protected_url | Filters the address a protected file is sent from instead of WordPress: a signed address on a CDN or in object storage, such as a CloudFront or S3 presigned URL or a Bunny or Cloudflare token, that stops working at $expires. Riff has checked that the visitor may have the file before it asks, and sends them on with a 302 nothing caches. Empty, the default, sends the file as riff_protected_send says. |
| riff_sources | Filters the sources tracks are read from, keyed by id. |
| riff_together_share | Filters whether a listener who hasn't chosen shares what they play with the site's other listeners. A site where listeners shouldn't see each other unless they ask, a class of children say, returns false. |
| riff_track | Filters a track before the player reads it. |
| riff_turntable | Filters whether Now Playing shows the record and the turntable. Off, it shows the cover on its own, and a touch screen on its side shows the cover beside the controls. |
| riff_unlock_url | Filters where a locked track sends the visitor to unlock it: a sign-up, membership or checkout page. |
| riff_video_first | Whether a song that has a video opens as the video. A listener's own choice of the song or the video, and a browser that saves data, come first. |
Actions
| Action | Description |
|---|---|
| riff_before_player | Fires before the player's markup. |
| riff_register | Fires once a request, before the player's controls and views are first read: register them here with riff_register_control() and riff_register_view(), or take one of Riff's own away. |
Functions
The bar's controls and Now Playing's views are registered on the server, as WordPress registers blocks, so the page has every button and every view before any script runs. Register them on the riff_register action; Riff registers its own there too, and any of them can be taken away. In the browser, window.riff.view() and window.riff.control() give each what it does, by its id. How the player works has the whole of it.
add_action( 'riff_register', function () {
riff_register_view( 'credits', array(
'label' => __( 'Credits', 'my-plugin' ),
'icon' => '<svg viewBox="0 0 24 24">…</svg>',
'order' => 32,
) );
} );riff_register_control( string $id, array $args = array() ): bool
Registers a control in the player's bar. Call it on the riff_register action.
Parameters
$idstring- Lowercase letters, digits and dashes.
$argsarray- The control.
labelstringWhat it is called, for a screen reader and a pointer's tooltip.iconstringAn icon of Riff's own by name, or SVG markup.orderintWhere it sits among the others, lowest first. Default 50.wideboolOnly on a wide screen; a phone's bar keeps to the track, Play and what it needs. Default false.rendercallableMarkup of its own in place of a button, for an element that is not one; it is given the id and returns one element.scriptstringThe script module that brings it to life, which Riff enqueues wherever the player is. Register the module yourself.
Return
bool Whether it was registered.
Since 5.8.0plugins/riff/src/functions.phpView on GitHub
riff_unregister_control( string $id ): bool
Takes a control away, Riff's own included.
Parameters
$idstring- The control's id.
Return
bool Whether there was one.
Since 5.8.0plugins/riff/src/functions.phpView on GitHub
riff_register_view( string $id, array $args = array() ): bool
Registers a view the listener opens from its button in the bar: a screen of Now Playing, or a panel beside the page. Call it on the riff_register action.
Parameters
$idstring- Lowercase letters, digits and dashes.
$argsarray- The view.
labelstringIts name: its button's, its chip's and its region's.iconstringAn icon of Riff's own by name, or SVG markup.orderintWhere its button sits among the bar's controls, lowest first. Default 50.placestringscreento take the whole screen above the bar, as Now Playing does;sidefor a panel beside the page. Defaultscreen.stageboolFor a screen that is Now Playing's own stage, the track's art or its record, rather than a region of its own. Default false.wideboolIts button only on a wide screen; on a phone its chip in Now Playing opens it. Default true.rendercallableMarkup for its region as the page is drawn; the script fills it as it opens. Given the id.scriptstringThe script module that brings it to life, which Riff enqueues wherever the player is. Register the module yourself.
Return
bool Whether it was registered.
Since 5.8.0plugins/riff/src/functions.phpView on GitHub
riff_unregister_view( string $id ): bool
Takes a view away, Riff's own included.
Parameters
$idstring- The view's id.
Return
bool Whether there was one.
Since 5.8.0plugins/riff/src/functions.phpView on GitHub
Sources
A source answers three questions: which posts it can read, what tracks a post holds, and how those tracks render as blocks the player takes over. The library asks every source; the first that claims a post reads it.
A plugin adds its own post type or catalogue by implementing Riff\Source and registering it on init; the library, the REST routes and the player then read it like any other.
add_action( 'init', function () {
Riff\Sources::register( new My_Catalogue_Source() );
} );The Riff\Source interface
public function id(): string
A short id, such as "blocks".
Return
string
Since 4.0.0plugins/riff/src/interface-source.phpView on GitHub
public function supports( WP_Post $post ): bool
Whether this source can read the post.
Parameters
$postWP_Post- Post.
Return
bool
Since 4.0.0plugins/riff/src/interface-source.phpView on GitHub
public function tracks( WP_Post $post ): array
The tracks in the post, in order, in the shape Tracks::schema() describes.
Parameters
$postWP_Post- Post.
Return
array[]
Since 4.0.0plugins/riff/src/interface-source.phpView on GitHub
public function html( WP_Post $post ): string
The tracks rendered as figures carrying data-riff-track, which riff.js turns into rows.
Parameters
$postWP_Post- Post.
Return
string
Since 4.0.0plugins/riff/src/interface-source.phpView on GitHub
public function where(): string
A WHERE clause fragment (without a leading AND) matching posts this source can read, or an empty string when the source cannot say from SQL alone.
Return
string
Since 4.0.0plugins/riff/src/interface-source.phpView on GitHub
Riff\Sources::register( Source $source ): void
Registers a source. The core blocks source registers itself at boot; a plugin registers its own on init.
Parameters
$sourceSource- Source.
Since 4.0.0plugins/riff/src/class-sources.phpView on GitHub
Riff\Sources::unregister( string $id ): void
Removes a source.
Parameters
$idstring- Source id.
Since 4.0.0plugins/riff/src/class-sources.phpView on GitHub
The track schema
One shape for a track: the REST field and routes, the block markup and the player script all use it, and WPGraphQL carries all of it. It is Riff\Tracks::schema(), version 1, and a track still matches it after the riff_track filter.
| Property | Type | Description |
|---|---|---|
id | string | The attachment ID, or "url:" and a hash for a file outside the Media Library. |
src | string | |
type | string | One of audio, video. |
title | string | |
artist | string | |
album | string | |
year | integer | The year from the file's tags, or 0. |
disc | integer | Which disc of a set the track is on, from the file's disc number tag (1 for "1/2"), or 0 when the tags do not say. |
duration | number | Seconds, 0 when unknown. |
lang | string | The language of the title and artist, as a lang attribute takes it, from the file's tags; empty when the file does not say. |
format | string | The container, lower case, as WordPress read it from the file: mp3, flac, m4a. Empty when unknown. |
bitrate | integer | Kilobits per second, 0 when unknown. |
lossless | boolean | Whether the encoding is lossless. |
bits | integer | Bits per sample, as WordPress read it from the file; 0 when the format does not say, as MP3 does not. |
rate | integer | Samples per second, 0 when unknown. |
levels | string | The track's loudness over time as digits 0 to 9, one per sample, when something has measured it; the drawn cover puts it in the groove. Empty otherwise. |
art | array | Artwork, smallest first. |
art[]. | string | |
art[]. | string | |
art[]. | string | What the picture shows, for a screen reader: the image's alt text, or the album and artist a drawn cover names. |
captions | array | Text tracks for a video: the WebVTT file its Captions field names, or the tracks its video block carries. |
captions[]. | string | |
captions[]. | string | |
captions[]. | string | |
captions[]. | string | One of captions, subtitles, descriptions. |
video | object | null | |
video. | string | |
video. | string | |
video. | array | |
video. | string | |
video. | string | |
video. | string | |
video. | string | One of captions, subtitles, descriptions. |
post | object | null | |
post. | integer | |
post. | string | |
post. | string | |
locked | boolean | Whether the current visitor may not play the track, as riff_can_play decided. A locked track has no src. |
unlock | string | Where a locked track sends the visitor to unlock it, from riff_unlock_url. Empty otherwise. |
Block Bindings
riff/track (“Riff track”) is a Block Bindings source: a Heading or Paragraph bound to it shows a track's details, and an Image bound to it shows the cover, with no Riff block on the page. The binding's key picks the detail and id names the attachment; with no id, it is the post's first track. Every value is the track as the track schema has it, after riff_track, and a named track shows only where the media route would show it. In the editor the block shows that it is bound; the value is filled on the front end.
<!-- wp:heading {"metadata":{"bindings":{"content":{"source":"riff/track","args":{"key":"title","id":123}}}}} -->
<h2 class="wp-block-heading"></h2>
<!-- /wp:heading -->
<!-- wp:image {"metadata":{"bindings":{"url":{"source":"riff/track","args":{"key":"cover","id":123}}}}} -->
<figure class="wp-block-image"><img src="" alt=""/></figure>
<!-- /wp:image -->| Key | Shows |
|---|---|
title | The track’s title. |
artist | The artist. |
album | The album. |
year | The year, or nothing when the file has none. |
duration | The length as the player shows it, such as 4:32, or nothing when unknown. |
quality | The format and rate as the player’s badge shows them, such as MP3 · 128 kbps or FLAC · 24-bit 96 kHz. |
cover | The address of the largest artwork: the file’s own, else its post’s, else the cover Riff draws. For an Image block’s url. |
Abilities
Through the Abilities API, AI tools and other plugins list the library and keep a listener's likes and playlists. Each ability runs its riff/v1 route as a REST request, so it answers what the route answers and is allowed what the route allows; the ones about likes, history and playlists need a signed-in user. Nothing plays through an ability: playback happens in a browser.
$albums = wp_get_ability( 'riff/albums' )->execute( array( 'search' => 'Compositions' ) );| Ability | What it does | Input | |
|---|---|---|---|
riff/tracks | Lists the tracks the requester can see, searchable by title, artist or album, or those on one album or by one artist, a page at a time. | search: Words to search for.album: Only the tracks on this album, by term ID, in album order.artist: Only the tracks by this artist, by term ID.orderby: By title, or the most recently added first.page: Page of results, from 1.per_page: Tracks per page, up to 100. | Read only |
riff/albums | Lists the albums with a track the requester can see, by name, each with its artist, artwork and track count, searchable by name. | search: Words to search for.page: Page of results, from 1. | Read only |
riff/artists | Lists the artists with a track the requester can see, by name, each with a track count, searchable by name. | search: Words to search for.page: Page of results, from 1. | Read only |
riff/library | Lists the posts with music the requester can see, newest first, each with its title, artwork, track count and length, a page at a time. | page: Page of results, from 1. | Read only |
riff/likes | Lists what the signed-in user has liked: tracks, albums and artists, newest first. | – | Read only |
riff/history | Lists the tracks the signed-in user has played, most recent first. | – | Read only |
riff/playlists | Lists the signed-in user's playlists, each with its tracks. | – | Read only |
riff/like | Adds a track, album or artist to the signed-in user's likes. | kind (required): What to like: a track, an album or an artist.id (required): Its ID: an audio attachment, an album term or an artist term. | Writes |
riff/unlike | Takes a track, album or artist out of the signed-in user's likes. | kind (required): What to like: a track, an album or an artist.id (required): Its ID: an audio attachment, an album term or an artist term. | Writes |
riff/add-to-playlist | Adds tracks, by audio attachment ID, to the end of one of the signed-in user's playlists. | playlist (required): The playlist's ID.tracks (required): Audio attachment IDs, in the order to add them. | Writes |
riff/remove-from-playlist | Takes the track at a place in one of the signed-in user's playlists out, counting from 0. | playlist (required): The playlist's ID.index (required): The track's place in the playlist, from 0. | Writes |
The Listen block
riff/app: Your music library and the player, on this page. Every post with audio or video is listed, and the music keeps playing while you browse. One per page. It supports align, color, typography, spacing, __experimentalBorder, shadow.
<!-- wp:riff/app {"align":"full"} /-->Anywhere blocks are not an option, the [riff] shortcode does the same.
[riff]
[riff], the same as the block.
Return
string
Since 4.0.0plugins/riff/features/listen/class-app.phpView on GitHub