Hooks & Filters Reference
Action hooks and filters are spread across four source files:
includes/bpsp-functions.php, includes/bpsp-gamification-hooks.php,
includes/class-bpsp-database.php, and
public/class-buddypress-sticky-post-public.php.
2.3.8 removal note:
bpsp_before_handle_sticky_postswas fired by the AJAX pin handler that was removed in 2.3.8. Do not use it — it will never fire. The REST API (POST /buddypress/v1/activity/{id}/sticky) replaced the AJAX handler; usebpsp_after_pin_postfor post-pin logic.
Filters
Section titled “Filters”bpsp_allow_user_roles
Section titled “bpsp_allow_user_roles”Roles allowed to pin posts globally. Default: array( 'administrator' ).
This is a legacy fallback filter. For new integrations, configure allowed
roles in Permissions → Pin to own profile in the admin panel. The
filter runs last in bpsp_user_can_pin() for back-compat with older code.
add_filter( 'bpsp_allow_user_roles', function ( $roles ) { $roles[] = 'editor'; return $roles;} );bpsp_get_sticky_posts
Section titled “bpsp_get_sticky_posts”Fires after the plugin reads the list of pinned activity IDs and before
it passes them to the activity query. $component is 'activity' or
'groups'; $group_id is set when called in a group context.
Parameters: ( array|string $ids, string $component, int $group_id )
add_filter( 'bpsp_get_sticky_posts', function ( $ids, $component, $group_id ) { // Remove any activities older than 60 days from the pinned list. return array_filter( (array) $ids, function ( $id ) { $activity = bp_activity_get_specific( array( 'activity_ids' => $id ) ); if ( empty( $activity['activities'] ) ) { return false; } return ( time() - strtotime( $activity['activities'][0]->date_recorded ) ) < 60 * DAY_IN_SECONDS; } );}, 10, 3 );bpsp_is_post_pinned
Section titled “bpsp_is_post_pinned”Override whether a specific activity is considered pinned. Return null
to fall through to the default logic (database or options check). Return
true or false to short-circuit.
Parameters: ( bool|null $is_pinned, int $activity_id )
add_filter( 'bpsp_is_post_pinned', function ( $is_pinned, $activity_id ) { // Force a specific activity to always appear as pinned. if ( 42 === $activity_id ) { return true; } return $is_pinned;}, 10, 2 );bpsp_before_add_sticky_post
Section titled “bpsp_before_add_sticky_post”Fires inside bpsp_add_sticky_post() before the pin is written. Return
false to block the pin. Return true (default) to continue. Returning
false skips both the options/user-meta write and the DB-table write —
the database wrapper filter (bpsp-functions-wrapper.php) also calls it.
Parameters: ( bool $continue, string $component, int $post_id, string $user_role, int $group_id )
// Block pinning activities older than 30 days.add_filter( 'bpsp_before_add_sticky_post', function ( $continue, $component, $post_id, $user_role, $group_id ) { $activity = new BP_Activity_Activity( $post_id ); if ( ! empty( $activity->date_recorded ) && ( time() - strtotime( $activity->date_recorded ) ) > 30 * DAY_IN_SECONDS ) { return false; } return $continue; }, 10, 5);bpsp_before_delete_sticky_post
Section titled “bpsp_before_delete_sticky_post”Same shape as bpsp_before_add_sticky_post but for unpins. Return false
to block the unpin (useful for “lock pins for 24 hours after creation”).
Parameters: ( bool $continue, string $component, int $post_id, string $user_role, int $group_id )
alter_bpsp_get_pin_post_label / alter_bpsp_get_unpin_post_label
Section titled “alter_bpsp_get_pin_post_label / alter_bpsp_get_unpin_post_label”Change the pin and unpin button labels. The same text can be set without code from Appearance → Button Labels in the admin panel; use the filter only when you need conditional logic.
Parameters: ( string $label )
add_filter( 'alter_bpsp_get_pin_post_label', fn() => __( 'Feature this post', 'mytd' ) );add_filter( 'alter_bpsp_get_unpin_post_label', fn() => __( 'Unfeature', 'mytd' ) );bpsp_activity_action
Section titled “bpsp_activity_action”The array of action buttons rendered inside the activity entry for the current activity. By default the plugin appends one button (pin or unpin, depending on pin state). Add custom buttons or remove the default one here.
Parameters: ( array $tools, int $activity_id )
Each item in $tools is an array with keys:
icon (FontAwesome class string), title (string), action (string),
class (array of CSS class strings).
bpsp_activity_pinned_tag
Section titled “bpsp_activity_pinned_tag”The HTML string used as the “Pinned” ribbon/badge on a pinned activity.
Returned value is output via wp_kses_post().
Parameters: ( string $html )
add_filter( 'bpsp_activity_pinned_tag', function () { return '<span class="custom-pinned-badge">Featured</span>';} );bpsp_edit_options
Section titled “bpsp_edit_options”Wraps every get_option() call made through bpsp_options(). Filters
any stored plugin option value before the plugin uses it. $option_id
is the raw option name (e.g., 'bpsp_activity_sticky_posts').
Parameters: ( mixed $value, string $option_id )
bpsp_admin_tabs
Section titled “bpsp_admin_tabs”The full sidebar tab registry for the plugin’s admin page. Tab entries
from add-on modules (e.g., Pro) inject themselves here. The shape of
each entry mirrors BPSP_Admin::get_tabs().
Parameters: ( array $tabs )
add_filter( 'bpsp_admin_tabs', function ( $tabs ) { $tabs['my-tab'] = array( 'label' => 'My Tab', 'icon' => 'dashicons-admin-generic', 'group' => 'settings', ); return $tabs;} );Action hooks
Section titled “Action hooks”Pin lifecycle
Section titled “Pin lifecycle”// Fired by bpsp_add_sticky_post() after a successful pin write.// Also fired by the DB-table storage path in bpsp-functions-db.php.do_action( 'bpsp_after_pin_post', $post_id, $component, $type, $group_id );
// Fired by bpsp_delete_sticky_post() after a successful unpin write.do_action( 'bpsp_after_unpin_post', $post_id, $component, $type, $group_id );
// Fired by bpsp_log_sticky_action() after a log row is written.do_action( 'bpsp_sticky_action_logged', $log_entry );
// Fired by the hourly expiration cron after it auto-unpins expired posts.do_action( 'bpsp_posts_expired', $expired_posts );
// Fired inside bpsp_posts_expired for each individual expired post.do_action( 'bpsp_sticky_post_expired', $post_id, $pinned_by, $component, $group_id );Parameter types for pin/unpin lifecycle hooks:
$post_id—intactivity ID$component—string'activity'or'groups'$type—string'user'or'administrator'$group_id—intgroup ID,0when not in a group
Generic + scope-specific pin actions
Section titled “Generic + scope-specific pin actions”These fire from bpsp_after_pin_post via the listener in
includes/bpsp-gamification-hooks.php. Use them for gamification
integrations (GamiPress, myCRED, AutomatorWP, BadgeOS).
// Any pin, any scope.do_action( 'bpsp_user_pinned_activity', $user_id, $post_id, $component, $type, $group_id );
// Sitewide activity stream pins.do_action( 'bpsp_user_pinned_activity_stream', $user_id, $post_id, $type );do_action( 'bpsp_user_pinned_own_activity', $user_id, $post_id ); // personal pindo_action( 'bpsp_admin_pinned_activity', $user_id, $post_id ); // sitewide admin pin
// Group pins.do_action( 'bpsp_user_pinned_group_activity', $user_id, $post_id, $group_id, $type );do_action( 'bpsp_group_admin_pinned_activity', $user_id, $post_id, $group_id ); // pinner is group admindo_action( 'bpsp_group_mod_pinned_activity', $user_id, $post_id, $group_id ); // pinner is group moddo_action( 'bpsp_group_member_pinned_activity',$user_id, $post_id, $group_id ); // pinner is regular memberMilestones & activity-type events
Section titled “Milestones & activity-type events”// First ever pin for this user.do_action( 'bpsp_user_first_pin', $user_id, $post_id, $component );
// Fires on every pin that crosses a milestone (5, 10, 25, 50, 100).do_action( 'bpsp_user_pin_milestone', $user_id, $pin_count, $component );
// Fires only for the specific milestone crossed.do_action( 'bpsp_user_pin_milestone_5', $user_id, $component );do_action( 'bpsp_user_pin_milestone_10', $user_id, $component );do_action( 'bpsp_user_pin_milestone_25', $user_id, $component );do_action( 'bpsp_user_pin_milestone_50', $user_id, $component );do_action( 'bpsp_user_pin_milestone_100', $user_id, $component );
// Fires for every pin; $activity_obj->type is the BP activity type// (e.g., 'activity_update', 'bp_docs_edited').do_action( "bpsp_user_pinned_{$activity_obj->type}", $user_id, $post_id, $activity_obj );Unpin counterparts
Section titled “Unpin counterparts”Each pin action has a matching unpin hook with the same argument shape:
do_action( 'bpsp_user_unpinned_activity', $user_id, $post_id, $component, $type, $group_id );do_action( 'bpsp_user_unpinned_activity_stream', $user_id, $post_id, $type );do_action( 'bpsp_user_unpinned_own_activity', $user_id, $post_id );do_action( 'bpsp_admin_unpinned_activity', $user_id, $post_id );do_action( 'bpsp_user_unpinned_group_activity', $user_id, $post_id, $group_id, $type );Core PHP functions
Section titled “Core PHP functions”These are the public API for add-ons or other plugins to call directly.
// Check if a specific activity is pinned.$is_pinned = bpsp_is_post_pinned( $activity_id );
// Get the array of pinned activity IDs for a context.$ids = bpsp_get_sticky_posts( 'activity' ); // sitewide / user profile$ids = bpsp_get_sticky_posts( 'groups', $group_id ); // specific group
// Pin or unpin an activity.// $user_role: 'administrator' for sitewide admin pins, any other string for personal pins.$ok = bpsp_add_sticky_post( $component, $activity_id, $user_role, $group_id );$ok = bpsp_delete_sticky_post( $component, $activity_id, $user_role, $group_id );
// Authorization helpers.// bpsp_user_can_pin() — preferred, context-free, works in REST and AJAX.// bpsp_user_can_posts() — deprecated 2.3.9; relied on BP front-end globals.bpsp_user_can_pin( $activity ); // BP_Activity_Activity or IDbpsp_user_can_unpin( $activity ); // more permissive — original pinner always passesbpsp_user_can_pin_in_group( $user_id, $group_id ); // honours group_pin_scope setting
// Write an activity log entry (respects 'enable_activity_log' setting).bpsp_log_sticky_action( 'pin', $activity_id, $user_id, $component, $group_id );
// Per-user pin count helpers.$count = bpsp_get_user_pin_count( $user_id, $component, $type, $group_id );$lifetime = bpsp_get_user_lifetime_pins( $user_id );Related
Section titled “Related”- REST API — fires the same hooks on REST writes.
- WP-CLI — fires the same hooks on CLI writes.
- Gamification — wiring myCRED / GamiPress / AutomatorWP.

