Skip to content

REST API

The plugin extends the BuddyPress REST namespace (/wp-json/buddypress/v1/, or the BuddyBoss Platform equivalent when BB Platform is active) with sticky-post endpoints, and augments existing activity responses with sticky metadata.

All custom endpoints live in includes/class-bpsp-rest-api.php. The gamification stats endpoint lives in includes/bpsp-gamification-hooks.php.


The plugin detects which namespace to use at runtime:

Platform Namespace
BuddyPress (default) buddypress/v1
BuddyBoss Platform Result of bp_rest_namespace() . '/' . bp_rest_version()
Older BP with BP_REST_NAMESPACE constant {BP_REST_NAMESPACE}/v1

In practice, BuddyBoss Platform typically resolves to buddyboss/v1. Replace buddypress/v1 with the correct namespace for your install.


Method Path Auth Purpose
GET /buddypress/v1/activity/{id}/sticky Public Sticky status of a single activity
POST /buddypress/v1/activity/{id}/sticky Logged-in + pin permission Pin the activity
DELETE /buddypress/v1/activity/{id}/sticky Logged-in + unpin permission Unpin the activity
GET /buddypress/v1/activity/sticky Public List all sticky activity IDs + objects
GET /bpsp/v1/users/{id}/stats Logged-in (read cap) Per-user pin statistics

POST and DELETE enforce the same per-user / per-admin pin quota as every other pin entry point — REST clients cannot bypass max_user_sticky_posts or max_admin_sticky_posts.


Terminal window
curl -s 'https://example.com/wp-json/buddypress/v1/activity/123/sticky'

Response when pinned:

{
"id": 123,
"is_sticky": true,
"sticky_data": {
"pinned_date": "2025-01-01T12:00:00",
"can_unpin": true
}
}

Response when not pinned:

{
"id": 124,
"is_sticky": false,
"can_pin": true
}

pinned_by (user ID) is added inside sticky_data only when the requester holds the bp_moderate capability.


Terminal window
curl -X POST \
-H 'X-WP-Nonce: <nonce>' \
'https://example.com/wp-json/buddypress/v1/activity/123/sticky'

Success response (200):

{ "id": 123, "is_sticky": true, "message": "Activity pinned successfully." }

The endpoint determines the pin scope from the activity itself: activities with component = 'groups' pin into that group’s scope; everything else pins as activity. Users holding bp_moderate pin as 'administrator' (sitewide admin quota applies); group admins acting inside their own group bypass the per-user quota.

Error responses:

Code HTTP status Cause
bp_rest_authorization_required 401 Not logged in
bp_rest_invalid_id 404 Activity does not exist
bp_rest_already_pinned 400 Activity already pinned
bp_rest_authorization_required 403 Logged in but no pin permission
bpsp_quota_exceeded 429 Per-user or per-admin pin cap reached
bp_rest_pin_failed 500 DB write failed

Terminal window
curl -X DELETE \
-H 'X-WP-Nonce: <nonce>' \
'https://example.com/wp-json/buddypress/v1/activity/123/sticky'

Success response (200):

{ "id": 123, "is_sticky": false, "message": "Activity unpinned successfully." }

The DELETE permission check is more permissive than POST: the user who originally pinned the activity can always remove their own pin, even if their role or group membership has since changed. This prevents “stuck” pins when permission rules tighten between plugin updates.


Terminal window
# Sitewide sticky activities
curl -s 'https://example.com/wp-json/buddypress/v1/activity/sticky'
# Group-specific sticky activities
curl -s 'https://example.com/wp-json/buddypress/v1/activity/sticky?component=groups&group_id=42'

Query parameters:

Parameter Type Default Description
component string activity activity or groups
group_id integer 0 Required when component=groups

Response shape:

{
"activities": [ /* full activity objects */ ],
"total": 3
}

Each activity object passes through BP_REST_Activity_Endpoint::prepare_item_for_response() so the shape matches every other BuddyPress activity response.


Terminal window
curl -s \
-H 'X-WP-Nonce: <nonce>' \
'https://example.com/wp-json/bpsp/v1/users/5/stats'

This endpoint uses its own namespace (bpsp/v1) regardless of whether BuddyBoss Platform is active.

Permission: current_user_can( 'read' ) — any logged-in user.

Response:

{
"user_id": 5,
"total_pins": 14,
"current_pins": 2,
"group_pins": 1
}
Field Description
total_pins Lifetime count of pin actions (from activity log)
current_pins Currently active personal-stream pins
group_pins Currently active group-stream pins

The plugin hooks into the standard /buddypress/v1/activity and /buddypress/v1/activity/{id} responses via bp_rest_activity_prepare_value / bp_rest_activity_prepare_item and adds three optional fields:

Field Present when Type Description
is_sticky Always boolean Whether the activity is currently pinned
sticky_data When is_sticky: true object { pinned_date, can_unpin, pinned_by? }
can_pin When is_sticky: false boolean Whether the requester can pin this activity

pinned_by inside sticky_data is only included for requesters with bp_moderate capability.

These additions are declared in the activity schema via bp_rest_activity_schema, so REST client SDKs that read the schema will discover them automatically.


The plugin’s own frontend uses wp.apiFetch from wp-api-fetch:

// Pin an activity
wp.apiFetch( {
path: '/buddypress/v1/activity/123/sticky',
method: 'POST',
} ).then( ( response ) => {
console.log( response.message ); // "Activity pinned successfully."
} );