membership_started * - non-recurring transaction done -> membership_started (a one-time purchase) * - subscription stopped -> membership_cancelled * - subscription paused / resumed -> membership_paused / _resumed * - subscription expired -> membership_expired * - transaction refunded -> membership_refunded * * Each recurring payment (`transaction-completed` every period) is not a * membership change and is not logged; nor is any amount or payment method. * Memberships themselves are `memberpressproduct` posts: post events. */ final class MemberPress implements Integration { public const PLUGIN = 'memberpress'; /** Hook => [type, summary format, details key for the model's id]. */ private const HOOKS = array( 'mepr-event-subscription-created' => array( Memberships::STARTED, 'User %1$s subscribed to membership "%2$s"', 'subscription_id' ), 'mepr-event-non-recurring-transaction-completed' => array( Memberships::STARTED, 'User %1$s bought membership "%2$s"', 'transaction_id' ), 'mepr-event-subscription-stopped' => array( Memberships::CANCELLED, 'User %1$s cancelled membership "%2$s"', 'subscription_id' ), 'mepr-event-subscription-paused' => array( Memberships::PAUSED, 'User %1$s paused membership "%2$s"', 'subscription_id' ), 'mepr-event-subscription-resumed' => array( Memberships::RESUMED, 'User %1$s resumed membership "%2$s"', 'subscription_id' ), 'mepr-event-subscription-expired' => array( Memberships::EXPIRED, 'Membership "%2$s" of user %1$s expired', 'subscription_id' ), 'mepr-event-transaction-refunded' => array( Memberships::REFUNDED, 'Membership "%2$s" of user %1$s refunded', 'transaction_id' ), ); public static function is_active(): bool { return Integrations::enabled( self::PLUGIN, defined( 'MEPR_VERSION' ) || class_exists( 'MeprCtrlFactory', false ) ); } public static function event_types(): array { $all = Memberships::event_types(); return array_intersect_key( $all, array_flip( array_unique( array_column( self::HOOKS, 0 ) ) ) ); } public static function register( ?bool $active = null ): void { if ( ! ( $active ?? self::is_active() ) ) { return; } add_action( 'mepr-event-subscription-created', array( __CLASS__, 'on_subscription_created' ) ); add_action( 'mepr-event-non-recurring-transaction-completed', array( __CLASS__, 'on_non_recurring_transaction_completed' ) ); add_action( 'mepr-event-subscription-stopped', array( __CLASS__, 'on_subscription_stopped' ) ); add_action( 'mepr-event-subscription-paused', array( __CLASS__, 'on_subscription_paused' ) ); add_action( 'mepr-event-subscription-resumed', array( __CLASS__, 'on_subscription_resumed' ) ); add_action( 'mepr-event-subscription-expired', array( __CLASS__, 'on_subscription_expired' ) ); add_action( 'mepr-event-transaction-refunded', array( __CLASS__, 'on_transaction_refunded' ) ); } public static function post_types(): array { return array(); } public static function internal_post_types(): array { return array(); } /** * @param mixed $event MeprEvent. */ public static function on_subscription_created( $event ): void { self::log( 'mepr-event-subscription-created', $event ); } /** * @param mixed $event MeprEvent. */ public static function on_non_recurring_transaction_completed( $event ): void { self::log( 'mepr-event-non-recurring-transaction-completed', $event ); } /** * @param mixed $event MeprEvent. */ public static function on_subscription_stopped( $event ): void { self::log( 'mepr-event-subscription-stopped', $event ); } /** * @param mixed $event MeprEvent. */ public static function on_subscription_paused( $event ): void { self::log( 'mepr-event-subscription-paused', $event ); } /** * @param mixed $event MeprEvent. */ public static function on_subscription_resumed( $event ): void { self::log( 'mepr-event-subscription-resumed', $event ); } /** * @param mixed $event MeprEvent, or the subscription itself (as documented for this hook). */ public static function on_subscription_expired( $event ): void { self::log( 'mepr-event-subscription-expired', $event ); } /** * @param mixed $event MeprEvent. */ public static function on_transaction_refunded( $event ): void { self::log( 'mepr-event-transaction-refunded', $event ); } /** * The transaction or subscription an event carries: its `get_data()`, * or the value itself when it is already the model. * * @param mixed $event MeprEvent or a model. */ public static function model( $event ): ?object { if ( ! is_object( $event ) ) { return null; } if ( method_exists( $event, 'get_data' ) ) { $data = $event->get_data(); return is_object( $data ) ? $data : null; } return isset( $event->user_id ) ? $event : null; } /** * @param string $hook The hook that fired. * @param mixed $event Its argument. */ private static function log( string $hook, $event ): void { $model = self::model( $event ); if ( null === $model ) { return; } $membership = isset( $model->product_id ) ? People::id( $model->product_id ) : 0; list( $type, $format, $id_key ) = self::HOOKS[ $hook ]; $details = array( 'plugin' => self::PLUGIN, 'membership_id' => $membership, ); if ( isset( $model->id ) && is_numeric( $model->id ) ) { $details[ $id_key ] = (int) $model->id; } People::log( $type, $format, isset( $model->user_id ) ? People::id( $model->user_id ) : 0, $membership > 0 ? People::post_title( $membership ) : 'unknown', $details ); } }