Skip to main content
The Bifrost Music plugin extends the WordPress REST API with custom fields and endpoints for the music content types.

Overview

All custom post types and taxonomies are REST API-enabled through the show_in_rest parameter:
  • Artists: /wp-json/wp/v2/music_artist
  • Albums: /wp-json/wp/v2/music_album
  • Genres: /wp-json/wp/v2/music_genre

Album Parent Field

Since the music_album post type is non-hierarchical but needs to maintain parent-child relationships with artists, a custom parent field is registered with the REST API.

Registration

Registered in inc/Content/Album.php:152
private function restRegister(): void
{
    register_rest_field(Definitions::POST_TYPE_ALBUM, 'parent', [
        'get_callback'    => fn($post) => (int) $post['parent'],
        'update_callback' => fn($value, $post) => wp_update_post([
            'ID'          => $post->ID,
            'post_parent' => (int) $value
        ]),
        'schema' => [
            'description' => __('Parent Artist ID', 'bifrost-music'),
            'type'        => 'integer',
            'context'     => ['view', 'edit']
        ]
    ]);
}

Field Schema

parent
integer
The ID of the parent artist for this album
description
string
default:"Parent Artist ID"
Human-readable description of the field
type
string
default:"integer"
Data type validation (must be an integer)
context
array
default:"['view', 'edit']"
Available in both view and edit contexts

Get Callback

Retrieves the parent artist ID from the post object:
'get_callback' => fn($post) => (int) $post['parent']
Returns: Integer ID of the parent artist, or 0 if no parent is set.

Update Callback

Updates the parent artist relationship:
'update_callback' => fn($value, $post) => wp_update_post([
    'ID'          => $post->ID,
    'post_parent' => (int) $value
])
Parameters:
  • $value (int): The new parent artist ID
  • $post (WP_Post): The album post object
Returns: The result of wp_update_post()

REST API Endpoints

Artists Endpoint

Retrieve a list of all artists.Query Parameters:
context
string
default:"view"
Scope under which the request is made. Options: view, embed, edit
page
integer
default:"1"
Current page of the collection
per_page
integer
default:"10"
Maximum number of items per page
Search artists by title
status
string
default:"publish"
Limit to artists with specific status
Example Request:
curl https://example.com/wp-json/wp/v2/music_artist?per_page=5
Example Response:
[
  {
    "id": 123,
    "date": "2026-03-09T10:00:00",
    "slug": "the-beatles",
    "status": "publish",
    "type": "music_artist",
    "link": "https://example.com/artists/the-beatles",
    "title": {
      "rendered": "The Beatles"
    },
    "content": {
      "rendered": "<p>Artist biography...</p>"
    },
    "featured_media": 456,
    "_links": { ... }
  }
]
Retrieve a specific artist by ID.Path Parameters:
id
integer
required
Unique identifier for the artist
Example Request:
curl https://example.com/wp-json/wp/v2/music_artist/123
Create a new artist.Required Capabilities: create_music_artistsBody Parameters:
title
string
required
The artist name
content
string
The artist biography (HTML content)
status
string
default:"draft"
The artist status. Options: publish, draft, pending
The ID of the featured image (artist photo)
Example Request:
curl -X POST https://example.com/wp-json/wp/v2/music_artist \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Pink Floyd",
    "content": "Progressive rock band...",
    "status": "publish"
  }'

Albums Endpoint

Retrieve a list of all albums.Query Parameters: Same as Artists endpoint, plus:
parent
integer
Filter albums by parent artist ID
music_genre
array
Filter albums by genre term ID(s)
Example Request:
# Get all albums by artist ID 123
curl https://example.com/wp-json/wp/v2/music_album?parent=123

# Get all rock albums
curl https://example.com/wp-json/wp/v2/music_album?music_genre=5
Example Response:
[
  {
    "id": 456,
    "date": "2026-03-09T11:00:00",
    "slug": "abbey-road",
    "status": "publish",
    "type": "music_album",
    "link": "https://example.com/albums/abbey-road",
    "title": {
      "rendered": "Abbey Road"
    },
    "parent": 123,
    "featured_media": 789,
    "music_genre": [5, 12],
    "_links": { ... }
  }
]
Create a new album.Required Capabilities: create_music_albumsBody Parameters: Same as Artists, plus:
parent
integer
The parent artist ID
music_genre
array
Array of genre term IDs to assign
Example Request:
curl -X POST https://example.com/wp-json/wp/v2/music_album \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "The Dark Side of the Moon",
    "parent": 124,
    "music_genre": [5, 12],
    "status": "publish"
  }'
Update an existing album, including its parent artist relationship.Required Capabilities: edit_music_albumExample Request:
# Change the parent artist for an album
curl -X PATCH https://example.com/wp-json/wp/v2/music_album/456 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"parent": 125}'

Genres Endpoint

Retrieve a list of all genres.Query Parameters:
hide_empty
boolean
default:"false"
Whether to hide genres with no assigned albums
per_page
integer
default:"10"
Maximum number of items per page
search
string
Search genres by name
Example Request:
curl https://example.com/wp-json/wp/v2/music_genre
Example Response:
[
  {
    "id": 5,
    "count": 42,
    "description": "",
    "link": "https://example.com/genres/rock",
    "name": "Rock",
    "slug": "rock",
    "taxonomy": "music_genre",
    "_links": { ... }
  }
]

Authentication

All write operations (POST, PUT, PATCH, DELETE) require authentication. WordPress supports several authentication methods:

Application Passwords

Built-in WordPress authentication method (WP 5.6+)

OAuth

OAuth 1.0a or 2.0 via plugins

JWT

JSON Web Tokens via third-party plugins

Cookie

WordPress cookie authentication (same-site only)

CORS Considerations

If accessing the API from a different domain, you may need to enable CORS. Add this to your theme’s functions.php or a custom plugin:
add_action('rest_api_init', function() {
    remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
    add_filter('rest_pre_serve_request', function($value) {
        header('Access-Control-Allow-Origin: https://your-frontend-domain.com');
        header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS');
        header('Access-Control-Allow-Credentials: true');
        return $value;
    });
}, 15);

Error Responses

The API returns standard WordPress REST API error responses:
{
  "code": "rest_forbidden",
  "message": "Sorry, you are not allowed to create music artists.",
  "data": {
    "status": 403
  }
}
Common error codes:
  • rest_forbidden (403): Insufficient permissions
  • rest_invalid_param (400): Invalid parameter value
  • rest_post_invalid_id (404): Post not found
  • rest_cannot_edit (401): Authentication required

Build docs developers (and LLMs) love