MS_Controller_Member

Controller for managing Members and Membership relationships.

Defined (1)

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

/app/controller/class-ms-controller-member.php  
  1. class MS_Controller_Member extends MS_Controller { 
  2.  
  3. /** 
  4. * AJAX action constant: Edit subscriptions of a single member. 
  5. * @since 1.0.0 
  6. * @var string 
  7. */ 
  8. const AJAX_ACTION_CHANGE_MEMBERSHIPS = 'member_subscriptions'; 
  9.  
  10. /** 
  11. * AJAX action constant: Validate a user field before creating the user. 
  12. * @since 1.0.1.0 
  13. * @var string 
  14. */ 
  15. const AJAX_ACTION_VALIDATE_FIELD = 'member_validate_field'; 
  16.  
  17. /** 
  18. * AJAX action constant: Search users via Ajax. 
  19. * @since 1.0.1.0 
  20. * @var string 
  21. */ 
  22. const AJAX_ACTION_SEARCH = 'member_search'; 
  23.  
  24. /** 
  25. * Used on the Add Member screen to indicate that a new WP User should be 
  26. * created and added to M2. 
  27. * @since 1.0.1.0 
  28. * @var string 
  29. */ 
  30. const ACTION_ADD_MEMBER = 'member_add'; 
  31.  
  32. /** 
  33. * Used on the Add Member screen to indicate that the submitted form details 
  34. * should update an existing user. 
  35. * @since 1.0.1.0 
  36. * @var string 
  37. */ 
  38. const ACTION_UPDATE_MEMBER = 'member_update'; 
  39.  
  40. /** 
  41. * Used on the Add Member screen to trigger a new subscription action for an 
  42. * existing user (user subscribes to one or multiple memberships) 
  43. * @since 1.0.1.0 
  44. * @var string 
  45. */ 
  46. const ACTION_MODIFY_SUBSCRIPTIONS = 'member_subscription'; 
  47.  
  48. /** 
  49. * Used on the Add Member screen to indicate that an existing WP User should 
  50. * be added to M2. 
  51. * @since 1.0.1.0 
  52. * @var string 
  53. */ 
  54. const ACTION_SELECT_MEMBER = 'member_select'; 
  55.  
  56. /** 
  57. * Prepare the Member manager. 
  58. * @since 1.0.0 
  59. */ 
  60. public function __construct() { 
  61. parent::__construct(); 
  62.  
  63. $this->add_action( 
  64. 'ms_controller_membership_setup_completed',  
  65. 'add_current_user' 
  66. ); 
  67.  
  68. $this->add_ajax_action( 
  69. self::AJAX_ACTION_CHANGE_MEMBERSHIPS,  
  70. 'ajax_action_change_memberships' 
  71. ); 
  72.  
  73. $this->add_ajax_action( 
  74. self::AJAX_ACTION_VALIDATE_FIELD,  
  75. 'ajax_action_validate_field' 
  76. ); 
  77.  
  78. $this->add_ajax_action( 
  79. self::AJAX_ACTION_SEARCH,  
  80. 'ajax_action_search' 
  81. ); 
  82.  
  83. /** 
  84. * Initialize the admin-side functions. 
  85. * @since 1.0.0 
  86. */ 
  87. public function admin_init() { 
  88. $hooks = array( 
  89. 'list' => MS_Controller_Plugin::admin_page_hook( 'members' ),  
  90. 'editor' => MS_Controller_Plugin::admin_page_hook( 'add-member' ),  
  91. ); 
  92.  
  93. foreach ( $hooks as $key => $hook ) { 
  94. $this->run_action( 'load-' . $hook, 'members_admin_page_process_' . $key ); 
  95. $this->run_action( 'admin_print_scripts-' . $hook, 'enqueue_scripts_' . $key ); 
  96. $this->run_action( 'admin_print_styles-' . $hook, 'enqueue_styles' ); 
  97.  
  98. /** 
  99. * Add the current user to the Members-List. 
  100. * This does NOT assign any membership to the user, but ensures that the 
  101. * admin user appears in the Members-List 
  102. * @since 1.0.0 
  103. */ 
  104. public function add_current_user() { 
  105. $member = MS_Factory::load( 
  106. 'MS_Model_Member',  
  107. get_current_user_id() 
  108. ); 
  109.  
  110. $member->is_member = true; 
  111. $member->save(); 
  112.  
  113. /** 
  114. * Manages membership actions. 
  115. * Verifies GET and POST requests to manage members 
  116. * @since 1.0.0 
  117. */ 
  118. public function members_admin_page_process_list() { 
  119. $msg = 0; 
  120. $redirect = false; 
  121.  
  122. if ( $this->is_admin_user() ) { 
  123. $fields_new = array( 'new_member', 'action' ); 
  124. $fields_edit = array( 'member_id', 'action' ); 
  125.  
  126. // Execute list table single action. 
  127. if ( $this->verify_nonce( null, 'GET' ) 
  128. && self::validate_required( $fields_edit, 'GET' ) 
  129. ) { 
  130. $msg = $this->member_list_do_action( 
  131. $_GET['action'],  
  132. array( $_GET['member_id'] ) 
  133. ); 
  134.  
  135. $redirect = esc_url_raw( 
  136. add_query_arg( 
  137. array( 'msg' => $msg ),  
  138. remove_query_arg( 
  139. array( 'member_id', 'action', '_wpnonce' ) 
  140. ); 
  141.  
  142. // Execute list table bulk actions. 
  143. elseif ( $this->verify_nonce( 'bulk' ) ) { 
  144. lib3()->array->equip_post( 'action', 'action2', 'member_id' ); 
  145. $action = $_POST['action']; 
  146. if ( empty( $action ) || $action == '-1' ) { 
  147. $action = $_POST['action2']; 
  148. $members = $_POST['member_id']; 
  149.  
  150. /** 
  151. * The Bulk-Edit action is built like 'cmd-id' 
  152. * e.g. 'add-123' will add membership 123 to the selected items. 
  153. */ 
  154. if ( empty( $action ) ) { 
  155. $cmd = array(); 
  156. } elseif ( empty( $members ) ) { 
  157. $cmd = array(); 
  158. } elseif ( '-1' == $action ) { 
  159. $cmd = array(); 
  160. } else { 
  161. $cmd = explode( '-', $action ); 
  162.  
  163. if ( 2 == count( $cmd ) ) { 
  164. $action = $cmd[0]; 
  165. $action_id = $cmd[1]; 
  166.  
  167. // Get a list of specified memberships... 
  168. if ( is_numeric( $action_id ) ) { 
  169. // ... either a single membership. 
  170. $memberships = array( 
  171. MS_Factory::load( 'MS_Model_Membership', $action_id ),  
  172. ); 
  173. } elseif ( 'all' == $action_id ) { 
  174. // ... or all memberships. 
  175. $memberships = MS_Model_Membership::get_memberships(); 
  176.  
  177. // Loop defined memberships and add/remove members. 
  178. foreach ( $memberships as $membership ) { 
  179. $msg = $this->member_list_do_action( 
  180. $action,  
  181. $members,  
  182. $membership->id 
  183. ); 
  184.  
  185. $redirect = esc_url_raw( 
  186. add_query_arg( array( 'msg' => $msg ) ) 
  187. ); 
  188.  
  189. // Execute edit view page action submit. 
  190. elseif ( isset( $_POST['submit'] ) 
  191. && $this->verify_nonce() 
  192. && self::validate_required( $fields_edit, 'POST' ) 
  193. ) { 
  194. if ( is_array( $_POST['member_id'] ) ) { 
  195. $member_ids = $_POST['member_id']; 
  196. } else { 
  197. $member_ids = explode( ', ', $_POST['member_id'] ); 
  198.  
  199. $msg = $this->member_list_do_action( 
  200. $_POST['action'],  
  201. $member_ids,  
  202. $_POST['membership_id'] 
  203. ); 
  204.  
  205. $redirect = esc_url_raw( 
  206. add_query_arg( array( 'msg' => $msg ) ) 
  207. ); 
  208.  
  209. if ( $redirect ) { 
  210. wp_safe_redirect( $redirect ); 
  211. exit; 
  212.  
  213. /** 
  214. * Manages membership actions for the ADD/EDIT screen. 
  215. * @since 1.0.1.0 
  216. */ 
  217. public function members_admin_page_process_editor() { 
  218. $msg = 0; 
  219. $redirect = false; 
  220.  
  221. if ( $this->is_admin_user() ) { 
  222. $fields_add = array( 'username', 'email' ); 
  223. $fields_select = array( 'user_id' ); 
  224. $fields_update = array( 'user_id', 'email' ); 
  225. $fields_modify = array( 'user_id', 'memberships' ); 
  226. $fields_subscribe = array( 'user_id', 'subscribe' ); 
  227.  
  228. // Process Action: Create new user. 
  229. if ( isset( $_POST['btn_create'] ) 
  230. && $this->verify_nonce() 
  231. && self::validate_required( $fields_add, 'POST' ) 
  232. ) { 
  233. $data = array( 
  234. 'user_login' => $_POST['username'],  
  235. 'user_email' => $_POST['email'],  
  236. 'first_name' => $_POST['first_name'],  
  237. 'last_name' => $_POST['last_name'],  
  238. 'user_pass' => $_POST['password'],  
  239. ); 
  240. $user_id = wp_insert_user( $data ); 
  241.  
  242. if ( ! is_wp_error( $user_id ) ) { 
  243. $redirect = esc_url_raw( 
  244. add_query_arg( array( 'user_id' => $user_id ) ) 
  245. ); 
  246.  
  247. // Process Action: Select existing user. 
  248. elseif ( isset( $_POST['btn_select'] ) 
  249. && $this->verify_nonce() 
  250. && self::validate_required( $fields_select, 'POST' ) 
  251. ) { 
  252. $user_id = intval( $_POST['user_id'] ); 
  253.  
  254. $redirect = esc_url_raw( 
  255. add_query_arg( array( 'user_id' => $user_id ) ) 
  256. ); 
  257.  
  258. // Process Action: Update existing user. 
  259. elseif ( isset( $_POST['btn_save'] ) 
  260. && $this->verify_nonce() 
  261. && self::validate_required( $fields_update, 'POST' ) 
  262. ) { 
  263. $data = array( 
  264. 'ID' => intval( $_POST['user_id'] ),  
  265. 'user_email' => $_POST['email'],  
  266. 'first_name' => $_POST['first_name'],  
  267. 'last_name' => $_POST['last_name'],  
  268. 'display_name' => $_POST['displayname'],  
  269. ); 
  270. wp_update_user( $data ); 
  271.  
  272. // Process Action: Subscribe to a new membership. 
  273. elseif ( isset( $_POST['btn_modify'] ) 
  274. && $this->verify_nonce() 
  275. ) { 
  276. $user_id = intval( $_POST['user_id'] ); 
  277. $user = MS_Factory::load( 'MS_Model_Member', $user_id ); 
  278.  
  279. // Modify existing subscriptions. 
  280. if ( self::validate_required( $fields_modify, 'POST' ) ) { 
  281. $memberships = lib3()->array->get( $_POST['memberships'] ); 
  282.  
  283. foreach ( $memberships as $membership_id ) { 
  284. if ( empty( $_POST['mem_' . $membership_id] ) ) { continue; } 
  285.  
  286. $subscription = $user->get_subscription( $membership_id ); 
  287. $data = $_POST['mem_' . $membership_id]; 
  288.  
  289. $subscription->start_date = $data['start']; 
  290. $subscription->expire_date = $data['expire']; 
  291. $subscription->status = $data['status']; 
  292. $subscription->save(); 
  293.  
  294. // Add new subscriptions. 
  295. if ( self::validate_required( $fields_subscribe, 'POST' ) ) { 
  296. $subscribe_to = $_POST['subscribe']; 
  297.  
  298. if ( MS_Model_Addon::is_enabled( MS_Model_Addon::ADDON_MULTI_MEMBERSHIPS ) ) { 
  299. // Memberships is an array. 
  300. foreach ( $subscribe_to as $membership_id ) { 
  301. $user->add_membership( $membership_id, 'admin' ); 
  302. } else { 
  303. // Memberships is a single ID. 
  304. foreach ( $user->subscriptions as $subscription ) { 
  305. $subscription->deactivate_membership( false ); 
  306. $user->add_membership( $subscribe_to, 'admin' ); 
  307.  
  308. $user->save(); 
  309.  
  310. if ( $redirect ) { 
  311. wp_safe_redirect( $redirect ); 
  312. exit; 
  313.  
  314. /** 
  315. * Show member list. 
  316. * Menu "All Members", show all members available. 
  317. * Called by MS_Controller_Plugin::route_submenu_request() 
  318. * @since 1.0.0 
  319. */ 
  320. public function admin_page() { 
  321. $data = array(); 
  322.  
  323. $view = MS_Factory::create( 'MS_View_Member_List' ); 
  324. $view->data = apply_filters( 'ms_view_member_list_data', $data ); 
  325. $view->render(); 
  326.  
  327. /** 
  328. * Show member editor. 
  329. * Menu "Add Member", add or edit a single member. 
  330. * Called by MS_Controller_Plugin::route_submenu_request() 
  331. * @since 1.0.1.0 
  332. */ 
  333. public function admin_page_editor() { 
  334. $data = array(); 
  335.  
  336. if ( ! empty( $_REQUEST['user_id'] ) && intval( $_REQUEST['user_id'] ) ) { 
  337. $data['user_id'] = intval( $_REQUEST['user_id'] ); 
  338. $data['action'] = 'edit'; 
  339. } else { 
  340. $data['user_id'] = 0; 
  341. $data['action'] = 'add'; 
  342.  
  343. $view = MS_Factory::create( 'MS_View_Member_Editor' ); 
  344. $view->data = apply_filters( 'ms_view_member_editor_data', $data ); 
  345. $view->render(); 
  346.  
  347. /** 
  348. * Handle Ajax change-memberships action. 
  349. * This action handler is only called by admin users via the Members admin 
  350. * page, so all memberships added here have gateway_id 'admin'. 
  351. * Related Action Hooks: 
  352. * - wp_ajax_change_memberships 
  353. * @since 1.0.0 
  354. */ 
  355. public function ajax_action_change_memberships() { 
  356. $msg = 0; 
  357. $this->_resp_reset(); 
  358.  
  359. $required = array( 'member' ); 
  360. if ( $this->_resp_ok() && ! $this->is_admin_user() ) { 
  361. $this->_resp_err( 'permission denied' ); 
  362. } elseif ( $this->_resp_ok() && ! $this->verify_nonce() ) { 
  363. $this->_resp_err( 'subscribe: nonce' ); 
  364. } elseif ( $this->_resp_ok() && ! self::validate_required( $required ) ) { 
  365. $this->_resp_err( 'subscribe: required' ); 
  366.  
  367. if ( $this->_resp_ok() ) { 
  368. $values = array(); 
  369. if ( isset( $_POST['values'] ) && is_array( $_POST['values'] ) ) { 
  370. $values = $_POST['values']; 
  371.  
  372. $msg = $this->assign_memberships( 
  373. $_POST['member'],  
  374. $values 
  375. ); 
  376. $msg .= $this->_resp_code(); 
  377.  
  378. echo $msg; 
  379. exit; 
  380.  
  381. /** 
  382. * Handle Ajax validate field action. 
  383. * This function should validate the field value before the user is created 
  384. * to make sure that the value is unique/valid. 
  385. * Related Action Hooks: 
  386. * - wp_ajax_validate_field 
  387. * @since 1.0.1.0 
  388. */ 
  389. public function ajax_action_validate_field() { 
  390. $msg = 0; 
  391. $this->_resp_reset(); 
  392.  
  393. $required = array( 'field', 'value' ); 
  394. if ( $this->_resp_ok() && ! $this->is_admin_user() ) { 
  395. $this->_resp_err( 'permission denied' ); 
  396. } elseif ( $this->_resp_ok() && ! self::validate_required( $required ) ) { 
  397. $this->_resp_err( 'validate: required' ); 
  398.  
  399. if ( $this->_resp_ok() ) { 
  400. $field = $_POST['field']; 
  401. $value = $_POST['value']; 
  402.  
  403. if ( 'email' == $field ) { 
  404. if ( ! is_email( $value ) ) { 
  405. $msg = __( 'Invalid Email address', 'membership2' ); 
  406. } elseif ( email_exists( $value ) ) { 
  407. $msg = __( 'Email already taken', 'membership2' ); 
  408. } else { 
  409. $msg = 1; 
  410. } elseif ( 'username' == $field ) { 
  411. if ( username_exists( $value ) ) { 
  412. $msg = __( 'Username already taken', 'membership2' ); 
  413. } else { 
  414. $msg = 1; 
  415. $msg .= $this->_resp_code(); 
  416.  
  417. echo $msg; 
  418. exit; 
  419.  
  420. /** 
  421. * Handle Ajax search users action. 
  422. * Related Action Hooks: 
  423. * - wp_ajax_search 
  424. * @since 1.0.1.0 
  425. */ 
  426. public function ajax_action_search() { 
  427. $res = (object) array( 
  428. 'items' => array(),  
  429. 'more' => false,  
  430. ); 
  431. $this->_resp_reset(); 
  432. $items_per_page = 20; 
  433.  
  434. $required = array( 'q' ); 
  435. if ( $this->_resp_ok() && ! $this->is_admin_user() ) { 
  436. $this->_resp_err( 'permission denied' ); 
  437. } elseif ( $this->_resp_ok() && ! self::validate_required( $required, 'any' ) ) { 
  438. $this->_resp_err( 'search: required' ); 
  439. if ( empty( $_REQUEST['p'] ) ) { $_REQUEST['p'] = 0; } 
  440.  
  441. if ( $this->_resp_ok() ) { 
  442. $term = $_REQUEST['q']; 
  443. $page = max( intval( $_REQUEST['p'] ) - 1, 0 ); 
  444. $offset = $page * $items_per_page; 
  445.  
  446. $args = array( 
  447. 'search' => '*' . $term . '*',  
  448. 'offset' => $offset,  
  449. 'number' => $items_per_page + 1,  
  450. 'fields' => array( 
  451. 'ID',  
  452. 'user_login',  
  453. 'display_name',  
  454. ),  
  455. 'orderby' => 'display_name',  
  456. ); 
  457. $users = get_users( $args ); 
  458.  
  459. if ( count( $users ) > $items_per_page ) { 
  460. $res->more = true; 
  461. array_pop( $users ); 
  462.  
  463. foreach ( $users as $user ) { 
  464. $res->items[] = array( 
  465. 'id' => $user->ID,  
  466. 'text' => sprintf( 
  467. '%s (%s)',  
  468. $user->display_name,  
  469. $user->user_login 
  470. ),  
  471. ); 
  472.  
  473. echo json_encode( $res ); 
  474. exit; 
  475.  
  476. /** 
  477. * Assigns (or removes) memberships to a Member. 
  478. * @since 1.0.0 
  479. * @param string $user_id 
  480. * @param array $memberships Memberships that will be assigned to the 
  481. * rule-item. Memberships that are not mentioned are removed. 
  482. * @return string [description] 
  483. */ 
  484. private function assign_memberships( $user_id, $memberships ) { 
  485. $member = MS_Factory::load( 'MS_Model_Member', $user_id ); 
  486.  
  487. $memberships = apply_filters( 
  488. 'ms_controller_member_assign_memberships',  
  489. $memberships,  
  490. $member,  
  491. $this 
  492. ); 
  493.  
  494. // Drop memberships that are not specified 
  495. foreach ( $member->get_membership_ids() as $old_id ) { 
  496. if ( in_array( $old_id, $memberships ) ) { continue; } 
  497. $member->drop_membership( $old_id ); 
  498.  
  499. // Add new memberships 
  500. foreach ( $memberships as $membership_id ) { 
  501. $subscription = $member->add_membership( $membership_id ); 
  502.  
  503. if ( $member->has_membership() ) { 
  504. $member->is_member = true; 
  505. } else { 
  506. $member->is_member = false; 
  507. $member->save(); 
  508.  
  509. do_action( 
  510. 'ms_controller_member_assign_memberships_done',  
  511. $member,  
  512. $memberships,  
  513. $this 
  514. ); 
  515.  
  516. return MS_Helper_Membership::MEMBERSHIP_MSG_UPDATED; 
  517.  
  518. /** 
  519. * Handles Member list actions. 
  520. * @since 1.0.0 
  521. * @param string $action The action to execute. 
  522. * @param object[] $members Array of members. 
  523. * @param int $membership_id The Membership to apply action to. 
  524. */ 
  525. public function member_list_do_action( $action, $members, $membership_id = null ) { 
  526. $msg = MS_Helper_Member::MSG_MEMBER_NOT_UPDATED; 
  527. if ( ! $this->is_admin_user() ) { 
  528. return $msg; 
  529.  
  530. foreach ( $members as $member_id ) { 
  531. // Member Model 
  532. $member = MS_Factory::load( 'MS_Model_Member', $member_id ); 
  533. switch ( $action ) { 
  534. case 'add': 
  535. $member->add_membership( $membership_id ); 
  536. $msg = MS_Helper_Member::MSG_MEMBER_ADDED; 
  537. break; 
  538.  
  539. case 'drop': 
  540. $member->drop_membership( $membership_id ); 
  541. $msg = MS_Helper_Member::MSG_MEMBER_DELETED; 
  542. break; 
  543.  
  544. case 'move': 
  545. if ( ! empty( $_POST['membership_move_from_id'] ) ) { 
  546. $member->move_membership( 
  547. $_POST['membership_move_from_id'],  
  548. $_POST['membership_id'] 
  549. ); 
  550. $msg = MS_Helper_Member::MSG_MEMBER_UPDATED; 
  551. break; 
  552.  
  553. case 'edit_date': 
  554. if ( is_array( $membership_id ) ) { 
  555. foreach ( $membership_id as $id ) { 
  556. $subscription = $member->get_subscriptions( $id ); 
  557. if ( ! empty( $_POST[ 'start_date_' . $id ] ) ) { 
  558. $subscription->start_date = $_POST[ 'start_date_' . $id ]; 
  559. $subscription->set_trial_expire_date(); 
  560.  
  561. if ( ! empty( $_POST[ 'expire_date_' . $id ] ) ) { 
  562. $subscription->expire_date = $_POST[ 'expire_date_' . $id ]; 
  563. $subscription->save(); 
  564. $msg = MS_Helper_Member::MSG_MEMBER_UPDATED; 
  565. break; 
  566. $member->save(); 
  567.  
  568. return apply_filters( 
  569. 'ms_controller_member_member_list_do_action',  
  570. $msg,  
  571. $action,  
  572. $members,  
  573. $membership_id,  
  574. $this 
  575. ); 
  576.  
  577. /** 
  578. * Load Member manager specific styles. 
  579. * @since 1.0.0 
  580. */ 
  581. public function enqueue_styles() { 
  582. lib3()->ui->add( 'jquery-ui' ); 
  583.  
  584. /** 
  585. * Load Member specific scripts for the LIST view. 
  586. * @since 1.0.0 
  587. */ 
  588. public function enqueue_scripts_list() { 
  589. $data = array( 
  590. 'ms_init' => array(),  
  591. ); 
  592. lib3()->array->equip_get( 'action' ); 
  593.  
  594. if ( 'edit_date' == $_GET['action'] ) { 
  595. // Start and expire date edit 
  596. wp_enqueue_script( 'jquery-ui-datepicker' ); 
  597. $data['ms_init'][] = 'view_member_date'; 
  598. } else { 
  599. // Members list 
  600. $data['ms_init'][] = 'view_member_list'; 
  601. $data['lang'] = array( 
  602. 'select_user' => __( 'Select an User', 'membership2' ),  
  603. ); 
  604.  
  605. lib3()->ui->data( 'ms_data', $data ); 
  606. wp_enqueue_script( 'ms-admin' ); 
  607.  
  608. /** 
  609. * Load Member specific scripts for ADD/EDIT screen. 
  610. * @since 1.0.1.0 
  611. */ 
  612. public function enqueue_scripts_editor() { 
  613. $data = array( 
  614. 'ms_init' => array(),  
  615. ); 
  616.  
  617. $data['ms_init'][] = 'view_member_editor'; 
  618.  
  619. lib3()->ui->data( 'ms_data', $data ); 
  620. wp_enqueue_script( 'ms-admin' ); 
  621.