1. Developer Tutorials
  2. Extending Access Controls

Extending Access Controls

This tutorial will guide you on how you can integrate and protect content with Access Control. Access Control blocks contents with groups and other certain options which are called rules.

About Access Controls Rule

A rule in access control contains details about cases when the specific item is blocked, where scenarios can be 

  1. Block an item based on the user authentication state.
  2. Block an item based on specifically selected groups.

Also, a rule can contain additional information such as restrict message which is used to show a custom redirect message when the user doesn’t have access to a specific Access Control rule. 

Writing a Integration for Access Controls

In Access Controls there are two parts where a custom integration can be done. 

  1. Extending Access Controls Conditions
  2. Restricting content using Access Controls Rules

Extending Access Controls Conditions

In this we will add a new condition to the Access Controls Module which later can be used to add a new Access Group into Access controls Module.

For this example we will demonstrate Platform Groups as an example to integrate with Access Controls.

1. Create one class file and extend \BuddyBossApp\AccessControls\Integration_Abstract .

class Platform_Groups_AccessControls extends \BuddyBossApp\AccessControls\Integration_Abstract
{

    /**
    * Function to set up the conditions.
    *
    * @return mixed|void
    */
    public function setup()
    {
       
    }
}

2. Next we register a new condition, which you can do by calling register_condition within the same instance. inside setup method. 

Tip: To check the full reference of this method click here.

...
public function setup() {
  $this->register_condition( array(
    'condition'         => 'platform-social-groups',
    'items_callback'    => array( $this, 'items_callback' ),
    'item_callback'     => array( $this, 'item_callback' ),
    'users_callback'    => array( $this, 'users_callback' ),
    'labels'            => array(
        'condition_name' => __( 'Example Social Groups', 'buddyboss-app' ),
        'item_singular'  => __( 'Group', 'buddyboss-app' ),
    ),
    'support_any_items'      => true,
    'has_any_items_callback' => array( $this, 'has_any_items_callback' ),
  ) );
}
...

3. Now we need to provide a callback function to items_callback.

Items_callback callback functions require 3 parameters which are $search, $page, $limit. Which you can use to return an expected return to the callback.

This callback is used to fetch the items while configuring the Access Groups.
For example in social groups condition items would be social groups. So we have to return the groups in this callback by respecting the 3 params provided in the callback.

This callback function will look like.

...public function items_callback( $search = '', $page = 1, $limit = 20 ) {
$list = array();

$args = array(
'search_terms' => $search,
'page'         => $page,
'show_hidden'  => true,
);

if ( - 1 !== $limit ) {
$args['per_page'] = $limit;
}

$results = \BP_Groups_Group::get( $args );

if ( ! empty( $results ) ) {
foreach ( $results['groups'] as $result ) {
$list[ $result->id ] = array(
'id'   => $result->id,
'name' => $result->name,
'link' => admin_url("admin.php?page=bp-groups&gid={$result->id}&action=edit" )
);
}
}

return $list;
}
...

Note: Make sure to return the array collection each containing keys id, name, link.

4. Now we need to provide a callback function to item_callback.
Items_callback callback functions require 1 parameter which is $item_value . Which you can use to return an expected return to the callback.

$item_value is the ID of the item. In our example it’s a ID of the group. In the callback we need to provide the information for that item.

This callback is also used to validate if the item is available to the customer or not. Based on this information Access Control decides if the Access Group linked to that specific item is valid or not.
Expected returns of these functions:

  1. Array containing keys id, name, link of items when the item is available.
  2. 2False boolean value when the item is not available.

This callback function will look like this.

...
public function item_callback( $item_value ) {

  $group = groups_get_group( $item_value );

  if ( empty( $group ) || is_wp_error( $group ) || empty( $group->slug ) ) {
    return false;
  }

  return array(
    'id'   => $group->id,
    'name' => $group->name,
    'link' => admin_url( "admin.php?page=bp-groups&gid={$group->id}&action=edit" )
  );
}
...

5. Now we need to provide a callback function to users_callback.

Items_callback callback functions require 3 parameters which are $data, $page, $limit. Which you can use to return an expected return to the callback.

This callback function is used by the Access Group to fetch the users for the provided condition  with specific configurations set to Access Group for that Condition.

For example if a user has selected a social group name Example in Access Group. Then this function will help Access Controls to fetch all members inside the Example Social Group.

In order to fetch the users in scalable manners we have provided the page parameter which should be used to return users in paginated data structure.
The configuration of conditions are provided inside the $data variable of this callback function. Which will be used to fetch members of specific Item or any items.
$data contains 

  1. ​​sub_condition – which can be enum of any or specific. Any means users from all items ( eg. social groups for this example )
  2. Item_value – Hold the ID of item if sub_condition is specific this can be used to fetch members of specific item. Eg. For the current example this will hold a Social Group ID.
  3. group_id – Hold the Access Group ID for which the users are being fetched. 
  4. rounds_count – Hold the information of how many times the member calculation job has called users_callback since it started.

This callback expects multiple types of returns which are. 

  1. return_users you can use this by calling $this->return_users($user_ids) method.
    1. return_users requires one parameter 
      1. $user_ids – the array list of users for the current callback pagination.
    2. Note – Returning an empty user list with this function will be assumed as Access Group Member calculation completion. If it returns users then Access Group will try to call the users_callback function again with increment $page number.
  2. return_wait you can use this by calling $this->return_wait($message); method
    1. This function has 1 parameter
      1. $message – you can provide the reason to wait. Which are stored into logs of Access Group while calculation members.
    2. Note – Use this function to skip the current users_callback and ask member calculation jobs to do callback again with the same $page number param.  This method can be helpful to do some prefetch jobs before returning a final users list with return_users method.
  3. return_error you can use this by calling $this->return_error($error)
    1. This function has 1 param
      1. $error – you can provide an error message for which the job wasn’t able to return users list collection.
    2. Note – Use this method if you want to return the error and stop the member calculation job.
    3. Note – Once this method is called it will stop the member calculation and disable the Access Group with error provided.

This callback function will look like.

public function users_callback( $data, $page = 1, $per_page = 10 ) {

  /**
  * @type string $sub_condition
  * @type string $item_value
  * @type string $group_id
  * @type int    $rounds_count
  */
  extract( $data );

  $group_args = array(
    'page'     => $page,
    'per_page' => $per_page,
  );

  if ( 'specific' === $sub_condition ) {
    $group_args['group_ids'] = array( $item_value );
  }

  // Return the error if method is not found. this will stop the calculation job.
  if(!function_exists( 'bb_get_all_members_for_groups' )) {
    return $this->return_error("Social Group feature is not available.");
  }

  $group_members = bb_get_all_members_for_groups( $group_args );
  $user_ids      = ( ! empty( $group_members ) ) ? $group_members : array();

  return $this->return_users( $user_ids );
}

6. If you want to support any items in condition then you need to
You can decide if you want Access Group to be able to fetch users for all items ( in this case social groups ) then you need to add support for any which is disabled by default.

To add support for any items in the condition you need to add `support_any_items` with true boolean and provide `has_any_items_callback` callback function.

As shown below 

...$this->register_condition( array(
  'condition'         => 'platform-social-groups',
  ...
  'support_any_items'      => true,
  'has_any_items_callback' => array( $this, 'has_any_items_callback' ),
) );...

Where in ‘has_any_items_callback’ callback functions require 1 parameter which is $user_id. Which you can use to return an expected return to the callback.

has_any_items_callback tells Access Control if the user has Access to any items or not. Which help Access Group with any configuration to decide if user needs to be revoked from Access or not.

This method only expects true or false. 

Callback method will look like this.

...public function has_any_items_callback( $user_id ) {
  $user_groups = bp_get_user_groups( $user_id, array( 'is_admin' => true, 'is_mod' => true ) );

  return ( ! empty( $user_groups ) ) ? true : false;
}...

Developers notes & good practice recommendation. 

  1. Make sure to make use of parameters provided by callbacks for example $page, $search, $limit these are added to make the module scalable with large scale websites.
  2. When fetching the users or items in the callback make sure to do optimized pagination database queries instead or getting all members and chunking the results with php.

Full Example Code

class Platform_Example_AccessControls extends \BuddyBossApp\AccessControls\Integration_Abstract {

  /**
  * Function to set up the conditions.
  *
  * @return mixed|void
  *
  */
  public function setup() {
    $this->register_condition( array(
        'condition'              => 'platform-social-groups',
        'items_callback'         => array( $this, 'items_callback' ),
        'item_callback'          => array( $this, 'item_callback' ),
        'users_callback'         => array( $this, 'users_callback' ),
        'labels'                 => array(
          'condition_name' => __( 'Example Social Groups', 'buddyboss-app' ),
          'item_singular'  => __( 'Group', 'buddyboss-app' ),
        ),
        'support_any_items'      => true,
        'has_any_items_callback' => array( $this, 'has_any_items_callback' ),
    ) );
  }

  public function items_callback( $search = '', $page = 1, $limit = 20 ) {
    $list = array();

    $args = array(
        'search_terms' => $search,
        'page'         => $page,
        'show_hidden'  => true,
    );

    if ( - 1 !== $limit ) {
        $args['per_page'] = $limit;
    }

    $results = \BP_Groups_Group::get( $args );

    if ( ! empty( $results ) ) {
        foreach ( $results['groups'] as $result ) {
          $list[ $result->id ] = array(
              'id'   => $result->id,
              'name' => $result->name,
              'link' => admin_url( "admin.php?page=bp-groups&gid={$result->id}&action=edit" )
          );
        }
    }

    return $list;
  }

  public function item_callback( $item_value ) {

    $group = groups_get_group( $item_value );

    if ( empty( $group ) || is_wp_error( $group ) || empty( $group->slug ) ) {
        return false;
    }

    return array(
        'id'   => $group->id,
        'name' => $group->name,
        'link' => admin_url( "admin.php?page=bp-groups&gid={$group->id}&action=edit" )
    );
  }

  public function users_callback( $data, $page = 1, $per_page = 10 ) {

    /**
      * @type string $sub_condition
      * @type string $item_value
      * @type string $group_id
      * @type int $rounds_count
      */
    extract( $data );

    $group_args = array(
        'page'     => $page,
        'per_page' => $per_page,
    );

    if ( 'specific' === $sub_condition ) {
        $group_args['group_ids'] = array( $item_value );
    }

    // Return the error if method is not found. this will stop the calculation job.
    if ( ! function_exists( 'bb_get_all_members_for_groups' ) ) {
        return $this->return_error( "Social Group feature is not available." );
    }

    $group_members = bb_get_all_members_for_groups( $group_args );
    $user_ids      = ( ! empty( $group_members ) ) ? $group_members : array();

    return $this->return_users( $user_ids );
  }

  public function has_any_items_callback( $user_id ) {
    $user_groups = bp_get_user_groups( $user_id, array( 'is_admin' => true, 'is_mod' => true ) );

    return ( ! empty( $user_groups ) ) ? true : false;
  }
}

Platform_Example_AccessControls::instance();

Integration_Abstract Methods References

register_condition 

Description 

Register condition is used for adding support for new conditions which will appear inside the configuration of Access Groups.

Parameters 

  1. $args (array) (required)  Array  of arguments for Register Condition.
    1. 1condition  (string) (required)  Unique name of the condition, shouldn’t contain space & special character excluding “-“,”_”*
  2. items_callback  (callable) (required)  Callback function which returns items lists. 
    1. The callback has 3 params.
      1. $search (string) Search string of which items are requests from callback.
      2. $page (int)  page position of the items which are requests from callback.
      3. $limit (int) limit per page of items which are requests from callback.
      4. The callback expected return is list of arrays in containing
        1. id (required) ID of an item.
        2. name (required) name of an item.
        3. link (required) link of an item.
  3. item_callback (callable) (required) Callback function which returns a single item information by Its ID.
    1. The callback has 1 param.
      1. $item_value (string) it’s a unique item.
    2. The callback expected return is array containing. 
      1.  id (required) ID of an item.
      2. name (required) name of an item.
      3. link (required) link of an item.
  4.  users_callback (callable) (required) Callback function which returns users based on condition configurations on group.
    1. The callback has 3 params.
      1. $data, (array) data configuration of condition containing keys.
        1. sub_condition  (string) type of condition ENUM (specific or any)
        2. item_value  (string) ID of the item which is selected inside Access Group.
        3. group_id (int) ID of the Access Group where the condition is configured.
        4. rounds_count (int) counts of how many times the callback has been called. it’s useful to judge if its a first round of the job to prefetch desired data.
        5. $page (int)  page position of the users which are requests from callback.
        6. $limit (int) limit per page of users which are requests from callback.
  1. labels  (array) (required) Labels array containing keys.
    1. condition_name (required) Label of the condition.
    2. item_singular (required) Singular item label.
    3. member_of_specific_item (required) Label used in condition select option for specific items.
    4. member_of_any_items  (optional) Label used in condition select option for any items. (required if support_any_items is true.)
  2. support_any_items (array) (optional) If the condition supports any items ( enabling any items will allow customers to fetch users for all items over the site.
  1. has_any_items_callback  (callable) (optional) Callback function which will validate if the user has any items access to them or not. This is required if support_any_items is true.

return_users

Description

Method is used for returning users inside the users callback function of register_condition.

Parameters

  1. $users (array) (required) list of user ids need to be returned to the callback function.

Note – Returning this method with an empty users IDs will end the users_callback function with a complete member calculation function.

return_wait

Description

Method is used for returning wait to the users callback function of register_condition.

When you use this function the member calculation job will repeat the same callback again with the same $page number. 

You can use return wait to get some more time to prefetch some of your data from the database before providing users to the callback.

Parameters

  1. $message (string) (required) message reason mentioning why wait is happening this information will be stored as a log in the Access Group.

return_error

Method is used for returning errors to the users callback function of register_condition.

When you use this method the member calculation job gets stopped and the Access Group gets disabled as shown in the Access Groups UI.

Tip: You can use this method if you find any error while calculating the members’ user data. 

Parameters

  1. $error (string) (required) error mentioning why error is happening this information will be stored as a log in the Access Group and shown in Access Group list UI.

Questions?

We're always happy to help with questions you might have! Search our documentation, contact support, or connect with our sales team.