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

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