MS_Model_Membership

Membership model.

Defined (1)

The class is defined in the following location(s).

/app/model/class-ms-model-membership.php  
  1. class MS_Model_Membership extends MS_Model_CustomPostType { 
  2.  
  3. /** 
  4. * Model custom post type. 
  5. * @since 1.0.0 
  6. * @internal self::get_post_type() to get this value! 
  7. * @var string $POST_TYPE 
  8. */ 
  9. protected static $POST_TYPE = 'ms_membership'; 
  10.  
  11. /** 
  12. * Membership type constant. 
  13. * @since 1.0.0 
  14. * @see $type $type property. 
  15. */ 
  16. const TYPE_STANDARD = 'simple'; 
  17.  
  18. /** 
  19. * Membership type constant. 
  20. * @since 1.0.0 
  21. * @see $type $type property. 
  22. */ 
  23. const TYPE_DRIPPED = 'dripped'; 
  24.  
  25. /** 
  26. * Membership type constant. 
  27. * System membership, hidden, created automatically. 
  28. * @since 1.0.0 
  29. * @see $type $type property. 
  30. */ 
  31. const TYPE_BASE = 'base'; 
  32.  
  33. /** 
  34. * Membership type constant. 
  35. * Guest membership, only one membership possible. 
  36. * @since 1.0.0 
  37. * @see $type $type property. 
  38. */ 
  39. const TYPE_GUEST = 'guest'; 
  40.  
  41. /** 
  42. * Membership type constant. 
  43. * User membership, only one membership possible. 
  44. * @since 1.0.0 
  45. * @see $type $type property. 
  46. */ 
  47. const TYPE_USER = 'user'; 
  48.  
  49. /** 
  50. * Membership payment type constants. 
  51. * @since 1.0.0 
  52. * @see $payment_type $payment_type property. 
  53. */ 
  54. const PAYMENT_TYPE_PERMANENT = 'permanent'; 
  55.  
  56. /** 
  57. * Membership payment type constants. 
  58. * @since 1.0.0 
  59. * @see $payment_type $payment_type property. 
  60. */ 
  61. const PAYMENT_TYPE_FINITE = 'finite'; 
  62.  
  63. /** 
  64. * Membership payment type constants. 
  65. * @since 1.0.0 
  66. * @see $payment_type $payment_type property. 
  67. */ 
  68. const PAYMENT_TYPE_DATE_RANGE = 'date-range'; 
  69.  
  70. /** 
  71. * Membership payment type constants. 
  72. * The only type that auto-renews without asking the user! 
  73. * @since 1.0.0 
  74. * @see $payment_type $payment_type property. 
  75. */ 
  76. const PAYMENT_TYPE_RECURRING = 'recurring'; 
  77.  
  78. /** 
  79. * Membership type. 
  80. * Default is TYPE_STANDARD. 
  81. * @since 1.0.0 
  82. * @var string $type 
  83. */ 
  84. protected $type = self::TYPE_STANDARD; 
  85.  
  86. /** 
  87. * Membership payment type. 
  88. * Default is PAYMENT_TYPE_PERMANENT. 
  89. * @since 1.0.0 
  90. * @var string $payment_type 
  91. */ 
  92. protected $payment_type = self::PAYMENT_TYPE_PERMANENT; 
  93.  
  94. /** 
  95. * Membership active status. 
  96. * By default a new membership is active. 
  97. * @since 1.0.0 
  98. * @var bool $active 
  99. */ 
  100. protected $active = true; 
  101.  
  102. /** 
  103. * Membership private status. 
  104. * Private means that the membership will not be displayed on the default 
  105. * registration page and membership list. 
  106. * Users can still stubscribe to the membership via the shortcode 
  107. * [ms-membership-buy] or by otherwise reaching the subscription URL. 
  108. * @since 1.0.0 
  109. * @var bool $private 
  110. */ 
  111. protected $private = false; 
  112.  
  113. /** 
  114. * A priority value that is used to determine the effective override 
  115. * settings if a user has multiple memberships. 
  116. * @since 1.0.1.0 
  117. * @var int $priority 
  118. */ 
  119. protected $priority = 0; 
  120.  
  121. /** 
  122. * Membership free status. 
  123. * @since 1.0.0 
  124. * @var bool $free. 
  125. */ 
  126. protected $is_free = false; 
  127.  
  128. /** 
  129. * Membership price. 
  130. * @since 1.0.0 
  131. * @var float $price. 
  132. */ 
  133. protected $price = 0; 
  134.  
  135. /** 
  136. * A list of disabled gateways. 
  137. * @since 1.0.0 
  138. * @var array $disabled_gateways. 
  139. */ 
  140. protected $disabled_gateways = array(); 
  141.  
  142. /** 
  143. * Membership period for finite access. 
  144. * Used for payment_type PAYMENT_TYPE_FINITE. 
  145. * @since 1.0.0 
  146. * @see $payment_type $payment_type property. 
  147. * @var array $period { 
  148. * @type int $period_unit The period of time quantity. 
  149. * @type string $period_type The period type (days, weeks, months, years). 
  150. * } 
  151. */ 
  152. protected $period = array( 'period_unit' => 1, 'period_type' => 'days' ); 
  153.  
  154. /** 
  155. * Membership payment recurring period cycle. 
  156. * Used for the payment_type PAYMENT_TYPE_RECURRING. 
  157. * @since 1.0.0 
  158. * @see $payment_type $payment_type property. 
  159. * @var array $pay_cycle_period {@see $period $period property}. 
  160. */ 
  161. protected $pay_cycle_period = array( 'period_unit' => 1, 'period_type' => 'days' ); 
  162.  
  163. /** 
  164. * Defines how many payments are made before the membership ends. 
  165. * Used for the payment_type PAYMENT_TYPE_RECURRING. 
  166. * @since 1.0.0 
  167. * @see $payment_type $payment_type property. 
  168. * @var int 
  169. */ 
  170. protected $pay_cycle_repetitions = 0; 
  171.  
  172. /** 
  173. * Membership start date for date range payment type. 
  174. * Used for the payment_type PAYMENT_TYPE_DATE_RANGE. 
  175. * @since 1.0.0 
  176. * @see $payment_type $payment_type property. 
  177. * @var string The membership start date. 
  178. */ 
  179. protected $period_date_start = ''; 
  180.  
  181. /** 
  182. * Membership end date for date range payment type. 
  183. * Used for the payment_type PAYMENT_TYPE_DATE_RANGE. 
  184. * @since 1.0.0 
  185. * @see $payment_type $payment_type property. 
  186. * @var string The membership end date. 
  187. */ 
  188. protected $period_date_end = ''; 
  189.  
  190. /** 
  191. * Membership trial period enabled indicator. 
  192. * Requires the Trial Period Add-on to work. 
  193. * @since 1.0.0 
  194. * @var bool $trial_period_enabled. 
  195. */ 
  196. protected $trial_period_enabled = false; 
  197.  
  198. /** 
  199. * Membership trial price value. 
  200. * Requires the Trial Period Add-on to work. 
  201. * @since 1.0.0 
  202. * @internal This property has no effect yet. 
  203. * @var float $trial_price. 
  204. */ 
  205. protected $trial_price = 0; 
  206.  
  207. /** 
  208. * Membership trial period. 
  209. * @since 1.0.0 
  210. * @var array $trial_period {@see $period $period property}. 
  211. */ 
  212. protected $trial_period = array( 'period_unit' => 1, 'period_type' => 'days' ); 
  213.  
  214. /** 
  215. * Move to Membership when the current one expires. 
  216. * After current membership expire move to the indicated membership_id. 
  217. * This membership is assigned when the current membership expires. 
  218. * @see MS_Model_Relationship::check_membership_status() 
  219. * @since 1.0.0 
  220. * @var int $on_end_membership_id. 
  221. */ 
  222. protected $on_end_membership_id = 0; 
  223.  
  224. /** 
  225. * Membership setup completed flag. 
  226. * We need this to determine if payment options of the membership are edited 
  227. * the first time during the setup assistant, or later via the membership 
  228. * list. 
  229. * @since 1.0.0 
  230. * @internal 
  231. * @var bool $is_setup_completed. 
  232. */ 
  233. protected $is_setup_completed = false; 
  234.  
  235. /** 
  236. * Where the data came from. Can only be changed by data import tool. 
  237. * @since 1.0.0 
  238. * @internal 
  239. * @var string 
  240. */ 
  241. protected $source = ''; 
  242.  
  243. /** 
  244. * Relevant for imported items. This is the ID that was used by the import 
  245. * source. 
  246. * @since 1.0.1.0 
  247. * @internal 
  248. * @var string 
  249. */ 
  250. protected $source_id = ''; 
  251.  
  252. /** 
  253. * Membership composite Rules. 
  254. * These are protection rules for this membership only. 
  255. * Network-wide mode: The rules stored in here are the rules that apply 
  256. * to the currently selected site in the network! 
  257. * Example: 
  258. * When the network has 10 sites then $rule_values will have 10 "page" rules 
  259. * which are stored as "1:page", "2:page", ... 
  260. * However, the $_rules property will only have ONE "page" rule, and that's 
  261. * the one for the currently visible site! 
  262. * @since 1.0.0 
  263. * @internal 
  264. * @var array MS_Rule[]. 
  265. */ 
  266. protected $_rules = array(); 
  267.  
  268. /** 
  269. * Only used for serialization of the membership. 
  270. * @see __sleep() 
  271. * @since 1.0.0 
  272. * @internal 
  273. * @var array 
  274. */ 
  275. protected $rule_values = array(); 
  276.  
  277. /** 
  278. * Defines which members can NOT subscribe to the current membership. 
  279. * @since 1.0.1.0 
  280. * @internal 
  281. * @var array 
  282. */ 
  283. protected $update_denied = array(); 
  284.  
  285. /** 
  286. * Defines if the current membership replaces other memberships on 
  287. * subscription. 
  288. * @since 1.0.1.0 
  289. * @internal 
  290. * @var array 
  291. */ 
  292. protected $update_replace = array(); 
  293.  
  294. /** 
  295. * An internal counter that is increased every time membership details are 
  296. * changed. 
  297. * @since 1.0.3.0 
  298. * @internal 
  299. * @var int 
  300. */ 
  301. protected $revision = 0; 
  302.  
  303. /** 
  304. * Used in simulation mode explaining why a page is allowed or denied. 
  305. * @since 1.0.0 
  306. * @internal 
  307. * @var array 
  308. */ 
  309. public $_access_reason = array(); 
  310.  
  311. /** 
  312. * Similar to $_access_reason, but only contains the rules that denied page 
  313. * access. 
  314. * @since 1.0.0 
  315. * @internal 
  316. * @var array 
  317. */ 
  318. public $_deny_rule = array(); 
  319.  
  320. /** 
  321. * Similar to $_access_reason, but only contains the rules that allowed page 
  322. * access. 
  323. * @since 1.0.0 
  324. * @internal 
  325. * @var array 
  326. */ 
  327. public $_allow_rule = array(); 
  328.  
  329. /** 
  330. * Stores the subscription-ID of the parent object. 
  331. * This value will only have a value when the Membership is loaded within 
  332. * the context of a subscription. 
  333. * @since 1.0.0 
  334. * @var int 
  335. */ 
  336. protected $subscription_id = 0; 
  337.  
  338. /** 
  339. * This property is used to build the signup list (shortcode). 
  340. * It's a temporary value that is not saved to database. 
  341. * @since 1.0.1.0 
  342. * @internal 
  343. * @var array 
  344. */ 
  345. public $_move_from = array(); 
  346.  
  347.  
  348. // 
  349. // 
  350. // 
  351. // -------------------------------------------------------------- COLLECTION 
  352.  
  353.  
  354. /** 
  355. * Returns the post-type of the current object. 
  356. * @since 1.0.0 
  357. * @api 
  358. * @return string The post-type name. 
  359. */ 
  360. public static function get_post_type() { 
  361. return parent::_post_type( self::$POST_TYPE ); 
  362.  
  363. /** 
  364. * Get custom register post type args for this model. 
  365. * @since 1.0.0 
  366. * @internal 
  367. */ 
  368. public static function get_register_post_type_args() { 
  369. $args = array( 
  370. 'label' => __( 'Membership2 Memberships', 'membership2' ),  
  371. 'description' => __( 'Memberships user can join to.', 'membership2' ),  
  372. 'show_ui' => false,  
  373. 'show_in_menu' => false,  
  374. 'menu_position' => 70, // below Users 
  375. 'menu_icon' => 'dashicons-lock',  
  376. 'public' => true,  
  377. 'has_archive' => false,  
  378. 'publicly_queryable' => false,  
  379. 'supports' => false,  
  380. 'hierarchical' => false,  
  381. 'exclude_from_search' => true 
  382. ); 
  383.  
  384. return apply_filters( 
  385. 'ms_customposttype_register_args',  
  386. $args,  
  387. self::get_post_type() 
  388. ); 
  389.  
  390. /** 
  391. * Get membership types. 
  392. * @since 1.0.0 
  393. * @internal 
  394. * @return array { 
  395. * Returns array of $type => $title. 
  396. * @type string $type The membership type 
  397. * @type string $title The membership type title 
  398. * } 
  399. */ 
  400. static public function get_types() { 
  401. $types = array( 
  402. self::TYPE_STANDARD => __( 'Standard Membership', 'membership2' ),  
  403. self::TYPE_DRIPPED => __( 'Dripped Content Membership', 'membership2' ),  
  404. self::TYPE_GUEST => __( 'Guest Membership', 'membership2' ),  
  405. self::TYPE_USER => __( 'Default Membership', 'membership2' ),  
  406. self::TYPE_BASE => __( 'System Membership', 'membership2' ),  
  407. ); 
  408.  
  409. return apply_filters( 'ms_model_membership_get_types', $types ); 
  410.  
  411. /** 
  412. * Get membership payment types. 
  413. * @since 1.0.0 
  414. * @internal 
  415. * @return array { 
  416. * Returns array of $type => $title. 
  417. * @type string $type The membership payment type 
  418. * @type string $title The membership payment type title 
  419. * } 
  420. */ 
  421. public static function get_payment_types( $type = 'paid' ) { 
  422. if ( 'free' == $type ) { 
  423. $payment_types = array( 
  424. self::PAYMENT_TYPE_PERMANENT => __( 'Permanent access', 'membership2' ),  
  425. self::PAYMENT_TYPE_FINITE => __( 'Finite access', 'membership2' ),  
  426. self::PAYMENT_TYPE_DATE_RANGE => __( 'Date range access', 'membership2' ),  
  427. ); 
  428. } else { 
  429. $payment_types = array( 
  430. self::PAYMENT_TYPE_PERMANENT => __( 'One payment for permanent access', 'membership2' ),  
  431. self::PAYMENT_TYPE_FINITE => __( 'One payment for finite access', 'membership2' ),  
  432. self::PAYMENT_TYPE_DATE_RANGE => __( 'One payment for date range access', 'membership2' ),  
  433. self::PAYMENT_TYPE_RECURRING => __( 'Recurring payments', 'membership2' ),  
  434. ); 
  435.  
  436. return apply_filters( 
  437. 'ms_model_membership_get_payment_types',  
  438. $payment_types,  
  439. $type 
  440. ); 
  441.  
  442. /** 
  443. * Get available Memberships count. 
  444. * @since 1.0.0 
  445. * @internal 
  446. * @param $args The query post args 
  447. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  448. * @return int The membership count. 
  449. */ 
  450. public static function get_membership_count( $args = null ) { 
  451. $ids = self::get_membership_ids( $args ); 
  452. $count = count( $ids ); 
  453.  
  454. return apply_filters( 
  455. 'ms_model_membership_get_membership_count',  
  456. $count,  
  457. $args 
  458. ); 
  459.  
  460. /** 
  461. * Find out if the installation has at least one paid membership 
  462. * @since 1.0.0 
  463. * @internal 
  464. * @return bool 
  465. */ 
  466. public static function have_paid_membership() { 
  467. static $Have_Paid = null; 
  468.  
  469. if ( null === $Have_Paid ) { 
  470. global $wpdb; 
  471. // Using a custom WPDB query because building the meta-query is more 
  472. // complex than really required here... 
  473. $sql = " 
  474. SELECT COUNT( 1 ) 
  475. FROM {$wpdb->posts} p 
  476. INNER JOIN {$wpdb->postmeta} free ON free.post_id = p.ID AND free.meta_key = %s 
  477. INNER JOIN {$wpdb->postmeta} pric ON pric.post_id = p.ID AND pric.meta_key = %s 
  478. INNER JOIN {$wpdb->postmeta} acti ON acti.post_id = p.ID AND acti.meta_key = %s 
  479. WHERE 
  480. p.post_type = %s 
  481. AND acti.meta_value = '1' 
  482. AND NOT ( 
  483. free.meta_value = '1' 
  484. OR pric.meta_value = '0' 
  485. "; 
  486.  
  487. $sql = $wpdb->prepare( 
  488. $sql,  
  489. 'is_free', // INNER JOIN 
  490. 'price', // INNER JOIN 
  491. 'active', // INNER JOIN 
  492. self::get_post_type() // WHERE condition 
  493. ); 
  494.  
  495. $res = $wpdb->get_var( $sql ); 
  496.  
  497. $Have_Paid = apply_filters( 
  498. 'ms_model_membership_have_paid_membership',  
  499. intval( $res ) > 0 
  500. ); 
  501.  
  502. return $Have_Paid; 
  503.  
  504. /** 
  505. * Get WP_Query object arguments. 
  506. * Default search arguments for this custom post_type. 
  507. * @since 1.0.0 
  508. * @internal 
  509. * @param $args The query post args 
  510. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  511. * @return array $args The parsed args. 
  512. */ 
  513. public static function get_query_args( $args = null ) { 
  514. $defaults = apply_filters( 
  515. 'ms_model_membership_get_query_args_defaults',  
  516. array( 
  517. 'post_type' => self::get_post_type(),  
  518. 'order' => 'ASC',  
  519. 'orderby' => 'menu_order',  
  520. 'post_status' => 'any',  
  521. 'post_per_page' => -1,  
  522. 'nopaging' => true,  
  523. 'include_base' => false,  
  524. 'include_guest' => true,  
  525. ); 
  526.  
  527. $args = wp_parse_args( $args, $defaults ); 
  528.  
  529. if ( isset( $args['active'] ) ) { 
  530. $args['meta_query']['active'] = array( 
  531. 'key' => 'active',  
  532. 'value' => 1,  
  533. ); 
  534.  
  535. if ( lib3()->is_true( $args['active'] ) ) { 
  536. $args['meta_query']['active']['compare'] = '='; 
  537. } else { 
  538. $args['meta_query']['active']['compare'] = '!='; 
  539.  
  540. if ( ! lib3()->is_true( $args['include_base'] ) ) { 
  541. $args['meta_query']['base'] = array( 
  542. 'key' => 'type',  
  543. 'value' => self::TYPE_BASE,  
  544. 'compare' => '!=',  
  545. ); 
  546.  
  547. if ( ! lib3()->is_true( $args['include_guest'] ) ) { 
  548. $args['meta_query']['guest'] = array( 
  549. 'key' => 'type',  
  550. 'value' => self::TYPE_GUEST,  
  551. 'compare' => '!=',  
  552. ); 
  553. $args['meta_query']['user'] = array( 
  554. 'key' => 'type',  
  555. 'value' => self::TYPE_USER,  
  556. 'compare' => '!=',  
  557. ); 
  558.  
  559. return apply_filters( 
  560. 'ms_model_membership_get_query_args',  
  561. $args,  
  562. $defaults 
  563. ); 
  564.  
  565. /** 
  566. * Returns a list of Membership IDs that match the given WP_Query arguments. 
  567. * @since 1.0.1.0 
  568. * @internal 
  569. * @param $args The query post args. 
  570. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  571. * @return array A list of membership IDs. 
  572. */ 
  573. static public function get_membership_ids( $args = null ) { 
  574. static $Membership_IDs = array(); 
  575. $args = self::get_query_args( $args ); 
  576. $key = md5( json_encode( $args ) ); 
  577.  
  578. if ( ! isset( $Membership_IDs[ $key ] ) ) { 
  579. $Membership_IDs[ $key ] = array(); 
  580.  
  581. MS_Factory::select_blog(); 
  582. $query = new WP_Query( $args ); 
  583. $items = $query->posts; 
  584. MS_Factory::revert_blog(); 
  585.  
  586. /** 
  587. * We only cache the IDs to avoid re-querying the database. 
  588. * The positive side effect is, that the memory used by the 
  589. * membership list will be freed again after the calling function 
  590. * is done with it. 
  591. * If we cache the whole list here, it would not occupy memory for 
  592. * the whole request duration which can cause memory_limit errors. 
  593. * @see MS_Model_Relationship::get_subscriptions() 
  594. */ 
  595. foreach ( $items as $item ) { 
  596. $Membership_IDs[ $key ][] = $item->ID; 
  597.  
  598. return apply_filters( 
  599. 'ms_model_membership_get_membership_ids',  
  600. $Membership_IDs[ $key ],  
  601. $args 
  602. ); 
  603.  
  604. /** 
  605. * Get Memberships models. 
  606. * When no $args are specified then all memberships except the base 
  607. * membership will be returned. 
  608. * To include the base membership use: 
  609. * $args = array( 'include_base' => 1 ) 
  610. * To exclude the guest membership use: 
  611. * $args = array( 'include_guest' => 0 ) 
  612. * @since 1.0.0 
  613. * @internal 
  614. * @param $args The query post args 
  615. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  616. * @return MS_Model_Membership[] The selected memberships. 
  617. */ 
  618. static public function get_memberships( $args = null ) { 
  619. $ids = self::get_membership_ids( $args ); 
  620. $memberships = array(); 
  621.  
  622. foreach ( $ids as $id ) { 
  623. $memberships[] = MS_Factory::load( 
  624. 'MS_Model_Membership',  
  625. $id 
  626. ); 
  627.  
  628. return apply_filters( 
  629. 'ms_model_membership_get_memberships',  
  630. $memberships,  
  631. $args 
  632. ); 
  633.  
  634. /** 
  635. * Returns a list of the dripped memberships. 
  636. * @since 1.0.0 
  637. * @internal 
  638. * @param $args The query post args 
  639. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  640. * @return MS_Model_Membership[] The selected memberships. 
  641. */ 
  642. static public function get_dripped_memberships( $args = null ) { 
  643. $drip_args = array( 
  644. 'meta_query' => array( 
  645. array( 
  646. 'key' => 'type',  
  647. 'value' => self::TYPE_DRIPPED,  
  648. ),  
  649. ),  
  650. ); 
  651.  
  652. $drip_args = wp_parse_args( $drip_args, $args ); 
  653. $memberships = self::get_memberships( $drip_args ); 
  654.  
  655. return apply_filters( 
  656. 'ms_model_membership_get_dripped_memberships',  
  657. $memberships,  
  658. $args 
  659. ); 
  660.  
  661. /** 
  662. * Get membership names. 
  663. * Note that this function returns an array with membership_id as index,  
  664. * while the function get_memberships() returns an array with sort-order as 
  665. * index. 
  666. * @since 1.0.0 
  667. * @internal 
  668. * @param $args The query post args 
  669. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  670. * @param bool $include_base_membership Include base membership from the list. 
  671. * @return array { 
  672. * Returns array of $membership_id => $name 
  673. * @type int $membership_id The membership Id. 
  674. * @type string $name The membership name; 
  675. * } 
  676. */ 
  677. public static function get_membership_names( $args = null ) { 
  678. $items = self::get_memberships( $args ); 
  679.  
  680. $memberships = array(); 
  681. foreach ( $items as $item ) { 
  682. $memberships[ $item->id ] = $item->name; 
  683.  
  684. return apply_filters( 
  685. 'ms_model_membership_get_membership_names',  
  686. $memberships,  
  687. $args 
  688. ); 
  689.  
  690. /** 
  691. * Get membership eligible to signup. 
  692. * This function also checks for membership permissions and only display 
  693. * memberships that are available for the current member. 
  694. * @since 1.0.0 
  695. * @internal 
  696. * @param $args The query post args 
  697. * @see @link http://codex.wordpress.org/Class_Reference/WP_Query 
  698. * @param int[] $exclude_ids Optional. The membership ids to exclude. 
  699. * @param bool $only_names Optional. Return only array { 
  700. * @type int $membership_id The membership ID. 
  701. * @type string $membership_name The membership name. 
  702. * } 
  703. * @param bool $include_private If private memberships should be listed 
  704. * This param is only recognized in the admin section so admins can 
  705. * manually assign a private membership to a user. 
  706. * @return array Returns sorted array of memberships. Sorted by priority. 
  707. */ 
  708. public static function get_signup_membership_list( 
  709. $args = null,  
  710. $exclude_ids = null,  
  711. $only_names = false,  
  712. $include_private = false 
  713. ) { 
  714. $not_in = array(); 
  715. if ( is_array( $exclude_ids ) ) { 
  716. $not_in = $exclude_ids; 
  717. $args['post__not_in'] = array_unique( $not_in ); 
  718. $member = MS_Model_Member::get_current_member(); 
  719.  
  720. if ( ! is_admin() ) { 
  721. $include_private = false; 
  722. // List of private memberships (they are grouped in own array). 
  723. $private = array(); 
  724.  
  725. // Retrieve memberships user is not part of, using selected args 
  726. $memberships = self::get_memberships( $args ); 
  727.  
  728. // Check the upgrade-paths settings 
  729. foreach ( $memberships as $key => $ms ) { 
  730. if ( $ms->is_system() ) { 
  731. unset( $memberships[ $key ] ); 
  732. } elseif ( ! $member->can_subscribe_to( $ms->id ) ) { 
  733. unset( $memberships[ $key ] ); 
  734.  
  735. // Filter memberships based on status. 
  736. $order = array(); 
  737. foreach ( $memberships as $key => $membership ) { 
  738. // Remove if not active. 
  739. if ( ! $membership->active ) { 
  740. unset( $memberships[ $key ] ); 
  741. continue; 
  742.  
  743. if ( $membership->private ) { 
  744. if ( $include_private ) { 
  745. // Move the private memberships to a option-group. 
  746. $private[ $key ] = $memberships[ $key ]; 
  747. unset( $memberships[ $key ] ); 
  748. continue; 
  749.  
  750. if ( $only_names ) { 
  751. $ms_names = array(); 
  752. foreach ( $memberships as $ms ) { 
  753. $ms_names[ $ms->id ] = $ms->name; 
  754. if ( ! empty( $private ) ) { 
  755. $priv_key = __( 'Private Memberships', 'membership2' ); 
  756. $ms_names[ $priv_key ] = array(); 
  757. foreach ( $private as $ms ) { 
  758. $ms_names[ $priv_key ][ $ms->id ] = $ms->name; 
  759. $memberships = $ms_names; 
  760. } else { 
  761. $memberships = array_merge( $memberships, $private ); 
  762.  
  763. // Sort memberships by priority. 
  764. usort( 
  765. $memberships,  
  766. array( __CLASS__, 'sort_by_priority' ) 
  767. ); 
  768.  
  769. return apply_filters( 
  770. 'ms_model_membership_get_signup_membership_list',  
  771. $memberships,  
  772. $exclude_ids,  
  773. $only_names 
  774. ); 
  775.  
  776. /** 
  777. * Sort function used as second param by `uasort()` to sort a membership 
  778. * list by priority. 
  779. * Memberships with equal priority are sorted alphabeically. 
  780. * @since 1.0.1.0 
  781. * @param MS_Model_Membership $a 
  782. * @param MS_Model_Membership $b 
  783. * @return int -1: a < b | 0: a = b | +1: a > b 
  784. */ 
  785. static public function sort_by_priority( $a, $b ) { 
  786. if ( $a->priority == $b->priority ) { 
  787. return $a->name < $b->name ? -1 : 1; 
  788. } else { 
  789. return $a->priority - $b->priority; 
  790.  
  791. /** 
  792. * Verify if membership is valid. 
  793. * Verify if membership was not deleted, trying to load from DB. 
  794. * @since 1.0.0 
  795. * @api 
  796. * @param int $membership_id The membership id to verify. 
  797. * @return bool True if is valid. 
  798. */ 
  799. public static function is_valid_membership( $membership_id ) { 
  800. $membership = MS_Factory::load( 'MS_Model_Membership', $membership_id, '_is_valid_' ); 
  801. $valid = ( $membership->id > 0 ); 
  802.  
  803. return apply_filters( 
  804. 'ms_model_membership_is_valid_membership',  
  805. $valid,  
  806. $membership_id 
  807. ); 
  808.  
  809. /** 
  810. * Get Membership2 membership. 
  811. * Create a new membership if membership does not exist. 
  812. * @since 1.0.0 
  813. * @internal 
  814. * @param string $type The membership to load [protected_content|role] 
  815. * @param book $create_missing If set to false then missing special 
  816. * memberships are not created. 
  817. * @return MS_Model_Membership The Membership2. 
  818. */ 
  819. public static function _get_system_membership( $type, $create_missing = true ) { 
  820. static $Special_Membership = array(); 
  821. $comp_key = $type; 
  822. $membership = false; 
  823.  
  824. if ( ! isset( $Special_Membership[ $comp_key ] ) ) { 
  825. $membership = false; 
  826. global $wpdb; 
  827.  
  828. MS_Factory::select_blog(); 
  829. /** 
  830. * We are using a normal SQL query instead of using the WP_Query object 
  831. * here, because the WP_Query object does some strange things sometimes: 
  832. * In some cases new Membership2 memberships were created when a 
  833. * guest accessed the page. 
  834. * By using a manual query we are very certain that only one 
  835. * base-membership exists on the database. 
  836. */ 
  837. $sql = " 
  838. SELECT ID 
  839. FROM {$wpdb->posts} p 
  840. INNER JOIN {$wpdb->postmeta} m_type ON m_type.post_id = p.ID 
  841. WHERE 
  842. p.post_type = %s 
  843. AND m_type.meta_key = %s 
  844. AND m_type.meta_value = %s 
  845. "; 
  846. $values = array( 
  847. self::get_post_type(),  
  848. 'type',  
  849. $type,  
  850. ); 
  851.  
  852. $sql = $wpdb->prepare( $sql, $values ); 
  853. $item = $wpdb->get_results( $sql ); 
  854. $base = array_shift( $item ); // Remove the base membership from the results 
  855. MS_Factory::revert_blog(); 
  856.  
  857. if ( ! empty( $base ) ) { 
  858. $membership = MS_Factory::load( 'MS_Model_Membership', $base->ID ); 
  859. } elseif ( $create_missing ) { 
  860. $names = self::get_types(); 
  861.  
  862. $description = __( 'Membership2 Core Membership', 'membership2' ); 
  863. $membership = MS_Factory::create( 'MS_Model_Membership' ); 
  864. $membership->name = $names[ $type ]; 
  865. $membership->title = $names[ $type ]; 
  866. $membership->description = $description; 
  867. $membership->type = $type; 
  868. $membership->save(); 
  869.  
  870. $Special_Membership[ $comp_key ] = $membership; 
  871.  
  872. return apply_filters( 
  873. 'ms_model_membership_get_system_membership',  
  874. $Special_Membership[ $comp_key ],  
  875. $type 
  876. ); 
  877.  
  878. /** 
  879. * Get Membership2 base membership. 
  880. * Create a new membership if membership does not exist. 
  881. * This is an internal membership which is never displayed anywhere. 
  882. * @since 1.0.0 
  883. * @api 
  884. * @return MS_Model_Membership The base membership. 
  885. */ 
  886. public static function get_base() { 
  887. static $Base_Membership = null; 
  888.  
  889. if ( null === $Base_Membership ) { 
  890. $Base_Membership = self::_get_system_membership( 
  891. self::TYPE_BASE 
  892. ); 
  893.  
  894. foreach ( $Base_Membership->_rules as $key => $rule ) { 
  895. $Base_Membership->_rules[ $key ]->is_base_rule = true; 
  896.  
  897. return apply_filters( 
  898. 'ms_model_membership_get_base',  
  899. $Base_Membership 
  900. ); 
  901.  
  902. /** 
  903. * Get special membership that is assigned to all guests. 
  904. * Create a new membership if membership does not exist. 
  905. * @since 1.0.0 
  906. * @api 
  907. * @param string $role A WordPress user-role. 
  908. * @return MS_Model_Membership The guest membership. 
  909. */ 
  910. public static function get_guest() { 
  911. static $Guest_Membership = null; 
  912.  
  913. if ( null === $Guest_Membership ) { 
  914. $Guest_Membership = self::_get_system_membership( 
  915. self::TYPE_GUEST,  
  916. false // Don't create this membership automatically 
  917. ); 
  918.  
  919. if ( ! $Guest_Membership ) { 
  920. $Guest_Membership = MS_Factory::create( 'MS_Model_Membership' ); 
  921.  
  922. return apply_filters( 
  923. 'ms_model_membership_get_guest',  
  924. $Guest_Membership 
  925. ); 
  926.  
  927. /** 
  928. * Get default membership for all logged-in users that did not yet subscribe 
  929. * to any membership. 
  930. * Create a new membership if membership does not exist. 
  931. * @since 1.0.0 
  932. * @api 
  933. * @param string $role A WordPress user-role. 
  934. * @return MS_Model_Membership The guest membership. 
  935. */ 
  936. public static function get_user() { 
  937. static $User_Membership = null; 
  938.  
  939. if ( null === $User_Membership ) { 
  940. $User_Membership = self::_get_system_membership( 
  941. self::TYPE_USER,  
  942. false // Don't create this membership automatically 
  943. ); 
  944.  
  945. if ( ! $User_Membership ) { 
  946. $User_Membership = MS_Factory::create( 'MS_Model_Membership' ); 
  947.  
  948. return apply_filters( 
  949. 'ms_model_membership_get_user',  
  950. $User_Membership 
  951. ); 
  952.  
  953. /** 
  954. * Checks if the specified string is a valid Membership-Type identifier. 
  955. * @since 1.0.1.0 
  956. * @param string $type A string to check against all known membership types. 
  957. * @return bool True if the string is a valid type. 
  958. */ 
  959. static public function is_valid_type( $type ) { 
  960. switch ( $type ) { 
  961. case self::TYPE_BASE: 
  962. case self::TYPE_GUEST: 
  963. case self::TYPE_USER: 
  964. case self::TYPE_DRIPPED: 
  965. $result = true; 
  966. break; 
  967.  
  968. default: 
  969. $result = false; 
  970. break; 
  971.  
  972. return apply_filters( 
  973. 'ms_model_membership_is_valid_type',  
  974. $result,  
  975. $type 
  976. ); 
  977.  
  978.  
  979. // 
  980. // 
  981. // 
  982. // ------------------------------------------------------------- SINGLE ITEM 
  983.  
  984.  
  985. /** 
  986. * Returns a list of variables that should be included in serialization,  
  987. * i.e. these values are the only ones that are stored in DB 
  988. * @since 1.0.0 
  989. * @internal 
  990. * @return array 
  991. */ 
  992. public function __sleep() { 
  993. /** 
  994. * Rule values are pre-processd before saving... 
  995. * Note: $this->_rules only contains rules for the *current* site, so 
  996. * all rules that are serialized here get the current-site prefix. 
  997. * Rules for the other sites are already in the $this->rule_values 
  998. * array and were not de-serialized on page load. 
  999. */ 
  1000. $this->rule_values = lib3()->array->get( $this->rule_values ); 
  1001. foreach ( $this->_rules as $rule_type => $rule ) { 
  1002. $key = MS_Rule::rule_key( $rule_type ); 
  1003.  
  1004. $this->rule_values[ $key ] = $rule->serialize(); 
  1005. if ( empty( $this->rule_values[ $key ] ) ) { 
  1006. unset( $this->rule_values[ $key ] ); 
  1007.  
  1008. return array( 
  1009. 'id',  
  1010. 'name',  
  1011. 'title',  
  1012. 'description',  
  1013. 'rule_values',  
  1014. 'type',  
  1015. 'payment_type',  
  1016. 'active',  
  1017. 'private',  
  1018. 'is_free',  
  1019. 'disabled_gateways',  
  1020. 'price',  
  1021. 'period',  
  1022. 'pay_cycle_period',  
  1023. 'pay_cycle_repetitions',  
  1024. 'period_date_start',  
  1025. 'period_date_end',  
  1026. 'trial_period_enabled',  
  1027. 'trial_price',  
  1028. 'trial_period',  
  1029. 'on_end_membership_id',  
  1030. 'is_setup_completed',  
  1031. 'source',  
  1032. 'source_id',  
  1033. 'custom_data',  
  1034. 'update_denied',  
  1035. 'update_replace',  
  1036. 'revision',  
  1037. ); 
  1038.  
  1039. /** 
  1040. * Set rules membership_id before saving. 
  1041. * @since 1.0.0 
  1042. * @internal 
  1043. */ 
  1044. public function before_save() { 
  1045. parent::before_save(); 
  1046.  
  1047. foreach ( $this->_rules as $rule ) { 
  1048. $rule->membership_id = $this->id; 
  1049.  
  1050. if ( $this->is_valid() ) { 
  1051. $this->check_revision(); 
  1052.  
  1053. /** 
  1054. * Save model and move the object to the singleton cache if required. 
  1055. * @since 1.0.0 
  1056. */ 
  1057. public function save() { 
  1058. parent::save(); 
  1059. parent::store_singleton(); 
  1060.  
  1061. /** 
  1062. * After the membership was saved to DB we make sure that it is published. 
  1063. * Network-wide mode: We are still in the switched blog (main site) so 
  1064. * there is no need to call MS_Factory::select_blog() in this function. 
  1065. * @since 1.0.0 
  1066. * @internal 
  1067. */ 
  1068. public function after_save() { 
  1069. // It is important! The Membership2 membership must be public 
  1070. // so that the membership options are available for guest users. 
  1071. wp_publish_post( $this->id ); 
  1072.  
  1073. /** 
  1074. * Save custom values in the wp_posts table. 
  1075. * @since 1.0.1.0 
  1076. * @internal 
  1077. */ 
  1078. public function save_post_data( $post ) { 
  1079. if ( $this->is_system() ) { 
  1080. $this->priority = 0; 
  1081. } elseif ( $this->priority < 1 ) { 
  1082. $this->priority = 1; 
  1083.  
  1084. $post['menu_order'] = $this->priority; 
  1085. return $post; 
  1086.  
  1087. /** 
  1088. * Called by the before_save() function to detect what kind of revision 
  1089. * was made (i.e. which values were changed). 
  1090. * This is used by the stripe gateway to sync membership infos with Stripe. 
  1091. * @since 1.0.3.0 
  1092. */ 
  1093. public function check_revision() { 
  1094. // Changes of these values are not counted as "revision". 
  1095. $ignore = array( 
  1096. 'revision',  
  1097. 'id',  
  1098. 'is_setup_completed',  
  1099. 'post_modified',  
  1100. 'source',  
  1101. 'source_id',  
  1102. 'subscription_id',  
  1103. 'title',  
  1104. 'user_id',  
  1105. ); 
  1106.  
  1107. $new_revision = false; 
  1108. $changes = array(); 
  1109. if ( empty( $this->revision ) ) { $this->revision = 0; } 
  1110.  
  1111. foreach ( $this->_saved_data as $field => $old_value ) { 
  1112. if ( in_array( $field, $ignore ) ) { continue; } 
  1113.  
  1114. $new_value = $this->$field; 
  1115. if ( ! is_scalar( $old_value ) ) { 
  1116. $old_value = json_encode( $old_value ); 
  1117. if ( ! is_scalar( $new_value ) ) { 
  1118. $new_value = json_encode( $new_value ); 
  1119.  
  1120. if ( $old_value == $new_value ) { continue; } 
  1121.  
  1122. $new_revision = true; 
  1123. $changes[] = $field; 
  1124.  
  1125. /** 
  1126. * Notification that a specific field of the membership changed. 
  1127. * @since 1.0.3.0 
  1128. * @param MS_Model_Membership The membership object (this). 
  1129. * @param mixed The old value, might be serialized. 
  1130. * @param mixed The new value. 
  1131. */ 
  1132. do_action( 
  1133. 'ms_model_membership_revision_change-' . $field,  
  1134. $this,  
  1135. $old_value,  
  1136. $this->$field 
  1137. ); 
  1138.  
  1139. if ( $new_revision ) { 
  1140. $this->revision += 1; 
  1141.  
  1142. /** 
  1143. * Notification that any field of the membership has changed. 
  1144. * @since 1.0.3.0 
  1145. * @param MS_Model_Membership The membership object (this). 
  1146. * @param array List of changed fields (only field-names). 
  1147. */ 
  1148. do_action( 
  1149. 'ms_model_membership_revision_change',  
  1150. $this,  
  1151. $changes 
  1152. ); 
  1153.  
  1154. /** 
  1155. * Load custom values from the wp_posts table. 
  1156. * @since 1.0.1.0 
  1157. * @internal 
  1158. */ 
  1159. public function load_post_data( $post ) { 
  1160. $this->priority = $post->menu_order; 
  1161.  
  1162. /** 
  1163. * Permanently delete the membership. 
  1164. * @since 1.0.0 
  1165. * @api 
  1166. * @return bool 
  1167. */ 
  1168. public function delete() { 
  1169. do_action( 'ms_model_membership_before_delete', $this ); 
  1170. $res = false; 
  1171.  
  1172. if ( $this->is_base() ) { 
  1173. throw new Exception( 
  1174. 'Can not delete the system membership.' 
  1175. ); 
  1176.  
  1177. if ( ! empty( $this->id ) ) { 
  1178. if ( $this->get_members_count() > 0 ) { 
  1179. $subscriptions = MS_Model_Relationship::get_subscriptions( 
  1180. array( 'membership_id' => $this->id ),  
  1181. true 
  1182. ); 
  1183.  
  1184. foreach ( $subscriptions as $subscription ) { 
  1185. $subscription->delete(); 
  1186.  
  1187. $res = ( false !== wp_delete_post( $this->id, true ) ); 
  1188.  
  1189. do_action( 'ms_model_membership_after_delete', $this, $res ); 
  1190. return $res; 
  1191.  
  1192. /** 
  1193. * Merge current rules to Membership2. 
  1194. * Assure the membership rules get updated whenever Membership2 is changed. 
  1195. * @since 1.0.0 
  1196. * @internal 
  1197. */ 
  1198. public function prepare_obj() { 
  1199. parent::prepare_obj(); 
  1200.  
  1201. if ( false !== strpos( $this->_factory_id, '_is_valid_' ) ) { 
  1202. // This object only checks if the item ID is valid. 
  1203. // No need to load any rules yet... 
  1204. return; 
  1205.  
  1206. foreach ( $this->rule_values as $key => $values ) { 
  1207. // Skip rules without any values. 
  1208. if ( empty( $values ) ) { continue; } 
  1209.  
  1210. // Network-wide: Only instanciate rules for the *current* site! 
  1211. if ( ! MS_Rule::is_current_site( $key ) ) { continue; } 
  1212.  
  1213. // Key could be "type" of "site:type" format. 
  1214. $rule_type = MS_Rule::rule_type( $key ); 
  1215.  
  1216. // At this point we have an empty rule-instance 
  1217. $rule = $this->get_rule( $rule_type ); 
  1218.  
  1219. // Now we populate that rule-instance with site-specific settings. 
  1220. $rule->populate( $values ); 
  1221.  
  1222. // validate rules using Membership2 rules 
  1223. if ( ! $this->is_base() && $this->is_valid() ) { 
  1224. $this->merge_protection_rules(); 
  1225.  
  1226. /** 
  1227. * Get current payment type description. 
  1228. * Description to show in the admin list table. 
  1229. * @since 1.0.0 
  1230. * @api 
  1231. * @return string The current payment type description. 
  1232. */ 
  1233. public function get_payment_type_desc() { 
  1234. $desc = __( 'N/A', 'membership2' ); 
  1235. $has_payment = ! $this->is_free(); 
  1236.  
  1237. switch ( $this->payment_type ) { 
  1238. case self::PAYMENT_TYPE_FINITE: 
  1239. if ( $has_payment ) { 
  1240. $desc = sprintf( 
  1241. __( 'Pay for %1$s', 'membership2' ),  
  1242. MS_Helper_Period::get_period_desc( $this->period, true ) 
  1243. ); 
  1244. } else { 
  1245. $desc = sprintf( 
  1246. __( 'Free for %1$s', 'membership2' ),  
  1247. MS_Helper_Period::get_period_desc( $this->period, true ) 
  1248. ); 
  1249. break; 
  1250.  
  1251. case self::PAYMENT_TYPE_DATE_RANGE: 
  1252. if ( $has_payment ) { 
  1253. $desc = sprintf( 
  1254. __( 'Pay from %1$s to %2$s', 'membership2' ),  
  1255. $this->period_date_start,  
  1256. $this->period_date_end 
  1257. ); 
  1258. } else { 
  1259. $desc = sprintf( 
  1260. __( 'Free from %1$s to %2$s', 'membership2' ),  
  1261. $this->period_date_start,  
  1262. $this->period_date_end 
  1263. ); 
  1264. break; 
  1265.  
  1266. case self::PAYMENT_TYPE_RECURRING: 
  1267. if ( $has_payment ) { 
  1268. $desc = __( 'Pay each %1$s', 'membership2' ); 
  1269. if ( 1 == $this->pay_cycle_repetitions ) { 
  1270. $desc = __( 'Single payment', 'membership2' ); 
  1271. } elseif ( $this->pay_cycle_repetitions > 1 ) { 
  1272. $desc .= ', ' . __( '%2$s payments', 'membership2' ); 
  1273. } else { 
  1274. $desc = __( 'Free access', 'membership2' ); 
  1275.  
  1276. $desc = sprintf( 
  1277. $desc,  
  1278. MS_Helper_Period::get_period_desc( $this->pay_cycle_period ),  
  1279. $this->pay_cycle_repetitions 
  1280. ); 
  1281. break; 
  1282.  
  1283. case self::PAYMENT_TYPE_PERMANENT: 
  1284. default: 
  1285. if ( $has_payment ) { 
  1286. $desc = __( 'Single payment', 'membership2' ); 
  1287. } else { 
  1288. $desc = __( 'Free access', 'membership2' ); 
  1289. break; 
  1290.  
  1291. return apply_filters( 
  1292. 'ms_model_membership_get_payment_type_desc',  
  1293. $desc,  
  1294. $this 
  1295. ); 
  1296.  
  1297. /** 
  1298. * Returns true if the current membership is free. 
  1299. * A membership is free when... 
  1300. * ... it is explicitely marked as "free" 
  1301. * ... the price is 0.00 
  1302. * ... it is a parent membership that cannot be signed up for 
  1303. * @since 1.0.0 
  1304. * @api 
  1305. * @return bool 
  1306. */ 
  1307. public function is_free() { 
  1308. $result = false; 
  1309.  
  1310. if ( $this->is_free ) { 
  1311. $result = true; 
  1312. } elseif ( 0 == (int) ($this->price * 100) ) { 
  1313. $result = true; 
  1314.  
  1315. $result = apply_filters( 
  1316. 'ms_model_membership_is_free',  
  1317. $result,  
  1318. $this 
  1319. ); 
  1320.  
  1321. if ( $result && $this->is_free ) { 
  1322. $this->is_free = $result; 
  1323.  
  1324. return $result; 
  1325.  
  1326. /** 
  1327. * Returns true if this membership is eligable for trial period. 
  1328. * @since 1.0.1.0 
  1329. * @return bool 
  1330. */ 
  1331. public function has_trial() { 
  1332. $result = $this->trial_period_enabled; 
  1333.  
  1334. if ( $result ) { 
  1335. if ( ! MS_Model_Addon::is_enabled( MS_Model_Addon::ADDON_TRIAL ) ) { 
  1336. $result = false; 
  1337.  
  1338. return $result; 
  1339.  
  1340. /** 
  1341. * Returns the access flag, if a specific membership can subscribe to the 
  1342. * current membership. 
  1343. * A special value for $id is 'guest', which is used for all users without 
  1344. * a normal membership (is_system() type memberships are not normal) 
  1345. * @since 1.0.1.0 
  1346. * @param int|string $id A membership ID or the value 'guest'. 
  1347. * @return bool True if the specified membership can subscribe. 
  1348. */ 
  1349. public function update_allowed( $id ) { 
  1350. $denied = false; 
  1351.  
  1352. if ( isset( $this->update_denied[ $id ] ) ) { 
  1353. $denied = $this->update_denied[ $id ]; 
  1354.  
  1355. return ! $denied; 
  1356.  
  1357. /** 
  1358. * Returns the update-replacement flag, which defines if the OLD membership 
  1359. * should be cancelled during subscription. 
  1360. * This is used in cases where the new membership is an upgraded version of 
  1361. * the old membership and the user can only have one of both memberships. 
  1362. * @since 1.0.1.0 
  1363. * @param int|string $id A membership ID. 
  1364. * @return bool True if the specified membership should be cancelled. 
  1365. */ 
  1366. public function update_replaces( $id ) { 
  1367. $deny = false; 
  1368.  
  1369. if ( isset( $this->update_replace[ $id ] ) ) { 
  1370. $deny = $this->update_replace[ $id ]; 
  1371.  
  1372. return ! ! $deny; 
  1373.  
  1374. /** 
  1375. * Checks if a specific payment gateway is allowed for the current 
  1376. * membership. 
  1377. * @since 1.0.0 
  1378. * @param string $gateway_id The payment gateway ID. 
  1379. * @return bool 
  1380. */ 
  1381. public function can_use_gateway( $gateway_id ) { 
  1382. $result = true; 
  1383.  
  1384. $this->disabled_gateways = lib3()->array->get( $this->disabled_gateways ); 
  1385. if ( isset( $this->disabled_gateways[ $gateway_id ] ) ) { 
  1386. $state = $this->disabled_gateways[ $gateway_id ]; 
  1387. $result = ! lib3()->is_true( $state ); 
  1388.  
  1389. if ( $result ) { 
  1390. $gateway = MS_Model_Gateway::factory( $gateway_id ); 
  1391. $result = $gateway->payment_type_supported( $this ); 
  1392.  
  1393. $result = apply_filters( 
  1394. 'ms_model_membership_can_use_gateway',  
  1395. $result,  
  1396. $gateway_id,  
  1397. $this 
  1398. ); 
  1399. return $result; 
  1400.  
  1401. /** 
  1402. * Get protection Rule Model. 
  1403. * Note for network-wide mode: 
  1404. * In DB the rules for each site are stored in different objects. 
  1405. * When loading a membership we will always load 1 instance of each 
  1406. * rule_type, and this is the instance that belongs to the current site! 
  1407. * Instances for other sites are not accessible. 
  1408. * -> This is why we do not use/need a site_id or similar in this function. 
  1409. * @since 1.0.0 
  1410. * @api 
  1411. * @param string $rule_type The rule model type @see MS_Rule 
  1412. * @return MS_Rule The requested rule model. 
  1413. */ 
  1414. public function get_rule( $rule_type ) { 
  1415. if ( 'attachment' === $rule_type ) { 
  1416. $rule_type = MS_Rule_Media::RULE_ID; 
  1417.  
  1418. if ( ! isset( $this->_rules[ $rule_type ] ) 
  1419. || ! is_object( $this->_rules[ $rule_type ] ) // During plugin update. 
  1420. ) { 
  1421. // Create a new rule model object. 
  1422. $rule = MS_Rule::rule_factory( 
  1423. $rule_type,  
  1424. $this->id,  
  1425. $this->subscription_id 
  1426. ); 
  1427.  
  1428. $rule = apply_filters( 
  1429. 'ms_model_membership_get_rule',  
  1430. $rule,  
  1431. $rule_type,  
  1432. $this 
  1433. ); 
  1434.  
  1435. $this->_rules[ $rule_type ] = $rule; 
  1436. if ( ! is_array( $rule->rule_value ) ) { 
  1437. $rule->rule_value = array(); 
  1438.  
  1439. return $this->_rules[ $rule_type ]; 
  1440.  
  1441. /** 
  1442. * Set protection Rule Model. 
  1443. * Note for network-wide mode: 
  1444. * In DB the rules for each site are stored in different objects. 
  1445. * When loading a membership we will always load 1 instance of each 
  1446. * rule_type, and this is the instance that belongs to the current site! 
  1447. * Instances for other sites are not accessible. 
  1448. * -> This is why we do not use/need a site_id or similar in this function. 
  1449. * @since 1.0.0 
  1450. * @api 
  1451. * @param string The rule model type @see MS_Rule 
  1452. * @param MS_Rule $rule The protection rule to set. 
  1453. */ 
  1454. public function set_rule( $rule_type, $rule ) { 
  1455. $this->_rules[ $rule_type ] = apply_filters( 
  1456. 'ms_model_membership_set_rule',  
  1457. $rule,  
  1458. $rule_type,  
  1459. $this 
  1460. ); 
  1461.  
  1462. /** 
  1463. * Returns the unique HEX color for this membership. 
  1464. * The color is calculated from the membership-ID and therefore will never 
  1465. * change. 
  1466. * @since 1.0.0 
  1467. * @api 
  1468. * @return string Hex color, e.g. '#FFFFFF' 
  1469. */ 
  1470. public function get_color() { 
  1471. return apply_filters( 
  1472. 'ms_model_membership_get_color',  
  1473. MS_Helper_Utility::color_index( $this->type . $this->id ),  
  1474. $this->type,  
  1475. $this->id 
  1476. ); 
  1477.  
  1478. /** 
  1479. * Returns a HTML tag that shows the membership name with the internal 
  1480. * membership color. 
  1481. * @since 1.0.0 
  1482. * @api 
  1483. * @param bool $with_tooltip Whether to add tooltip with Membership infos. 
  1484. * @return string The title HTML code. 
  1485. */ 
  1486. public function get_name_tag( $with_tooltip = false ) { 
  1487. if ( $with_tooltip ) { 
  1488. $tooltip = sprintf( 
  1489. __( 'Revision: %s | Type: %s', 'membership2' ),  
  1490. $this->revision,  
  1491. $this->type 
  1492. ); 
  1493. $tag = sprintf( 
  1494. '<span class="ms-membership" style="background:%%2$s" title="%s">%%1$s</span>',  
  1495. $tooltip 
  1496. ); 
  1497. } else { 
  1498. $tag = '<span class="ms-membership" style="background:%2$s">%1$s</span>'; 
  1499.  
  1500. $code = sprintf( 
  1501. $tag,  
  1502. esc_html( $this->name ),  
  1503. $this->get_color() 
  1504. ); 
  1505.  
  1506. return $code; 
  1507.  
  1508. /** 
  1509. * Echo a HTML tag that shows the membership name with the internal 
  1510. * membership color. 
  1511. * @since 1.0.0 
  1512. * @api 
  1513. */ 
  1514. public function name_tag() { 
  1515. echo $this->get_name_tag(); 
  1516.  
  1517. /** 
  1518. * Returns the parsed membership description for display. Shortcodes are 
  1519. * replaced and the content is filtered. 
  1520. * @since 1.0.1.2 
  1521. * @return string The parsed membership description. 
  1522. */ 
  1523. public function get_description() { 
  1524. $desc = apply_filters( 
  1525. 'ms_model_membership_get_description',  
  1526. $this->description,  
  1527. $this 
  1528. ); 
  1529.  
  1530. $desc = do_shortcode( wpautop( $desc ) ); 
  1531.  
  1532. return $desc; 
  1533.  
  1534. /** 
  1535. * Get current membership type description. 
  1536. * @since 1.0.0 
  1537. * @api 
  1538. * @return string The membership type description. 
  1539. */ 
  1540. public function get_type_description() { 
  1541. $types = self::get_types(); 
  1542. $desc = $types[ $this->type ]; 
  1543.  
  1544. return apply_filters( 
  1545. 'ms_model_membership_get_type_description',  
  1546. $desc,  
  1547. $this 
  1548. ); 
  1549.  
  1550. /** 
  1551. * Either creates or updates the value of a custom data field. 
  1552. * Note: Remember to prefix the $key with a unique string to prevent 
  1553. * conflicts with other plugins that also use this function. 
  1554. * @since 1.0.0 
  1555. * @api 
  1556. * @param string $key The field-key. 
  1557. * @param mixed $value The new value to assign to the field. 
  1558. */ 
  1559. public function set_custom_data( $key, $value ) { 
  1560. // Wrapper function, so this function shows up in API docs. 
  1561. parent::set_custom_data( $key, $value ); 
  1562.  
  1563. /** 
  1564. * Removes a custom data field from this object. 
  1565. * @since 1.0.0 
  1566. * @api 
  1567. * @param string $key The field-key. 
  1568. */ 
  1569. public function delete_custom_data( $key ) { 
  1570. // Wrapper function, so this function shows up in API docs. 
  1571. parent::delete_custom_data( $key ); 
  1572.  
  1573. /** 
  1574. * Returns the value of a custom data field. 
  1575. * @since 1.0.0 
  1576. * @api 
  1577. * @param string $key The field-key. 
  1578. * @return mixed The value that was previously assigned to the custom field 
  1579. * or false if no value was set for the field. 
  1580. */ 
  1581. public function get_custom_data( $key ) { 
  1582. // Wrapper function, so this function shows up in API docs. 
  1583. return parent::get_custom_data( $key ); 
  1584.  
  1585. /** 
  1586. * Merge Membership2 rules. 
  1587. * Merge every rule model with Membership2/visitor membership rules. 
  1588. * This ensure rules are consistent with Membership2 rules. 
  1589. * @since 1.0.0 
  1590. * @internal 
  1591. */ 
  1592. public function merge_protection_rules() { 
  1593. if ( $this->is_base() ) { 
  1594. // This is the visitor membership, no need to merge anything. 
  1595. return; 
  1596.  
  1597. $base_rules = self::get_base()->_rules; 
  1598.  
  1599. foreach ( $base_rules as $key => $base_rule ) { 
  1600. try { 
  1601. // Key could be "type" of "site:type" format. 
  1602. $rule_type = MS_Rule::rule_type( $key ); 
  1603.  
  1604. $rule = $this->get_rule( $rule_type ); 
  1605. $rule->protect_undefined_items( $base_rule, true ); 
  1606. $this->set_rule( $rule_type, $rule ); 
  1607. } catch ( Exception $e ) { 
  1608. MS_Helper_Debug::log( $e ); 
  1609.  
  1610. $this->_rules = apply_filters( 
  1611. 'ms_model_membership_merge_protection_rules',  
  1612. $this->_rules,  
  1613. $this 
  1614. ); 
  1615.  
  1616. /** 
  1617. * Get after membership expired options. 
  1618. * Memberships can be downgraded to the guest level protection. 
  1619. * @since 1.0.0 
  1620. * @api 
  1621. * @return array { 
  1622. * Returns array of $membership_id => $description. 
  1623. * @type int $membership_id The membership Id. 
  1624. * @type string $description The expired option description. 
  1625. * } 
  1626. */ 
  1627. public function get_after_ms_ends_options() { 
  1628. $options = array( 
  1629. 0 => __( 'Restrict access to Visitor-Level', 'membership2' ),  
  1630. ); 
  1631.  
  1632. $args = array( 
  1633. 'include_guest' => false,  
  1634. ); 
  1635. $options += $this->get_membership_names( $args ); 
  1636. unset( $options[ $this->id ] ); 
  1637.  
  1638. $label = __( 'Change to: %s', 'membership2' ); 
  1639. foreach ( $options as $id => $option ) { 
  1640. if ( $id > 0 ) { 
  1641. $options[ $id ] = sprintf( $label, $option ); 
  1642.  
  1643. return apply_filters( 
  1644. 'ms_model_membership_get_membership_names',  
  1645. $options,  
  1646. $this 
  1647. ); 
  1648.  
  1649. /** 
  1650. * Get a list of all subscriptions to this membership. 
  1651. * Note that this function will also return expired/cancelled subscriptions. 
  1652. * @since 1.0.1.0 
  1653. * @api 
  1654. * @return array All subscriptions. 
  1655. */ 
  1656. public function get_subscriptions() { 
  1657. $subscriptions = MS_Model_Relationship::get_subscriptions( 
  1658. array( 'membership_id' => $this->id ) 
  1659. ); 
  1660.  
  1661. return apply_filters( 
  1662. 'ms_model_membership_get_subscriptions',  
  1663. $subscriptions 
  1664. ); 
  1665.  
  1666. /** 
  1667. * Get members count of this membership. 
  1668. * This will also count members that have "cancelled" or "expired" 
  1669. * subscriptions but not "pending" or "deactivated". 
  1670. * To change this use the filter parameter: 
  1671. * $args = array( 'status' => 'all' ) 
  1672. * @since 1.0.0 
  1673. * @api 
  1674. * @param array $args The query post args 
  1675. * @return int The members count. 
  1676. */ 
  1677. public function get_members_count( $args = null ) { 
  1678. $args = wp_parse_args( 
  1679. array( 'membership_id' => $this->id ),  
  1680. $args 
  1681. ); 
  1682.  
  1683. $count = MS_Model_Relationship::get_subscription_count( $args ); 
  1684.  
  1685. return apply_filters( 
  1686. 'ms_model_membership_get_members_count',  
  1687. $count,  
  1688. $args,  
  1689. $this 
  1690. ); 
  1691.  
  1692. /** 
  1693. * Get members list of this membership. 
  1694. * This will also count members that have "cancelled" or "expired" 
  1695. * subscriptions but not "pending" or "deactivated". 
  1696. * To change this use the filter parameter: 
  1697. * $args = array( 'status' => 'all' ) 
  1698. * @since 1.0.1.0 
  1699. * @api 
  1700. * @param array $args The query post args 
  1701. * @return array List of members. 
  1702. */ 
  1703. public function get_members( $args = null ) { 
  1704. $args = wp_parse_args( 
  1705. array( 'membership_id' => $this->id ),  
  1706. $args 
  1707. ); 
  1708.  
  1709. // Get a list of subscriptions. 
  1710. $items = MS_Model_Relationship::get_subscriptions( $args ); 
  1711.  
  1712. // Get a list of members. 
  1713. $result = array(); 
  1714. foreach ( $items as $item ) { 
  1715. $result[ $item->user_id ] = $item->get_member(); 
  1716.  
  1717. return apply_filters( 
  1718. 'ms_model_membership_get_members',  
  1719. $result,  
  1720. $args,  
  1721. $this 
  1722. ); 
  1723.  
  1724. /** 
  1725. * Return membership has dripped content. 
  1726. * Verify post and page rules if there is a dripped content. 
  1727. * @since 1.0.0 
  1728. * @api 
  1729. * @return boolean 
  1730. */ 
  1731. public function has_dripped_content() { 
  1732. $has_dripped = false; 
  1733. $dripped = array( 'post', 'page' ); 
  1734.  
  1735. foreach ( $dripped as $rule_type ) { 
  1736. // using count() as !empty() never returned true 
  1737. if ( 0 < count( $this->get_rule( $rule_type )->dripped ) ) { 
  1738. $has_dripped = true; 
  1739.  
  1740. return apply_filters( 
  1741. 'ms_model_membership_has_dripped_content',  
  1742. $has_dripped,  
  1743. $this 
  1744. ); 
  1745.  
  1746. /** 
  1747. * Get protection rules sorted. 
  1748. * First one has priority over the last one. 
  1749. * These rules are used to determine access. 
  1750. * @since 1.0.0 
  1751. * @internal 
  1752. */ 
  1753. private function get_rules_hierarchy() { 
  1754. $rule_types = MS_Model_Rule::get_rule_types(); 
  1755. $rules = array(); 
  1756. $subscription = MS_Factory::load( 'MS_Model_Relationship', $this->subscription_id ); 
  1757.  
  1758. foreach ( $rule_types as $rule_type ) { 
  1759. $rule = $this->get_rule( $rule_type ); 
  1760.  
  1761. if ( $rule->rule_type != $rule_type ) { 
  1762. // This means that the $rule_type was not found... 
  1763. continue; 
  1764.  
  1765. // Sometimes the $subscription->id can be 0, which is intentional: 
  1766. // This is the case when the membership was auto-assigned to guest 
  1767. // or default membership. 
  1768. $rule->_subscription_id = $subscription->id; 
  1769.  
  1770. $rule->membership_id = $this->id; 
  1771. $rules[ $rule_type ] = $rule; 
  1772.  
  1773. return apply_filters( 
  1774. 'ms_model_membership_get_rules_hierarchy',  
  1775. $rules,  
  1776. $this 
  1777. ); 
  1778.  
  1779. /** 
  1780. * Mark membership setup as completed. 
  1781. * Only purpose of this flag is to display the correct update message to the 
  1782. * user: If setup_completed() returns true, then "Membership added" is 
  1783. * displayed, otherwise "Membership updated" 
  1784. * @since 1.0.0 
  1785. * @internal 
  1786. * @return bool $marked True in the first time setup is finished. 
  1787. */ 
  1788. public function setup_completed() { 
  1789. $marked = false; 
  1790.  
  1791. if ( ! $this->is_setup_completed ) { 
  1792. $this->is_setup_completed = true; 
  1793. $marked = true; 
  1794.  
  1795. return apply_filters( 
  1796. 'ms_model_membership_setup_completed',  
  1797. $marked,  
  1798. $this 
  1799. ); 
  1800.  
  1801. /** 
  1802. * Returns true if the membership the base membership. 
  1803. * @since 1.0.0 
  1804. * @see description of MS_Model_Membership::get_base() 
  1805. * @api 
  1806. * @return bool 
  1807. */ 
  1808. public function is_base( $type = null ) { 
  1809. if ( ! $type ) { $type = $this->type; } 
  1810. $res = (self::TYPE_BASE == $type); 
  1811.  
  1812. return apply_filters( 
  1813. 'ms_model_membership_is_base',  
  1814. $res,  
  1815. $type 
  1816. ); 
  1817.  
  1818. /** 
  1819. * Returns true if the membership the guest membership. 
  1820. * @since 1.0.0 
  1821. * @see description of MS_Model_Membership::get_guest() 
  1822. * @api 
  1823. * @return bool 
  1824. */ 
  1825. public function is_guest( $type = null ) { 
  1826. if ( ! $type ) { $type = $this->type; } 
  1827. $res = (self::TYPE_GUEST == $type); 
  1828.  
  1829. return apply_filters( 
  1830. 'ms_model_membership_is_guest',  
  1831. $res,  
  1832. $type 
  1833. ); 
  1834.  
  1835. /** 
  1836. * Returns true if the membership the user membership. 
  1837. * @since 1.0.0 
  1838. * @see description of MS_Model_Membership::get_user() 
  1839. * @api 
  1840. * @return bool 
  1841. */ 
  1842. public function is_user( $type = null ) { 
  1843. if ( ! $type ) { $type = $this->type; } 
  1844. $res = (self::TYPE_USER == $type); 
  1845.  
  1846. return apply_filters( 
  1847. 'ms_model_membership_is_user',  
  1848. $res,  
  1849. $type 
  1850. ); 
  1851.  
  1852. /** 
  1853. * Returns true if the membership a dripped membership. 
  1854. * @since 1.0.0 
  1855. * @api 
  1856. * @return bool 
  1857. */ 
  1858. public function is_dripped( $type = null ) { 
  1859. if ( ! $type ) { $type = $this->type; } 
  1860. $res = (self::TYPE_DRIPPED == $type); 
  1861.  
  1862. return apply_filters( 
  1863. 'ms_model_membership_is_dripped',  
  1864. $res,  
  1865. $type 
  1866. ); 
  1867.  
  1868. /** 
  1869. * Returns true if the membership the base or guest/user membership. 
  1870. * @since 1.0.0 
  1871. * @api 
  1872. * @return bool 
  1873. */ 
  1874. public function is_system( $type = null ) { 
  1875. if ( ! $type ) { $type = $this->type; } 
  1876.  
  1877. $res = false; 
  1878. if ( $this->is_base( $type ) ) { 
  1879. $res = true; 
  1880. } elseif ( $this->is_guest( $type ) ) { 
  1881. $res = true; 
  1882. } elseif ( $this->is_user( $type ) ) { 
  1883. $res = true; 
  1884.  
  1885. return apply_filters( 
  1886. 'ms_model_membership_is_system',  
  1887. $res,  
  1888. $type 
  1889. ); 
  1890.  
  1891. /** 
  1892. * Can be used to validate if the current membership is actually loaded 
  1893. * from database. If this function returns false, then the specified 
  1894. * membership-ID does not exist in DB. 
  1895. * @since 1.0.0 
  1896. * @api 
  1897. * @return bool 
  1898. */ 
  1899. public function is_valid() { 
  1900. $res = ! empty( $this->id ); 
  1901.  
  1902. return apply_filters( 
  1903. 'ms_model_membership_is_valid',  
  1904. $res,  
  1905. $this 
  1906. ); 
  1907.  
  1908. /** 
  1909. * Verify access to current page. 
  1910. * Verify membership rules hierarchy for content accessed directly. 
  1911. * If 'has access' is found, it does have access. 
  1912. * Only for active memberships. 
  1913. * @since 1.0.0 
  1914. * @api 
  1915. * @param int $post_id 
  1916. * @return bool|null True if has access to current page. Default is false. 
  1917. * Null means: Rule not relevant for current page. 
  1918. */ 
  1919. public function has_access_to_current_page( $post_id = null ) { 
  1920. $has_access = null; 
  1921. $this->_access_reason = array(); 
  1922. $this->_deny_rule = array(); 
  1923. $this->_allow_rule = array(); 
  1924.  
  1925. // Only verify access if membership is Active. 
  1926. if ( $this->active ) { 
  1927.  
  1928. // If 'has access' is found in the hierarchy, it does have access. 
  1929. $rules = $this->get_rules_hierarchy(); 
  1930. foreach ( $rules as $rule ) { 
  1931. $rule_access = $rule->has_access( $post_id ); 
  1932.  
  1933. if ( null === $rule_access ) { 
  1934. $this->_access_reason[] = sprintf( 
  1935. __( 'Ignored: Rule "%s"', 'membership2' ),  
  1936. $rule->rule_type 
  1937. ); 
  1938. continue; 
  1939.  
  1940. $this->_access_reason[] = sprintf( 
  1941. __( '%s: Rule "%s"', 'membership2' ),  
  1942. $rule_access ? __( 'Allow', 'membership2' ) : __( 'Deny', 'membership2' ),  
  1943. $rule->rule_type 
  1944. ); 
  1945.  
  1946. if ( ! $rule_access ) { 
  1947. $this->_deny_rule[] = $rule->rule_type; 
  1948. } else { 
  1949. $this->_allow_rule[] = $rule->rule_type; 
  1950.  
  1951. // URL groups have final decission. 
  1952. if ( MS_Rule_Url::RULE_ID === $rule->rule_type ) { 
  1953. $has_access = $rule_access; 
  1954. break; 
  1955.  
  1956. // Special pages have final decission after URL groups. 
  1957. if ( MS_Rule_Special::RULE_ID === $rule->rule_type ) { 
  1958. $has_access = $rule_access; 
  1959. $this->_access_reason[] = $rule->matched_type; 
  1960. break; 
  1961.  
  1962. $has_access = ( $has_access || $rule_access ); 
  1963.  
  1964. if ( true === $has_access ) { 
  1965. break; 
  1966.  
  1967. return apply_filters( 
  1968. 'ms_model_membership_has_access_to_current_page',  
  1969. $has_access,  
  1970. $post_id,  
  1971. $this 
  1972. ); 
  1973.  
  1974. /** 
  1975. * Verify access to post. 
  1976. * Verify membership rules hierarchy for specific post or CPT. 
  1977. * @since 1.0.0 
  1978. * @api 
  1979. * @param int $post_id ID of specific post 
  1980. * @return boolean True if has access to current page. Default is false. 
  1981. */ 
  1982. public function has_access_to_post( $post_id ) { 
  1983. $has_access = null; 
  1984.  
  1985. if ( MS_Model_Member::is_normal_admin() ) { 
  1986. return true; 
  1987.  
  1988. if ( ! empty( $post_id ) ) { 
  1989. $post = get_post( $post_id ); 
  1990. if ( 'attachment' === $post->post_type ) { 
  1991. $post_id = get_post_field( 'post_parent', $post_id ); 
  1992.  
  1993. // If 'has access' is found in the hierarchy, it does have access. 
  1994. $rules = $this->get_rules_hierarchy(); 
  1995. foreach ( $rules as $rule ) { 
  1996. $rule->prepare_rule( $subscription ); 
  1997.  
  1998. // url groups have final decision 
  1999. if ( MS_Rule_Url::RULE_ID == $rule->rule_type 
  2000. && $rule->has_rule_for_post( $post_id ) 
  2001. ) { 
  2002. $has_access = $rule->has_access( $post_id ); 
  2003. break; 
  2004. } else { 
  2005. $rule_access = $rule->has_access( $post_id ); 
  2006. if ( null !== $rule_access ) { 
  2007. $has_access = $rule_access; 
  2008.  
  2009. if ( $has_access ) { 
  2010. break; 
  2011.  
  2012. if ( null === $has_access ) { 
  2013. // The post is not denied by any rule, so allow access. 
  2014. $has_access = true; 
  2015.  
  2016. return apply_filters( 
  2017. 'ms_model_membership_has_access_to_post',  
  2018. $has_access,  
  2019. $this 
  2020. ); 
  2021.  
  2022. /** 
  2023. * Set up the membership. This is always done, regardless if the user is 
  2024. * a normal user or an Admin user. 
  2025. * @since 1.0.0 
  2026. * @internal 
  2027. * @param MS_Model_Relationship $subscription The membership relationship. 
  2028. */ 
  2029. public function initialize( $subscription ) { 
  2030. do_action( 
  2031. 'ms_model_membership_initialize_before',  
  2032. $subscription,  
  2033. $this 
  2034. ); 
  2035.  
  2036. $this->subscription_id = $subscription->id; 
  2037. $rules = $this->get_rules_hierarchy(); 
  2038.  
  2039. // Apply protection settings of all rules (replace/hide contents, ...) 
  2040. foreach ( $rules as $rule ) { 
  2041. $rule->prepare_rule( $subscription ); 
  2042.  
  2043. do_action( 
  2044. 'ms_model_membership_initialize_after',  
  2045. $subscription,  
  2046. $this 
  2047. ); 
  2048.  
  2049. /** 
  2050. * Set initial protection for front-end. 
  2051. * This function is only executed when the current user is no Admin user. 
  2052. * Hide restricted content for this membership. 
  2053. * @since 1.0.0 
  2054. * @internal 
  2055. */ 
  2056. public function protect_content() { 
  2057. do_action( 
  2058. 'ms_model_membership_protect_content_before',  
  2059. $this 
  2060. ); 
  2061.  
  2062. $rules = $this->get_rules_hierarchy(); 
  2063.  
  2064. // Apply protection settings of all rules (replace/hide contents, ...) 
  2065. foreach ( $rules as $rule ) { 
  2066. $rule->protect_content(); 
  2067.  
  2068. do_action( 
  2069. 'ms_model_membership_protect_content_after',  
  2070. $this 
  2071. ); 
  2072.  
  2073. /** 
  2074. * Check protection for front-end. 
  2075. * Return if content is restricted for this membership. 
  2076. * @since 1.0.0 
  2077. * @internal 
  2078. */ 
  2079. public function has_access_to_content( $id ) { 
  2080. $rules = $this->get_rules_hierarchy(); 
  2081. return $rules['content']->get_rule_value($id); 
  2082. }  
  2083.  
  2084. /** 
  2085. * Set initial protection for admin side. 
  2086. * Hide restricted content for this membership. 
  2087. * @since 1.0.0 
  2088. * @internal 
  2089. */ 
  2090. public function protect_admin_content() { 
  2091. do_action( 
  2092. 'ms_model_membership_protect_content_before',  
  2093. $this 
  2094. ); 
  2095.  
  2096. $rules = $this->get_rules_hierarchy(); 
  2097.  
  2098. foreach ( $rules as $rule ) { 
  2099. $rule->protect_admin_content(); 
  2100.  
  2101. do_action( 
  2102. 'ms_model_membership_protect_content_after',  
  2103. $this 
  2104. ); 
  2105.  
  2106. /** 
  2107. * Checks if the user is allowed to change the payment details for the 
  2108. * current membership. 
  2109. * Payment details can only be changed when 
  2110. * (A) no payment details were saved yet - OR - 
  2111. * (B) no members signed up for the memberships 
  2112. * @since 1.0.0 
  2113. * @api 
  2114. * @return bool 
  2115. */ 
  2116. public function can_change_payment() { 
  2117. // Allow if Membership is new/unsaved. 
  2118. if ( empty( $this->id ) ) { return true; } 
  2119.  
  2120. // Allow if no payment detail was entered yet (incomplete setup). 
  2121. if ( empty( $this->payment_type ) ) { return true; } 
  2122.  
  2123. // Allow if no members signed up yet. 
  2124. $members = MS_Model_Relationship::get_subscription_count( 
  2125. array( 'membership_id' => $this->id ) 
  2126. ); 
  2127. if ( empty( $members ) ) { return true; } 
  2128.  
  2129. // Otherwise payment details cannot be changed anymore. 
  2130. return false; 
  2131.  
  2132. /** 
  2133. * Returns property associated with the render. 
  2134. * @since 1.0.0 
  2135. * @internal 
  2136. * @param string $property The name of a property. 
  2137. * @return mixed Returns mixed value of a property or NULL if a property doesn't exist. 
  2138. */ 
  2139. public function __get( $property ) { 
  2140. $value = null; 
  2141.  
  2142. switch ( $property ) { 
  2143. case 'type': 
  2144. if ( ! self::is_valid_type( $this->type ) ) { 
  2145. $this->type = self::TYPE_STANDARD; 
  2146.  
  2147. $value = $this->type; 
  2148. break; 
  2149.  
  2150. case 'payment_type': 
  2151. $types = self::get_payment_types(); 
  2152. if ( ! array_key_exists( $this->payment_type, $types ) ) { 
  2153. $this->payment_type = self::PAYMENT_TYPE_PERMANENT; 
  2154. $value = $this->payment_type; 
  2155. break; 
  2156.  
  2157. case 'trial_period_enabled': 
  2158. case 'active': 
  2159. case 'private': 
  2160. case 'is_free': 
  2161. $value = lib3()->is_true( $this->$property ); 
  2162. break; 
  2163.  
  2164. case 'type_description': 
  2165. $value = $this->get_type_description(); 
  2166. break; 
  2167.  
  2168. case 'period_unit': 
  2169. $value = MS_Helper_Period::get_period_value( $this->period, 'period_unit' ); 
  2170. break; 
  2171.  
  2172. case 'period_type': 
  2173. $value = MS_Helper_Period::get_period_value( $this->period, 'period_type' ); 
  2174. break; 
  2175.  
  2176. case 'pay_cycle_period_unit': 
  2177. $value = MS_Helper_Period::get_period_value( $this->pay_cycle_period, 'period_unit' ); 
  2178. break; 
  2179.  
  2180. case 'pay_cycle_period_type': 
  2181. $value = MS_Helper_Period::get_period_value( $this->pay_cycle_period, 'period_type' ); 
  2182. break; 
  2183.  
  2184. case 'trial_period_unit': 
  2185. $value = MS_Helper_Period::get_period_value( $this->trial_period, 'period_unit' ); 
  2186. break; 
  2187.  
  2188. case 'trial_period_type': 
  2189. $value = MS_Helper_Period::get_period_value( $this->trial_period, 'period_type' ); 
  2190. break; 
  2191.  
  2192. case 'price': 
  2193. if ( $this->is_free() ) { 
  2194. $value = 0; 
  2195. } else { 
  2196. $value = $this->price; 
  2197. break; 
  2198.  
  2199. case 'total_price': 
  2200. if ( $this->is_free() ) { 
  2201. $value = 0; 
  2202. } else { 
  2203. $value = $this->price; 
  2204.  
  2205. $value = apply_filters( 
  2206. 'ms_apply_taxes',  
  2207. $value,  
  2208. $this 
  2209. ); 
  2210. break; 
  2211.  
  2212. case 'pay_cycle_repetitions': 
  2213. $value = absint( $this->pay_cycle_repetitions ); 
  2214. break; 
  2215.  
  2216. case 'disabled_gateways': 
  2217. $value = lib3()->array->get( $this->disabled_gateways ); 
  2218. break; 
  2219.  
  2220. case 'is_paid': 
  2221. $value = ! $this->is_free; 
  2222. break; 
  2223.  
  2224. case 'public': 
  2225. $value = ! $this->private; 
  2226. break; 
  2227.  
  2228. default: 
  2229. if ( property_exists( $this, $property ) ) { 
  2230. $value = $this->$property; 
  2231. break; 
  2232.  
  2233. return apply_filters( 
  2234. 'ms_model_membership__get',  
  2235. $value,  
  2236. $property,  
  2237. $this 
  2238. ); 
  2239.  
  2240. /** 
  2241. * Validate specific property before set. 
  2242. * @since 1.0.0 
  2243. * @internal 
  2244. * @param string $property The name of a property to associate. 
  2245. * @param mixed $value The value of a property. 
  2246. */ 
  2247. public function __set( $property, $value ) { 
  2248. if ( property_exists( $this, $property ) ) { 
  2249. switch ( $property ) { 
  2250. case 'name': 
  2251. case 'title': 
  2252. $this->$property = sanitize_text_field( $value ); 
  2253. break; 
  2254.  
  2255. case 'description': 
  2256. $this->$property = wp_kses( $value, 'post' ); 
  2257. break; 
  2258.  
  2259. case 'type': 
  2260. if ( ! self::is_valid_type( $value ) ) { 
  2261. $value = self::TYPE_STANDARD; 
  2262.  
  2263. if ( $this->is_system( $value ) ) { 
  2264. // Only one instance of these types can exist. 
  2265. $existing = $this->_get_system_membership( $value, false ); 
  2266.  
  2267. if ( $existing && $existing->id != $this->id ) { 
  2268. $value = self::TYPE_STANDARD; 
  2269. } else { 
  2270. $this->active = true; 
  2271. $this->private = true; 
  2272. $this->is_free = true; 
  2273. $this->price = 0; 
  2274. $this->post_name = sanitize_html_class( $this->title ); 
  2275. $this->payment_type = self::PAYMENT_TYPE_PERMANENT; 
  2276. $this->post_author = get_current_user_id(); 
  2277.  
  2278. $this->type = $value; 
  2279. break; 
  2280.  
  2281. case 'payment_type': 
  2282. $types = self::get_payment_types(); 
  2283. if ( array_key_exists( $value, $types ) ) { 
  2284. $this->payment_type = $value; 
  2285. } else { 
  2286. throw new Exception( 'Invalid membership type.' ); 
  2287. break; 
  2288.  
  2289. case 'trial_period_enabled': 
  2290. case 'active': 
  2291. case 'private': 
  2292. case 'is_free': 
  2293. $this->$property = lib3()->is_true( $value ); 
  2294. break; 
  2295.  
  2296. case 'price': 
  2297. case 'trial_price': 
  2298. $this->$property = floatval( $value ); 
  2299. break; 
  2300.  
  2301. case 'pay_cycle_repetitions': 
  2302. $this->$property = absint( $value ); 
  2303. break; 
  2304.  
  2305. case 'period': 
  2306. case 'pay_cycle_period': 
  2307. case 'trial_period': 
  2308. $this->$property = $this->validate_period( $value ); 
  2309. break; 
  2310.  
  2311. case 'period_date_start': 
  2312. case 'period_date_end': 
  2313. $this->$property = $this->validate_date( $value ); 
  2314. break; 
  2315.  
  2316. case 'on_end_membership_id': 
  2317. if ( 0 == $value ) { 
  2318. $this->$property = 0; 
  2319. } else if ( 0 < MS_Factory::load( 'MS_Model_Membership', $value )->id ) { 
  2320. $this->$property = $value; 
  2321. break; 
  2322.  
  2323. default: 
  2324. $this->$property = $value; 
  2325. break; 
  2326. } else { 
  2327. switch ( $property ) { 
  2328. case 'period_unit': 
  2329. $this->period['period_unit'] = $this->validate_period_unit( $value ); 
  2330. break; 
  2331.  
  2332. case 'period_type': 
  2333. $this->period['period_type'] = $this->validate_period_type( $value ); 
  2334. break; 
  2335.  
  2336. case 'pay_cycle_period_unit': 
  2337. $this->pay_cycle_period['period_unit'] = $this->validate_period_unit( $value ); 
  2338. break; 
  2339.  
  2340. case 'pay_cycle_period_type': 
  2341. $this->pay_cycle_period['period_type'] = $this->validate_period_type( $value ); 
  2342. break; 
  2343.  
  2344. case 'trial_period_unit': 
  2345. $this->trial_period['period_unit'] = $this->validate_period_unit( $value ); 
  2346. break; 
  2347.  
  2348. case 'trial_period_type': 
  2349. $this->trial_period['period_type'] = $this->validate_period_type( $value ); 
  2350. break; 
  2351.  
  2352. case 'public': 
  2353. $this->private = ! lib3()->is_true( $value ); 
  2354. break; 
  2355.  
  2356. case 'is_paid': 
  2357. $this->is_free = ! lib3()->is_true( $value ); 
  2358. break; 
  2359.  
  2360. case 'deny_update': 
  2361. foreach ( $value as $key => $state ) { 
  2362. $this->update_denied[ $key ] = lib3()->is_true( $state ); 
  2363. break; 
  2364.  
  2365. case 'replace_update': 
  2366. foreach ( $value as $key => $state ) { 
  2367. $this->update_replace[ $key ] = lib3()->is_true( $state ); 
  2368. break; 
  2369.  
  2370.  
  2371. do_action( 
  2372. 'ms_model_membership__set_after',  
  2373. $property,  
  2374. $value,  
  2375. $this 
  2376. ); 
  2377.  
  2378. /** 
  2379. * Check if property isset. 
  2380. * @since 1.0.0 
  2381. * @internal 
  2382. * @param string $property The name of a property. 
  2383. * @return mixed Returns true/false. 
  2384. */ 
  2385. public function __isset( $property ) { 
  2386. return isset($this->$property); 
  2387. }