MS_Controller_Membership

Controller for managing Memberships and Membership Rules.

Defined (1)

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

/app/controller/class-ms-controller-membership.php  
  1. class MS_Controller_Membership extends MS_Controller { 
  2.  
  3. /** 
  4. * AJAX action constants. 
  5. * @since 1.0.0 
  6. * @var string 
  7. */ 
  8. const AJAX_ACTION_TOGGLE_MEMBERSHIP = 'toggle_membership'; 
  9. const AJAX_ACTION_UPDATE_MEMBERSHIP = 'update_membership'; 
  10. const AJAX_ACTION_SET_CUSTOM_FIELD = 'membership_set_custom_field'; 
  11.  
  12. /** 
  13. * Membership page step constants. 
  14. * @since 1.0.0 
  15. * @var string 
  16. */ 
  17. const STEP_MS_LIST = 'list'; 
  18. const STEP_EDIT = 'edit'; 
  19. const STEP_OVERVIEW = 'overview'; 
  20. const STEP_NEWS = 'news'; 
  21. const STEP_WELCOME_SCREEN = 'welcome'; 
  22. const STEP_ADD_NEW = 'add'; 
  23. const STEP_PAYMENT = 'payment'; 
  24.  
  25. /** 
  26. * Membership Editor tabs. 
  27. * @since 1.0.1.0 
  28. * @var string 
  29. */ 
  30. const TAB_DETAILS = 'details'; 
  31. const TAB_TYPE = 'type'; 
  32. const TAB_PAYMENT = 'payment'; 
  33. // Upgrade paths IS PRO ONLY! 
  34. const TAB_PAGES = 'pages'; 
  35. const TAB_MESSAGES = 'messages'; 
  36. const TAB_EMAILS = 'emails'; 
  37.  
  38. // Actions 
  39. const ACTION_SAVE = 'save_membership'; 
  40.  
  41. /** 
  42. * The model to use for loading/saving Membership data. 
  43. * @since 1.0.0 
  44. * @var MS_Model_Membership 
  45. */ 
  46. private $model = null; 
  47.  
  48. /** 
  49. * The current active tab in the vertical navigation. 
  50. * @since 1.0.1.0 
  51. * @var string 
  52. */ 
  53. private $active_tab = null; 
  54.  
  55. /** 
  56. * Prepare the Membership manager. 
  57. * @since 1.0.0 
  58. */ 
  59. public function __construct() { 
  60. parent::__construct(); 
  61.  
  62. $this->add_ajax_action( 
  63. self::AJAX_ACTION_TOGGLE_MEMBERSHIP,  
  64. 'ajax_action_toggle_membership' 
  65. ); 
  66. $this->add_ajax_action( 
  67. self::AJAX_ACTION_UPDATE_MEMBERSHIP,  
  68. 'ajax_action_update_membership' 
  69. ); 
  70. $this->add_ajax_action( 
  71. self::AJAX_ACTION_SET_CUSTOM_FIELD,  
  72. 'ajax_action_set_custom_field' 
  73. ); 
  74.  
  75. // Tries to auto-detect the currently displayed membership-ID. 
  76. $this->add_filter( 
  77. 'ms_detect_membership_id',  
  78. 'autodetect_membership' 
  79. ); 
  80.  
  81. /** 
  82. * Initialize the admin-side functions. 
  83. * @since 1.0.0 
  84. */ 
  85. public function admin_init() { 
  86. $hooks = array( 
  87. MS_Controller_Plugin::admin_page_hook(),  
  88. MS_Controller_Plugin::admin_page_hook( 'setup' ),  
  89. ); 
  90.  
  91. foreach ( $hooks as $hook ) { 
  92. $this->run_action( 'load-' . $hook, 'process_admin_page' ); 
  93. $this->run_action( 'admin_print_scripts-' . $hook, 'enqueue_scripts' ); 
  94. $this->run_action( 'admin_print_styles-' . $hook, 'enqueue_styles' ); 
  95.  
  96. if ( self::TAB_EMAILS == $this->get_active_edit_tab() ) { 
  97. $this->run_action( 
  98. 'admin_head-' . $hook,  
  99. array( 'MS_Controller_Communication', 'add_mce_buttons' ) 
  100. ); 
  101.  
  102. /** 
  103. * Handle Ajax toggle action. 
  104. * Related Action Hooks: 
  105. * - wp_ajax_toggle_membership 
  106. * @since 1.0.0 
  107. */ 
  108. public function ajax_action_toggle_membership() { 
  109. $msg = 0; 
  110.  
  111. $required = array( 'membership_id', 'field' ); 
  112.  
  113. if ( $this->verify_nonce() 
  114. && self::validate_required( $required, 'POST', false ) 
  115. && $this->is_admin_user() 
  116. ) { 
  117. $msg = $this->membership_list_do_action( 
  118. 'toggle_' . $_POST['field'],  
  119. array( $_POST['membership_id'] ) 
  120. ); 
  121.  
  122. do_action( 
  123. 'ms_controller_membership_ajax_action_toggle_membership',  
  124. $msg,  
  125. $this 
  126. ); 
  127.  
  128. wp_die( $msg ); 
  129.  
  130. /** 
  131. * Handle Ajax toggle action. 
  132. * Related Action Hooks: 
  133. * - wp_ajax_update_membership 
  134. * @since 1.0.0 
  135. */ 
  136. public function ajax_action_update_membership() { 
  137. $msg = 0; 
  138.  
  139. $required = array( 'membership_id', 'field', 'value' ); 
  140.  
  141. if ( $this->verify_nonce() 
  142. && self::validate_required( $required, 'POST', false ) 
  143. && $this->is_admin_user() 
  144. ) { 
  145. lib3()->array->strip_slashes( $_POST, 'value', 'field' ); 
  146.  
  147. $msg = $this->save_membership( 
  148. array( $_POST['field'] => $_POST['value'] ) 
  149. ); 
  150.  
  151. do_action( 
  152. 'ms_controller_membership_ajax_action_update_membership',  
  153. $msg,  
  154. $this 
  155. ); 
  156.  
  157. wp_die( $msg ); 
  158.  
  159. /** 
  160. * Ajax handler to update a custom field of the membership. 
  161. * Related Action Hooks: 
  162. * - wp_ajax_membership_set_custom_field 
  163. * @since 1.0.1.0 
  164. */ 
  165. public function ajax_action_set_custom_field() { 
  166. $msg = 0; 
  167.  
  168. $required = array( 'membership_id', 'field', 'value' ); 
  169.  
  170. if ( $this->verify_nonce() 
  171. && self::validate_required( $required, 'POST', false ) 
  172. && $this->is_admin_user() 
  173. ) { 
  174. lib3()->array->strip_slashes( $_POST, 'value', 'field' ); 
  175. $membership = MS_Factory::load( 
  176. 'MS_Model_Membership',  
  177. intval( $_POST['membership_id'] ) 
  178. ); 
  179. $membership->set_custom_data( $_POST['field'], $_POST['value'] ); 
  180. $membership->save(); 
  181.  
  182. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_UPDATED; 
  183.  
  184. do_action( 
  185. 'ms_controller_membership_ajax_action_update_membership',  
  186. $msg,  
  187. $this 
  188. ); 
  189.  
  190. wp_die( $msg ); 
  191.  
  192. /** 
  193. * Load membership from request. 
  194. * @since 1.0.0 
  195. * @return MS_Model_Membership The membership model object. 
  196. */ 
  197. public function load_membership() { 
  198. $membership_id = 0; 
  199.  
  200. if ( empty( $this->model ) ) { 
  201. if ( ! empty( $_REQUEST['membership_id'] ) ) { 
  202. $membership_id = absint( $_REQUEST['membership_id'] ); 
  203.  
  204. if ( $membership_id == MS_Model_Membership::get_base()->id ) { 
  205. wp_safe_redirect( 
  206. esc_url_raw( 
  207. remove_query_arg( array( 'membership_id' ) ) 
  208. ); 
  209.  
  210. $this->model = MS_Factory::load( 
  211. 'MS_Model_Membership',  
  212. $membership_id 
  213. ); 
  214.  
  215. $this->model = apply_filters( 
  216. 'ms_controller_membership_load_membership',  
  217. $this->model,  
  218. $this 
  219. ); 
  220.  
  221. return $this->model; 
  222.  
  223. /** 
  224. * Tries to auto-detect the currently displayed membership-ID. 
  225. * Use this function by calling the filter `ms_detect_membership_id` 
  226. * Detection logic: 
  227. * 1. If a valid preferred value was specified then this value is used. 
  228. * 2. Examine REQUEST data and look for membership/subscription/invoice. 
  229. * 3. Check currently logged in user and use the top-priority subscription. 
  230. * @since 1.0.1.0 
  231. * @param int $preferred The preferred ID is only used if it is a valid ID. 
  232. * @param bool $no_member_check If set to true the member subscriptions are 
  233. * not checked, which means only REQUEST data is examined. 
  234. * @return int A valid Membership ID or 0 if all tests fail. 
  235. */ 
  236. public function autodetect_membership( $preferred = 0, $no_member_check = false ) { 
  237. $membership_id = 0; 
  238.  
  239. // Check 1: If the preferred value is correct use it. 
  240. if ( $preferred ) { 
  241. $membership = MS_Factory::load( 'MS_Model_Membership', $preferred ); 
  242. if ( $membership->id == $preferred ) { 
  243. $membership_id = $membership->id; 
  244.  
  245. // Check 2: Examine the REQUEST parameters to find a valid ID. 
  246. if ( ! $membership_id ) { 
  247. if ( ! $membership_id ) { 
  248. if ( isset( $_REQUEST['membership_id'] ) ) { 
  249. $membership_id = $_REQUEST['membership_id']; 
  250. } elseif ( isset( $_REQUEST['subscription_id'] ) ) { 
  251. $sub_id = $_REQUEST['subscription_id']; 
  252. $subscription = MS_Factory::load( 'MS_Model_Relationship', $sub_id ); 
  253. $membership_id = $subscription->membership_id; 
  254. } elseif ( isset( $_REQUEST['ms_relationship_id'] ) ) { 
  255. $sub_id = $_REQUEST['ms_relationship_id']; 
  256. $subscription = MS_Factory::load( 'MS_Model_Relationship', $sub_id ); 
  257. $membership_id = $subscription->membership_id; 
  258. } elseif ( isset( $_REQUEST['invoice_id'] ) ) { 
  259. $inv_id = $_REQUEST['invoice_id']; 
  260. $invoice = MS_Factory::load( 'MS_Model_Invoice', $inv_id ); 
  261. $membership_id = $invoice->membership_id; 
  262. $membership_id = intval( $membership_id ); 
  263.  
  264. // Check 3: Check subscriptions of the current user. 
  265. if ( ! $no_member_check && ! $membership_id && is_user_logged_in() ) { 
  266. $member = MS_Model_Member::get_current_member(); 
  267. $subscription = $member->get_subscription( 'priority' ); 
  268. if ( $subscription ) { 
  269. $membership_id = $subscription->membership_id; 
  270.  
  271. return apply_filters( 
  272. 'ms_controller_membership_autodetect_membership',  
  273. $membership_id,  
  274. $preferred,  
  275. $no_member_check 
  276. ); 
  277.  
  278. /** 
  279. * Process membership pages requests 
  280. * Verifies GET and POST requests to manage memberships. 
  281. * Redirect to next step after processing. 
  282. * @since 1.0.0 
  283. */ 
  284. public function process_admin_page() { 
  285. $msg = 0; 
  286. $next_step = null; 
  287. $step = $this->get_step(); 
  288. $goto_url = null; 
  289. $membership = $this->load_membership(); 
  290. $membership_id = $membership->id; 
  291. $completed = false; 
  292. $is_wizard = MS_Plugin::is_wizard(); 
  293. $save_data = array(); 
  294.  
  295. // Check if user came from WPMU Dashboard plugin 
  296. if ( ! $is_wizard && isset( $_SERVER['HTTP_REFERER'] ) ) { 
  297. $referer = $_SERVER['HTTP_REFERER']; 
  298. $params = parse_url( $referer, PHP_URL_QUERY ); 
  299. $fields = array(); 
  300. parse_str( $params, $fields ); 
  301. if ( isset( $fields['page'] ) && 'wpmudev-plugins' == $fields['page'] ) { 
  302. $url = MS_Controller_Plugin::get_admin_url( 'settings' ); 
  303.  
  304. wp_safe_redirect( $url ); 
  305. exit; 
  306.  
  307. // MS_Controller_Rule is executed using this action. 
  308. do_action( 'ms_controller_membership_admin_page_process_' . $step ); 
  309.  
  310. // Only accessible to admin users 
  311. if ( ! $this->is_admin_user() ) { return false; } 
  312.  
  313. if ( $this->verify_nonce( null, 'any' ) ) { 
  314. // Take next actions based in current step. 
  315.  
  316. // Check if we are editing a membership. 
  317. $save_membership = $this->verify_nonce( self::ACTION_SAVE ); 
  318.  
  319. if ( $save_membership ) { 
  320. // Save the current Setup-Process. 
  321. $save_data = $_POST; 
  322. unset( $save_data['_wpnonce'] ); 
  323. unset( $save_data['action'] ); 
  324.  
  325. if ( isset( $_POST['set_private_flag'] ) ) { 
  326. lib3()->array->equip_post( 'public' ); 
  327. $save_data['public'] = ! lib3()->is_true( $_POST['public'] ); 
  328. if ( isset( $_POST['set_paid_flag'] ) ) { 
  329. lib3()->array->equip_post( 'paid' ); 
  330. $save_data['is_free'] = ! lib3()->is_true( $_POST['paid'] ); 
  331.  
  332. $msg = $this->save_membership( $save_data ); 
  333.  
  334. // Refresh the $membership variable. 
  335. $membership = $this->load_membership(); 
  336. $membership_id = $membership->id; 
  337.  
  338. switch ( $step ) { 
  339. case self::STEP_MS_LIST: 
  340. // Display a list of all memberships 
  341.  
  342. $fields = array( 'action', 'membership_id' ); 
  343. if ( self::validate_required( $fields, 'GET' ) ) { 
  344. $msg = $this->membership_list_do_action( 
  345. $_GET['action'],  
  346. array( absint( $_GET['membership_id'] ) ) 
  347. ); 
  348. $next_step = self::STEP_MS_LIST; 
  349. break; 
  350.  
  351. case self::STEP_ADD_NEW: 
  352. // Create Membership: Select the Membership-Type 
  353.  
  354. $paid = isset( $_POST['set_paid_flag'] ) 
  355. && isset( $_POST['paid'] ) 
  356. && lib3()->is_true( $_POST['paid'] ); 
  357.  
  358. if ( $paid ) { 
  359. $next_step = self::STEP_PAYMENT; 
  360. } else { 
  361. $next_step = self::STEP_MS_LIST; 
  362. $msg = $this->mark_setup_completed(); 
  363. $completed = true; 
  364. break; 
  365.  
  366. case self::STEP_PAYMENT: 
  367. // Setup payment options 
  368.  
  369. $next_step = self::STEP_MS_LIST; 
  370. break; 
  371.  
  372. case self::STEP_EDIT: 
  373. $this->process_edit_page(); 
  374. break; 
  375.  
  376. if ( ! empty( $next_step ) ) { 
  377. $args = array( 
  378. 'step' => $next_step,  
  379. 'membership_id' => $membership_id,  
  380. ); 
  381.  
  382. if ( ! empty( $msg ) ) { 
  383. $args['msg'] = $msg; 
  384.  
  385. /** 
  386. * Param 'MENU_SLUG' forces the admin-URL to use the top-level 
  387. * menu slug instead of the current base_slug. 
  388. * During Setup-wizard the base_slug ends in '-setup', but when 
  389. * we reach this point the wizard is completed. 
  390. */ 
  391. $slug = 'MENU_SLUG'; 
  392.  
  393. $goto_url = esc_url_raw( 
  394. add_query_arg( 
  395. $args,  
  396. MS_Controller_Plugin::get_admin_url( $slug ) 
  397. ); 
  398.  
  399. $goto_url = apply_filters( 
  400. 'ms_controller_membership_membership_admin_page_process_goto_url',  
  401. $goto_url,  
  402. $next_step 
  403. ); 
  404.  
  405. if ( $completed ) { 
  406. MS_Plugin::flush_rewrite_rules( $goto_url ); 
  407. } else { 
  408. wp_safe_redirect( $goto_url ); 
  409. exit; 
  410. } else { 
  411. // No action request found. 
  412.  
  413. /** 
  414. * Process form data submitted via the edit page. 
  415. * When this function is called the nonce is already confirmed. 
  416. * @since 1.0.1.0 
  417. */ 
  418. protected function process_edit_page() { 
  419. $redirect = false; 
  420.  
  421. switch ( $this->get_active_edit_tab() ) { 
  422. case self::TAB_TYPE: 
  423. $fields_type = array( 'membership_id', 'type' ); 
  424.  
  425. if ( self::validate_required( $fields_type ) ) { 
  426. $id = intval( $_POST['membership_id'] ); 
  427. $membership = MS_Factory::load( 'MS_Model_Membership', $id ); 
  428.  
  429. if ( $membership->id == $id && ! $membership->is_system() ) { 
  430. $membership->type = $_POST['type']; 
  431. $membership->save(); 
  432. break; 
  433.  
  434. case self::TAB_MESSAGES: 
  435. break; 
  436.  
  437. if ( $redirect ) { 
  438. wp_safe_redirect( $redirect ); 
  439. exit(); 
  440.  
  441. /** 
  442. * Route page request to handling method. 
  443. * @since 1.0.0 
  444. */ 
  445. public function admin_page_router() { 
  446. $this->wizard_tracker(); 
  447. $step = $this->get_step(); 
  448.  
  449. if ( self::is_valid_step( $step ) ) { 
  450. $method = 'page_' . $step; 
  451.  
  452. if ( method_exists( $this, $method ) ) { 
  453. $callback = apply_filters( 
  454. 'ms_controller_membership_admin_page_router_callback',  
  455. array( $this, $method ),  
  456. $this 
  457. ); 
  458. call_user_func( $callback ); 
  459. } else { 
  460. do_action( 
  461. 'ms_controller_membership_admin_page_router_' . $step,  
  462. $this 
  463. ); 
  464. MS_Helper_Debug::log( "Method $method not found for step $step" ); 
  465. } else { 
  466. MS_Helper_Debug::log( "Invalid step: $step" ); 
  467.  
  468. do_action( 
  469. 'ms_controller_membership_admin_page_router',  
  470. $step,  
  471. $this 
  472. ); 
  473.  
  474. /** 
  475. * Mark membership setup as complete. 
  476. * @since 1.0.0 
  477. * @return int $msg The action status message code. 
  478. */ 
  479. private function mark_setup_completed() { 
  480. $msg = 0; 
  481. $membership = $this->load_membership(); 
  482.  
  483. if ( $membership->setup_completed() ) { 
  484. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_ADDED; 
  485.  
  486. /** 
  487. * Action run after a new membership was created. 
  488. * @since 1.0.1.0 
  489. * @param MS_Model_Membership $membership The new membership. 
  490. */ 
  491. do_action( 
  492. 'ms_controller_membership_created',  
  493. $membership 
  494. ); 
  495.  
  496. if ( MS_Plugin::is_wizard() ) { 
  497. $this->wizard_tracker( null, true ); 
  498.  
  499. /** 
  500. * Action run after the first membership was created and the 
  501. * setup wizard is completed. 
  502. * This hook is used by M2 to auto-setup some settings according 
  503. * to the first membership that was created (e.g. create menu 
  504. * items, enable Automatic Email Responses, etc.) 
  505. * This filter is only executed ONCE! To perform actions always 
  506. * when a membership was created use the '_created' action above. 
  507. * @since 1.0.0 
  508. * @param MS_Model_Membership $membership The new membership. 
  509. */ 
  510. do_action( 
  511. 'ms_controller_membership_setup_completed',  
  512. $membership 
  513. ); 
  514.  
  515. return apply_filters( 
  516. 'ms_controller_membership_mark_setup_completed',  
  517. $msg,  
  518. $this 
  519. ); 
  520.  
  521. /** 
  522. * Display Choose Membership Type page. 
  523. * @since 1.0.0 
  524. */ 
  525. public function page_add() { 
  526. $data = array(); 
  527. $data['step'] = $this->get_step(); 
  528. $data['action'] = self::ACTION_SAVE; 
  529. $data['membership'] = $this->load_membership(); 
  530.  
  531. $view = MS_Factory::create( 'MS_View_Membership_Add' ); 
  532. $view->data = apply_filters( 'ms_view_membership_add_data', $data, $this ); 
  533. $view->render(); 
  534.  
  535. /** 
  536. * Display Membership List page. 
  537. * @since 1.0.0 
  538. */ 
  539. public function page_list() { 
  540. $membership = $this->load_membership(); 
  541.  
  542. $data = array(); 
  543. $data['step'] = $this->get_step(); 
  544. $data['action'] = self::ACTION_SAVE; 
  545. $data['membership'] = $membership; 
  546. $data['create_new_url'] = MS_Controller_Plugin::get_admin_url( 
  547. false,  
  548. array( 'step' => self::STEP_ADD_NEW ) 
  549. ); 
  550.  
  551. $view = MS_Factory::create( 'MS_View_Membership_List' ); 
  552. $view->data = apply_filters( 'ms_view_membership_list_data', $data, $this ); 
  553. $view->render(); 
  554.  
  555. /** 
  556. * Display Membership Edit page. 
  557. * @since 1.0.0 
  558. */ 
  559. public function page_edit() { 
  560. $membership = $this->load_membership(); 
  561.  
  562. $data = array(); 
  563. $data['tabs'] = $this->get_edit_tabs(); 
  564. $data['settings'] = MS_Plugin::instance()->settings; 
  565. $data['membership'] = $membership; 
  566.  
  567. switch ( $this->get_active_edit_tab() ) { 
  568. case self::TAB_EMAILS: 
  569. $default_type = MS_Model_Communication::COMM_TYPE_REGISTRATION; 
  570. if ( ! empty( $_REQUEST['membership_id'] ) ) { 
  571. $membership_id = intval( $_REQUEST['membership_id'] ); 
  572. $comm_types = array_keys( 
  573. MS_Model_Communication::get_communication_type_titles( 
  574. $membership_id 
  575. ); 
  576. $default_type = reset( $comm_types ); 
  577.  
  578. $temp_type = isset( $_GET['comm_type'] ) ? $_GET['comm_type'] : ''; 
  579. if ( MS_Model_Communication::is_valid_communication_type( $temp_type ) ) { 
  580. $type = $temp_type; 
  581. } else { 
  582. $type = $default_type; 
  583.  
  584. $comm = MS_Model_Communication::get_communication( 
  585. $type,  
  586. $membership,  
  587. true 
  588. ); 
  589.  
  590. $data['comm'] = $comm; 
  591. break; 
  592.  
  593. $view = MS_Factory::create( 'MS_View_Membership_Edit' ); 
  594. $view->data = apply_filters( 'ms_view_membership_edit_data', $data, $this ); 
  595. $view->render(); 
  596.  
  597. /** 
  598. * Display Setup Payment page. 
  599. * @since 1.0.0 
  600. */ 
  601. public function page_payment() { 
  602. $membership = $this->load_membership(); 
  603.  
  604. $data = array(); 
  605. $data['step'] = $this->get_step(); 
  606. $data['action'] = 'save_payment_settings'; 
  607. $data['membership'] = $membership; 
  608. $data['is_global_payments_set'] = MS_Plugin::instance()->settings->is_global_payments_set; 
  609. $data['bread_crumbs'] = $this->get_bread_crumbs(); 
  610.  
  611. if ( isset( $_GET['edit'] ) ) { 
  612. $data['show_next_button'] = false; 
  613. } else { 
  614. $data['show_next_button'] = array( 
  615. 'id' => 'next',  
  616. 'value' => __( 'Finish', 'membership2' ),  
  617. 'action' => 'next',  
  618. ); 
  619.  
  620. $view = MS_Factory::create( 'MS_View_Membership_PaymentSetup' ); 
  621. $view->data = apply_filters( 'ms_view_membership_payment_data', $data, $this ); 
  622. $view->render(); 
  623.  
  624. /** 
  625. * Display Membership Overview page. 
  626. * @since 1.0.0 
  627. */ 
  628. public function page_overview() { 
  629. $membership = $this->load_membership(); 
  630. $membership_id = $membership->id; 
  631.  
  632. $data = array(); 
  633. $data['step'] = $this->get_step(); 
  634. $data['action'] = self::ACTION_SAVE; 
  635. $data['membership'] = $membership; 
  636. $data['bread_crumbs'] = $this->get_bread_crumbs(); 
  637.  
  638. $data['members'] = array(); 
  639. $subscriptions = MS_Model_Relationship::get_subscriptions( 
  640. array( 'membership_id' => $membership->id ) 
  641. ); 
  642.  
  643. foreach ( $subscriptions as $subscription ) { 
  644. $data['members'][] = $subscription->get_member(); 
  645.  
  646. switch ( $membership->type ) { 
  647. case MS_Model_Membership::TYPE_DRIPPED: 
  648. $view = MS_Factory::create( 'MS_View_Membership_Overview_Dripped' ); 
  649. break; 
  650.  
  651. default: 
  652. case MS_Model_Membership::TYPE_STANDARD: 
  653. $view = MS_Factory::create( 'MS_View_Membership_Overview_Simple' ); 
  654. break; 
  655.  
  656. // Select Events args 
  657. $args = array(); 
  658. $args['meta_query']['membership_id'] = array( 
  659. 'key' => 'membership_id',  
  660. 'value' => array( $membership_id, 0 ),  
  661. 'compare' => 'IN',  
  662. ); 
  663. $data['events'] = MS_Model_Event::get_events( $args ); 
  664.  
  665. $view = apply_filters( 'ms_view_membership_overview', $view ); 
  666. $view->data = apply_filters( 'ms_view_membership_overview_data', $data, $this ); 
  667. $view->render(); 
  668.  
  669. /** 
  670. * Display Membership News page. 
  671. * @since 1.0.0 
  672. */ 
  673. public function page_news() { 
  674. $data = array(); 
  675. $data['step'] = $this->get_step(); 
  676. $data['action'] = ''; 
  677. $data['membership'] = $this->load_membership(); 
  678.  
  679. $args = apply_filters( 
  680. 'ms_controller_membership_page_news_event_args',  
  681. array( 'posts_per_page' => -1 ) 
  682. ); 
  683. $data['events'] = MS_Model_Event::get_events( $args ); 
  684.  
  685. $view = MS_Factory::create( 'MS_View_Membership_News' ); 
  686. $view->data = apply_filters( 'ms_view_membership_news_data', $data, $this ); 
  687. $view->render(); 
  688.  
  689. /** 
  690. * Display a welcome screen. 
  691. * @since 1.0.0 
  692. */ 
  693. public function page_welcome() { 
  694. $data = array(); 
  695. $data['step'] = $this->get_step(); 
  696. $data['action'] = 'start'; 
  697.  
  698. $view = MS_Factory::create( 'MS_View_Welcome' ); 
  699. $view->data = apply_filters( 'ms_view_welcome_data', $data, $this ); 
  700. $view->render(); 
  701.  
  702. /** 
  703. * Get Membership setup steps. 
  704. * @since 1.0.0 
  705. * @return string[] The existing steps. 
  706. */ 
  707. public static function get_steps() { 
  708. static $Steps; 
  709.  
  710. if ( empty( $Steps ) ) { 
  711. $Steps = array( 
  712. self::STEP_MS_LIST,  
  713. self::STEP_OVERVIEW,  
  714. self::STEP_EDIT,  
  715. self::STEP_NEWS,  
  716. self::STEP_ADD_NEW,  
  717. self::STEP_PAYMENT,  
  718. ); 
  719.  
  720. if ( MS_Plugin::is_wizard() ) { 
  721. $Steps[] = self::STEP_WELCOME_SCREEN; 
  722.  
  723. return apply_filters( 
  724. 'ms_controller_membership_get_steps',  
  725. $Steps 
  726. ); 
  727.  
  728. /** 
  729. * Validate Membership setup step. 
  730. * @since 1.0.0 
  731. * @param string $step The step name to validate. 
  732. * @return boolean True if valid step. 
  733. */ 
  734. public static function is_valid_step( $step ) { 
  735. $valid = false; 
  736.  
  737. $steps = self::get_steps(); 
  738. if ( in_array( $step, $steps ) ) { 
  739. $valid = true; 
  740.  
  741. return apply_filters( 
  742. 'ms_controller_membership_is_valid_step',  
  743. $valid,  
  744. $step 
  745. ); 
  746.  
  747. /** 
  748. * Get current step. 
  749. * Try to retrieve step from request. 
  750. * Validate the step, returning a default if not valid. 
  751. * since 1.0.0 
  752. * @return string The current step. 
  753. */ 
  754. public function get_step() { 
  755. // Initial step 
  756. $step = self::STEP_MS_LIST; 
  757. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  758. $membership = $this->load_membership(); 
  759.  
  760. // Get current step from request 
  761. if ( ! empty( $_REQUEST['step'] ) && self::is_valid_step( $_REQUEST['step'] ) ) { 
  762. $step = $_REQUEST['step']; 
  763.  
  764. // If user has left before completing the wizard, try to recover last wizard step. 
  765. elseif ( MS_Plugin::is_wizard() ) { 
  766. $wizard_steps = apply_filters( 
  767. 'ms_controller_membership_wizard_steps',  
  768. array( 
  769. self::STEP_WELCOME_SCREEN,  
  770. self::STEP_ADD_NEW,  
  771. ); 
  772.  
  773. if ( $settings->wizard_step 
  774. && in_array( $settings->wizard_step, $wizard_steps ) 
  775. ) { 
  776. $step = $settings->wizard_step; 
  777. } else { 
  778. $step = self::STEP_WELCOME_SCREEN; 
  779.  
  780. // Can't modify membership type 
  781. if ( self::STEP_ADD_NEW == $step && $membership->is_valid() ) { 
  782. $step = self::STEP_OVERVIEW; 
  783.  
  784. return apply_filters( 
  785. 'ms_controller_membership_get_next_step',  
  786. $step,  
  787. $this 
  788. ); 
  789.  
  790. /** 
  791. * Get available tabs for Membership2 page. 
  792. * @since 1.0.0 
  793. * @return array The tabs configuration. 
  794. */ 
  795. public function get_edit_tabs() { 
  796. static $Tabs = null; 
  797.  
  798. if ( null === $Tabs ) { 
  799. $membership = $this->load_membership(); 
  800.  
  801. $args = array( 'include_guest' => false ); 
  802. $count = MS_Model_Membership::get_membership_count( $args ); 
  803.  
  804. $Tabs = array( 
  805. self::TAB_DETAILS => array( 
  806. 'title' => __( 'Details', 'membership2' ),  
  807. ),  
  808. self::TAB_TYPE => array( 
  809. 'title' => __( 'Membership Type', 'membership2' ),  
  810. ),  
  811. self::TAB_PAYMENT => array( 
  812. 'title' => __( 'Payment options', 'membership2' ),  
  813. ),  
  814. /** 
  815. PRO FEATURE => array( 
  816. 'title' => __( 'Upgrade paths', 'membership2' ),  
  817. ),  
  818. Not yet finished... will be added soon. 
  819. self::TAB_PAGES => array( 
  820. 'title' => __( 'Membership Pages', 'membership2' ),  
  821. ),  
  822. PRO FEATURE => array( 
  823. 'title' => __( 'Protection Messages', 'membership2' ),  
  824. ),  
  825.   
  826. PRO FEATURE => array( 
  827. 'title' => __( 'Automated Email Responses', 'membership2' ),  
  828. ),  
  829. */ 
  830. ); 
  831.  
  832. if ( $membership->is_system() ) { 
  833. unset( $Tabs[self::TAB_TYPE] ); 
  834. unset( $Tabs[self::TAB_PAYMENT] ); 
  835. // EMAIL OVERRIDES is PRO ONLY 
  836. // UPGRADE PATHS is PRO ONLY 
  837. } elseif ( $membership->is_free ) { 
  838. $Tabs[self::TAB_PAYMENT]['title'] = __( 'Access options', 'membership2' ); 
  839.  
  840. // UPGRADE PATHS is PRO ONLY 
  841.  
  842. // Allow Add-ons to add or remove rule tabs 
  843. $Tabs = apply_filters( 
  844. 'ms_controller_membership_tabs',  
  845. $Tabs 
  846. ); 
  847.  
  848. foreach ( $Tabs as $key => $tab ) { 
  849. if ( ! empty( $Tabs['key']['url'] ) ) { continue; } 
  850.  
  851. $url = sprintf( 
  852. '%1$s?page=%2$s&step=%3$s&tab=%4$s&membership_id=%5$s',  
  853. admin_url( 'admin.php' ),  
  854. esc_attr( $_REQUEST['page'] ),  
  855. MS_Controller_Membership::STEP_EDIT,  
  856. $key,  
  857. $membership->id 
  858. ); 
  859.  
  860. $Tabs[$key]['url'] = $url; 
  861.  
  862. return $Tabs; 
  863.  
  864. /** 
  865. * Get the current active settings page/tab. 
  866. * @since 1.0.1.0 
  867. */ 
  868. public function get_active_edit_tab() { 
  869. if ( null === $this->active_tab ) { 
  870. if ( self::STEP_EDIT != $this->get_step() ) { 
  871. $this->active_tab = ''; 
  872. } else { 
  873. $tabs = $this->get_edit_tabs(); 
  874.  
  875. reset( $tabs ); 
  876. $first_key = key( $tabs ); 
  877.  
  878. // Setup navigation tabs. 
  879. lib3()->array->equip_get( 'tab' ); 
  880. $active_tab = sanitize_html_class( $_GET['tab'], $first_key ); 
  881.  
  882. if ( ! array_key_exists( $active_tab, $tabs ) ) { 
  883. $active_tab = $first_key; 
  884. $this->active_tab = $active_tab; 
  885.  
  886. return apply_filters( 
  887. 'ms_controller_membership_get_active_edit_tab',  
  888. $this->active_tab,  
  889. $this 
  890. ); 
  891.  
  892. /** 
  893. * Track wizard step. 
  894. * Save current step. 
  895. * since 1.0.0 
  896. * @param string $step Optional. The step to save. Default to current step. 
  897. * @param boolean $end_wizard Optional. Whether end the wizard mode. 
  898. * @return string The current step. 
  899. */ 
  900. public function wizard_tracker( $step = null, $end_wizard = false ) { 
  901. $settings = MS_Plugin::instance()->settings; 
  902.  
  903. if ( empty( $step ) ) { 
  904. $step = $this->get_step(); 
  905.  
  906. if ( MS_Plugin::is_wizard() ) { 
  907. $settings->wizard_step = $step; 
  908.  
  909. if ( $end_wizard ) { 
  910. $settings->initial_setup = false; 
  911. $settings->save(); 
  912.  
  913. do_action( 
  914. 'ms_controller_membership_wizard_tracker',  
  915. $step,  
  916. $end_wizard,  
  917. $settings,  
  918. $this 
  919. ); 
  920.  
  921. /** 
  922. * Execute action in Membership model. 
  923. * @since 1.0.0 
  924. * @todo There is no more bulk actions. Deprecate this method and create a specific one. 
  925. * @param string $action The action to execute. 
  926. * @param int[] $membership_ids The membership ids which action will be taken. 
  927. * @return number Resulting message id. 
  928. */ 
  929. private function membership_list_do_action( $action, $membership_ids ) { 
  930. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_NOT_UPDATED; 
  931.  
  932. if ( ! $this->is_admin_user() ) { 
  933. return $msg; 
  934.  
  935. $msg = 0; 
  936. foreach ( $membership_ids as $membership_id ) { 
  937. $membership = MS_Factory::load( 'MS_Model_Membership', $membership_id ); 
  938.  
  939. switch ( $action ) { 
  940. case 'toggle_active': 
  941. case 'toggle_activation': 
  942. $membership->active = ! $membership->active; 
  943. $membership->save(); 
  944. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_ACTIVATION_TOGGLED; 
  945. break; 
  946.  
  947. case 'toggle_public': 
  948. $membership->private = ! $membership->private; 
  949. $membership->save(); 
  950. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_STATUS_TOGGLED; 
  951. break; 
  952.  
  953. case 'delete': 
  954. try { 
  955. $membership->delete(); 
  956. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_DELETED; 
  957. catch( Exception $e ) { 
  958. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_NOT_DELETED; 
  959. break; 
  960.  
  961. return $msg; 
  962.  
  963. /** 
  964. * Get Membership page bread crumbs. 
  965. * @since 1.0.0 
  966. * @return array The bread crumbs array. 
  967. */ 
  968. public function get_bread_crumbs() { 
  969. $step = $this->get_step(); 
  970. $membership = $this->load_membership(); 
  971.  
  972. $bread_crumbs = array(); 
  973.  
  974. switch ( $step ) { 
  975. case self::STEP_OVERVIEW: 
  976. $bread_crumbs['prev'] = array( 
  977. 'title' => __( 'Memberships', 'membership2' ),  
  978. 'url' => MS_Controller_Plugin::get_admin_url( 
  979. false,  
  980. array( 'step' => self::STEP_MS_LIST ) 
  981. ),  
  982. ); 
  983. $bread_crumbs['current'] = array( 
  984. 'title' => $membership->name,  
  985. ); 
  986. break; 
  987.  
  988. case self::STEP_PAYMENT: 
  989. $bread_crumbs['prev'] = array( 
  990. 'title' => $membership->name,  
  991. 'url' => MS_Controller_Plugin::get_admin_url( 
  992. false,  
  993. array( 
  994. 'step' => self::STEP_OVERVIEW,  
  995. 'membership_id' => $membership->id,  
  996. ),  
  997. ); 
  998. $bread_crumbs['current'] = array( 
  999. 'title' => __( 'Payment', 'membership2' ),  
  1000. ); 
  1001. break; 
  1002.  
  1003. // Add the "edit" param if it is set. 
  1004. if ( isset( $_GET['edit'] ) ) { 
  1005. foreach ( $bread_crumbs as $key => $data ) { 
  1006. if ( isset( $bread_crumbs[$key]['url'] ) ) { 
  1007. $bread_crumbs[$key]['url'] .= '&edit=1'; 
  1008.  
  1009. return apply_filters( 
  1010. 'ms_controller_membership_get_bread_crumbs',  
  1011. $bread_crumbs,  
  1012. $this 
  1013. ); 
  1014.  
  1015. /** 
  1016. * Save membership general tab fields 
  1017. * @since 1.0.0 
  1018. * @param mixed[] $fields 
  1019. */ 
  1020. private function save_membership( $fields ) { 
  1021. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_NOT_UPDATED; 
  1022.  
  1023. if ( $this->is_admin_user() ) { 
  1024. $membership = $this->load_membership(); 
  1025.  
  1026. if ( is_array( $fields ) ) { 
  1027. $updated = 0; 
  1028. $failed = 0; 
  1029. foreach ( $fields as $field => $value ) { 
  1030. $key = false; 
  1031.  
  1032. // Very basic support for array updates. 
  1033. // We only support updating 1-dimensional arrays with a 
  1034. // specified key value. 
  1035. if ( strpos( $field, '[' ) ) { 
  1036. $field = str_replace( ']', '', $field ); 
  1037. list( $field, $key ) = explode( '[', $field, 2 ); 
  1038.  
  1039. try { 
  1040. $the_value = $membership->$field; 
  1041. if ( $key ) { 
  1042. $the_value = lib3()->array->get( $the_value ); 
  1043. $the_value[$key] = $value; 
  1044. } else { 
  1045. $the_value = $value; 
  1046. $membership->$field = $the_value; 
  1047.  
  1048. $updated += 1; 
  1049. catch ( Exception $e ) { 
  1050. $failed += 1; 
  1051. $membership->save(); 
  1052.  
  1053. if ( $updated > 0 ) { 
  1054. if ( ! $failed ) { 
  1055. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_UPDATED; 
  1056. } else { 
  1057. $msg = MS_Helper_Membership::MEMBERSHIP_MSG_PARTIALLY_UPDATED; 
  1058.  
  1059. return apply_filters( 
  1060. 'ms_controller_membership_save_membership_msg',  
  1061. $msg,  
  1062. $fields,  
  1063. $this 
  1064. ); 
  1065.  
  1066. /** 
  1067. * Load Membership manager specific styles. 
  1068. * @since 1.0.0 
  1069. */ 
  1070. public function enqueue_styles() { 
  1071. lib3()->ui->add( 'jquery-ui' ); 
  1072.  
  1073. do_action( 'ms_controller_membership_enqueue_styles', $this ); 
  1074.  
  1075. /** 
  1076. * Load Membership manager specific scripts. 
  1077. * @since 1.0.0 
  1078. */ 
  1079. public function enqueue_scripts() { 
  1080. $data = array( 
  1081. 'ms_init' => array(),  
  1082. 'lang' => array( 
  1083. 'msg_delete' => __( 'Do you want to completely delete the membership <strong>%s</strong> including all subscriptions?', 'membership2' ),  
  1084. 'btn_delete' => __( 'Delete', 'membership2' ),  
  1085. 'btn_cancel' => __( 'Cancel', 'membership2' ),  
  1086. 'quickedit_error' => __( 'Error while saving changes.', 'membership2' ),  
  1087. ),  
  1088. ); 
  1089.  
  1090. $step = $this->get_step(); 
  1091.  
  1092. switch ( $step ) { 
  1093. case self::STEP_WELCOME_SCREEN: 
  1094. break; 
  1095.  
  1096. case self::STEP_ADD_NEW: 
  1097. $data['ms_init'][] = 'view_membership_add'; 
  1098. $data['initial_url'] = MS_Controller_Plugin::get_admin_url(); 
  1099. break; 
  1100.  
  1101. case self::STEP_OVERVIEW: 
  1102. $data['ms_init'][] = 'view_membership_overview'; 
  1103. break; 
  1104.  
  1105. case self::STEP_PAYMENT: 
  1106. $data['ms_init'][] = 'view_membership_payment'; 
  1107. $data['ms_init'][] = 'view_settings_payment'; 
  1108. break; 
  1109.  
  1110. case self::STEP_EDIT: 
  1111. $data['ms_init'][] = 'view_membership_payment'; 
  1112. $tab = $this->get_active_edit_tab(); 
  1113.  
  1114. switch ( $tab ) { 
  1115. case self::TAB_TYPE: 
  1116. add_thickbox(); 
  1117. $data['ms_init'][] = 'view_membership_add'; 
  1118. break; 
  1119.  
  1120. // UPGRADE PATHS is PRO ONLY 
  1121.  
  1122. // MESSAGE OVERRIDE is PRO ONLY 
  1123.  
  1124. // EMAIL OVERRIDE id PRO ONLY 
  1125.  
  1126. do_action( 
  1127. 'ms_controller_membership_enqueue_scripts_tab-' . $tab,  
  1128. $this 
  1129. ); 
  1130. break; 
  1131.  
  1132. case self::STEP_MS_LIST: 
  1133. $data['ms_init'][] = 'view_membership_list'; 
  1134. $data['ms_init'][] = 'view_settings_setup'; 
  1135. break; 
  1136.  
  1137. lib3()->ui->data( 'ms_data', $data ); 
  1138. wp_enqueue_script( 'ms-admin' ); 
  1139. wp_enqueue_script( 'jquery-validate' ); 
  1140.  
  1141. do_action( 
  1142. 'ms_controller_membership_enqueue_scripts',  
  1143. $this 
  1144. ); 
  1145. do_action( 
  1146. 'ms_controller_membership_enqueue_scripts-' . $step,  
  1147. $this 
  1148. ); 
  1149.