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

  1. <?php 
  2. /** 
  3. * This file defines the MS_Controller_Registration class. 
  4. * 
  5. * @copyright Incsub (http://incsub.com/) 
  6. * 
  7. * @license http://opensource.org/licenses/GPL-2.0 GNU General Public License, version 2 (GPL-2.0) 
  8. * 
  9. * This program is free software; you can redistribute it and/or modify 
  10. * it under the terms of the GNU General Public License, version 2, as 
  11. * published by the Free Software Foundation. 
  12. * 
  13. * This program is distributed in the hope that it will be useful,  
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  16. * GNU General Public License for more details. 
  17. * 
  18. * You should have received a copy of the GNU General Public License 
  19. * along with this program; if not, write to the Free Software 
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  
  21. * MA 02110-1301 USA 
  22. * 
  23. */ 
  24.  
  25. /** 
  26. * Creates the controller for Membership/User registration. 
  27. * 
  28. * @since 1.0.0 
  29. * 
  30. * @package Membership2 
  31. * @subpackage Controller 
  32. */ 
  33. class MS_Controller_Frontend extends MS_Controller { 
  34.  
  35. /** 
  36. * Signup/register process step constants. 
  37. * 
  38. * @since 1.0.0 
  39. * 
  40. * @var string 
  41. */ 
  42. const STEP_CHOOSE_MEMBERSHIP = 'choose_membership'; 
  43. const STEP_REGISTER_FORM = 'register'; 
  44. const STEP_REGISTER_FORM_ALT = 'register_form'; 
  45. const STEP_REGISTER_SUBMIT = 'register_submit'; 
  46. const STEP_PAYMENT_TABLE = 'payment_table'; 
  47. const STEP_GATEWAY_FORM = 'gateway_form'; 
  48. const STEP_PROCESS_PURCHASE = 'process_purchase'; 
  49.  
  50. /** 
  51. * AJAX action constants. 
  52. * 
  53. * @since 1.0.0 
  54. * 
  55. * @var string 
  56. */ 
  57. const ACTION_EDIT_PROFILE = 'edit_profile'; 
  58. const ACTION_VIEW_INVOICES = 'view_invoices'; 
  59. const ACTION_VIEW_ACTIVITIES = 'view_activities'; 
  60. const ACTION_VIEW_RESETPASS = 'rp'; 
  61.  
  62. /** 
  63. * Whether Membership2 will handle the registration process or not. 
  64. * This should not be changed directly but via filter ms_frontend_handle_registration 
  65. * 
  66. * @since 1.1.1.3 
  67. * 
  68. * @var bool 
  69. */ 
  70. static public $handle_registration = true; 
  71.  
  72. /** 
  73. * User registration errors. 
  74. * 
  75. * @since 1.0.0 
  76. * 
  77. * @var string 
  78. */ 
  79. private $register_errors; 
  80.  
  81. /** 
  82. * Allowed actions to execute in template_redirect hook. 
  83. * 
  84. * @since 1.0.0 
  85. * 
  86. * @var string 
  87. */ 
  88. private $allowed_actions = array( 'signup_process', 'register_user' ); 
  89.  
  90. /** 
  91. * Prepare for Member registration. 
  92. * 
  93. * @since 1.0.0 
  94. */ 
  95. public function __construct() { 
  96. parent::__construct(); 
  97.  
  98. if ( MS_Plugin::is_enabled() ) { 
  99. do_action( 'ms_controller_frontend_construct', $this ); 
  100.  
  101. // Process actions like register new account. 
  102. $this->add_action( 'template_redirect', 'process_actions', 1 ); 
  103.  
  104. // Check if the current page is a Membership Page. 
  105. $this->add_action( 'template_redirect', 'check_for_membership_pages', 2 ); 
  106.  
  107. // Propagates SSL cookies when user logs in. 
  108. $this->add_action( 'wp_login', 'propagate_ssl_cookie', 10, 2 ); 
  109.  
  110. // Enqueue scripts. 
  111. $this->add_action( 'wp_enqueue_scripts', 'enqueue_scripts' ); 
  112.  
  113. // Add classes for all memberships the user is registered to. 
  114. $this->add_filter( 'body_class', 'body_class' ); 
  115.  
  116. // Clears the shortcode memory at the beginning of the_content 
  117. $this->add_filter( 'the_content', 'clear_content_memory', 1 ); 
  118.  
  119. /** 
  120. * This allows WordPress to provide the default register form. 
  121. * 
  122. * Set the filter response to FALSE to stop Membership2 from 
  123. * handling the registration process. WordPress or other plugins can 
  124. * register users in that case. 
  125. * 
  126. * @since 1.1.1.3 
  127. */ 
  128. self::$handle_registration = apply_filters( 
  129. 'ms_frontend_handle_registration',  
  130. true 
  131. ); 
  132.  
  133. if ( self::$handle_registration ) { 
  134. // Set the registration URL to the 'Register' Membership Page. 
  135. $this->add_filter( 'wp_signup_location', 'signup_location', 999 ); 
  136. $this->add_filter( 'register_url', 'signup_location', 999 ); 
  137.  
  138. // Redirect users to their Account page after login. 
  139. $this->add_filter( 'login_redirect', 'login_redirect', 10, 3 ); 
  140.  
  141. /** 
  142. * Handle URI actions for registration. 
  143. * 
  144. * Matches returned 'action' to method to execute. 
  145. * 
  146. * Related Action Hooks: 
  147. * - template_redirect 
  148. * 
  149. * @since 1.0.0 
  150. */ 
  151. public function process_actions() { 
  152. $action = $this->get_action(); 
  153.  
  154. /** 
  155. * If $action is set, then call relevant method. 
  156. * 
  157. * Methods: 
  158. * @see $allowed_actions property 
  159. * 
  160. */ 
  161. if ( ! empty( $action ) 
  162. && method_exists( $this, $action ) 
  163. && in_array( $action, $this->allowed_actions ) 
  164. ) { 
  165. $this->$action(); 
  166.  
  167. /** 
  168. * Check pages for the presence of Membership special pages. 
  169. * 
  170. * Related Action Hooks: 
  171. * - template_redirect 
  172. * 
  173. * @since 1.0.0 
  174. */ 
  175. public function check_for_membership_pages() { 
  176. global $post, $wp_query; 
  177.  
  178. // For invoice page purchase process 
  179. $fields = array( 'gateway', 'ms_relationship_id', 'step' ); 
  180.  
  181. if ( ! empty( $post ) 
  182. && isset( $post->post_type ) 
  183. && $post->post_type == MS_Model_Invoice::get_post_type() 
  184. && self::validate_required( $fields ) 
  185. && self::STEP_PROCESS_PURCHASE == $_POST['step'] 
  186. ) { 
  187. do_action( 
  188. 'ms_controller_frontend_signup_process_purchase',  
  189. $this 
  190. ); 
  191.  
  192. $the_page = MS_Model_Pages::current_page(); 
  193.  
  194. if ( $the_page ) { 
  195. // Fix the main query flags for best theme support: 
  196. // Our Membership-Pages are always single pages... 
  197.  
  198. $wp_query->is_single = false; 
  199. $wp_query->is_page = true; 
  200. $wp_query->is_singular = true; 
  201. $wp_query->is_home = false; 
  202. $wp_query->is_frontpage = false; 
  203. $wp_query->tax_query = null; 
  204.  
  205. $the_type = MS_Model_Pages::get_page_type( $the_page ); 
  206. switch ( $the_type ) { 
  207. case MS_Model_Pages::MS_PAGE_MEMBERSHIPS: 
  208. if ( ! MS_Model_Member::is_logged_in() ) { 
  209. wp_safe_redirect( 
  210. MS_Model_Pages::get_page_url( MS_Model_Pages::MS_PAGE_REGISTER ) 
  211. ); 
  212. exit; 
  213. // no break; 
  214.  
  215. case MS_Model_Pages::MS_PAGE_REGISTER: 
  216. if ( MS_Helper_Membership::MEMBERSHIP_ACTION_CANCEL == $this->get_action() ) { 
  217. $this->membership_cancel(); 
  218. } else { 
  219. $this->signup_process(); 
  220. break; 
  221.  
  222. case MS_Model_Pages::MS_PAGE_ACCOUNT: 
  223. $this->user_account_mgr(); 
  224. break; 
  225.  
  226. case MS_Model_Pages::MS_PAGE_PROTECTED_CONTENT: 
  227. // Set up the protection shortcode. 
  228. $scode = MS_Plugin::instance()->controller->controllers['membership_shortcode']; 
  229. $scode->page_is_protected(); 
  230. break; 
  231.  
  232. case MS_Model_Pages::MS_PAGE_REG_COMPLETE: 
  233. $this->add_filter( 'the_content', 'reg_complete_page', 1 ); 
  234. break; 
  235.  
  236. default: 
  237. break; 
  238.  
  239. /** 
  240. * Appends classes to the HTML body that identify all memberships that the 
  241. * current user is registered to. This allows webdesigners to adjust layout 
  242. * or hide elements based on the membership a user has. 
  243. * 
  244. * @since 1.0.2 
  245. * 
  246. * @param array $class Class-names to attach to the body. 
  247. * @return array Modified class-names to attach to the body. 
  248. */ 
  249. public function body_class( $class ) { 
  250. $info = MS_Plugin::instance()->controller->get_access_info(); 
  251. foreach ( $info['memberships'] as $membership_id ) { 
  252. $class[] = 'ms-' . absint( $membership_id ); 
  253.  
  254. return $class; 
  255.  
  256. /** 
  257. * Clears the shortcode memory at the beginning of each call to the_content. 
  258. * 
  259. * This is required when there are several parts of the page that are 
  260. * rendered via the_content, e.g. a main content and a footer area (this 
  261. * is a theme-specific scenario). Or if the page contains an excerpt and a 
  262. * main content block, ... 
  263. * 
  264. * @since 1.0.4.6 
  265. * @param string $content The page content 
  266. * @return string Value of $content (unmodified) 
  267. */ 
  268. public function clear_content_memory( $content ) { 
  269. global $wp_current_filter; 
  270. $reset = false; 
  271.  
  272. // Correctly handle nesting. 
  273. foreach ( $wp_current_filter as $filter ) { 
  274. if ( 'the_content' === $filter ) { 
  275. if ( $reset ) { 
  276. /** 
  277. * the_content is called inside the_content. 
  278. * Don't reset again! 
  279. * This can happen for example: A shortcode parses the 
  280. * return code via apply_filters( 'the_content' ) 
  281. */ 
  282. $reset = false; 
  283. break; 
  284. } else { 
  285. $reset = true; 
  286.  
  287. if ( $reset ) { 
  288. MS_Helper_Shortcode::reset_shortcode_usage(); 
  289.  
  290. return $content; 
  291.  
  292. /** 
  293. * Handle entire signup process. 
  294. * 
  295. * @since 1.0.0 
  296. */ 
  297. public function signup_process() { 
  298. $step = $this->get_signup_step(); 
  299.  
  300. do_action( 'ms_frontend_register-' . $step ); 
  301.  
  302. switch ( $step ) { 
  303. /** 
  304. * Initial state. 
  305. */ 
  306. case self::STEP_CHOOSE_MEMBERSHIP: 
  307. $this->add_filter( 'the_content', 'choose_membership', 1 ); 
  308. break; 
  309.  
  310. /** 
  311. * If not registered. 
  312. */ 
  313. case self::STEP_REGISTER_FORM: 
  314. case self::STEP_REGISTER_FORM_ALT: 
  315. $this->add_filter( 'the_content', 'register_form', 1 ); 
  316. break; 
  317.  
  318. /** 
  319. * Process user registration. 
  320. */ 
  321. case self::STEP_REGISTER_SUBMIT: 
  322. $this->register_user(); 
  323. break; 
  324.  
  325. /** 
  326. * Show payment table. 
  327. */ 
  328. case self::STEP_PAYMENT_TABLE: 
  329. $this->add_filter( 'the_content', 'payment_table', 1 ); 
  330. break; 
  331.  
  332. /** 
  333. * Show gateway extra form. 
  334. * Handled by MS_Controller_Gateway. 
  335. */ 
  336. case self::STEP_GATEWAY_FORM: 
  337. do_action( 
  338. 'ms_controller_frontend_signup_gateway_form',  
  339. $this 
  340. ); 
  341. break; 
  342.  
  343. /** 
  344. * Process the purchase action. 
  345. * Handled by MS_Controller_Gateway. 
  346. */ 
  347. case self::STEP_PROCESS_PURCHASE: 
  348. do_action( 
  349. 'ms_controller_frontend_signup_process_purchase',  
  350. $this 
  351. ); 
  352. break; 
  353.  
  354. default: 
  355. MS_Helper_Debug::log( "No handler for step: $step" ); 
  356. break; 
  357.  
  358. /** 
  359. * Get signup process step (multi step form). 
  360. * 
  361. * @since 1.0.0 
  362. * 
  363. * @return string The current signup step after validation. 
  364. */ 
  365. private function get_signup_step() { 
  366. static $Valid_Steps = null; 
  367. static $Login_Steps = null; 
  368.  
  369. if ( empty( $Valid_Steps ) ) { 
  370. $Valid_Steps = apply_filters( 
  371. 'ms_controller_frontend_signup_steps',  
  372. array( 
  373. self::STEP_CHOOSE_MEMBERSHIP,  
  374. self::STEP_REGISTER_FORM,  
  375. self::STEP_REGISTER_FORM_ALT,  
  376. self::STEP_REGISTER_SUBMIT,  
  377. self::STEP_PAYMENT_TABLE,  
  378. self::STEP_GATEWAY_FORM,  
  379. self::STEP_PROCESS_PURCHASE,  
  380. ); 
  381.  
  382. // These steps are only available to logged-in users. 
  383. $Login_Steps = apply_filters( 
  384. 'ms_controller_frontend_signup_steps_private',  
  385. array( 
  386. self::STEP_PAYMENT_TABLE,  
  387. self::STEP_GATEWAY_FORM,  
  388. self::STEP_PROCESS_PURCHASE,  
  389. ); 
  390.  
  391. lib2()->array->equip_request( 'step', 'membership_id' ); 
  392.  
  393. if ( in_array( $_REQUEST['step'], $Valid_Steps ) ) { 
  394. $step = $_REQUEST['step']; 
  395. } else { 
  396. // Initial step 
  397. $step = self::STEP_CHOOSE_MEMBERSHIP; 
  398.  
  399. if ( self::STEP_PAYMENT_TABLE == $step ) { 
  400. if ( ! MS_Model_Membership::is_valid_membership( $_REQUEST['membership_id'] ) ) { 
  401. $step = self::STEP_CHOOSE_MEMBERSHIP; 
  402.  
  403. if ( self::STEP_CHOOSE_MEMBERSHIP == $step && ! empty( $_GET['membership_id'] ) ) { 
  404. $step = self::STEP_PAYMENT_TABLE; 
  405.  
  406. if ( ! MS_Model_Member::is_logged_in() && in_array( $step, $Login_Steps ) ) { 
  407. $step = self::STEP_REGISTER_FORM_ALT; 
  408.  
  409. return apply_filters( 
  410. 'ms_controller_frontend_get_signup_step',  
  411. $step,  
  412. $this 
  413. ); 
  414.  
  415. /** 
  416. * Show choose membership form. 
  417. * 
  418. * Search for signup shortcode, injecting if not found. 
  419. * 
  420. * Related Filter Hooks: 
  421. * * the_content 
  422. * 
  423. * @since 1.0.0 
  424. * 
  425. * @param string $content The page content to filter. 
  426. * @return string The filtered content. 
  427. */ 
  428. public function choose_membership( $content ) { 
  429. remove_filter( 'the_content', 'wpautop' ); 
  430.  
  431. if ( ! MS_Helper_Shortcode::has_shortcode( MS_Helper_Shortcode::SCODE_SIGNUP, $content ) ) { 
  432. $content .= do_shortcode( '['. MS_Helper_Shortcode::SCODE_SIGNUP .']' ); 
  433.  
  434. return apply_filters( 
  435. 'ms_controller_frontend_choose_membership_content',  
  436. $content,  
  437. $this 
  438. ); 
  439.  
  440. /** 
  441. * Returns the URL to user registration page. 
  442. * If Membership2 handles registration we can provide the registration 
  443. * step via function param $step. 
  444. * 
  445. * @since 1.1.1.3 
  446. * @param string $step Empty uses default step (choose_membership). 
  447. * 'choose_membership' show list of memberships. 
  448. * 'register' shows the registration form. 
  449. * @return string URL to the registration page. 
  450. */ 
  451. static public function get_registration_url( $step = null ) { 
  452. $url = wp_registration_url(); 
  453.  
  454. if ( self::$handle_registration && ! empty( $step ) ) { 
  455. $url = esc_url_raw( add_query_arg( 'step', $step, $url ) ); 
  456.  
  457. return $url; 
  458.  
  459. /** 
  460. * Show register user form. 
  461. * 
  462. * Search for register user shortcode, injecting if not found. 
  463. * 
  464. * Related Filter Hooks: 
  465. * - the_content 
  466. * 
  467. * @since 1.0.0 
  468. * 
  469. * @param string $content The page content to filter. 
  470. * @return string The filtered content. 
  471. */ 
  472. public function register_form( $content ) { 
  473. // Check if the WordPress settings allow user registration. 
  474. if ( ! MS_Model_Member::can_register() ) { 
  475. return __( 'Registration is currently not allowed.', MS_TEXT_DOMAIN ); 
  476.  
  477. // Do not parse the form when building the excerpt 
  478. global $wp_current_filter; 
  479. if ( in_array( 'get_the_excerpt', $wp_current_filter ) ) { return ''; } 
  480.  
  481. /** 
  482. * Add-ons or other plugins can use this filter to define a completely 
  483. * different registration form. If this filter returns any content, then 
  484. * the default form will not be generated 
  485. * 
  486. * @since 1.1.0 
  487. * @var string 
  488. */ 
  489. $custom_code = apply_filters( 
  490. 'ms_frontend_custom_registration_form',  
  491. '',  
  492. $this->register_errors,  
  493. $this 
  494. ); 
  495.  
  496. if ( ! empty( $custom_code ) ) { 
  497. return $custom_code; 
  498.  
  499. remove_filter( 'the_content', 'wpautop' ); 
  500.  
  501. $did_form = MS_Helper_Shortcode::has_shortcode( 
  502. MS_Helper_Shortcode::SCODE_REGISTER_USER,  
  503. $content 
  504. ); 
  505.  
  506. if ( ! $did_form ) { 
  507. $scode = sprintf( 
  508. '[%s errors="%s"]',  
  509. MS_Helper_Shortcode::SCODE_REGISTER_USER,  
  510. str_replace( '"', "'", $this->register_errors ) 
  511. ); 
  512. $reg_form = do_shortcode( $scode ); 
  513.  
  514. if ( ! MS_Model_Member::is_logged_in() ) { 
  515. $content = $reg_form; 
  516. } else { 
  517. $content .= $reg_form; 
  518.  
  519. return apply_filters( 
  520. 'ms_controller_frontend_register_form_content',  
  521. $content,  
  522. $this 
  523. ); 
  524.  
  525. /** 
  526. * Handles register user submit. 
  527. * 
  528. * On validation errors, step back to register form. 
  529. * 
  530. * @since 1.0.0 
  531. */ 
  532. public function register_user() { 
  533. do_action( 'ms_controller_frontend_register_user_before', $this ); 
  534.  
  535. if ( ! $this->verify_nonce() ) { 
  536. return; 
  537.  
  538. try { 
  539. $user = MS_Factory::create( 'MS_Model_Member' ); 
  540.  
  541. // Default WP registration filter 
  542. $fields = apply_filters( 'signup_user_init', $_REQUEST ); 
  543. foreach ( $fields as $field => $value ) { 
  544. $user->$field = $value; 
  545.  
  546. $user->save(); 
  547.  
  548. // Default WP action hook 
  549. do_action( 'signup_finished' ); 
  550.  
  551. $user->signon_user(); 
  552.  
  553. if ( ! MS_Model_Event::save_event( MS_Model_Event::TYPE_MS_REGISTERED, $user ) ) { 
  554. wp_new_user_notification( $user->id, $user->password ); 
  555.  
  556. do_action( 'ms_controller_frontend_register_user_complete', $user ); 
  557.  
  558. // Go to membership signup payment form. 
  559. if ( empty( $_REQUEST['membership_id'] ) ) { 
  560. $redirect = esc_url_raw( 
  561. add_query_arg( 
  562. array( 
  563. 'step' => self::STEP_CHOOSE_MEMBERSHIP,  
  564. ); 
  565. } else { 
  566. $redirect = esc_url_raw( 
  567. add_query_arg( 
  568. array( 
  569. 'step' => self::STEP_PAYMENT_TABLE,  
  570. 'membership_id' => absint( $_REQUEST['membership_id'] ),  
  571. ); 
  572.  
  573. wp_safe_redirect( $redirect ); 
  574. exit; 
  575. catch( Exception $e ) { 
  576. $this->register_errors = $e->getMessage(); 
  577. MS_Helper_Debug::log( $this->register_errors ); 
  578.  
  579. // step back 
  580. $this->add_action( 'the_content', 'register_form', 1 ); 
  581. do_action( 
  582. 'ms_controller_frontend_register_user_error',  
  583. $this->register_errors 
  584. ); 
  585.  
  586. /** 
  587. * Render membership payment information. 
  588. * 
  589. * Related Filter Hooks: 
  590. * - the_content 
  591. * 
  592. * @since 1.0.0 
  593. * 
  594. * @param string $content The page content to filter. 
  595. * @return string The filtered content. 
  596. */ 
  597. public function payment_table( $content ) { 
  598. $data = array(); 
  599. $subscription = null; 
  600. $member = MS_Model_Member::get_current_member(); 
  601. $membership_id = 0; 
  602.  
  603. lib2()->array->equip_request( 'membership_id', 'move_from_id', 'ms_relationship_id' ); 
  604.  
  605. if ( ! empty( $_REQUEST['membership_id'] ) ) { 
  606. // First time loading 
  607. $membership_id = $_REQUEST['membership_id']; 
  608. $membership = MS_Factory::load( 'MS_Model_Membership', $membership_id ); 
  609. $move_from_id = absint( $_REQUEST['move_from_id'] ); 
  610. $subscription = MS_Model_Relationship::create_ms_relationship( 
  611. $membership_id,  
  612. $member->id,  
  613. '',  
  614. $move_from_id 
  615. ); 
  616. } elseif ( ! empty( $_POST['ms_relationship_id'] ) ) { 
  617. // Error path, showing payment table again with error msg 
  618. $subscription = MS_Factory::load( 
  619. 'MS_Model_Relationship',  
  620. absint( $_POST['ms_relationship_id'] ) 
  621. ); 
  622. $membership = $subscription->get_membership(); 
  623. $membership_id = $membership->id; 
  624.  
  625. if ( ! empty( $_POST['error'] ) ) { 
  626. lib2()->array->strip_slashes( $_POST, 'error' ); 
  627.  
  628. $data['error'] = $_POST['error']; 
  629. } else { 
  630. MS_Helper_Debug::log( 'Error: missing POST params' ); 
  631. MS_Helper_Debug::log( $_POST ); 
  632. return $content; 
  633.  
  634. $invoice = $subscription->get_current_invoice(); 
  635.  
  636. /** 
  637. * Notify Add-ons that we are preparing payment details for a membership 
  638. * subscription. 
  639. * 
  640. * E.g. Coupon discount is applied by this hook. 
  641. * 
  642. * @since 1.1.0 
  643. */ 
  644. $invoice = apply_filters( 
  645. 'ms_signup_payment_details',  
  646. $invoice,  
  647. $subscription,  
  648. $membership 
  649. ); 
  650. $invoice->save(); 
  651.  
  652. $data['invoice'] = $invoice; 
  653. $data['membership'] = $membership; 
  654. $data['member'] = $member; 
  655. $data['ms_relationship'] = $subscription; 
  656.  
  657. $view = MS_Factory::load( 'MS_View_Frontend_Payment' ); 
  658. $view->data = apply_filters( 
  659. 'ms_view_frontend_payment_data',  
  660. $data,  
  661. $membership_id,  
  662. $subscription,  
  663. $member,  
  664. $this 
  665. ); 
  666.  
  667. return apply_filters( 
  668. 'ms_controller_frontend_payment_table',  
  669. $view->to_html(),  
  670. $this 
  671. ); 
  672.  
  673. /** 
  674. * Handles membership_cancel action. 
  675. * 
  676. * @since 1.0.0 
  677. */ 
  678. public function membership_cancel() { 
  679. if ( ! empty( $_REQUEST['membership_id'] ) && $this->verify_nonce( null, 'any' ) ) { 
  680. $membership_id = absint( $_REQUEST['membership_id'] ); 
  681. $member = MS_Model_Member::get_current_member(); 
  682. $member->cancel_membership( $membership_id ); 
  683. $member->save(); 
  684.  
  685. $url = MS_Model_Pages::get_page_url( MS_Model_Pages::MS_PAGE_REGISTER ); 
  686. wp_safe_redirect( $url ); 
  687. exit; 
  688.  
  689. /** 
  690. * Manage user account actions. 
  691. * 
  692. * @since 1.0.0 
  693. * 
  694. */ 
  695. public function user_account_mgr() { 
  696. $action = $this->get_action(); 
  697. $member = MS_Model_Member::get_current_member(); 
  698.  
  699. switch ( $action ) { 
  700. case self::ACTION_EDIT_PROFILE: 
  701. $data = array(); 
  702.  
  703. if ( $this->verify_nonce() ) { 
  704. if ( is_array( $_POST ) ) { 
  705. foreach ( $_POST as $field => $value ) { 
  706. $member->$field = $value; 
  707.  
  708. try { 
  709. $member->validate_member_info(); 
  710. $member->save(); 
  711. wp_safe_redirect( 
  712. esc_url_raw( remove_query_arg( 'action' ) ) 
  713. ); 
  714. exit; 
  715.  
  716. catch ( Exception $e ) { 
  717. $data['errors'] = $e->getMessage(); 
  718. $view = MS_Factory::create( 'MS_View_Frontend_Profile' ); 
  719. $data['member'] = $member; 
  720. $data['action'] = $action; 
  721. $view->data = apply_filters( 'ms_view_frontend_profile_data', $data, $this ); 
  722. $view->add_filter( 'the_content', 'to_html', 1 ); 
  723. break; 
  724.  
  725. case self::ACTION_VIEW_INVOICES: 
  726. $data['invoices'] = MS_Model_Invoice::get_public_invoices( 
  727. $member->id 
  728. ); 
  729.  
  730. $view = MS_Factory::create( 'MS_View_Frontend_Invoices' ); 
  731. $view->data = apply_filters( 
  732. 'ms_view_frontend_frontend_invoices',  
  733. $data,  
  734. $this 
  735. ); 
  736. $view->add_filter( 'the_content', 'to_html', 1 ); 
  737. break; 
  738.  
  739. case self::ACTION_VIEW_ACTIVITIES: 
  740. $data['events'] = MS_Model_Event::get_events( 
  741. array( 
  742. 'author' => $member->id,  
  743. 'posts_per_page' => -1,  
  744. ); 
  745.  
  746. $view = MS_Factory::create( 'MS_View_Frontend_Activities' ); 
  747. $view->data = apply_filters( 
  748. 'ms_view_frontend_frontend_activities',  
  749. $data,  
  750. $this 
  751. ); 
  752. $view->add_filter( 'the_content', 'to_html', 1 ); 
  753. break; 
  754.  
  755. case self::ACTION_VIEW_RESETPASS: 
  756. /** 
  757. * Reset password action. 
  758. * This action is accessed via the password-reset email 
  759. * @see class-ms-controller-dialog.php 
  760. * 
  761. * The action is targeted to the Account-page but actually calls 
  762. * the Login-Shortcode. 
  763. */ 
  764. $view = MS_Factory::create( 'MS_View_Shortcode_Login' ); 
  765. $view->data = array( 'action' => 'resetpass' ); 
  766.  
  767. $view->add_filter( 'the_content', 'to_html', 1 ); 
  768. break; 
  769.  
  770. default: 
  771. do_action( 'ms_controller_frontend_user_account_mgr_' . $action, $this ); 
  772. $this->add_filter( 'the_content', 'user_account', 1 ); 
  773. break; 
  774.  
  775. /** 
  776. * Show user account page. 
  777. * 
  778. * Search for account shortcode, injecting if not found. 
  779. * 
  780. * Related Filter Hooks: 
  781. * * the_content 
  782. * 
  783. * @since 1.0.0 
  784. * 
  785. * @param string $content The page content to filter. 
  786. * @return string The filtered content. 
  787. */ 
  788. public function user_account( $content ) { 
  789. remove_filter( 'the_content', 'wpautop' ); 
  790.  
  791. if ( ! MS_Helper_Shortcode::has_shortcode( MS_Helper_Shortcode::SCODE_MS_ACCOUNT, $content ) ) { 
  792. $content .= do_shortcode( '['. MS_Helper_Shortcode::SCODE_MS_ACCOUNT .']' ); 
  793.  
  794. return apply_filters( 
  795. 'ms_controller_frontend_user_account',  
  796. $content,  
  797. $this 
  798. ); 
  799.  
  800. /** 
  801. * Show registration complete page. 
  802. * 
  803. * Related Filter Hooks: 
  804. * * the_content 
  805. * 
  806. * @since 1.0.0 
  807. * 
  808. * @param string $content The page content to filter. 
  809. * @return string The filtered content. 
  810. */ 
  811. public function reg_complete_page( $content ) { 
  812. return apply_filters( 
  813. 'ms_controller_frontend_reg_complete_page',  
  814. $content,  
  815. $this 
  816. ); 
  817.  
  818. /** 
  819. * Display login form. 
  820. * 
  821. * Search for login shortcode, injecting if not found. 
  822. * 
  823. * Related Filter Hooks: 
  824. * * the_content 
  825. * 
  826. * @since 1.0.0 
  827. * 
  828. * @param string $content The page content to filter. 
  829. * @return string The filtered content. 
  830. */ 
  831. public function display_login_form( $content ) { 
  832. if ( ! MS_Helper_Shortcode::has_shortcode( MS_Helper_Shortcode::SCODE_LOGIN, $content ) ) { 
  833. $scode = '[' . MS_Helper_Shortcode::SCODE_LOGIN . ']'; 
  834. $content = do_shortcode( $scode ); 
  835.  
  836. return apply_filters( 
  837. 'ms_controller_frontend_display_login_form',  
  838. $content,  
  839. $this 
  840. ); 
  841.  
  842. /** 
  843. * Get the URL the user used to register for a subscription. 
  844. * 
  845. * Uses the default registration page unless the registration was embedded 
  846. * on another page (e.g. using a shortcode). 
  847. * 
  848. * Related Filter Hooks: 
  849. * - wp_signup_location 
  850. * - register_url 
  851. * 
  852. * @since 1.0.0 
  853. * 
  854. * @param string $url The url to filter. 
  855. * @return The new signup url. 
  856. */ 
  857. public function signup_location( $url ) { 
  858. $url = MS_Model_Pages::get_page_url( MS_Model_Pages::MS_PAGE_REGISTER ); 
  859.  
  860. return apply_filters( 
  861. 'ms_controller_frontend_signup_location',  
  862. $url,  
  863. $this 
  864. ); 
  865.  
  866. /** 
  867. * Propagates SSL cookies when user logs in. 
  868. * 
  869. * Related Action Hooks: 
  870. * - wp_login 
  871. * 
  872. * @since 1.0.0 
  873. * 
  874. * @param type $login The login info. 
  875. * @param WP_User $user The user to login. 
  876. */ 
  877. public function propagate_ssl_cookie( $login, $user = null ) { 
  878. if ( empty( $user ) || ! is_a( $user, 'WP_User' ) ) { 
  879. $user = get_user_by( 'login', $login ); 
  880.  
  881. if ( is_a( $user, 'WP_User' ) && ! is_ssl() ) { 
  882. wp_set_auth_cookie( $user->ID, true, true ); 
  883.  
  884. do_action( 
  885. 'ms_controller_frontend_propagate_ssl_cookie',  
  886. $login,  
  887. $user,  
  888. $this 
  889. ); 
  890.  
  891. /** 
  892. * Redirect user to account page. 
  893. * 
  894. * Only redirect when no previous redirect_to is set or when going to /wp-admin/. 
  895. * 
  896. * @since 1.0.0 
  897. * 
  898. * @param string $redirect_to URL to redirect to. 
  899. * @param string $request URL the user is coming from. 
  900. * @param object $user Logged user's data. 
  901. * @return string The redirect url. 
  902. */ 
  903. public function login_redirect( $redirect_to, $request, $user ) { 
  904. if ( ! empty( $user->ID ) 
  905. && ! MS_Model_Member::is_admin_user( $user->ID ) 
  906. && ( empty( $redirect_to ) || admin_url() == $redirect_to ) 
  907. ) { 
  908. $redirect_to = MS_Model_Pages::get_page_url( MS_Model_Pages::MS_PAGE_ACCOUNT ); 
  909.  
  910. return apply_filters( 
  911. 'ms_controller_frontend_login_redirect',  
  912. $redirect_to,  
  913. $request,  
  914. $user,  
  915. $this 
  916. ); 
  917.  
  918. /** 
  919. * Adds CSS and JS for Membership special pages used in the front end. 
  920. * 
  921. * @since 1.0.0 
  922. * 
  923. * @return void 
  924. */ 
  925. public function enqueue_scripts() { 
  926. do_action( 
  927. 'ms_controller_frontend_enqueue_scripts',  
  928. $this->get_signup_step(),  
  929. $this->get_action(),  
  930. $this 
  931. ); 
  932.  
  933. $is_ms_page = MS_Model_Pages::is_membership_page(); 
  934. $is_profile = self::ACTION_EDIT_PROFILE == $this->get_action() 
  935. && MS_Model_Pages::is_membership_page( null, MS_Model_Pages::MS_PAGE_ACCOUNT ); 
  936.  
  937. if ( $is_ms_page ) { 
  938. $data = array( 
  939. 'ms_init' => array( 'shortcode' ),  
  940. 'cancel_msg' => __( 'Are you sure you want to cancel?', MS_TEXT_DOMAIN ),  
  941. ); 
  942.  
  943. lib2()->ui->css( 'ms-styles' ); 
  944. lib2()->ui->js( 'jquery-validate' ); 
  945. lib2()->ui->js( 'ms-public' ); 
  946. MS_Controller_Plugin::translate_jquery_validator(); 
  947.  
  948. if ( $is_profile ) { 
  949. $data['ms_init'][] = 'frontend_profile'; 
  950.  
  951. lib2()->ui->data( 'ms_data', $data ); 
.