Skip to content

Understanding the internal structure and design of BuddyPress Moderation Pro.


  • Plugin file structure and organization
  • Core class responsibilities
  • Data flow for moderation actions
  • Database schema design
  • Hook system architecture
  • Performance optimizations

buddypress-moderation-pro/
├── buddypress-moderation-pro.php # Main plugin bootstrap
├── includes/ # Core functionality
│ ├── class-buddypress-moderation-pro.php
│ ├── class-buddypress-moderation-pro-loader.php
│ ├── class-buddypress-moderation-pro-i18n.php
│ ├── class-buddypress-moderation-pro-activator.php
│ ├── class-buddypress-moderation-pro-upgrader.php
│ ├── class-bmpro-cli.php
│ └── buddypress-moderation-pro-functions.php
├── admin/ # Admin functionality
│ ├── class-buddypress-moderation-pro-admin.php
│ ├── class-buddypress-moderation-pro-cleanup.php
│ ├── class-buddypress-moderation-pro-bbpress.php
│ ├── inc/ # Settings tabs
│ │ ├── bmpro-welcome-setting-tab.php
│ │ ├── bmpro-general-setting-tab.php
│ │ ├── bmpro-restrictions-setting-tab.php
│ │ └── ...
│ ├── css/
│ └── js/
├── public/ # Frontend functionality
│ ├── class-buddypress-moderation-pro-public.php
│ ├── class-buddypress-activity-moderation.php
│ ├── class-buddypress-comments-moderation.php
│ ├── class-buddypress-members-moderation.php
│ ├── class-buddypress-groups-moderation.php
│ ├── class-buddypress-messages-moderation.php
│ ├── class-buddypress-topics-moderation.php
│ ├── class-buddypress-replies-moderation.php
│ ├── class-buddypress-avatar-moderation.php
│ ├── class-buddypress-moderation-pro-email-notifications.php
│ ├── class-buddypress-moderation-pro-bp-notifications.php
│ ├── css/
│ └── js/
├── templates/ # Overridable templates
│ ├── bmpo-bp-moderations.php
│ ├── blocking.php
│ └── blocked.php
├── languages/ # Translations
└── docs/ # Documentation
├── user/
└── developer/

┌─────────────────────────────────────────────────────────────────┐
│ Buddypress_Moderation_Pro │
│ (Main Orchestrator) │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Buddypress_Moderation_Pro_Loader │
│ (Hook Registration) │
└────────────────────────────┬────────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Admin │ │ Public │ │ i18n │
│ (Admin Panel) │ │ (Frontend UI) │ │ (Translations) │
└────────┬─────────┘ └────────┬─────────┘ └──────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌────────────────────────────────────────┐
│ - Settings │ │ Content Type Handlers: │
│ - Meta Boxes │ │ - Activity Moderation │
│ - Cleanup │ │ - Comments Moderation │
│ - Post Types │ │ - Members Moderation │
└──────────────────┘ │ - Groups Moderation │
│ - Messages Moderation │
│ - Topics/Replies Moderation │
│ - Avatar Moderation │
└────────────────────────────────────────┘

File: includes/class-buddypress-moderation-pro.php

The main plugin class that orchestrates all functionality.

Responsibilities:

  • Define plugin constants
  • Load dependencies
  • Set locale for i18n
  • Initialize admin and public hooks
  • Run the loader
class Buddypress_Moderation_Pro {
protected $loader;
protected $plugin_name;
protected $version;
public function __construct() {
$this->plugin_name = 'buddypress-moderation-pro';
$this->version = BMPRO_PLUGIN_VERSION;
$this->load_dependencies();
$this->set_locale();
$this->define_admin_hooks();
$this->define_public_hooks();
}
public function run() {
$this->loader->run();
}
}

File: includes/class-buddypress-moderation-pro-loader.php

Centralized hook registration system.

Responsibilities:

  • Queue action hooks
  • Queue filter hooks
  • Execute all registered hooks
class Buddypress_Moderation_Pro_Loader {
protected $actions = array();
protected $filters = array();
public function add_action( $hook, $component, $callback, $priority = 10, $args = 1 ) {
$this->actions[] = compact( 'hook', 'component', 'callback', 'priority', 'args' );
}
public function add_filter( $hook, $component, $callback, $priority = 10, $args = 1 ) {
$this->filters[] = compact( 'hook', 'component', 'callback', 'priority', 'args' );
}
public function run() {
foreach ( $this->filters as $hook ) {
add_filter( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['args'] );
}
foreach ( $this->actions as $hook ) {
add_action( $hook['hook'], array( $hook['component'], $hook['callback'] ), $hook['priority'], $hook['args'] );
}
}
}

Each content type has a dedicated handler class:

Class File Purpose
Buddypress_Moderation_Pro_Activity_Moderation public/class-buddypress-activity-moderation.php Activity stream moderation
Buddypress_Moderation_Pro_Comments public/class-buddypress-comments-moderation.php Activity comments
Buddypress_Moderation_Pro_Members public/class-buddypress-members-moderation.php Member profiles
Buddypress_Moderation_Pro_Groups public/class-buddypress-groups-moderation.php BuddyPress groups
Buddypress_Moderation_Pro_Messages public/class-buddypress-messages-moderation.php Private messages
Buddypress_Moderation_Pro_Topics public/class-buddypress-topics-moderation.php bbPress topics
Buddypress_Moderation_Pro_Replies public/class-buddypress-replies-moderation.php bbPress replies
Buddypress_Moderation_Pro_Avatar public/class-buddypress-avatar-moderation.php Profile/group avatars

Common Handler Pattern:

class Content_Handler {
public function __construct() {
// Register hooks
}
// Show flag button in UI
public function show_flag_button() { }
// AJAX: Show report modal
public function ajax_show_report_modal() { }
// AJAX: Process flag submission
public function ajax_flag_content() { }
// AJAX: Process unflag
public function ajax_unflag_content() { }
// Filter: Hide flagged content
public function filter_content_visibility() { }
// Check auto-moderation threshold
public function check_auto_moderation() { }
}

User Clicks Flag Button
│
▼
┌─────────────────────┐
│ JavaScript Event │
│ (Modal Opens) │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ User Fills Form │
│ (Reason + Details) │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ AJAX Request │
│ (with nonce) │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ PHP Handler │
│ - Verify nonce │
│ - Validate input │
│ - Check permissions│
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Create Report Post │
│ (bmpro_spam) │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Update Meta Data │
│ - Reporter list │
│ - Content meta │
│ - User meta │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Fire Action Hook │
│ (bpmp_*_flagged) │
└──────────┬──────────┘
│
┌─────┴─────┐
▼ ▼
┌─────────┐ ┌─────────────┐
│ Email │ │ BP │
│ Notify │ │ Notification│
└─────────┘ └─────────────┘
│
▼
┌─────────────────────┐
│ Check Auto-Mod │
│ Threshold │
└──────────┬──────────┘
│
┌─────┴─────┐
▼ ▼
Threshold Under
Met Threshold
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ Hide │ │ Keep │
│ Content │ │ Visible │
└─────────┘ └─────────┘
Content Query Requested
│
▼
┌─────────────────────┐
│ Filter Hook Fires │
│ (bp_ajax_querystring│
│ or similar) │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Get Excluded IDs │
│ bmpro_exclude_ │
│ moderated_content()│
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Check User Context │
│ - Is admin? │
│ - Is reporter? │
│ - Is content owner?│
└──────────┬──────────┘
│
┌─────┴─────────────────┐
▼ ▼
Show to Hide
Admin/Reporter from User
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Return Content │ │ Filter Out IDs │
│ with Flag │ │ from Query │
└─────────────────┘ └─────────────────┘

-- Uses wp_posts table
post_type = 'bmpro_spam'
-- Post structure
ID bigint(20) -- Report ID
post_author bigint(20) -- Reporter user ID
post_title text -- Report title
post_status varchar(20) -- 'publish'
post_date datetime -- Report creation time

Meta Keys:

Key Type Description
bmpro_spam_activity_id int Original content ID
bmpro_spam_reported_by array Reporter user IDs
bmpro_spam_status string ‘awaiting_moderation’ / ‘spam’
bmpro_hide_mode string ‘reporters’ / ‘all_users’
bmpro_member_actions array Actions taken on member
bmpro_groups_actions array Actions taken on group
bmpro_lock_member_account string ‘yes’ if locked
-- Uses wp_posts table
post_type = 'bmpro_avatar_spam'

Meta Keys:

Key Type Description
_bp_user_id int User ID for profile avatars
_bp_group_id int Group ID for group avatars
_bp_user_avatar_flag int 0=pending, 1=approved, 2=rejected
_bp_group_avatar_flag int 0=pending, 1=approved, 2=rejected
_bp_is_group_avatar bool True for group avatars
-- bmpro_content_type taxonomy
-- Terms: activity_update, activity_comment, member, group,
-- message, topic, reply, group_avatar, user_avatar
Key Description
bmpro_flagged_activities Array tracking user’s flagging activity
bmpro_member_punish Punishment status
bmpro_flagged_member_meta Reporter info
Location Key Description
Activity bmpro_flagged_activity_meta Reporter list
Activity _bp_moderation Auto-moderated flag
Comment bmpro_flagged_comment_meta Reporter list
Message bmpro_flagged_message_meta Reporter list
Group bmpro_flagged_group_meta Reporter list
Topic bmpro_flagged_topic_meta Reporter list
Reply bmpro_flagged_reply_meta Reporter list

┌──────────────────────────────────────────────────────────────┐
│ REPORTING HOOKS │
├──────────────────────────────────────────────────────────────┤
│ bpmp_members_flagged │ When member reported │
│ bpmp_activity_flagged │ When activity reported │
│ bpmp_activity_comment_flagged │ When comment reported │
│ bpmp_groups_flagged │ When group reported │
│ bpmp_message_flagged │ When message reported │
│ bpmp_topic_flagged │ When topic reported │
│ bpmp_reply_flagged │ When reply reported │
│ bpmp_avatar_flagged │ When avatar uploaded │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ MODERATION HOOKS │
├──────────────────────────────────────────────────────────────┤
│ bmpro_member_suspended │ When member suspended │
│ bmpro_member_unsuspended │ When suspension lifted │
│ bmpro_user_blocked │ When user blocks another │
│ bmpro_user_unblocked │ When user unblocks │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ CLEANUP HOOKS │
├──────────────────────────────────────────────────────────────┤
│ bmpro_spam_cleanup_filter_function │ When content cleaned │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ CONTENT FILTERS │
├──────────────────────────────────────────────────────────────┤
│ bmpro_content_to_flag │ Content types array │
│ bmpro_exclude_moderated_content │ Hide content check │
│ bmpro_spam_statuses_types │ Status options │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ SETTINGS FILTERS │
├──────────────────────────────────────────────────────────────┤
│ bmpro_auto_mod_limit_filter │ Threshold number │
│ bmpro_auto_moderation_enable │ Auto-mod toggle │
│ bmpro_get_moderation_mode_filter │ Visibility mode │
│ bmpro_get_flag_unflag_text │ Button text │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ PERMISSION FILTERS │
├──────────────────────────────────────────────────────────────┤
│ bmpro_user_can_report │ Report permission │
│ bpmp_moderator_users │ Moderator list │
│ bmpro_allow_activity_update_user_roles │ Update roles │
└──────────────────────────────────────────────────────────────┘

// Spam data preloading for activity loops
function bmpro_preload_spam_data( $activity_ids ) {
global $wpdb;
// Single query for all activities
$ids_string = implode( ',', array_map( 'intval', $activity_ids ) );
$results = $wpdb->get_results( $wpdb->prepare(
"SELECT post_id, meta_value
FROM {$wpdb->postmeta}
WHERE meta_key = 'bmpro_spam_activity_id'
AND meta_value IN ($ids_string)"
) );
// Cache results
foreach ( $results as $row ) {
wp_cache_set(
'bmpro_spam_' . $row->meta_value,
$row->post_id,
'bmpro'
);
}
}
// Individual lookup uses cache
function bmpro_get_spam_post_id( $activity_id ) {
$cached = wp_cache_get( 'bmpro_spam_' . $activity_id, 'bmpro' );
if ( $cached !== false ) {
return $cached;
}
// Fallback to database query
// ...
}
// Efficient excluded content query
function get_excluded_content_ids( $content_type ) {
$cache_key = 'bmpro_excluded_' . $content_type;
$excluded = wp_cache_get( $cache_key, 'bmpro' );
if ( $excluded === false ) {
global $wpdb;
$excluded = $wpdb->get_col( $wpdb->prepare(
"SELECT pm.meta_value
FROM {$wpdb->posts} p
INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
INNER JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
INNER JOIN {$wpdb->terms} t ON tt.term_id = t.term_id
WHERE p.post_type = 'bmpro_spam'
AND pm.meta_key = 'bmpro_spam_activity_id'
AND t.slug = %s
AND p.post_status = 'publish'",
$content_type
) );
wp_cache_set( $cache_key, $excluded, 'bmpro', HOUR_IN_SECONDS );
}
return $excluded;
}
// Only load assets on relevant pages
function bmpro_get_is_relevant_buddypress_page() {
if ( ! function_exists( 'bp_is_active' ) ) {
return false;
}
// Check specific BuddyPress pages
return bp_is_activity_component() ||
bp_is_members_component() ||
bp_is_groups_component() ||
bp_is_messages_component() ||
( function_exists( 'bbp_is_forum' ) && bbp_is_forum() );
}
// Conditional enqueue
if ( bmpro_get_is_relevant_buddypress_page() ) {
wp_enqueue_script( 'bmpro-public' );
wp_enqueue_style( 'bmpro-public' );
}

// All AJAX handlers follow this pattern
public function ajax_flag_content() {
// 1. Verify nonce
check_ajax_referer( 'bmpro_ajax_nonce', 'nonce' );
// 2. Verify user is logged in
if ( ! is_user_logged_in() ) {
wp_send_json_error( 'Not authenticated' );
}
// 3. Verify permissions
if ( ! bmpro_user_can_report() ) {
wp_send_json_error( 'Not authorized' );
}
// 4. Sanitize input
$content_id = absint( $_POST['content_id'] );
$reason = sanitize_text_field( $_POST['reason'] );
$details = sanitize_textarea_field( $_POST['details'] );
// 5. Validate content exists
if ( ! $this->content_exists( $content_id ) ) {
wp_send_json_error( 'Content not found' );
}
// 6. Process request
// ...
}
// All output is escaped
echo esc_html( $report_reason );
echo esc_attr( $content_id );
echo esc_url( $profile_url );
echo wp_kses_post( $report_details );
// Admin operations require proper capabilities
if ( ! current_user_can( 'edit_post', $spam_post_id ) ) {
wp_die( 'Not authorized' );
}
// Moderator role has specific capabilities
$caps = array(
'edit_bmpro_spam',
'delete_bmpro_spam',
'read_bmpro_spam',
'bp_moderate',
);

  1. Register content type via filter
  2. Create AJAX handlers for flag/unflag
  3. Add admin meta box for moderation
  4. Implement cleanup handler
  1. Add action via filter hook
  2. Implement action handler
  3. Add UI in admin meta box
  1. Hook into reporting actions
  2. Use bp_notifications_add_notification()
  3. Register notification component

class Buddypress_Moderation_Pro_Upgrader {
public function __construct() {
add_action( 'admin_init', array( $this, 'check_version' ) );
}
public function check_version() {
$current = get_option( 'bmpro_version', '0' );
if ( version_compare( $current, BMPRO_PLUGIN_VERSION, '<' ) ) {
$this->upgrade( $current );
update_option( 'bmpro_version', BMPRO_PLUGIN_VERSION );
}
}
private function upgrade( $from_version ) {
if ( version_compare( $from_version, '3.0', '<' ) ) {
$this->upgrade_to_3_0();
}
if ( version_compare( $from_version, '4.0', '<' ) ) {
$this->upgrade_to_4_0();
}
}
}

class BMPRO_CLI extends WP_CLI_Command {
/**
* Get moderation status
*
* ## EXAMPLES
* wp bmpro status
*/
public function status() {
// Implementation
}
/**
* Report a member
*
* ## OPTIONS
* <member_id>
* [--reason=<reason>]
* [--reporter=<reporter_id>]
*/
public function report( $args, $assoc_args ) {
// Implementation
}
}
// Register command
if ( class_exists( 'WP_CLI' ) ) {
WP_CLI::add_command( 'bmpro', 'BMPRO_CLI' );
}

tests/
├── bootstrap.php
├── test-functions.php
├── test-activity-moderation.php
├── test-member-moderation.php
├── test-auto-moderation.php
└── test-permissions.php
class Test_Activity_Moderation extends WP_UnitTestCase {
public function test_flag_activity() {
// Setup
$user_id = $this->factory->user->create();
$activity_id = bp_activity_add( array(
'user_id' => $user_id,
'content' => 'Test activity',
) );
// Act
$result = $this->flag_activity( $activity_id, $user_id );
// Assert
$this->assertTrue( $result );
$this->assertEquals( 1, $this->get_report_count( $activity_id ) );
}
}

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

See Also: