* @link https://TheTempusProject.com * @license https://opensource.org/licenses/MIT [MIT LICENSE] */ namespace TheTempusProject\Plugins; use TheTempusProject\TheTempusProject as App; use TheTempusProject\Classes\Plugin; use Stripe\StripeClient; use TheTempusProject\Bedrock\Classes\Config; use TheTempusProject\Hermes\Functions\Route as Routes; use TheTempusProject\Models\Memberships; use TheTempusProject\Models\MembershipProducts as Products; use TheTempusProject\Canary\Bin\Canary as Debug; class Members extends Plugin { public static $stripe; public static $memberships; private static $loaded = false; public $pluginName = 'TP Membership'; public $configName = 'memberships'; public $pluginAuthor = 'JoeyK'; public $pluginWebsite = 'https://TheTempusProject.com'; public $modelVersion = '1.0'; public $pluginVersion = '3.0'; public $pluginDescription = 'A simple plugin which adds a site wide membership system.'; public $permissionMatrix = [ 'memberAccess' => [ 'pretty' => 'Access Member Areas', 'default' => false, ], 'controlMemberships' => [ 'pretty' => 'User can Access and Control user memberships.', 'default' => false, ], ]; public $admin_links = [ [ 'text' => ' Memberships', 'url' => [ [ 'text' => ' Products', 'url' => '{ROOT_URL}admin/products', ], [ 'text' => ' Subscriptions', 'url' => '{ROOT_URL}admin/records', ], [ 'text' => ' Scripts', 'url' => '{ROOT_URL}admin/members', ], ], ], ]; public $main_links = [ [ 'text' => 'My Membership', 'url' => '{ROOT_URL}member/index', 'filter' => 'member', ], [ 'text' => 'Subscribe', 'url' => '{ROOT_URL}member/join', 'filter' => 'nonmember', ], [ 'text' => 'Upgrade', 'url' => '{ROOT_URL}member/upgrade', 'filter' => 'upgrade', ], ]; public $resourceMatrix = [ 'groups' => [ [ 'name' => 'Member', 'permissions' => '{"adminAccess":false}', ] ], ]; public $configMatrix = [ 'stripePublishable' => [ 'type' => 'text', 'pretty' => 'Stripe Publishable key', 'default' => 'pk_xxxxxxxxxxxxxxx', ], 'stripeSecret' => [ 'type' => 'text', 'pretty' => 'Stripe Secret key', 'default' => 'sk_xxxxxxxxxxxxxxx', ], ]; public static $webhookEvents = [ 'customer.subscription.created', 'customer.subscription.updated', 'customer.subscription.deleted', 'customer.updated', 'customer.deleted', 'payment_method.automatically_updated', 'invoice.payment_action_required', 'invoice.payment_succeeded', 'checkout.session.completed', ]; public static $userLinks = [ "url" => "{ROOT_URL}member/manage", "name" => "Subscriptions" ]; public function __construct( $load = false ) { if ( ! self::$loaded && $load ) { if ( App::$isLoggedIn ) { App::$isMember = $this->groupHasMemberAccess( App::$activeGroup ); if ( empty( App::$isMember ) ) { App::$isMember = $this->userHasActiveMembership( App::$activeUser->ID ); } } $this->filters[] = [ 'name' => 'member', 'find' => '#{MEMBER}(.*?){/MEMBER}#is', 'replace' => ( App::$isMember ? '$1' : '' ), 'enabled' => true, ]; $this->filters[] = [ 'name' => 'nonmember', 'find' => '#{NONMEMBER}(.*?){/NONMEMBER}#is', 'replace' => ( App::$isLoggedIn && App::$isMember == false ? '$1' : '' ), 'enabled' => true, ]; $this->filters[] = [ 'name' => 'upgrade', 'find' => '#{UPGRADE}(.*?){/UPGRADE}#is', 'replace' => ( App::$isLoggedIn && ( App::$isMember === 'monthly' ) ? '$1' : '' ), 'enabled' => true, ]; } parent::__construct( $load ); if ( $this->checkEnabled() && App::$isLoggedIn ) { if ( ! self::$loaded && $load ) { App::$userCPlinks[] = (object) self::$userLinks; App::$topNavRightDropdown .= '
  • Subscriptions
  • '; } } if ( ! self::$loaded && $load ) { self::$loaded = true; } $api_key = Config::getValue( 'memberships/stripeSecret' ); if ( $api_key == 'sk_xxxxxxxxxxxxxxx' || empty($api_key) ) { self::$stripe = false; } else { self::$stripe = new StripeClient( $api_key ); } } public function groupHasMemberAccess( $activeGroup ) { if ( $activeGroup->memberAccess == true ) { return true; } return false; } public function userHasActiveMembership( $user_id ) { $memberships = new Memberships; $membership = $memberships->findActiveByUserID( $user_id ); if ( empty( $membership ) ) { return false; } $products = new Products; $product = $products->findByPriceID( $membership->subscription_price_id ); if ( empty( $product ) ) { Debug::error('Active membership on non-existent product'); return false; } if ( $product->stripe_price_monthly == $membership->subscription_price_id ) { return 'monthly'; } return 'yearly'; } public static function webhookSetup() { $root = Routes::getAddress(); $response = self::$stripe->webhookEndpoints->create([ 'enabled_events' => self::$webhookEvents, 'url' => $root . 'api/stripe/webhook', ]); return $response; } public static function webhookList() { $response = self::$stripe->webhookEndpoints->all(['limit' => 25]); return $response; } public static function webhookRemove( $id ) { $response = self::$stripe->webhookEndpoints->delete( $id, []); return $response; } public static function orphanAbandon( $id ) { $response = self::$stripe->prices->update( $id, ['lookup_key' => ""] ); return $response; } public static function findOrphans() { $orphans = []; // any prices with keys not represented in our local db will show as an orphan $result = self::$stripe->prices->search([ 'query' => 'lookup_key:"membership-monthly"', ]); $products = new Products; if ( ! empty( $result->data ) ) { $product = $products->findByPriceID( $result->data[0]->id ); if ( empty( $product ) ) { $data = $result->data[0]; $child = new \stdClass; $child->price_id = $data->id; $child->product = $data->product; $child->lookup_key = $data->lookup_key; $child->amount = $data->unit_amount; $orphans[] = $child; } } $result = self::$stripe->prices->search([ 'query' => 'lookup_key:"membership-yearly"', ]); if ( ! empty( $result->data ) ) { $product = $products->findByPriceID( $result->data[0]->id ); if ( empty( $product ) ) { $data = $result->data[0]; $child = new \stdClass; $child->price_id = $data->id; $child->product = $data->product; $child->lookup_key = $data->lookup_key; $child->amount = $data->unit_amount; $orphans[] = $child; } } return $orphans; } }