1. Developer Tutorials
  2. Extending the In-App Purchases Component

Extending the In-App Purchases Component

In this tutorial, you will learn how to support third-party plugins for In-App Purchases (IAP). This allows you to sell access to content coming from third-party plugins, through IAP from the Apple App Store and Google Play Store.

The BuddyBoss App already supports purchasing LearnDash courses and memberships from many popular membership plugins, but if there’s a specific plugin that you need to support with in-app purchases, you can add support for it by using custom code.


In your own plugin:

1. Create one class file and extend ‘BuddyBossApp\InAppPurchases\IntegrationAbstract’.

use BuddyBossApp\InAppPurchases\IntegrationAbstract;

class <ClassName> extends IntegrationAbstract {
   // Class code
}

2. Register your third party plugin for In-App Purchases.

Integration_slug 	: Integration slug.
integration_type 	: Integration type to identify integration items.
integration_label 	: Integration label
Item_label 	 	: Integration item label
Enabled 	 	: Integration should be enabled or disabled. 
Class 	 		: In-app purchase integration class name
/**
* Setup IAP integration
*/
public function register() {

	$this->integration_slug  = '<iap_slug>';
	$this->integration_type  = '<iap_type>';
	$this->integration_label = '<iap_label>';
	$this->item_label        = '<iap_item_label>';

	// Register 3rd party plugin for iap
	bbapp_iap()->integrations[ $this->integration_slug ] = array(
		'type'    => $this->integration_type,
		'label'   => $this->integration_label,
		'enabled' => true,
		'class'   => self::class,
	);

	parent::set_up( $this->integration_type, $this->integration_label );

	// Register Instance
	bbapp_iap()->integration[ $this->integration_type ] = $this::instance();
}

3. Implement an abstract method in the newly created class.  The next steps will provide you with detailed information for each abstract method.

Abstract Methods

4. Iap_linking_options

Iap_linking_options 	: Use the method helps to show integration items in the BuddyBoss App Plugin Product via Ajax.
Results 	 	: Items list for this Integration.
Public function iap_linking_options( $results ) {
	// TODO: Implement iap_linking_options() method.
      /* Data should be return in following format
	return array(
		array(
			'id' => '<item_id>',
			'text' => '<item_label>',
		),
		...
	);*/
}

5. Iap_integration_ids

Iap_integration_ids 	: This method converts items IDs into labels.
Results 	 	: Items listed for this Integration.
integration_ids 	: Item IDs.
Public function iap_integration_ids( $results, $integration_ids ) {
	// TODO: Implement iap_integration_ids() method.

	/* Data should be return in following format
	return array(
		array(
			'id' => '<item_id>',
			'text' => '<item_label>',
		),
		...
	);*/
}

6. item_id_permalink

item_id_permalink 	: This method updates the link url of items page.
Public function item_id_permalink( $link, $item_id ) {
	// TODO: Implement item_id_permalink() method.
}

7. is_purchase_available

is_purchase_available 	: This method allows you to check whether an item is available to purchase or not for a particular post.
Is_available 	 	: Flag for if an item is available or not for purchase
forItemId 	 	: Post ID or item ID. (This value mostly passes by endpoint to find out available items for a particular post)
Integration_item_id 	: Integration item ID.
Public function is_purchase_available( $is_available, $forItemId, $integration_item_id ) {
	// TODO: Implement is_purchase_available() method.
}

8. has_access

has_access 		: This method checks if a current user has access to a given item.
item_ids 		: item IDs
Order 			: Order object
Public function has_access( $item_ids, $order ) {
	// TODO: Implement has_access() method.
}

9. on_order_completed

on_order_completed	: This method executes when an order is completed so you can give item access to the user.
item_ids		: items IDs
Order			: Order object
Public function on_order_completed( $item_ids, $order ) {
	// TODO: Implement on_order_completed() method.
}

10. on_order_activate

on_order_activate	: This method executes when an order is activated so you can give item access to the user.
item_ids		: items IDs
Order			: Order object
Public function on_order_activate( $item_ids, $order ) {
	// TODO: Implement on_order_activate() method.
}

11. on_order_cancelled

on_order_cancelled	: This method executes when an order is cancelled so you can remove item access from the user.
item_ids		: items IDs
Order			: Order object
Public function on_order_cancelled( $item_ids, $order ) {
	// TODO: Implement on_order_cancelled() method.
}

12. on_order_expired

on_order_expired	: This method executes when an order is expired so you can remove item access from the user.
item_ids		: items ids
Order			: Order object
Public function on_order_expired( $item_ids, $order ) {
	// TODO: Implement on_order_expired() method.
}

Example Plugin

You can assemble the two PHP template files below into a folder, to create a plugin that will allow users to purchase access for LearnDash Groups, which can be seen when editing a product’s “Integration Type” at BuddyBoss App > In-App Purchases > Products.

Our built-in IAP system already allows you to select LearnDash LMS (groups) from within the Membership option in the dropdown, so you would not actually need this new integration. It is just an example of testing. You would want to modify this example to enroll users into some other membership system or enrollment type.

Note: For this example to actually display in your app or website, we are assuming you are using LearnDash and have created some LearnDash Groups already.

buddyboss-app-custom.php

This is the loader file. Create a plugin folder and add this file into it.

<?php
/*
Plugin Name: BuddyBoss App Custom In-App Purchases
Plugin URI: {add your own}
Description: {add your own}
Version: 1.0.0
Author: {add your own}
Author URI: {add your own}
*/
if ( ! defined( 'ABSPATH' ) ) {
	exit();
}

/**
 * Load Custom work
 */
function bbapp_custom_work_init() {
	if ( class_exists( 'bbapp' ) ) {
		include 'buddyboss-app-custom-iap.php';
		BuddyBossApp\Custom\IAP::instance();
	}
}
add_action( 'plugins_loaded', 'bbapp_custom_work_init' );

buddyboss-app-custom-iap.php

This file also goes into your plugin folder. This file contains the functional code to register the new In-App Purchase integration type.

<?php

namespace BuddyBossApp\Custom;

if ( ! defined( 'ABSPATH' ) ) {
	exit();
}

use BuddyBossApp\InAppPurchases\IntegrationAbstract;
use BuddyBossApp\InAppPurchases\Orders;

// Learndash Group Integration for BuddyBossApp InAppPurchases.
final class IAP extends IntegrationAbstract {

	private static $instance = null;

	/**
	 * LearnDashGroupIntegration constructor.
	 */
	private function __construct() {
		// ... leave empty, see Singleton below
	}

	/**
	 * Get the instance of this class.
	 * @return IAP|null
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			$className      = __CLASS__;
			self::$instance = new $className;
			self::$instance->register();
		}

		return self::$instance;
	}

	/**
	 * Setup IAP integration
	 */
	public function register() {

		$this->integration_slug  = 'ld-groups';
		$this->integration_type  = 'ld-groups';
		$this->integration_label = __( 'LearnDash Group', 'buddyboss-app' );
		$this->item_label        = __( 'LearnDash Group', 'buddyboss-app' );;

		// Register 3rd party plugin for iap
		bbapp_iap()->integrations[ $this->integration_slug ] = array(
			'type'    => $this->integration_type,
			'label'   => $this->integration_label,
			'enabled' => true,
			'class'   => self::class,
		);

		parent::set_up( $this->integration_type, $this->integration_label );

		// Register Instance
		bbapp_iap()->integration[ $this->integration_type ] = $this::instance();
	}

	/**
	 * Below function get triggers when(hook) order is completed.
	 *
	 * @param $item_ids
	 * @param $order
	 *
	 * @return mixed
	 */
	public function on_order_completed( $item_ids, $order ) {

		foreach ( $item_ids as $item_identifier ) {

			$split    = explode( ':', $item_identifier );
			$group_id = $split[0];

			$readable_item_ids[] = "<a href=\"post.php?post=$group_id&action=edit\" target='_blank'>$group_id</a>";

			// grant the group access
			ld_update_group_access( $order->user_id, $group_id, false );
			// update user group count.
			$this->user_update_count( $group_id, $order->user_id, "plus" );

		}
		$readable_item_ids = implode( ', ', $readable_item_ids );

		Orders::instance()->add_history( $order->id, 'info', sprintf( __( "User enrolled in Group(s), ID(s) are : %s", 'buddyboss-app' ), $readable_item_ids ) );

		Orders::instance()->update_meta( $order->id, "_learndash_group_ids", serialize( $item_ids ) );

	}

	/**
	 * Below function get triggers when(hook) order is activated.
	 *
	 * @param $item_ids
	 * @param $order
	 *
	 * @return mixed
	 */
	public function on_order_activate( $item_ids, $order ) {
		// NOTE : Similar to onOrderCompleted($order) until something needs to be changed?
		return $this->on_order_completed( $item_ids, $order );
	}

	/**
	 * Below function get triggers when(hook) order is expired.
	 *
	 * @param $item_ids
	 * @param $order
	 *
	 * @return mixed
	 */
	public function on_order_expired( $item_ids, $order ) {
		// NOTE : Similar to onOrderCancelled($order) until something needs to be changed?
		$this->on_order_cancelled( $item_ids, $order );
	}

	/**
	 * Below function get triggers when(hook) order is cancelled.
	 *
	 * @param $item_ids
	 * @param $order
	 *
	 * @return mixed
	 */
	public function on_order_cancelled( $item_ids, $order ) {

		//$item_ids = unserialize( Orders::instance()->get_meta( $order->id, "_learndash_course_ids" ) );

		foreach ( $item_ids as $item_identifier ) {
			$split    = explode( ':', $item_identifier );
			$group_id = $split[0];

			$readable_item_ids[] = "<a href=\"post.php?post=$group_id&action=edit\" target='_blank'>$group_id</a>";

			// revoke the group access
			ld_update_group_access( $order->user_id, $group_id, true );
			// update user group count.
			$this->user_update_count( $group_id, $order->user_id, "minus" );

		}
		$readable_item_ids = implode( ', ', $readable_item_ids );

		Orders::instance()->add_history( $order->id, 'info', sprintf( __( "User un-enrolled in group(s), ID(s) are : %s ", 'buddyboss-app' ), $readable_item_ids ) );
	}

	/**
	 * Helper function to update users group counts.
	 *
	 * @param        $group_id
	 * @param        $user_id
	 * @param string $action
	 */
	public function user_update_count( $group_id, $user_id, $action = "plus" ) {

		$groups = get_user_meta( $user_id, '_learndash_inapp_purchase_enrolled_group_access_counter', true );

		if ( ! empty( $groups ) ) {
			$groups = maybe_unserialize( $groups );
		} else {
			$groups = array();
		}

		if ( isset( $groups[ $group_id ] ) ) {
			if ( $action == "plus" ) {
				$groups[ $group_id ] += 1;
			} else {
				$groups[ $group_id ] -= 1;
			}
		} else {
			$groups[ $group_id ] = ( $action == "plus" ) ? 1 : 0;
		}

		update_user_meta( $user_id, '_learndash_inapp_purchase_enrolled_group_access_counter', $groups );

	}

	function iap_linking_options( $results ) {
		return \BuddyBossApp\Admin\InAppPurchases\Helpers::getIntegrationItems( 'groups' );
	}

	function iap_integration_ids( $results, $integration_ids ) {

		foreach ( $integration_ids as $key => $integration_id ) {
			$results[ $key ]['id']   = $integration_id;
			$results[ $key ]['text'] = get_the_title( $integration_id );
		}

		return $results;
	}

	function item_id_permalink( $link, $item_id ) {
		return "post.php?post=$item_id&action=edit";
	}

	function is_purchase_available( $is_available, $item_id, $integration_item_id ) {
		return learndash_group_has_course( $integration_item_id, $item_id );
	}

	/**
	 * Check given integration item has access.
	 *
	 * @param $item_ids
	 * @param $order
	 *
	 * @return false
	 */
	function has_access( $item_ids, $order ) {
		$has_access = false;

		foreach ( $item_ids as $item_identifier ) {
			$split    = explode( ':', $item_identifier );
			$group_id = $split[0];
			if ( learndash_is_user_in_group( $order->user_id, $group_id ) ) {
				$has_access = true;
				break;
			}
		}

		return $has_access;
	}
}

Questions?

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