MS_Controller_Gateway

Gateway controller.

Defined (1)

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

/app/controller/class-ms-controller-gateway.php  
  1. class MS_Controller_Gateway extends MS_Controller { 
  2.  
  3. /** 
  4. * AJAX action constants. 
  5. * @since 1.0.0 
  6. * @var string 
  7. */ 
  8. const AJAX_ACTION_TOGGLE_GATEWAY = 'toggle_gateway'; 
  9. const AJAX_ACTION_UPDATE_GATEWAY = 'update_gateway'; 
  10.  
  11. /** 
  12. * Allowed actions to execute in template_redirect hook. 
  13. * @since 1.0.0 
  14. * @var string 
  15. */ 
  16. private $allowed_actions = array( 'update_card', 'purchase_button' ); 
  17.  
  18. /** 
  19. * Prepare the gateway controller. 
  20. * @since 1.0.0 
  21. */ 
  22. public function __construct() { 
  23. parent::__construct(); 
  24.  
  25. $this->add_action( 'template_redirect', 'process_actions', 1 ); 
  26.  
  27. $this->add_action( 'ms_controller_gateway_settings_render_view', 'gateway_settings_edit' ); 
  28.  
  29. $this->add_action( 'ms_view_shortcode_invoice_purchase_button', 'invoice_purchase_button', 10, 2 ); 
  30. $this->add_action( 'ms_view_frontend_payment_purchase_button', 'purchase_button', 10, 2 ); 
  31.  
  32. $this->add_action( 'ms_controller_frontend_signup_gateway_form', 'gateway_form_mgr', 1 ); 
  33. $this->add_action( 'ms_controller_frontend_signup_process_purchase', 'process_purchase', 1 ); 
  34. $this->add_filter( 'ms_view_shortcode_membershipsignup_cancel_button', 'cancel_button', 10, 2 ); 
  35.  
  36. $this->add_action( 'ms_view_shortcode_account_card_info', 'card_info' ); 
  37.  
  38. $this->add_action( 'pre_get_posts', 'handle_payment_return', 1 ); 
  39. $this->add_action( 'ms_gateway_transaction_log', 'log_transaction', 10, 8 ); 
  40.  
  41. $this->add_action( 'ms_controller_frontend_enqueue_scripts', 'enqueue_scripts' ); 
  42.  
  43. $this->add_ajax_action( self::AJAX_ACTION_TOGGLE_GATEWAY, 'toggle_ajax_action' ); 
  44. $this->add_ajax_action( self::AJAX_ACTION_UPDATE_GATEWAY, 'ajax_action_update_gateway' ); 
  45.  
  46. /** 
  47. * Handle URI actions for registration. 
  48. * Matches returned 'action' to method to execute. 
  49. * Related action hooks: 
  50. * - template_redirect 
  51. * @since 1.0.0 
  52. */ 
  53. public function process_actions() { 
  54. $action = $this->get_action(); 
  55.  
  56. /** 
  57. * If $action is set, then call relevant method. 
  58. * Methods: 
  59. * @see $allowed_actions property 
  60. */ 
  61. if ( ! empty( $action ) 
  62. && method_exists( $this, $action ) 
  63. && in_array( $action, $this->allowed_actions ) 
  64. ) { 
  65. $this->$action(); 
  66.  
  67. /** 
  68. * Handle Ajax toggle action. 
  69. * Related action hooks: 
  70. * - wp_ajax_toggle_gateway 
  71. * @since 1.0.0 
  72. */ 
  73. public function toggle_ajax_action() { 
  74. $msg = 0; 
  75.  
  76. $fields = array( 'gateway_id' ); 
  77. if ( $this->verify_nonce() 
  78. && self::validate_required( $fields ) 
  79. && $this->is_admin_user() 
  80. ) { 
  81. $msg = $this->gateway_list_do_action( 
  82. 'toggle_activation',  
  83. array( $_POST['gateway_id'] ) 
  84. ); 
  85.  
  86. wp_die( $msg ); 
  87.  
  88. /** 
  89. * Handle Ajax update gateway action. 
  90. * Related action hooks: 
  91. * - wp_ajax_update_gateway 
  92. * @since 1.0.0 
  93. */ 
  94. public function ajax_action_update_gateway() { 
  95. $msg = MS_Helper_Settings::SETTINGS_MSG_NOT_UPDATED; 
  96.  
  97. $fields = array( 'action', 'gateway_id', 'field', 'value' ); 
  98.  
  99. if ( $this->verify_nonce() 
  100. && ( self::validate_required( $fields ) || $_POST['field'] == 'pay_button_url' ) 
  101. && $this->is_admin_user() 
  102. ) { 
  103. lib3()->array->strip_slashes( $_POST, 'value' ); 
  104.  
  105. $msg = $this->gateway_list_do_action( 
  106. $_POST['action'],  
  107. array( $_POST['gateway_id'] ),  
  108. array( $_POST['field'] => $_POST['value'] ) 
  109. ); 
  110.  
  111. wp_die( $msg ); 
  112.  
  113. /** 
  114. * Show gateway settings page. 
  115. * Related action hooks: 
  116. * - ms_controller_gateway_settings_render_view 
  117. * @since 1.0.0 
  118. */ 
  119. public function gateway_settings_edit( $gateway_id ) { 
  120. if ( ! empty( $gateway_id ) 
  121. && MS_Model_Gateway::is_valid_gateway( $gateway_id ) 
  122. ) { 
  123. switch ( $gateway_id ) { 
  124. case MS_Gateway_Manual::ID: 
  125. $view = MS_Factory::create( 'MS_Gateway_Manual_View_Settings' ); 
  126. break; 
  127.  
  128. case MS_Gateway_Paypalsingle::ID: 
  129. $view = MS_Factory::create( 'MS_Gateway_Paypalsingle_View_Settings' ); 
  130. break; 
  131.  
  132. case MS_Gateway_Paypalstandard::ID: 
  133. $view = MS_Factory::create( 'MS_Gateway_Paypalstandard_View_Settings' ); 
  134. break; 
  135.  
  136. case MS_Gateway_Authorize::ID: 
  137. $view = MS_Factory::create( 'MS_Gateway_Authorize_View_Settings' ); 
  138. break; 
  139.  
  140. case MS_Gateway_Stripe::ID: 
  141. $view = MS_Factory::create( 'MS_Gateway_Stripe_View_Settings' ); 
  142. break; 
  143.  
  144. default: 
  145. // Empty form... 
  146. $view = MS_Factory::create( 'MS_View' ); 
  147. break; 
  148.  
  149. $data = array( 
  150. 'model' => MS_Model_Gateway::factory( $gateway_id ),  
  151. 'action' => 'edit',  
  152. ); 
  153.  
  154. $view->data = apply_filters( 
  155. 'ms_gateway_view_settings_edit_data',  
  156. $data 
  157. ); 
  158. $view = apply_filters( 
  159. 'ms_gateway_view_settings_edit',  
  160. $view,  
  161. $gateway_id 
  162. ); 
  163.  
  164. $view->render(); 
  165.  
  166. /** 
  167. * Handle Payment Gateway list actions. 
  168. * @since 1.0.0 
  169. * @param string $action The action to execute. 
  170. * @param int[] $gateways The gateways IDs to process. 
  171. * @param mixed[] $fields The data to process. 
  172. */ 
  173. public function gateway_list_do_action( $action, $gateways, $fields = null ) { 
  174. $msg = MS_Helper_Settings::SETTINGS_MSG_NOT_UPDATED; 
  175. if ( ! $this->is_admin_user() ) { 
  176. return $msg; 
  177.  
  178. foreach ( $gateways as $gateway_id ) { 
  179. $gateway = MS_Model_Gateway::factory( $gateway_id ); 
  180.  
  181. switch ( $action ) { 
  182. case 'toggle_activation': 
  183. $gateway->active = ! $gateway->active; 
  184. $gateway->save(); 
  185. $msg = MS_Helper_Settings::SETTINGS_MSG_UPDATED; 
  186.  
  187. /** 
  188. * Hook called after a gateway-status was toggled. 
  189. * @since 1.0.0 
  190. */ 
  191. do_action( 'ms_gateway_toggle_' . $gateway_id, $gateway ); 
  192. break; 
  193.  
  194. case 'edit': 
  195. case 'update_gateway': 
  196. foreach ( $fields as $field => $value ) { 
  197. $gateway->$field = trim( $value ); 
  198. $gateway->save(); 
  199.  
  200. /** 
  201. * $settings->is_global_payments_set is used to hide global 
  202. * payment settings in the membership setup payment step 
  203. */ 
  204. if ( $gateway->is_configured() ) { 
  205. $settings = MS_Factory::load( 'MS_Model_Settings' ); 
  206. $settings->is_global_payments_set = true; 
  207. $settings->save(); 
  208. $msg = MS_Helper_Settings::SETTINGS_MSG_UPDATED; 
  209. } else { 
  210. $msg = MS_Helper_Settings::SETTINGS_MSG_UNCONFIGURED; 
  211.  
  212. /** 
  213. * Hook called after a gateway-settings were modified. 
  214. * @since 1.0.0 
  215. */ 
  216. do_action( 'ms_gateway_changed_' . $gateway_id, $gateway ); 
  217. break; 
  218.  
  219. return apply_filters( 
  220. 'ms_controller_gateway_gateway_list_do_action',  
  221. $msg,  
  222. $action,  
  223. $gateways,  
  224. $fields,  
  225. $this 
  226. ); 
  227.  
  228. /** 
  229. * Show gateway purchase button. 
  230. * Related action hooks: 
  231. * - ms_view_frontend_payment_purchase_button 
  232. * - ms_view_shortcode_invoice_purchase_button 
  233. * @since 1.0.0 
  234. */ 
  235. public function purchase_button( $subscription, $invoice ) { 
  236. // Get only active gateways 
  237. $gateways = MS_Model_Gateway::get_gateways( true ); 
  238. $data = array(); 
  239.  
  240. $membership = $subscription->get_membership(); 
  241. $is_free = false; 
  242.  
  243. if ( $membership->is_free() ) { 
  244. $is_free = true; 
  245. } elseif ( 0 == $invoice->total ) { 
  246. $is_free = true; 
  247. } elseif ( $invoice->uses_trial ) { 
  248. if ( defined( 'MS_PAYPAL_TRIAL_SUBSCRIPTION' ) && MS_PAYPAL_TRIAL_SUBSCRIPTION ) { 
  249. $is_free = false; 
  250. } else { 
  251. $is_free = true; 
  252.  
  253. // show gateway purchase button for every active gateway 
  254. foreach ( $gateways as $gateway ) { 
  255. $view = null; 
  256.  
  257. // Skip gateways that are not configured. 
  258. if ( ! $gateway->is_configured() ) { continue; } 
  259. if ( ! $membership->can_use_gateway( $gateway->id ) ) { continue; } 
  260.  
  261. $data['ms_relationship'] = $subscription; 
  262. $data['gateway'] = $gateway; 
  263. $data['step'] = MS_Controller_Frontend::STEP_PROCESS_PURCHASE; 
  264.  
  265. // Free membership, show only free gateway 
  266. if ( $is_free ) { 
  267. if ( MS_Gateway_Free::ID !== $gateway->id ) { 
  268. continue; 
  269. } elseif ( MS_Gateway_Free::ID === $gateway->id ) { 
  270. // Skip free gateway 
  271. continue; 
  272.  
  273. $view_class = get_class( $gateway ) . '_View_Button'; 
  274. $view = MS_Factory::create( $view_class ); 
  275.  
  276. if ( MS_Gateway_Authorize::ID == $gateway->id ) { 
  277. /** 
  278. * set additional step for authorize.net (gateway specific form) 
  279. * @todo change to use popup, instead of another step (like stripe) 
  280. */ 
  281. $data['step'] = 'gateway_form'; 
  282.  
  283. if ( ! empty( $view ) ) { 
  284. $view = apply_filters( 
  285. 'ms_gateway_view_button',  
  286. $view,  
  287. $gateway->id 
  288. ); 
  289.  
  290. $view->data = apply_filters( 
  291. 'ms_gateway_view_button_data',  
  292. $data,  
  293. $gateway->id 
  294. ); 
  295.  
  296. $html = apply_filters( 
  297. 'ms_controller_gateway_purchase_button_' . $gateway->id,  
  298. $view->to_html(),  
  299. $subscription,  
  300. $this 
  301. ); 
  302.  
  303. echo $html; 
  304.  
  305.  
  306.  
  307. /** 
  308. * Show gateway purchase button in invoice 
  309. * Related action hooks: 
  310. * - ms_view_frontend_payment_purchase_button 
  311. * - ms_view_shortcode_invoice_purchase_button 
  312. * @since 1.0.2.7 
  313. */ 
  314. public function invoice_purchase_button( $subscription, $invoice ) { 
  315. // Get only active gateways 
  316. $gateways = MS_Model_Gateway::get_gateways( true ); 
  317. $data = array(); 
  318.  
  319. $membership = $subscription->get_membership(); 
  320. $is_free = false; 
  321. $is_trial = false; 
  322.  
  323. if ( $membership->is_free() ) { 
  324. $is_free = true; 
  325. } elseif ( 0 == $invoice->total ) { 
  326. $is_free = true; 
  327. } elseif ( $invoice->uses_trial ) { 
  328. if ( defined( 'MS_PAYPAL_TRIAL_SUBSCRIPTION' ) && MS_PAYPAL_TRIAL_SUBSCRIPTION ) { 
  329. $is_free = false; 
  330. } else { 
  331. $is_free = true; 
  332. $is_trial = true; 
  333.  
  334. // show gateway purchase button for every active gateway 
  335. foreach ( $gateways as $gateway ) { 
  336. $view = null; 
  337.  
  338. // Skip gateways that are not configured. 
  339. if ( ! $gateway->is_configured() ) { continue; } 
  340. if ( ! $membership->can_use_gateway( $gateway->id ) ) { continue; } 
  341.  
  342. $data['ms_relationship'] = $subscription; 
  343. $data['gateway'] = $gateway; 
  344. $data['step'] = MS_Controller_Frontend::STEP_PROCESS_PURCHASE; 
  345.  
  346. // Free membership, show only free gateway 
  347. if ( $is_free && ! $is_trial ) { 
  348. if ( MS_Gateway_Free::ID !== $gateway->id ) { 
  349. continue; 
  350. } elseif ( MS_Gateway_Free::ID === $gateway->id ) { 
  351. // Skip free gateway 
  352. continue; 
  353.  
  354. $view_class = get_class( $gateway ) . '_View_Button'; 
  355. $view = MS_Factory::create( $view_class ); 
  356.  
  357. if ( MS_Gateway_Authorize::ID == $gateway->id ) { 
  358. /** 
  359. * set additional step for authorize.net (gateway specific form) 
  360. * @todo change to use popup, instead of another step (like stripe) 
  361. */ 
  362. $data['step'] = 'gateway_form'; 
  363.  
  364. if ( ! empty( $view ) ) { 
  365. $view = apply_filters( 
  366. 'ms_gateway_view_button',  
  367. $view,  
  368. $gateway->id 
  369. ); 
  370.  
  371. $view->data = apply_filters( 
  372. 'ms_gateway_view_button_data',  
  373. $data,  
  374. $gateway->id 
  375. ); 
  376.  
  377. $html = apply_filters( 
  378. 'ms_controller_gateway_purchase_button_'. $gateway->id,  
  379. $view->to_html(),  
  380. $subscription,  
  381. $this 
  382. ); 
  383.  
  384. echo $html; 
  385.  
  386.  
  387. /** 
  388. * Show gateway purchase button. 
  389. * Related action hooks: 
  390. * - ms_view_shortcode_membershipsignup_cancel_button 
  391. * @since 1.0.0 
  392. */ 
  393. public function cancel_button( $button, $subscription ) { 
  394. $view = null; 
  395. $data = array(); 
  396. $data['ms_relationship'] = $subscription; 
  397. $new_button = null; 
  398.  
  399. switch ( $subscription->gateway_id ) { 
  400. case MS_Gateway_Paypalstandard::ID: 
  401. $view = MS_Factory::create( 'MS_Gateway_Paypalstandard_View_Cancel' ); 
  402. $data['gateway'] = $subscription->get_gateway(); 
  403. break; 
  404.  
  405. case MS_Gateway_Authorize::ID: 
  406. case MS_Gateway_Paypalsingle::ID: 
  407. case MS_Gateway_Stripe::ID: 
  408. case MS_Gateway_Free::ID: 
  409. case MS_Gateway_Manual::ID: 
  410. default: 
  411. break; 
  412. $view = apply_filters( 'ms_gateway_view_cancel_button', $view ); 
  413.  
  414. if ( $view && is_a( $view, 'MS_View' ) ) { 
  415. $view->data = apply_filters( 
  416. 'ms_gateway_view_cancel_button_data',  
  417. $data 
  418. ); 
  419.  
  420. $new_button = $view->get_button(); 
  421.  
  422. if ( ! $new_button ) { 
  423. $new_button = $button; 
  424.  
  425. return apply_filters( 
  426. 'ms_controller_gateway_cancel_button',  
  427. $new_button,  
  428. $subscription,  
  429. $this 
  430. ); 
  431.  
  432. /** 
  433. * Set hook to handle gateway extra form to commit payments. 
  434. * Related action hooks: 
  435. * - ms_controller_frontend_signup_gateway_form 
  436. * @since 1.0.0 
  437. */ 
  438. public function gateway_form_mgr() { 
  439. // Display gateway form 
  440. $this->add_filter( 'the_content', 'gateway_form', 10 ); 
  441.  
  442. // Enqueue styles and scripts used 
  443. $this->add_action( 'wp_enqueue_scripts', 'enqueue_scripts' ); 
  444.  
  445. /** 
  446. * Handles gateway extra form to commit payments. 
  447. * Related filter hooks: 
  448. * - the_content 
  449. * @since 1.0.0 
  450. * @param string $content The page content to filter. 
  451. * @return string The filtered content. 
  452. */ 
  453. public function gateway_form( $content ) { 
  454. $data = array(); 
  455. $html = ''; 
  456.  
  457. // Do not parse the form when building the excerpt. 
  458. global $wp_current_filter; 
  459. if ( in_array( 'get_the_excerpt', $wp_current_filter ) ) { 
  460. return ''; 
  461.  
  462. $fields = array( 'gateway', 'ms_relationship_id' ); 
  463. if ( self::validate_required( $fields ) 
  464. && MS_Model_Gateway::is_valid_gateway( $_POST['gateway'] ) 
  465. ) { 
  466. $data['gateway'] = $_POST['gateway']; 
  467. $data['ms_relationship_id'] = $_POST['ms_relationship_id']; 
  468. $view = null; 
  469.  
  470. $subscription = MS_Factory::load( 
  471. 'MS_Model_Relationship',  
  472. $_POST['ms_relationship_id'] 
  473. ); 
  474.  
  475. switch ( $_POST['gateway'] ) { 
  476. case MS_Gateway_Authorize::ID: 
  477. $member = $subscription->get_member(); 
  478. $view = MS_Factory::create( 'MS_Gateway_Authorize_View_Form' ); 
  479. $gateway = MS_Model_Gateway::factory( MS_Gateway_Authorize::ID ); 
  480. $data['countries'] = $gateway->get_country_codes(); 
  481.  
  482. $data['action'] = $this->get_action(); 
  483.  
  484. if ( 'update_card' == $this->get_action() ) { 
  485. // Only new card option available on update card action. 
  486. $data['cim_profiles'] = array(); 
  487. } else { 
  488. // show existing credit card. 
  489. $data['cim_profiles'] = $gateway->get_cim_profile( $member ); 
  490.  
  491. lib3()->array->strip_slashes( $_POST, 'auth_error' ); 
  492.  
  493. $data['cim_payment_profile_id'] = $gateway->get_cim_payment_profile_id( $member ); 
  494. $data['auth_error'] = ! empty( $_POST['auth_error'] ) ? $_POST['auth_error'] : ''; 
  495. break; 
  496.  
  497. default: 
  498. break; 
  499.  
  500. $view = apply_filters( 
  501. 'ms_gateway_view_form',  
  502. $view,  
  503. $_POST['gateway'],  
  504. $subscription 
  505. ); 
  506.  
  507. if ( $view && is_a( $view, 'MS_View' ) ) { 
  508. $view->data = apply_filters( 
  509. 'ms_gateway_view_form_data',  
  510. $data 
  511. ); 
  512.  
  513. $html = $view->to_html(); 
  514.  
  515. return apply_filters( 
  516. 'ms_controller_gateway_form',  
  517. $html,  
  518. $this 
  519. ); 
  520.  
  521. /** 
  522. * Process purchase using gateway. 
  523. * Related Action Hooks: 
  524. * - ms_controller_frontend_signup_process_purchase 
  525. * @since 1.0.0 
  526. */ 
  527. public function process_purchase() { 
  528. $fields = array( 'gateway', 'ms_relationship_id' ); 
  529.  
  530. lib3()->array->equip_request( 'gateway', 'ms_relationship_id' ); 
  531.  
  532. $valid = true; 
  533. $nonce_name = $_REQUEST['gateway'] . '_' . $_REQUEST['ms_relationship_id']; 
  534.  
  535. if ( ! self::validate_required( $fields, 'any' ) ) { 
  536. $valid = false; 
  537. $err = 'GAT-01 (invalid fields)'; 
  538. } elseif ( ! MS_Model_Gateway::is_valid_gateway( $_REQUEST['gateway'] ) ) { 
  539. $valid = false; 
  540. $err = 'GAT-02 (invalid gateway)'; 
  541. } elseif ( ! $this->verify_nonce( $nonce_name, 'any' ) ) { 
  542. $valid = false; 
  543. $err = 'GAT-03 (invalid nonce)'; 
  544.  
  545. if ( $valid ) { 
  546. $subscription = MS_Factory::load( 
  547. 'MS_Model_Relationship',  
  548. $_REQUEST['ms_relationship_id'] 
  549. ); 
  550.  
  551. $gateway_id = $_REQUEST['gateway']; 
  552. $gateway = MS_Model_Gateway::factory( $gateway_id ); 
  553.  
  554. try { 
  555. $invoice = $gateway->process_purchase( $subscription ); 
  556.  
  557. // If invoice is successfully paid, redirect to welcome page. 
  558. if ( $invoice->is_paid() 
  559. || ( $invoice->uses_trial 
  560. && MS_Model_Invoice::STATUS_BILLED == $invoice->status 
  561. ) { 
  562. // Make sure to respect the single-membership rule 
  563. $this->validate_membership_states( $subscription ); 
  564.  
  565. // Redirect user to the Payment-Completed page. 
  566. if ( ! defined( 'IS_UNIT_TEST' ) ) { 
  567. MS_Model_Pages::redirect_to( 
  568. MS_Model_Pages::MS_PAGE_REG_COMPLETE,  
  569. array( 'ms_relationship_id' => $subscription->id ) 
  570. ); 
  571. } elseif ( MS_Gateway_Manual::ID == $gateway_id ) { 
  572. // For manual gateway payments. 
  573. $this->add_action( 'the_content', 'purchase_info_content' ); 
  574. } else { 
  575. // Something went wrong, the payment was not successful. 
  576. $this->add_action( 'the_content', 'purchase_error_content' ); 
  577. } catch ( Exception $e ) { 
  578. MS_Helper_Debug::log( $e->getMessage() ); 
  579.  
  580. switch ( $gateway_id ) { 
  581. case MS_Gateway_Authorize::ID: 
  582. $_POST['auth_error'] = $e->getMessage(); 
  583. // call action to step back 
  584. do_action( 'ms_controller_frontend_signup_gateway_form' ); 
  585. break; 
  586.  
  587. case MS_Gateway_Stripe::ID: 
  588. case MS_Gateway_Stripeplan::ID: 
  589. $_POST['error'] = sprintf( 
  590. __( 'Error: %s', 'membership2' ),  
  591. $e->getMessage() 
  592. ); 
  593.  
  594. // Hack to send the error message back to the payment_table. 
  595. MS_Plugin::instance()->controller->controllers['frontend']->add_action( 
  596. 'the_content',  
  597. 'payment_table', 1 
  598. ); 
  599. break; 
  600.  
  601. default: 
  602. do_action( 'ms_controller_gateway_form_error', $e ); 
  603. $this->add_action( 'the_content', 'purchase_error_content' ); 
  604. break; 
  605. } else { 
  606. MS_Helper_Debug::log( 'Error Code ' . $err ); 
  607.  
  608. $this->add_action( 'the_content', 'purchase_error_content' ); 
  609.  
  610. // Hack to show signup page in case of errors 
  611. $ms_page = MS_Model_Pages::get_page( MS_Model_Pages::MS_PAGE_REGISTER ); 
  612.  
  613. if ( $ms_page ) { 
  614. // During unit-testing the $ms_page object might be empty. 
  615. global $wp_query; 
  616. $wp_query->query_vars['page_id'] = $ms_page->ID; 
  617. $wp_query->query_vars['post_type'] = 'page'; 
  618.  
  619. do_action( 
  620. 'ms_controller_gateway_process_purchase_after',  
  621. $this 
  622. ); 
  623.  
  624. /** 
  625. * Make sure that we respect the Single-Membership rule. 
  626. * This rule is active when the "Multiple-Memberships" Add-on is DISABLED. 
  627. * @since 1.0.0 
  628. * @param MS_Model_Relationship $new_relationship 
  629. */ 
  630. protected function validate_membership_states( $new_relationship ) { 
  631. if ( MS_Model_Addon::is_enabled( MS_Model_Addon::ADDON_MULTI_MEMBERSHIPS ) ) { 
  632. // Multiple memberships allowed. No need to check anything. 
  633. return; 
  634.  
  635. $cancel_these = array( 
  636. MS_Model_Relationship::STATUS_TRIAL,  
  637. MS_Model_Relationship::STATUS_ACTIVE,  
  638. MS_Model_Relationship::STATUS_PENDING,  
  639. ); 
  640.  
  641. $member = $new_relationship->get_member(); 
  642. foreach ( $member->subscriptions as $subscription ) { 
  643. if ( $subscription->id === $new_relationship->id ) { continue; } 
  644. if ( in_array( $subscription->status, $cancel_these ) ) { 
  645. $subscription->cancel_membership(); 
  646.  
  647. /** 
  648. * Show signup page with custom content. 
  649. * This is used by manual gateway (overridden) to show payment info. 
  650. * Related action hooks: 
  651. * @since 1.0.0 
  652. * @param string $content The page content to filter. 
  653. * @return string The filtered content. 
  654. */ 
  655. public function purchase_info_content( $content ) { 
  656. return apply_filters( 
  657. 'ms_controller_gateway_purchase_info_content',  
  658. $content,  
  659. $this 
  660. ); 
  661.  
  662. /** 
  663. * Show error message in the signup page. 
  664. * Related action hooks: 
  665. * @since 1.0.0 
  666. */ 
  667. public function purchase_error_content( $content ) { 
  668. return apply_filters( 
  669. 'ms_controller_gateway_purchase_error_content',  
  670. __( 'Sorry, your signup request has failed. Try again.', 'membership2' ),  
  671. $content,  
  672. $this 
  673. ); 
  674.  
  675. /** 
  676. * Handle payment gateway return IPNs. 
  677. * Used by Paypal gateways. 
  678. * A redirection rule is set up in the main MS_Plugin object 
  679. * (protected_content.php): 
  680. * /ms-payment-return/XYZ becomes index.php?paymentgateway=XYZ 
  681. * Related action hooks: 
  682. * - pre_get_posts 
  683. * @todo Review how this works when we use OAuth API's with gateways. 
  684. * @since 1.0.0 
  685. * @param WP_Query $wp_query The WordPress query object 
  686. */ 
  687. public function handle_payment_return( $wp_query ) { 
  688. // Do not check custom loops. 
  689. if ( ! $wp_query->is_main_query() ) { return; } 
  690.  
  691. if ( ! empty( $wp_query->query_vars['paymentgateway'] ) ) { 
  692. $gateway = $wp_query->query_vars['paymentgateway']; 
  693.  
  694. /** 
  695. * In 1.1.0 the underscore in payment gateway names was removed. 
  696. * To compensate for this we need to continue listen to these old 
  697. * gateway-names. 
  698. */ 
  699. switch ( $gateway ) { 
  700. case 'paypal_single': $gateway = 'paypalsingle'; break; 
  701. case 'paypal_standard': $gateway = 'paypalstandard'; break; 
  702. case 'paypal-single': $gateway = 'paypalsingle'; break; 
  703. case 'paypal-standard': $gateway = 'paypalstandard'; break; 
  704. case 'paypalsolo': $gateway = 'paypalsingle'; break; // M1 
  705. case 'paypalexpress': $gateway = 'paypalstandard'; break; //M1 
  706.  
  707. if ( MS_Model_Gateway::is_active( $gateway ) ) { 
  708. $action = 'ms_gateway_handle_payment_return_' . $gateway; 
  709. do_action( $action ); 
  710. } else { 
  711. // Log the payment attempt when the gateway is not active. 
  712. if ( MS_Model_Gateway::is_valid_gateway( $gateway ) ) { 
  713. $note = __( 'Gateway is inactive', 'membership2' ); 
  714. } else { 
  715. $note = sprintf( 
  716. __( 'Unknown Gateway: %s', 'membership2' ),  
  717. $gateway 
  718. ); 
  719.  
  720. do_action( 
  721. 'ms_gateway_transaction_log',  
  722. $gateway, // gateway ID 
  723. 'handle', // request|process|handle 
  724. false, // success flag 
  725. 0, // subscription ID 
  726. 0, // invoice ID 
  727. 0, // charged amount 
  728. $note, // Descriptive text 
  729. '' // External ID 
  730. ); 
  731.  
  732. /** 
  733. * Show gateway credit card information. 
  734. * If a card is used, show it in account's page. 
  735. * Related action hooks: 
  736. * - ms_view_shortcode_account_card_info 
  737. * @since 1.0.0 
  738. * @param mixed $data The data passed to hooked view. 
  739. */ 
  740. public function card_info( $data = null ) { 
  741. if ( ! empty( $data['gateway'] ) && is_array( $data['gateway'] ) ) { 
  742. $gateways = array(); 
  743.  
  744. foreach ( $data['gateway'] as $ms_relationship_id => $gateway ) { 
  745. // avoid duplicates 
  746. if ( ! in_array( $gateway->id, $gateways ) ) { 
  747. $gateways[] = $gateway->id; 
  748. } else { 
  749. continue; 
  750. $view = null; 
  751.  
  752. switch ( $gateway->id ) { 
  753. case MS_Gateway_Stripe::ID: 
  754. $member = MS_Model_Member::get_current_member(); 
  755. $data['stripe'] = $member->get_gateway_profile( 
  756. $gateway->id 
  757. ); 
  758.  
  759. if ( empty( $data['stripe']['card_exp'] ) ) { 
  760. continue 2; 
  761.  
  762. $view = MS_Factory::create( 'MS_Gateway_Stripe_View_Card' ); 
  763. $data['member'] = $member; 
  764. $data['publishable_key'] = $gateway->get_publishable_key(); 
  765. $data['ms_relationship_id'] = $ms_relationship_id; 
  766. $data['gateway'] = $gateway; 
  767. break; 
  768.  
  769. case MS_Gateway_Authorize::ID: 
  770. $member = MS_Model_Member::get_current_member(); 
  771. $data['authorize'] = $member->get_gateway_profile( 
  772. $gateway->id 
  773. ); 
  774.  
  775. if ( empty( $data['authorize']['card_exp'] ) ) { 
  776. continue 2; 
  777.  
  778. $view = MS_Factory::create( 'MS_Gateway_Authorize_View_Card' ); 
  779. $data['member'] = $member; 
  780. $data['ms_relationship_id'] = $ms_relationship_id; 
  781. $data['gateway'] = $gateway; 
  782. break; 
  783.  
  784. default: 
  785. break; 
  786.  
  787. if ( ! empty( $view ) ) { 
  788. $view = apply_filters( 
  789. 'ms_gateway_view_change_card',  
  790. $view,  
  791. $gateway->id 
  792. ); 
  793. $view->data = apply_filters( 
  794. 'ms_gateway_view_change_card_data',  
  795. $data,  
  796. $gateway->id 
  797. ); 
  798.  
  799. $html = $view->to_html(); 
  800. echo '' . $html; 
  801.  
  802. /** 
  803. * Handle update credit card information in gateway. 
  804. * Used to change credit card info in account's page. 
  805. * Related action hooks: 
  806. * - template_redirect 
  807. * @since 1.0.0 
  808. */ 
  809. public function update_card() { 
  810. if ( ! empty( $_POST['gateway'] ) ) { 
  811. $gateway = MS_Model_Gateway::factory( $_POST['gateway'] ); 
  812. $member = MS_Model_Member::get_current_member(); 
  813.  
  814. switch ( $gateway->id ) { 
  815. case MS_Gateway_Stripe::ID: 
  816. if ( ! empty( $_POST['stripeToken'] ) && $this->verify_nonce() ) { 
  817. lib3()->array->strip_slashes( $_POST, 'stripeToken' ); 
  818.  
  819. $gateway->add_card( $member, $_POST['stripeToken'] ); 
  820. if ( ! empty( $_POST['ms_relationship_id'] ) ) { 
  821. $ms_relationship = MS_Factory::load( 
  822. 'MS_Model_Relationship',  
  823. $_POST['ms_relationship_id'] 
  824. ); 
  825. MS_Model_Event::save_event( 
  826. MS_Model_Event::TYPE_UPDATED_INFO,  
  827. $ms_relationship 
  828. ); 
  829.  
  830. wp_safe_redirect( 
  831. esc_url_raw( add_query_arg( array( 'msg' => 1 ) ) ) 
  832. ); 
  833. exit; 
  834. break; 
  835.  
  836. case MS_Gateway_Authorize::ID: 
  837. if ( $this->verify_nonce() ) { 
  838. do_action( 
  839. 'ms_controller_frontend_signup_gateway_form',  
  840. $this 
  841. ); 
  842. } elseif ( ! empty( $_POST['ms_relationship_id'] ) 
  843. && $this->verify_nonce( $_POST['gateway'] .'_' . $_POST['ms_relationship_id'] ) 
  844. ) { 
  845. $gateway->update_cim_profile( $member ); 
  846. $gateway->save_card_info( $member ); 
  847. if ( ! empty( $_POST['ms_relationship_id'] ) ) { 
  848. $ms_relationship = MS_Factory::load( 
  849. 'MS_Model_Relationship',  
  850. $_POST['ms_relationship_id'] 
  851. ); 
  852. MS_Model_Event::save_event( 
  853. MS_Model_Event::TYPE_UPDATED_INFO,  
  854. $ms_relationship 
  855. ); 
  856.  
  857. wp_safe_redirect( 
  858. esc_url_raw( add_query_arg( array( 'msg' => 1 ) ) ) 
  859. ); 
  860. exit; 
  861. break; 
  862.  
  863. default: 
  864. break; 
  865.  
  866. do_action( 
  867. 'ms_controller_gateway_update_card',  
  868. $this 
  869. ); 
  870.  
  871. /** 
  872. * Saves transaction details to the database. The transaction logs can later 
  873. * be displayed in the Billings section. 
  874. * @since 1.0.0 
  875. * @internal Action handler for 'ms_gateway_transaction_log' 
  876. * @param string $gateway_id The gateway ID. 
  877. * @param string $method Following values: 
  878. * "handle": IPN response 
  879. * "process": Process order (i.e. user comes from Payment screen) 
  880. * "request": Automatically request recurring payment 
  881. * @param bool $success True means that the transaction was paid/successful. 
  882. * False indicates an error. 
  883. * NULL indicates a message that was intentionally skipped. 
  884. * @param int $subscription_id 
  885. * @param int $invoice_id 
  886. * @param float $amount Payment amount. 
  887. * @param string $notes Additional text to describe the transaction or error. 
  888. * @param string $external_id The gateways transaction ID. 
  889. */ 
  890. public function log_transaction( $gateway_id, $method, $success, $subscription_id, $invoice_id, $amount, $notes, $external_id ) { 
  891. $log = MS_Factory::create( 'MS_Model_Transactionlog' ); 
  892. $log->description = $notes; 
  893. $log->gateway_id = $gateway_id; 
  894. $log->method = $method; 
  895. $log->success = $success; 
  896. $log->subscription_id = $subscription_id; 
  897. $log->invoice_id = $invoice_id; 
  898. $log->amount = $amount; 
  899. $log->external_id = $external_id; 
  900. $log->save(); 
  901.  
  902. /** 
  903. * Adds CSS and javascript 
  904. * @since 1.0.0 
  905. */ 
  906. public function enqueue_scripts( $step = null ) { 
  907. if ( empty( $step ) && ! empty( $_POST['step'] ) ) { 
  908. $step = $_POST['step']; 
  909.  
  910. lib3()->array->equip_post( 'gateway' ); 
  911. $gateway_id = $_POST['gateway']; 
  912.  
  913. switch ( $step ) { 
  914. case MS_Controller_Frontend::STEP_GATEWAY_FORM: 
  915. case MS_Controller_Frontend::STEP_PROCESS_PURCHASE: 
  916. if ( MS_Gateway_Authorize::ID == $gateway_id ) { 
  917. wp_enqueue_script( 'jquery-validate' ); 
  918.  
  919. $data = array( 
  920. 'ms_init' => array( 'gateway_authorize' ),  
  921. ); 
  922.  
  923. lib3()->ui->add( 'core' ); 
  924. lib3()->ui->add( 'select' ); 
  925. lib3()->ui->data( 'ms_data', $data ); 
  926. wp_enqueue_script( 'ms-public' ); 
  927. break;