Skip to content

Learn how to integrate BuddyPress Moderation Pro with your theme or plugin.


  • Add moderation support to custom themes
  • Integrate moderation with custom plugins
  • Extend moderation for custom content types
  • Customize the moderation UI
  • Handle moderation events in your code
  • WordPress 6.0+
  • PHP 8.0+
  • BuddyPress 7.0+
  • BuddyPress Moderation Pro 4.0+
  • Basic understanding of WordPress hooks and filters

Before using any moderation functions, verify the plugin is loaded:

if ( function_exists( 'bmpro_user_can_report' ) ) {
// Plugin is active, safe to use functions
}
// Or check for the class
if ( class_exists( 'Buddypress_Moderation_Pro' ) ) {
// Plugin is active
}
add_action( 'my_custom_content_actions', 'add_moderation_button' );
function add_moderation_button( $content_id ) {
// Check if user can report
if ( ! bmpro_user_can_report() ) {
return;
}
$flag_text = bmpro_get_flag_button_text( 'flag' );
printf(
'<button class="bmpro-flag-btn" data-content-id="%d">%s</button>',
esc_attr( $content_id ),
esc_html( $flag_text )
);
}

Register your theme as a supported theme for built-in styling:

add_filter( 'buddypress_moderation_theme_suuport', 'my_theme_moderation_support' );
function my_theme_moderation_support( $themes ) {
$themes[] = 'my-theme-slug';
return $themes;
}

Tip: Supported themes automatically receive optimized CSS and button placement.

Override default button placement in your theme:

// Remove default activity button
remove_action( 'bp_activity_entry_meta', array(
Buddypress_Moderation_Pro_Activity_Moderation::class,
'show_flag_button'
) );
// Add custom placement
add_action( 'my_theme_activity_actions', 'custom_flag_button_placement' );
function custom_flag_button_placement() {
if ( ! bmpro_user_can_report() ) {
return;
}
// Your custom button HTML
do_action( 'bmpro_render_activity_flag_button' );
}

Override modal styles in your theme:

/* Custom modal styling */
.bmpro-modal {
--bmpro-modal-bg: #ffffff;
--bmpro-modal-border-radius: 12px;
--bmpro-primary-color: #0066cc;
}
.bmpro-modal-wrap {
background: var(--bmpro-modal-bg);
border-radius: var(--bmpro-modal-border-radius);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
}
.bmpro-modal-button {
background: var(--bmpro-primary-color);
border-radius: 6px;
padding: 12px 24px;
}

Copy templates to your theme for customization:

your-theme/
├── buddypress-moderation-pro/
│ ├── bmpo-bp-moderations.php
│ ├── blocking.php
│ └── blocked.php
// In your theme's functions.php
add_filter( 'bmpro_template_path', 'my_theme_moderation_templates' );
function my_theme_moderation_templates( $path ) {
$theme_template = get_template_directory() . '/buddypress-moderation-pro/';
if ( file_exists( $theme_template ) ) {
return $theme_template;
}
return $path;
}

Step 1: Register Content Type

add_filter( 'bmpro_content_to_flag', 'register_my_content_type' );
function register_my_content_type( $content_types ) {
$content_types['my_custom_content'] = __( 'My Custom Content', 'my-plugin' );
return $content_types;
}

Step 2: Handle Report Submission

add_action( 'wp_ajax_bmpro_flag_my_custom_content_function', 'handle_my_content_report' );
function handle_my_content_report() {
// Verify nonce
check_ajax_referer( 'bmpro_ajax_nonce', 'nonce' );
$content_id = absint( $_POST['content_id'] );
$reason = sanitize_text_field( $_POST['reason'] );
$details = sanitize_textarea_field( $_POST['details'] );
// Create report post
$post_id = wp_insert_post( array(
'post_type' => 'bmpro_spam',
'post_title' => sprintf( 'Report: My Content #%d', $content_id ),
'post_status' => 'publish',
'post_author' => get_current_user_id(),
) );
if ( $post_id ) {
// Add meta data
update_post_meta( $post_id, 'bmpro_spam_activity_id', $content_id );
update_post_meta( $post_id, 'bmpro_spam_status', 'awaiting_moderation' );
update_post_meta( $post_id, 'bmpro_spam_reported_by', array( get_current_user_id() ) );
// Set taxonomy term
wp_set_object_terms( $post_id, 'my_custom_content', 'bmpro_content_type' );
// Fire action hook
do_action( 'bmpro_my_custom_content_flagged', $content_id, get_current_user_id(), $post_id );
wp_send_json_success( array( 'message' => __( 'Report submitted', 'my-plugin' ) ) );
}
wp_send_json_error( array( 'message' => __( 'Failed to submit report', 'my-plugin' ) ) );
}

Step 3: Add Admin Meta Box

add_action( 'bmpro_create_meta_box_for_content_type', 'my_content_metabox', 10, 1 );
function my_content_metabox( $term_slug ) {
if ( $term_slug !== 'my_custom_content' ) {
return;
}
add_meta_box(
'bmpro_my_content_actions',
__( 'My Content Actions', 'my-plugin' ),
'render_my_content_metabox',
'bmpro_spam',
'side',
'high'
);
}
function render_my_content_metabox( $post ) {
$content_id = get_post_meta( $post->ID, 'bmpro_spam_activity_id', true );
?>
<p>
<strong><?php _e( 'Content ID:', 'my-plugin' ); ?></strong>
<?php echo esc_html( $content_id ); ?>
</p>
<p>
<a href="/bp-family/buddypress-moderation/developer-guide/</?php echo esc_url( get_permalink( $content_id ) ); ?>"
class="button" target="_blank">
<?php _e( 'View Content', 'my-plugin' ); ?>
</a>
</p>
<p>
<button type="button" class="button button-primary"
onclick="handleMyContentAction('approve', <?php echo $post->ID; ?>)">
<?php _e( 'Approve', 'my-plugin' ); ?>
</button>
<button type="button" class="button"
onclick="handleMyContentAction('remove', <?php echo $post->ID; ?>)">
<?php _e( 'Remove Content', 'my-plugin' ); ?>
</button>
</p>
<?php
}
// When member is flagged
add_action( 'bpmp_members_flagged', 'on_member_flagged', 10, 3 );
function on_member_flagged( $member_id, $reporter_id, $post_id ) {
// Log to external service
my_analytics_track( 'member_reported', array(
'member_id' => $member_id,
'reporter_id' => $reporter_id,
'timestamp' => current_time( 'timestamp' ),
) );
// Send Slack notification
my_slack_notify( sprintf(
'Member #%d was reported by #%d. Review: %s',
$member_id,
$reporter_id,
admin_url( 'post.php?post=' . $post_id . '&action=edit' )
) );
}
// When member is suspended
add_action( 'bmpro_member_suspended', 'on_member_suspended', 10, 3 );
function on_member_suspended( $member_id, $duration, $reason ) {
// Revoke API access
delete_user_meta( $member_id, 'api_access_token' );
// Cancel subscriptions
my_subscription_service_suspend( $member_id, $duration );
// Send notification email
$user = get_userdata( $member_id );
wp_mail(
$user->user_email,
__( 'Account Suspended', 'my-plugin' ),
sprintf(
__( 'Your account has been suspended for %d days. Reason: %s', 'my-plugin' ),
$duration,
$reason
)
);
}
// When user blocks another user
add_action( 'bmpro_user_blocked', 'on_user_blocked', 10, 2 );
function on_user_blocked( $blocked_id, $blocker_id ) {
// Remove from friend list
if ( function_exists( 'friends_remove_friend' ) ) {
friends_remove_friend( $blocker_id, $blocked_id );
}
// Remove from group memberships
my_remove_shared_group_memberships( $blocker_id, $blocked_id );
}
// Dynamic threshold based on user reputation
add_filter( 'bmpro_auto_mod_limit_filter', 'reputation_based_threshold', 10, 2 );
function reputation_based_threshold( $limit, $settings ) {
global $bp;
// Get content author
$author_id = $bp->current_activity->user_id ?? 0;
if ( ! $author_id ) {
return $limit;
}
$reputation = (int) get_user_meta( $author_id, 'user_reputation', true );
// Higher reputation = higher threshold
if ( $reputation > 1000 ) {
return 10; // Trusted users
} elseif ( $reputation > 500 ) {
return 7;
} elseif ( $reputation > 100 ) {
return 5;
}
return 3; // New users
}
// Disable auto-moderation during business hours
add_filter( 'bmpro_auto_moderation_enable', 'business_hours_moderation', 10, 2 );
function business_hours_moderation( $enabled, $component ) {
$hour = (int) current_time( 'H' );
// Business hours: 9 AM - 5 PM
if ( $hour >= 9 && $hour <= 17 ) {
return false; // Manual review during business hours
}
return $enabled;
}

add_filter( 'bp_rest_activity_prepare_value', 'add_moderation_to_rest', 10, 3 );
function add_moderation_to_rest( $response, $request, $activity ) {
$data = $response->get_data();
// Add moderation info
$data['moderation'] = array(
'is_flagged' => bmpro_exclude_moderated_content( 'activity', $activity->id ),
'report_count' => bmpro_get_reports_count( $activity->id, 'activity' )['count'],
'can_report' => bmpro_user_can_report(),
'flag_text' => bmpro_get_flag_button_text( 'flag' ),
);
$response->set_data( $data );
return $response;
}
add_action( 'rest_api_init', 'register_moderation_endpoints' );
function register_moderation_endpoints() {
register_rest_route( 'my-plugin/v1', '/report', array(
'methods' => 'POST',
'callback' => 'handle_rest_report',
'permission_callback' => function() {
return is_user_logged_in() && bmpro_user_can_report();
},
'args' => array(
'content_type' => array(
'required' => true,
'type' => 'string',
),
'content_id' => array(
'required' => true,
'type' => 'integer',
),
'reason' => array(
'required' => true,
'type' => 'string',
),
),
) );
}
function handle_rest_report( $request ) {
$content_type = $request->get_param( 'content_type' );
$content_id = $request->get_param( 'content_id' );
$reason = $request->get_param( 'reason' );
// Create report using existing AJAX handler logic
// ...
return new WP_REST_Response( array(
'success' => true,
'message' => __( 'Report submitted', 'my-plugin' ),
), 200 );
}

// Custom report functionality
(function($) {
'use strict';
class CustomReportHandler {
constructor() {
this.ajaxUrl = bmpro_ajax_object.ajax_url;
this.nonce = bmpro_ajax_object.ajax_nonce;
this.init();
}
init() {
$(document).on('click', '.my-custom-report-btn', this.showModal.bind(this));
$(document).on('click', '.my-custom-submit-report', this.submitReport.bind(this));
}
showModal(e) {
e.preventDefault();
const contentId = $(e.currentTarget).data('content-id');
// Show your custom modal
this.modal = $('<div class="my-report-modal">')
.html(this.getModalContent(contentId))
.appendTo('body');
}
getModalContent(contentId) {
return `
<div class="modal-overlay">
<div class="modal-content">
<h3>Report Content</h3>
<form id="my-report-form">
<input type="hidden" name="content_id" value="${contentId}">
<select name="reason" required>
<option value="">Select reason...</option>
<option value="spam">Spam</option>
<option value="inappropriate">Inappropriate</option>
<option value="harassment">Harassment</option>
</select>
<textarea name="details" placeholder="Additional details..."></textarea>
<button type="submit" class="my-custom-submit-report">Submit Report</button>
<button type="button" class="close-modal">Cancel</button>
</form>
</div>
</div>
`;
}
submitReport(e) {
e.preventDefault();
const $form = $('#my-report-form');
const data = {
action: 'bmpro_flag_my_custom_content_function',
nonce: this.nonce,
content_id: $form.find('[name="content_id"]').val(),
reason: $form.find('[name="reason"]').val(),
details: $form.find('[name="details"]').val()
};
$.post(this.ajaxUrl, data)
.done((response) => {
if (response.success) {
this.showSuccess(response.data.message);
this.closeModal();
} else {
this.showError(response.data.message);
}
})
.fail(() => {
this.showError('Request failed. Please try again.');
});
}
showSuccess(message) {
// Your success notification
}
showError(message) {
// Your error notification
}
closeModal() {
if (this.modal) {
this.modal.remove();
}
}
}
// Initialize
$(document).ready(() => new CustomReportHandler());
})(jQuery);
// Listen for built-in events
jQuery(document).on('bmpro:report:submitted', function(e, data) {
console.log('Report submitted:', data);
// Update UI
jQuery('.report-count-' + data.contentId).text(data.newCount);
// Track analytics
if (typeof gtag === 'function') {
gtag('event', 'content_reported', {
content_type: data.contentType,
content_id: data.contentId
});
}
});
jQuery(document).on('bmpro:modal:opened', function(e, modalType) {
console.log('Modal opened:', modalType);
});
jQuery(document).on('bmpro:modal:closed', function(e, modalType) {
console.log('Modal closed:', modalType);
});

/**
* Add product reporting to WooCommerce
*/
// Register content type
add_filter( 'bmpro_content_to_flag', 'add_wc_product_reporting' );
function add_wc_product_reporting( $types ) {
if ( class_exists( 'WooCommerce' ) ) {
$types['wc_product'] = __( 'Products', 'my-plugin' );
}
return $types;
}
// Add report button to product page
add_action( 'woocommerce_single_product_summary', 'show_product_report_button', 35 );
function show_product_report_button() {
if ( ! bmpro_user_can_report() ) {
return;
}
global $product;
?>
<button class="bmpro-flag-product-btn button"
data-product-id="<?php echo esc_attr( $product->get_id() ); ?>">
<?php echo esc_html( bmpro_get_flag_button_text( 'flag' ) ); ?> Product
</button>
<?php
}
// Handle report
add_action( 'wp_ajax_bmpro_flag_wc_product', 'handle_product_report' );
function handle_product_report() {
check_ajax_referer( 'bmpro_ajax_nonce', 'nonce' );
$product_id = absint( $_POST['product_id'] );
$reason = sanitize_text_field( $_POST['reason'] );
$product = wc_get_product( $product_id );
if ( ! $product ) {
wp_send_json_error( array( 'message' => 'Product not found' ) );
}
// Create report
$post_id = wp_insert_post( array(
'post_type' => 'bmpro_spam',
'post_title' => sprintf( 'Product Report: %s', $product->get_name() ),
'post_status' => 'publish',
) );
update_post_meta( $post_id, 'bmpro_spam_activity_id', $product_id );
update_post_meta( $post_id, 'bmpro_spam_status', 'awaiting_moderation' );
wp_set_object_terms( $post_id, 'wc_product', 'bmpro_content_type' );
// Notify shop manager
$shop_managers = get_users( array( 'role' => 'shop_manager' ) );
foreach ( $shop_managers as $manager ) {
wp_mail(
$manager->user_email,
'Product Reported: ' . $product->get_name(),
sprintf(
'Product "%s" has been reported. Reason: %s. Review: %s',
$product->get_name(),
$reason,
admin_url( 'post.php?post=' . $post_id . '&action=edit' )
)
);
}
wp_send_json_success( array( 'message' => 'Report submitted' ) );
}

class My_Moderation_Integration_Test extends WP_UnitTestCase {
public function test_can_report_check() {
// Create test user
$user_id = $this->factory->user->create( array( 'role' => 'subscriber' ) );
wp_set_current_user( $user_id );
// Test permission
$this->assertTrue( bmpro_user_can_report( $user_id ) );
}
public function test_custom_content_type_registered() {
$types = bmpro_content_to_flag_array();
$this->assertArrayHasKey( 'my_custom_content', $types );
}
public function test_report_creation() {
// Create report
$post_id = wp_insert_post( array(
'post_type' => 'bmpro_spam',
'post_title' => 'Test Report',
'post_status' => 'publish',
) );
update_post_meta( $post_id, 'bmpro_spam_status', 'awaiting_moderation' );
// Verify
$this->assertEquals(
'awaiting_moderation',
get_post_meta( $post_id, 'bmpro_spam_status', true )
);
}
}
  • Report button appears for logged-in users
  • Report modal opens correctly
  • Report submission creates database entry
  • Admin receives notification
  • Auto-moderation triggers at threshold
  • Content visibility changes after moderation
  • User blocking prevents interactions

Possible causes:

  • User not logged in
  • User role not allowed to report
  • Content type not enabled

Solution:

// Debug permissions
add_action( 'wp_footer', function() {
if ( is_user_logged_in() ) {
$can_report = bmpro_user_can_report();
error_log( 'Can report: ' . ( $can_report ? 'yes' : 'no' ) );
}
} );

Check nonce:

console.log('Nonce:', bmpro_ajax_object.ajax_nonce);

Verify action:

// In your AJAX handler
error_log( 'Received action: ' . $_POST['action'] );
error_log( 'POST data: ' . print_r( $_POST, true ) );

Verify hook is registered:

global $wp_filter;
if ( isset( $wp_filter['bpmp_members_flagged'] ) ) {
error_log( 'Hook has ' . count( $wp_filter['bpmp_members_flagged']->callbacks ) . ' callbacks' );
}

  1. Always check permissions before showing moderation UI
  2. Use nonces for all AJAX requests
  3. Sanitize all input data
  4. Cache expensive queries using transients
  5. Log moderation actions for audit trail
  6. Test with different user roles
  7. Handle edge cases (deleted content, banned users)

Last Updated: 2025-12-20 Plugin Version: 4.x+

See Also: