Groups API

New in version 0.9.80

The Groups module provides a comprehensive API for managing cohorts, teams, and group-based access. This guide covers the public API functions, hooks, and filters available for extending the Groups functionality.

Checking Module Status

Before using Groups APIs, verify the module is active:

use BaselMedia\BricksMembers\Core\ModuleRegistry;

if ( ModuleRegistry::is_active( 'groups' ) ) {
    // Groups functionality available
}

Helper Functions

GroupsHelperService::get_instance()->get_user_active_group_for_post()

Get the user’s active group ID for a specific post context.

/**
 * @param int $user_id User ID
 * @param int $post_id Post ID
 * @return int|null Group ID or null if no active group
 */
$group_id = \BaselMedia\BricksMembers\Modules\Groups\GroupsHelperService::get_instance()
    ->get_user_active_group_for_post( $user_id, $post_id );

brm_get_group()

Retrieve group data by ID.

/**
 * @param int $group_id Group ID
 * @return array|null Group data or null if not found
 */
$group = brm_get_group( $group_id );

// Returns array with keys:
// id, name, owner_user_id, group_type, total_seats, used_seats,
// reserved_seats, grantable_levels, default_levels, status, starts_at, expires_at,
// invite_guest_redirect_page_id, invite_post_claim_redirect_page_id

brm_get_user_groups()

Get all groups a user belongs to.

/**
 * @param int   $user_id User ID
 * @param array $args    Optional: status, role filters
 * @return array Array of group arrays
 */
$groups = brm_get_user_groups( $user_id, array( 'status' => 'active' ) );

brm_is_group_member()

Check if a user is a member of a group.

/**
 * @param int $group_id Group ID
 * @param int $user_id  User ID
 * @return bool
 */
$is_member = brm_is_group_member( $group_id, $user_id );

brm_get_user_group_role()

Get a user’s role within a group.

/**
 * @param int $group_id Group ID
 * @param int $user_id  User ID
 * @return string|null 'member', 'leader', or null if not a member
 */
$role = brm_get_user_group_role( $group_id, $user_id );

brm_group_grants_access_to_post()

Check if group membership grants access to a post.

/**
 * @param int $group_id Group ID
 * @param int $post_id  Post ID
 * @return bool
 */
$has_access = brm_group_grants_access_to_post( $group_id, $post_id );

GroupService Class

For more complex operations, use the GroupService singleton:

use BaselMedia\BricksMembers\Modules\Groups\GroupService;

$service = GroupService::get_instance();

Creating Groups

$group_id = $service->create_group( array(
    'name'           => 'Spring 2026 Cohort',
    'owner_user_id'  => get_current_user_id(),
    'group_type'     => 'cohort',
    'total_seats'    => 25,
    'default_levels' => array( 1, 2 ),
    'starts_at'      => '2026-04-01 00:00:00',
    'expires_at'     => '2026-07-01 00:00:00',
) );

if ( is_wp_error( $group_id ) ) {
    // Handle error
}

Updating Groups

$result = $service->update_group( $group_id, array(
    'name'        => 'Updated Name',
    'total_seats' => 30,
) );

Archiving Groups

$service->archive_group( $group_id );

Member Management

// Add a member
$membership_id = $service->add_member( $group_id, $user_id, 'member' );

// Remove a member
$service->remove_member( $group_id, $user_id );

// Change role
$service->change_member_role( $group_id, $user_id, 'leader' );

// Transfer member to another group
$service->transfer_member( $user_id, $from_group_id, $to_group_id );

Getting Members

// Get all members
$members = $service->get_group_members( $group_id, array(
    'status' => 'active',
    'role'   => 'member', // or 'leader'
) );

// Get a specific membership
$membership = $service->get_membership( $group_id, $user_id );

InvitationService Class

use BaselMedia\BricksMembers\Modules\Groups\InvitationService;

$invitation_service = InvitationService::get_instance();

Creating Invitations

// Email invitation (single-use, specific recipient)
$invitation_id = $invitation_service->create_email_invitation(
    $group_id,
    'student@example.com',
    get_current_user_id(),
    array(
        'role'       => 'member',
        'expires_at' => '2026-04-01 00:00:00',
    )
);

// Send the email
$invitation_service->send_invitation_email( $invitation_id );

// Join link (reusable, public)
$link_id = $invitation_service->create_join_link(
    $group_id,
    get_current_user_id(),
    array(
        'role'       => 'member',
        // For limited groups: must be <= current available seats.
        // If omitted, defaults to available seats.
        'max_uses'   => 10,
        'expires_at' => '2026-04-01 00:00:00',
    )
);

// Get the shareable URL
$invitation = $invitation_service->get_invitation( $link_id );
$url = $invitation_service->get_claim_url( $invitation['token'] );

Validating and Claiming

// Validate before claiming
$validation = $invitation_service->validate_invitation( $token, $user_id );
if ( is_wp_error( $validation ) ) {
    echo $validation->get_error_message();
    return;
}

// Claim the invitation
$membership_id = $invitation_service->claim_invitation( $token, $user_id );

Managing Invitations

// Get by token
$invitation = $invitation_service->get_invitation_by_token( $token );

// Get all for a group
$invitations = $invitation_service->get_group_invitations( $group_id, array(
    'status' => 'pending',
    'type'   => 'email',   // or 'link'
) );

// Delete permanently
$invitation_service->delete_invitation( $invitation_id );

// Resend email
$invitation_service->send_invitation_email( $invitation_id );

SeatRuleService Class

For automated group creation from purchases:

use BaselMedia\BricksMembers\Modules\Groups\SeatRuleService;

$seat_service = SeatRuleService::get_instance();

// Create a rule
$rule_id = $seat_service->create_rule( array(
    'product_ref'     => 'team-license-pro',
    'provider'        => 'webhook',
    'group_type'      => 'team',
    'levels_to_grant' => array( 1, 2 ),
    'total_seats'     => 5,
    'create_mode'     => 'per_purchase',
) );

// Process a purchase (creates group automatically)
$result = $seat_service->process_purchase(
    'team-license-pro', // product_ref
    '',                 // variation_ref
    $owner_user_id,     // who purchased
    'order-123'         // unique reference
);

// $result contains: group_id, membership_id, levels_granted

Member Chat Integration

When the Member Chat module is enabled, Groups becomes the lifecycle owner for primary group rooms.

  • brm_event_group_created is used to create or resolve the primary group room
  • brm_event_group_member_added synchronizes the new user into the room
  • brm_event_group_member_removed removes the user from the group’s chat rooms
  • brm_event_group_archived archives the group’s related chat rooms

The current primary-room contract is one room per group with scope = group and room_kind = primary_group in the Member Chat tables.

Actions (Hooks)

Group Lifecycle

// After group is created
add_action( 'brm_group_created', function( $group_id, $data ) {
    // Send welcome email to owner, log analytics, etc.
}, 10, 2 );

// After group is updated
add_action( 'brm_group_updated', function( $group_id, $old_data, $new_data ) {
    // Track changes
}, 10, 3 );

// After group is archived
add_action( 'brm_group_archived', function( $group_id, $reason ) {
    // Cleanup, notifications
}, 10, 2 );

Member Lifecycle

// After member joins
add_action( 'brm_member_added', function( $group_id, $user_id, $role, $granted_levels ) {
    // Welcome email, onboarding
}, 10, 4 );

// After member leaves/removed
add_action( 'brm_member_removed', function( $group_id, $user_id, $reason ) {
    // Cleanup, notifications
}, 10, 3 );

// After role change
add_action( 'brm_member_role_changed', function( $group_id, $user_id, $old_role, $new_role ) {
    // Update permissions, notify
}, 10, 4 );

Invitation Lifecycle

// After invitation created
add_action( 'brm_invitation_created', function( $invitation_id, $group_id, $email, $invited_by ) {
    // Custom notifications, logging
}, 10, 4 );

// After invitation claimed
add_action( 'brm_invitation_claimed', function( $invitation_id, $user_id, $group_id, $invitation ) {
    // Welcome sequence, analytics
}, 10, 4 );

// After invitation email sent
add_action( 'brm_invitation_email_sent', function( $invitation_id, $invitation ) {
    // Track delivery
}, 10, 2 );

Filters

Customizing Invitation Emails

// Custom subject
add_filter( 'brm_invitation_email_subject', function( $subject, $invitation, $group ) {
    return sprintf( 'Join %s - Exclusive Invitation', $group['name'] );
}, 10, 3 );

// Custom message body
add_filter( 'brm_invitation_email_message', function( $message, $invitation, $group, $claim_url ) {
    return "You've been personally invited to join {$group['name']}.\n\n"
         . "Click here to accept: {$claim_url}\n\n"
         . "This is a limited opportunity!";
}, 10, 4 );

Customizing Claim Redirects

// After successful claim
add_filter( 'brm_invitation_claim_success_redirect', function( $url, $group_id, $user_id ) {
    return home_url( '/welcome-to-group/?group=' . $group_id );
}, 10, 3 );

// After failed claim
add_filter( 'brm_invitation_claim_error_redirect', function( $url, $error, $token ) {
    return home_url( '/invitation-error/?code=' . $error->get_error_code() );
}, 10, 3 );

Customizing Claim URL Base

add_filter( 'brm_invitation_claim_base_url', function( $url ) {
    return home_url( '/join/' ); // Custom join page
} );

Bricks Integration

Custom Conditions

Register custom Bricks conditions based on groups:

add_filter( 'bricks/conditions/options', function( $options ) {
    $options[] = array(
        'key'     => 'brm_custom_group_condition',
        'label'   => 'Custom Group Check',
        'group'   => 'brm',
        'compare' => array(
            '='  => 'equals',
            '!=' => 'not equals',
        ),
        'value'   => array(
            'type'   => 'text',
            'placeholder' => 'Group type',
        ),
    );
    return $options;
}, 15 );

add_filter( 'bricks/conditions/result', function( $result, $key, $condition ) {
    if ( 'brm_custom_group_condition' !== $key ) {
        return $result;
    }
    
    $group_id = \BaselMedia\BricksMembers\Modules\Groups\GroupsHelperService::get_instance()
        ->get_user_active_group_for_post( get_current_user_id(), get_the_ID() );
    if ( ! $group_id ) {
        return false;
    }
    
    $group = brm_get_group( $group_id );
    $compare_value = $condition['value'] ?? '';
    $compare = $condition['compare'] ?? '=';
    
    $matches = $group['group_type'] === $compare_value;
    return '=' === $compare ? $matches : ! $matches;
}, 10, 3 );

Custom Dynamic Tags

add_filter( 'bricks/dynamic_tags_list', function( $tags ) {
    $tags[] = array(
        'name'  => '{brm_group:custom_field}',
        'label' => 'Group Custom Field',
        'group' => 'BricksMembers',
    );
    return $tags;
} );

add_filter( 'bricks/dynamic_data/render_tag', function( $value, $tag, $post, $context ) {
    if ( strpos( $tag, '{brm_group:custom_field}' ) === false ) {
        return $value;
    }
    
    $group_id = \BaselMedia\BricksMembers\Modules\Groups\GroupsHelperService::get_instance()
        ->get_user_active_group_for_post( get_current_user_id(), get_the_ID() );
    if ( ! $group_id ) {
        return '';
    }
    
    // Return your custom field value
    return get_post_meta( $group_id, '_custom_group_field', true );
}, 10, 4 );

Database Schema

The Groups module uses four custom tables:

brm_groups

  • id – Primary key
  • name – Group name
  • owner_user_id – WordPress user ID of owner
  • group_type – Type (cohort, team, etc.)
  • total_seats, used_seats – Seat tracking
  • reserved_seats – Pending email invite seat reservations
  • grantable_levels, default_levels – JSON arrays
  • invite_guest_redirect_page_id, invite_post_claim_redirect_page_id – Optional redirect overrides
  • status – active, archived
  • starts_at, expires_at – Dates

brm_group_members

  • id – Primary key
  • group_id – FK to brm_groups
  • user_id – WordPress user ID
  • role – member, leader
  • granted_levels – JSON array of level IDs
  • status – active, removed, transferred
  • joined_at, last_active_at – Timestamps

brm_seat_rules

  • id – Primary key
  • product_ref – Product identifier
  • provider – webhook, surecart, etc.
  • group_type, total_seats – Group settings
  • levels_to_grant – JSON array
  • create_mode – per_purchase, shared

brm_group_invitations

  • id – Primary key
  • group_id – FK to brm_groups
  • token – Unique claim token
  • type – email, link
  • email – Recipient email (for email type)
  • role – Role to assign
  • max_uses, use_count – Usage limits
  • status – pending, claimed, active, exhausted, expired, revoked

Best Practices

  1. Always check module status before using Groups APIs
  2. Use helper functions for simple lookups, services for complex operations
  3. Handle WP_Error returns from service methods
  4. Use filters to customize behavior rather than overriding
  5. Clear caches after direct database operations (use MutationContract)

Related Documentation

Early Bird Deal

Start Building Your Membership Site Today

Create, sell, and manage your content without limits. BricksMembers gives you everything you need to build membership and LMS sites with Bricks Builder.

Lifetime updates & bug fixes • Premium support • 0% transaction fees • 60-day money-back guarantee