Skip to content

Hooks & Filters Reference

This document lists every action hook and filter the plugin exposes for extension. Each entry has been verified against the live code in includes/, public/, and bp-stats.php as of 2.0.1. Fired at line numbers are a navigation aid and move between releases; the file path is the stable part.

2.0.0 note: the entire wp_ajax_* surface is gone. Any filter or action that used to fire from a bp_stats_*_callback AJAX handler is documented here only if it still fires from the REST controller, service, template, or public class that replaced it. The activity-log display filters (bp_stats_get_user_display, bp_stats_topic_badge, etc.) still apply because the row formatter was inlined into Bp_Stats_REST_Activity_Log::format_datatable_row().


These three hooks let a child theme or companion plugin teach BP Stats how to read native to a new theme.

Map an active WordPress template slug to a CSS compat handle. The handle is then registered via wp_register_style() and enqueued when that template is active.

Signature: apply_filters( 'bp_stats_theme_compat_map', array $map ) Args:

  • $map (array<string,string>) - template_slug => handle pairs. Default ships:
    • 'buddyx''bp-stats-theme-buddyx-family'
    • 'buddyx-pro''bp-stats-theme-buddyx-family'

Since: 2.0.0 Fired at: public/class-bp-stats-public.php:167

add_filter( 'bp_stats_theme_compat_map', function ( $map ) {
$map['reign'] = 'bp-stats-theme-reign';
return $map;
} );

The handle bp-stats-theme-reign will be registered with a URL that resolves to public/css/themes/bp-stats-theme-reign.css inside this plugin. To point it at a different file (e.g. ship the stylesheet from a companion plugin), use bp_stats_theme_compat_url.


Replace the URL of the stylesheet that ships for a known compat handle.

Signature: apply_filters( 'bp_stats_theme_compat_url', string $url, string $handle ) Args:

  • $url (string) - Default URL: public/css/themes/{$handle}.css inside this plugin.
  • $handle (string) - The compat handle being registered.

Since: 2.0.0 Fired at: public/class-bp-stats-public.php:189

add_filter( 'bp_stats_theme_compat_url', function ( $url, $handle ) {
if ( 'bp-stats-theme-reign' === $handle ) {
return plugin_dir_url( __FILE__ ) . 'assets/css/my-reign-overrides.css';
}
return $url;
}, 10, 2 );

bp_stats_after_theme_compat_enqueue (action)

Section titled “bp_stats_after_theme_compat_enqueue (action)”

Fires immediately after a theme compat stylesheet has been enqueued. Use it to enqueue companion assets (per-theme JS tweaks, font preloads, accent JSON, etc.).

Signature: do_action( 'bp_stats_after_theme_compat_enqueue', string $active_template, string $handle ) Args:

  • $active_template (string) - Value of get_template() at enqueue time.
  • $handle (string) - The compat handle that was just enqueued.

Since: 2.0.0 Fired at: public/class-bp-stats-public.php:215

add_action( 'bp_stats_after_theme_compat_enqueue', function ( $template, $handle ) {
if ( 'bp-stats-theme-reign' === $handle ) {
wp_enqueue_script(
'my-reign-bp-stats-tweaks',
plugin_dir_url( __FILE__ ) . 'assets/js/reign-tweaks.js',
array( 'jquery' ),
'1.0.0',
true
);
}
}, 10, 2 );

bp_stats_general_default_settings (filter)

Section titled “bp_stats_general_default_settings (filter)”

Modify the default settings shipped by the plugin (read by get_option( 'bp_stats_general_settings', $default )).

Fired at: bp-stats.php:624

add_filter( 'bp_stats_general_default_settings', function ( $defaults ) {
$defaults['show_member_stats'] = 'no';
$defaults['log_retention_days'] = 180;
$defaults['anonymize_ip_addresses'] = 'yes';
return $defaults;
} );

Default array (see bp_stats_general_default_settings() in bp-stats.php):

Key Default Notes
show_member_stats 'yes' Master toggle for the Profile Statistics tab
show_user_roles all WP roles except administrator Roles whose stats can be viewed
show_profile_*_report 'yes' Per-section toggles on the profile page
show_group_stats 'yes' Master toggle for the Group Statistics tab
show_group_roles ['admin','mod','member'] Which group roles can view group stats
show_group_privacy ['public','private','hidden'] Group visibilities that expose stats
show_group_*_report 'yes' Per-section toggles on the group page
log_retention_days 90 Used by bp_stats_cleanup_old_logs cron
anonymize_ip_addresses 'yes' GDPR - last octet → 0 (IPv4), last 80 bits → 0 (IPv6)

Control who can view a target user’s statistics. Called both by the page renderer and by permission_member on REST /profile/* routes.

Fired at: bp-stats.php:531

// Let friends of the displayed member see their stats.
add_filter( 'bp_stats_can_view_user_stats', function ( $can_view, $user_id ) {
if ( function_exists( 'friends_check_friendship' ) && friends_check_friendship( get_current_user_id(), $user_id ) ) {
return true;
}
return $can_view;
}, 10, 2 );

Args:

  • $can_view (bool) - Always false when passed in. The filter only runs after bp_stats_can_view_user_stats() has already returned true for administrators and for a member viewing their own stats, and false when the displayed user’s role is not in show_user_roles. It decides the remaining case: another logged-in member viewing an allowed profile.
  • $user_id (int) - User ID being viewed.

Filter the IP address before storing or returning. Useful for additional anonymization or proxy normalization.

Fired at: bp-stats.php:481

add_filter( 'bp_stats_get_user_ip', function ( $ip ) {
// Drop two octets instead of one
return preg_replace( '/\.\d+\.\d+$/', '.0.0', $ip );
} );

These fire from Bp_Stats_Public when the BP navigation is being set up.

Label for the Statistics tab on member profiles. Default: 'Statistics'. Fired at: public/class-bp-stats-public.php:2709

add_filter( 'bp_stats_statistics_label', fn () => 'My Activity' );

URL slug for the Statistics tab. Default: 'statistics'. Fired at: public/class-bp-stats-public.php:2710

add_filter( 'bp_stats_statistics_slug', fn () => 'my-activity' );

bp_stats_profile_statistics_tab_filter (filter)

Section titled “bp_stats_profile_statistics_tab_filter (filter)”

Position of the Statistics tab on member profiles. Default: 80. Fired at: public/class-bp-stats-public.php:2724

Since 2.0.1 the profile tab is added whenever show_member_stats is yes and the viewer passes bp_stats_can_view_user_stats(), even if every per-chart show_profile_*_report toggle is off: the Impact, Streak and Journey sections still render.

add_filter( 'bp_stats_profile_statistics_tab_filter', fn () => 50 );

Show or hide the Statistics tab on group pages. Fired at: public/class-bp-stats-public.php:2807

add_filter( 'bp_stats_show_group_stats_tab', function ( $show ) {
return is_user_logged_in() ? $show : false;
} );

bp_stats_group_statistics_tab_filter (filter)

Section titled “bp_stats_group_statistics_tab_filter (filter)”

Position of the Statistics tab on group pages. Default: 80. Fired at: public/class-bp-stats-public.php:2822


Which activity types get logged when a BP activity is created. Fired at: public/class-bp-stats-public.php:1328

add_filter( 'bp_stats_activity_types_insert', function ( $types, $args ) {
$types[] = 'new_blog_post';
return $types;
}, 10, 2 );

Default: [ 'activity_update', 'activity_comment', 'activity_status' ]

Mirror of the above for deletion events. Fired at: public/class-bp-stats-public.php:1441

Cap on the size of the top-contributors collection. Default: 10. Fired at: public/class-bp-stats-public.php:3738


bp_stats_user_scope_ids (filter - since 2.0.1)

Section titled “bp_stats_user_scope_ids (filter - since 2.0.1)”

Restrict every admin analytics query to a subset of members, for example when a companion plugin gives a group leader a dashboard for their own members only.

Return Effect
null or [] (default) No restriction, all members counted
Array of user IDs Queries add user_id IN (...) (sender_id for messages, the term relationship object_id for member types); scoped results use their own cache keys
Non-empty array with no valid ID (e.g. [0], ['abc']) Scoped to nobody, charts show zero rather than falling back to all members

Parameters: $scope_ids (int[]|null), $context (string) - one of engagement, engagement_trends, user_activity, top_contributors, user_health_segments, monthly_retention, member_type_chart, xprofile_field_chart, xprofile_multi_field_chart, daily_active, top_contributors_inline.

add_filter( 'bp_stats_user_scope_ids', function ( $scope_ids, $context ) {
if ( current_user_can( 'manage_options' ) ) {
return $scope_ids;
}
return my_plugin_member_ids_for_current_leader();
}, 10, 2 );

Not yet applied to the Overview summary cards, Pulse, the Users table or the Activity Log. Resolved by: bp_stats_get_user_scope_ids() in bp-stats.php


These tune how many items appear in the per-user information drawer (Users tab → row click). All read by the partial includes/admin/partials/bp-stats-user-information.php.

Filter Default Purpose
bp_stats_user_friends_limit 5 Friends list size
bp_stats_user_activity_update_limit 5 Recent activity updates
bp_stats_user_create_group_limit 5 Groups created
bp_stats_user_join_group_limit 5 Groups joined
bp_stats_user_posts_limit 5 Blog posts
add_filter( 'bp_stats_user_activity_update_limit', fn () => 10 );

Override the retention setting at runtime. Default: the log_retention_days setting (90); the optimizer enforces a 7-day minimum before the filter runs. Fired at: BP_Stats_DB_Optimizer::bp_stats_cleanup_old_logs() (includes/class-bp-stats-db-optimizer.php:96) and Bp_Stats_Deactivator (includes/class-bp-stats-deactivator.php:98, default 90)

add_filter( 'bp_stats_days_to_keep_logs', fn () => 180 );

bp_stats_clean_logs_on_deactivate (filter)

Section titled “bp_stats_clean_logs_on_deactivate (filter)”

bp_stats_clean_options_on_deactivate (filter)

Section titled “bp_stats_clean_options_on_deactivate (filter)”

bp_stats_clean_user_meta_on_deactivate (filter)

Section titled “bp_stats_clean_user_meta_on_deactivate (filter)”

Opt in to purging data when the plugin is deactivated. All default to false. Fired at: Bp_Stats_Deactivator

add_filter( 'bp_stats_clean_logs_on_deactivate', '__return_true' );

Customise which queries the hourly warm-cache cron populates. Fired at: Bp_Stats_Cache::get_cache_warming_queries() (includes/class-stats-cache-handler.php:563)


These fire from Bp_Stats_REST_Activity_Log::format_datatable_row() (inlined from the legacy activity-log class in Phase B+).

Filter Args Where
bp_stats_get_datatable_data $row_data (array) Final row payload - last chance to munge before send. class-bp-stats-rest-activity-log.php:359
bp_stats_get_user_display $user_display (string), $log (object) Initial value before the default renderer runs. :371
bp_stats_user_display $user_display (string) Final rendered HTML for the user column. :373, :377, :397
bp_stats_topic_badge $badge_html (string) Final rendered topic badge. :419
bp_stats_topic_style $style (string), $topic (string) Per-topic inline style. :444
bp_stats_topic_colors $topic_colors (array) The base color map used to derive $style. :477
bp_stats_format_ip_address $ip (string) IP before display. :490
bp_stats_format_ip_address_display $ip (string) Final IP string after format_ip_address. :499
bp_stats_format_meta_data $meta (mixed) Decoded meta value. :515
add_filter( 'bp_stats_topic_colors', function ( $colors ) {
$colors['custom_topic'] = '#8B5CF6';
return $colors;
} );
add_filter( 'bp_stats_format_ip_address', function ( $ip ) {
return preg_replace( '/\.\d+\.\d+$/', '.xxx.xxx', $ip );
} );

bp_stats_rest_search_users (filter - since 2.0.0)

Section titled “bp_stats_rest_search_users (filter - since 2.0.0)”

Filter the result set returned by GET /bp-stats/v1/admin/users/search.

Signature: apply_filters( 'bp_stats_rest_search_users', array $results, string $query ) Fired at: includes/rest/class-bp-stats-rest-admin.php:591

add_filter( 'bp_stats_rest_search_users', function ( $results, $query ) {
// Trim out users that fail your own visibility check
return array_values( array_filter( $results, fn ( $u ) => my_user_is_visible( $u['id'] ) ) );
}, 10, 2 );

bp_stats_before_format_activity_log (action)

Section titled “bp_stats_before_format_activity_log (action)”

Fires immediately before an activity log row is formatted. Args: $log (object) Fired at: includes/rest/class-bp-stats-rest-activity-log.php:321

add_action( 'bp_stats_before_format_activity_log', function ( $log ) {
// pre-processing hook
} );

bp_stats_after_format_activity_log (action)

Section titled “bp_stats_after_format_activity_log (action)”

Fires immediately after a row has been formatted. Args: $row_data (array - the final row payload) Fired at: includes/rest/class-bp-stats-rest-activity-log.php:357

Fires at the end of the hourly warm-cache cron pass. Args: $results (array - warmed, skipped and errors counts) Fired at: Bp_Stats_Cache::warm_cache() (includes/class-stats-cache-handler.php:505)

add_action( 'bp_stats_cache_warmed', function ( $results ) {
error_log( 'BP Stats: hourly cache warm complete' );
} );

bp_stats_after_theme_compat_enqueue (action - since 2.0.0)

Section titled “bp_stats_after_theme_compat_enqueue (action - since 2.0.0)”

Documented in Theme Compatibility Hooks above.


The hooks below used to exist as part of the 1.8.0 AJAX surface. They no longer fire because the handlers they lived on are gone. Any filter still listed above is verified against the live code.

  • All bp_stats_*_callback AJAX handlers - replaced by the REST surface. The plugin no longer registers any wp_ajax_* action.
  • bp_stats_ajax nonce action - replaced by the standard X-WP-Nonce (action wp_rest).
  • wbcom_admin_setting_header shortcode + the two wp_ajax_wbcom_* actions - removed with the admin/wbcom/ wrapper.

If you have a 1.8.0 integration that hooked into a removed filter, the most common landing pad is one of:

Old (gone) New
bp_stats_json_search_users filter bp_stats_rest_search_users (since 2.0.0)
Inline wp_ajax_* permission filters The permission_callback chain in Bp_Stats_REST_Controller (override the cap check via user_has_cap)
Activity-log row filters (bp_stats_get_datatable_data etc.) Still apply - the row formatter was inlined into the REST controller