/app/controller/class-ms-controller-membership.php

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