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