PMProGateway_paypalexpress

The Paid Memberships Pro PMProGateway paypalexpress class.

Defined (1)

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

/classes/gateways/class.pmprogateway_paypalexpress.php  
  1. class PMProGateway_paypalexpress extends PMProGateway 
  2. function __construct($gateway = NULL) 
  3. $this->gateway = $gateway; 
  4. return $this->gateway; 
  5.  
  6. /** 
  7. * Run on WP init 
  8. * @since 1.8 
  9. */ 
  10. static function init() 
  11. //make sure PayPal Express is a gateway option 
  12. add_filter('pmpro_gateways', array('PMProGateway_paypalexpress', 'pmpro_gateways')); 
  13.  
  14. //add fields to payment settings 
  15. add_filter('pmpro_payment_options', array('PMProGateway_paypalexpress', 'pmpro_payment_options')); 
  16.  
  17. /** 
  18. Filter pmpro_next_payment to get actual value 
  19. via the PayPal API. This is disabled by default 
  20. for performance reasons, but you can enable it 
  21. by copying this line into a custom plugin or 
  22. your active theme's functions.php and uncommenting 
  23. it there. 
  24. */ 
  25. //add_filter('pmpro_next_payment', array('PMProGateway_paypalexpress', 'pmpro_next_payment'), 10, 3); 
  26.  
  27. /** 
  28. This code is the same for PayPal Website Payments Pro, PayPal Express, and PayPal Standard 
  29. So we only load it if we haven't already. 
  30. */ 
  31. global $pmpro_payment_option_fields_for_paypal; 
  32. if(empty($pmpro_payment_option_fields_for_paypal)) 
  33. add_filter('pmpro_payment_option_fields', array('PMProGateway_paypalexpress', 'pmpro_payment_option_fields'), 10, 2); 
  34. $pmpro_payment_option_fields_for_paypal = true; 
  35.  
  36. //code to add at checkout 
  37. $gateway = pmpro_getGateway(); 
  38. if($gateway == "paypalexpress") 
  39. add_filter('pmpro_include_billing_address_fields', '__return_false'); 
  40. add_filter('pmpro_include_payment_information_fields', '__return_false'); 
  41. add_filter('pmpro_required_billing_fields', array('PMProGateway_paypalexpress', 'pmpro_required_billing_fields')); 
  42. add_filter('pmpro_checkout_new_user_array', array('PMProGateway_paypalexpress', 'pmpro_checkout_new_user_array')); 
  43. add_filter('pmpro_checkout_confirmed', array('PMProGateway_paypalexpress', 'pmpro_checkout_confirmed')); 
  44. add_action('pmpro_checkout_before_processing', array('PMProGateway_paypalexpress', 'pmpro_checkout_before_processing')); 
  45. add_filter('pmpro_checkout_default_submit_button', array('PMProGateway_paypalexpress', 'pmpro_checkout_default_submit_button')); 
  46. add_action('pmpro_checkout_after_form', array('PMProGateway_paypalexpress', 'pmpro_checkout_after_form')); 
  47. add_action('http_api_curl', array('PMProGateway_paypalexpress', 'http_api_curl'), 10, 3); 
  48.  
  49. /** 
  50. * Update the SSLVERSION for CURL to support PayPal Express moving to TLS 1.2 
  51. * @since 1.8.9.1 
  52. */ 
  53. static function http_api_curl($handle, $r, $url) { 
  54. if(strpos($url, 'paypal.com') !== false) 
  55. curl_setopt( $handle, CURLOPT_SSLVERSION, 6 ); 
  56.  
  57. /** 
  58. * Make sure this gateway is in the gateways list 
  59. * @since 1.8 
  60. */ 
  61. static function pmpro_gateways($gateways) 
  62. if(empty($gateways['paypalexpress'])) 
  63. $gateways['paypalexpress'] = __('PayPal Express', 'paid-memberships-pro' ); 
  64.  
  65. return $gateways; 
  66.  
  67. /** 
  68. * Get a list of payment options that the this gateway needs/supports. 
  69. * @since 1.8 
  70. */ 
  71. static function getGatewayOptions() 
  72. $options = array( 
  73. 'sslseal',  
  74. 'nuclear_HTTPS',  
  75. 'gateway_environment',  
  76. 'gateway_email',  
  77. 'apiusername',  
  78. 'apipassword',  
  79. 'apisignature',  
  80. 'currency',  
  81. 'use_ssl',  
  82. 'tax_state',  
  83. 'tax_rate',  
  84. 'paypalexpress_skip_confirmation' 
  85. ); 
  86.  
  87. return $options; 
  88.  
  89. /** 
  90. * Set payment options for payment settings page. 
  91. * @since 1.8 
  92. */ 
  93. static function pmpro_payment_options($options) 
  94. //get stripe options 
  95. $paypal_options = PMProGateway_paypalexpress::getGatewayOptions(); 
  96.  
  97. //merge with others. 
  98. $options = array_merge($paypal_options, $options); 
  99.  
  100. return $options; 
  101.  
  102. /** 
  103. * Display fields for this gateway's options. 
  104. * @since 1.8 
  105. */ 
  106. static function pmpro_payment_option_fields($values, $gateway) 
  107. ?> 
  108. <tr class="pmpro_settings_divider gateway gateway_paypal gateway_paypalexpress gateway_paypalstandard" <?php if($gateway != "paypal" && $gateway != "paypalexpress" && $gateway != "paypalstandard") { ?>style="display: none;"<?php } ?>> 
  109. <td colspan="2"> 
  110. <?php _e('PayPal Settings', 'paid-memberships-pro' ); ?> 
  111. </td> 
  112. </tr> 
  113. <tr class="gateway gateway_paypalstandard" <?php if($gateway != "paypalstandard") { ?>style="display: none;"<?php } ?>> 
  114. <td colspan="2"> 
  115. <strong><?php _e('Note', 'paid-memberships-pro' );?>:</strong> <?php _e('We do not recommend using PayPal Standard. We suggest using PayPal Express, Website Payments Pro (Legacy), or PayPal Pro (Payflow Pro). <a target="_blank" href="http://www.paidmembershipspro.com/2013/09/read-using-paypal-standard-paid-memberships-pro/">More information on why can be found here.</a>', 'paid-memberships-pro' );?> 
  116. </td> 
  117. </tr> 
  118. <tr class="gateway gateway_paypal gateway_paypalexpress gateway_paypalstandard" <?php if($gateway != "paypal" && $gateway != "paypalexpress" && $gateway != "paypalstandard") { ?>style="display: none;"<?php } ?>> 
  119. <th scope="row" valign="top"> 
  120. <label for="gateway_email"><?php _e('Gateway Account Email', 'paid-memberships-pro' );?>:</label> 
  121. </th> 
  122. <td> 
  123. <input type="text" id="gateway_email" name="gateway_email" size="60" value="<?php echo esc_attr($values['gateway_email'])?>" /> 
  124. </td> 
  125. </tr> 
  126. <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>> 
  127. <th scope="row" valign="top"> 
  128. <label for="apiusername"><?php _e('API Username', 'paid-memberships-pro' );?>:</label> 
  129. </th> 
  130. <td> 
  131. <input type="text" id="apiusername" name="apiusername" size="60" value="<?php echo esc_attr($values['apiusername'])?>" /> 
  132. </td> 
  133. </tr> 
  134. <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>> 
  135. <th scope="row" valign="top"> 
  136. <label for="apipassword"><?php _e('API Password', 'paid-memberships-pro' );?>:</label> 
  137. </th> 
  138. <td> 
  139. <input type="text" id="apipassword" name="apipassword" size="60" value="<?php echo esc_attr($values['apipassword'])?>" /> 
  140. </td> 
  141. </tr> 
  142. <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>> 
  143. <th scope="row" valign="top"> 
  144. <label for="apisignature"><?php _e('API Signature', 'paid-memberships-pro' );?>:</label> 
  145. </th> 
  146. <td> 
  147. <input type="text" id="apisignature" name="apisignature" size="60" value="<?php echo esc_attr($values['apisignature'])?>" /> 
  148. </td> 
  149. </tr> 
  150. <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>> 
  151. <th scope="row" valign="top"> 
  152. <label for="paypalexpress_skip_confirmation"><?php _e('Confirmation Step', 'paid-memberships-pro' );?>:</label> 
  153. </th> 
  154. <td> 
  155. <select id="paypalexpress_skip_confirmation" name="paypalexpress_skip_confirmation"> 
  156. <option value="0" <?php selected(pmpro_getOption('paypalexpress_skip_confirmation'), 0);?>>Require an extra confirmation after users return from PayPal Express.</option> 
  157. <option value="1" <?php selected(pmpro_getOption('paypalexpress_skip_confirmation'), 1);?>>Skip the extra confirmation after users return from PayPal Express.</option> 
  158. </select> 
  159. </td> 
  160. </tr> 
  161. <tr class="gateway gateway_paypal gateway_paypalexpress gateway_paypalstandard" <?php if($gateway != "paypal" && $gateway != "paypalexpress" && $gateway != "paypalstandard") { ?>style="display: none;"<?php } ?>> 
  162. <th scope="row" valign="top"> 
  163. <label><?php _e('IPN Handler URL', 'paid-memberships-pro' );?>:</label> 
  164. </th> 
  165. <td> 
  166. <p><?php _e('To fully integrate with PayPal, be sure to set your IPN Handler URL to ', 'paid-memberships-pro' );?> <pre><?php echo admin_url("admin-ajax.php") . "?action=ipnhandler";?></pre></p> 
  167. </td> 
  168. </tr> 
  169. <?php 
  170.  
  171. /** 
  172. * Remove required billing fields 
  173. * @since 1.8 
  174. */ 
  175. static function pmpro_required_billing_fields($fields) 
  176. unset($fields['bfirstname']); 
  177. unset($fields['blastname']); 
  178. unset($fields['baddress1']); 
  179. unset($fields['bcity']); 
  180. unset($fields['bstate']); 
  181. unset($fields['bzipcode']); 
  182. unset($fields['bphone']); 
  183. unset($fields['bemail']); 
  184. unset($fields['bcountry']); 
  185. unset($fields['CardType']); 
  186. unset($fields['AccountNumber']); 
  187. unset($fields['ExpirationMonth']); 
  188. unset($fields['ExpirationYear']); 
  189. unset($fields['CVV']); 
  190.  
  191. return $fields; 
  192.  
  193. /** 
  194. * Save session vars before processing 
  195. * @since 1.8 
  196. */ 
  197. static function pmpro_checkout_before_processing() 
  198. global $current_user, $gateway; 
  199.  
  200. //save user fields for PayPal Express 
  201. if(!$current_user->ID) 
  202. //get values from post 
  203. if(isset($_REQUEST['username'])) 
  204. $username = trim($_REQUEST['username']); 
  205. else 
  206. $username = ""; 
  207. if(isset($_REQUEST['password'])) 
  208. $password = $_REQUEST['password']; 
  209. else 
  210. $password = ""; 
  211. if(isset($_REQUEST['bemail'])) 
  212. $bemail = $_REQUEST['bemail']; 
  213. else 
  214. $bemail = ""; 
  215.  
  216. //save to session 
  217. $_SESSION['pmpro_signup_username'] = $username; 
  218. $_SESSION['pmpro_signup_password'] = $password; 
  219. $_SESSION['pmpro_signup_email'] = $bemail; 
  220.  
  221. //can use this hook to save some other variables to the session 
  222. do_action("pmpro_paypalexpress_session_vars"); 
  223.  
  224. /** 
  225. * Review and Confirmation code. 
  226. * @since 1.8 
  227. */ 
  228. static function pmpro_checkout_confirmed($pmpro_confirmed) 
  229. global $pmpro_msg, $pmpro_msgt, $pmpro_level, $current_user, $pmpro_review, $pmpro_paypal_token, $discount_code, $bemail; 
  230.  
  231. //PayPal Express Call Backs 
  232. if(!empty($_REQUEST['review'])) 
  233. if(!empty($_REQUEST['PayerID'])) 
  234. $_SESSION['payer_id'] = $_REQUEST['PayerID']; 
  235. if(!empty($_REQUEST['paymentAmount'])) 
  236. $_SESSION['paymentAmount'] = $_REQUEST['paymentAmount']; 
  237. if(!empty($_REQUEST['currencyCodeType'])) 
  238. $_SESSION['currCodeType'] = $_REQUEST['currencyCodeType']; 
  239. if(!empty($_REQUEST['paymentType'])) 
  240. $_SESSION['paymentType'] = $_REQUEST['paymentType']; 
  241.  
  242. $morder = new MemberOrder(); 
  243. $morder->getMemberOrderByPayPalToken($_REQUEST['token']); 
  244. $morder->Token = $morder->paypal_token; $pmpro_paypal_token = $morder->paypal_token; 
  245. if($morder->Token) 
  246. if($morder->Gateway->getExpressCheckoutDetails($morder)) 
  247. $pmpro_review = true; 
  248. else 
  249. $pmpro_msg = $morder->error; 
  250. $pmpro_msgt = "pmpro_error"; 
  251. else 
  252. $pmpro_msg = __("The PayPal Token was lost.", 'paid-memberships-pro' ); 
  253. $pmpro_msgt = "pmpro_error"; 
  254.  
  255. if(empty($pmpro_msg) && 
  256. (!empty($_REQUEST['confirm']) || 
  257. (pmpro_getOption('paypalexpress_skip_confirmation') && $pmpro_review)) 
  258. $morder = new MemberOrder(); 
  259. $morder->getMemberOrderByPayPalToken($_REQUEST['token']); 
  260. $morder->Token = $morder->paypal_token; $pmpro_paypal_token = $morder->paypal_token; 
  261. if($morder->Token) 
  262. //set up values 
  263. $morder->membership_id = $pmpro_level->id; 
  264. $morder->membership_name = $pmpro_level->name; 
  265. $morder->discount_code = $discount_code; 
  266. $morder->InitialPayment = $pmpro_level->initial_payment; 
  267. $morder->PaymentAmount = $pmpro_level->billing_amount; 
  268. $morder->ProfileStartDate = date_i18n("Y-m-d") . "T0:0:0"; 
  269. $morder->BillingPeriod = $pmpro_level->cycle_period; 
  270. $morder->BillingFrequency = $pmpro_level->cycle_number; 
  271. $morder->Email = $bemail; 
  272.  
  273. //set up level var 
  274. $morder->getMembershipLevel(); 
  275. $morder->membership_level = apply_filters("pmpro_checkout_level", $morder->membership_level); 
  276.  
  277. //tax 
  278. $morder->subtotal = $morder->InitialPayment; 
  279. $morder->getTax(); 
  280. if($pmpro_level->billing_limit) 
  281. $morder->TotalBillingCycles = $pmpro_level->billing_limit; 
  282.  
  283. if(pmpro_isLevelTrial($pmpro_level)) 
  284. $morder->TrialBillingPeriod = $pmpro_level->cycle_period; 
  285. $morder->TrialBillingFrequency = $pmpro_level->cycle_number; 
  286. $morder->TrialBillingCycles = $pmpro_level->trial_limit; 
  287. $morder->TrialAmount = $pmpro_level->trial_amount; 
  288.  
  289. if($morder->confirm()) 
  290. $pmpro_confirmed = true; 
  291. else 
  292. $pmpro_msg = $morder->error; 
  293. $pmpro_msgt = "pmpro_error"; 
  294. else 
  295. $pmpro_msg = __("The PayPal Token was lost.", 'paid-memberships-pro' ); 
  296. $pmpro_msgt = "pmpro_error"; 
  297.  
  298. if(!empty($morder)) 
  299. return array("pmpro_confirmed"=>$pmpro_confirmed, "morder"=>$morder); 
  300. else 
  301. return $pmpro_confirmed; 
  302.  
  303. /** 
  304. * Swap in user/pass/etc from session 
  305. * @since 1.8 
  306. */ 
  307. static function pmpro_checkout_new_user_array($new_user_array) 
  308. global $current_user; 
  309.  
  310. if(!$current_user->ID) 
  311. //reload the user fields 
  312. $new_user_array['user_login'] = $_SESSION['pmpro_signup_username']; 
  313. $new_user_array['user_pass'] = $_SESSION['pmpro_signup_password']; 
  314. $new_user_array['user_email'] = $_SESSION['pmpro_signup_email']; 
  315.  
  316. //unset the user fields in session 
  317. unset($_SESSION['pmpro_signup_username']); 
  318. unset($_SESSION['pmpro_signup_password']); 
  319. unset($_SESSION['pmpro_signup_email']); 
  320.  
  321. return $new_user_array; 
  322.  
  323. /** 
  324. * Process at checkout 
  325. * Repurposed in v2.0. The old process() method is now confirm(). 
  326. */ 
  327. function process(&$order) 
  328. $order->payment_type = "PayPal Express"; 
  329. $order->cardtype = ""; 
  330. $order->ProfileStartDate = date_i18n("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod)) . "T0:0:0"; 
  331. $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order); 
  332.  
  333. return $this->setExpressCheckout($order); 
  334.  
  335. /** 
  336. * Process charge or subscription after confirmation. 
  337. * @since 1.8 
  338. */ 
  339. function confirm(&$order) 
  340. if(pmpro_isLevelRecurring($order->membership_level)) 
  341. $order->ProfileStartDate = date_i18n("Y-m-d", strtotime("+ " . $order->BillingFrequency . " " . $order->BillingPeriod, current_time("timestamp"))) . "T0:0:0"; 
  342. $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order); 
  343. return $this->subscribe($order); 
  344. else 
  345. return $this->charge($order); 
  346.  
  347. /** 
  348. * Swap in our submit buttons. 
  349. * @since 1.8 
  350. */ 
  351. static function pmpro_checkout_default_submit_button($show) 
  352. global $gateway, $pmpro_requirebilling; 
  353.  
  354. //show our submit buttons 
  355. ?> 
  356. <span id="pmpro_paypalexpress_checkout" <?php if(($gateway != "paypalexpress" && $gateway != "paypalstandard") || !$pmpro_requirebilling) { ?>style="display: none;"<?php } ?>> 
  357. <input type="hidden" name="submit-checkout" value="1" /> 
  358. <input type="image" class="pmpro_btn-submit-checkout" value="<?php _e('Check Out with PayPal', 'paid-memberships-pro' );?> »" src="<?php echo apply_filters("pmpro_paypal_button_image", "https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif");?>" /> 
  359. </span> 
  360.  
  361. <span id="pmpro_submit_span" <?php if(($gateway == "paypalexpress" || $gateway == "paypalstandard") && $pmpro_requirebilling) { ?>style="display: none;"<?php } ?>> 
  362. <input type="hidden" name="submit-checkout" value="1" /> 
  363. <input type="submit" class="pmpro_btn pmpro_btn-submit-checkout" value="<?php if($pmpro_requirebilling) { _e('Submit and Check Out', 'paid-memberships-pro' ); } else { _e('Submit and Confirm', 'paid-memberships-pro' );}?> »" /> 
  364. </span> 
  365. <?php 
  366.  
  367. //don't show the default 
  368. return false; 
  369.  
  370. /** 
  371. * Scripts for checkout page. 
  372. * @since 1.8 
  373. */ 
  374. static function pmpro_checkout_after_form() 
  375. ?> 
  376. <script> 
  377. <!-- 
  378. //choosing payment method 
  379. jQuery('input[name=gateway]').click(function() { 
  380. if(jQuery(this).val() == 'paypal') 
  381. jQuery('#pmpro_paypalexpress_checkout').hide(); 
  382. jQuery('#pmpro_billing_address_fields').show(); 
  383. jQuery('#pmpro_payment_information_fields').show(); 
  384. jQuery('#pmpro_submit_span').show(); 
  385. else 
  386. jQuery('#pmpro_billing_address_fields').hide(); 
  387. jQuery('#pmpro_payment_information_fields').hide(); 
  388. jQuery('#pmpro_submit_span').hide(); 
  389. jQuery('#pmpro_paypalexpress_checkout').show(); 
  390. }); 
  391.  
  392. //select the radio button if the label is clicked on 
  393. jQuery('a.pmpro_radio').click(function() { 
  394. jQuery(this).prev().click(); 
  395. }); 
  396. --> 
  397. </script> 
  398. <?php 
  399.  
  400. //PayPal Express, this is run first to authorize from PayPal 
  401. function setExpressCheckout(&$order) 
  402. global $pmpro_currency; 
  403.  
  404. if(empty($order->code)) 
  405. $order->code = $order->getRandomCode(); 
  406.  
  407. //clean up a couple values 
  408. $order->payment_type = "PayPal Express"; 
  409. $order->CardType = ""; 
  410. $order->cardtype = ""; 
  411.  
  412. //taxes on initial amount 
  413. $initial_payment = $order->InitialPayment; 
  414. $initial_payment_tax = $order->getTaxForPrice($initial_payment); 
  415. $initial_payment = round((float)$initial_payment + (float)$initial_payment_tax, 2); 
  416.  
  417. //taxes on the amount 
  418. $amount = $order->PaymentAmount; 
  419. $amount_tax = $order->getTaxForPrice($amount); 
  420. $amount = round((float)$amount + (float)$amount_tax, 2); 
  421.  
  422. //paypal profile stuff 
  423. $nvpStr = ""; 
  424. $nvpStr .="&AMT=" . $initial_payment . "&CURRENCYCODE=" . $pmpro_currency; 
  425. if(!empty($order->ProfileStartDate) && strtotime($order->ProfileStartDate, current_time("timestamp")) > 0) 
  426. $nvpStr .= "&PROFILESTARTDATE=" . $order->ProfileStartDate; 
  427. if(!empty($order->BillingFrequency)) 
  428. $nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLOUTAMT=AddToNextBilling&L_BILLINGTYPE0=RecurringPayments"; 
  429. $nvpStr .= "&DESC=" . urlencode( apply_filters( 'pmpro_paypal_level_description', substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127), $order->membership_level->name, $order, get_bloginfo("name")) ); 
  430. $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler"); 
  431. $nvpStr .= "&NOSHIPPING=1&L_BILLINGAGREEMENTDESCRIPTION0=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127)) . "&L_PAYMENTTYPE0=Any"; 
  432.  
  433. //if billing cycles are defined 
  434. if(!empty($order->TotalBillingCycles)) 
  435. $nvpStr .= "&TOTALBILLINGCYCLES=" . $order->TotalBillingCycles; 
  436.  
  437. //if a trial period is defined 
  438. if(!empty($order->TrialBillingPeriod)) 
  439. $trial_amount = $order->TrialAmount; 
  440. $trial_tax = $order->getTaxForPrice($trial_amount); 
  441. $trial_amount = round((float)$trial_amount + (float)$trial_tax, 2); 
  442.  
  443. $nvpStr .= "&TRIALBILLINGPERIOD=" . $order->TrialBillingPeriod . "&TRIALBILLINGFREQUENCY=" . $order->TrialBillingFrequency . "&TRIALAMT=" . $trial_amount; 
  444. if(!empty($order->TrialBillingCycles)) 
  445. $nvpStr .= "&TRIALTOTALBILLINGCYCLES=" . $order->TrialBillingCycles; 
  446.  
  447. if(!empty($order->discount_code)) 
  448. $nvpStr .= "&ReturnUrl=" . urlencode(pmpro_url("checkout", "?level=" . $order->membership_level->id . "&discount_code=" . $order->discount_code . "&review=" . $order->code)); 
  449. else 
  450. $nvpStr .= "&ReturnUrl=" . urlencode(pmpro_url("checkout", "?level=" . $order->membership_level->id . "&review=" . $order->code)); 
  451.  
  452. $additional_parameters = apply_filters("pmpro_paypal_express_return_url_parameters", array()); 
  453. if(!empty($additional_parameters)) 
  454. foreach($additional_parameters as $key => $value) 
  455. $nvpStr .= urlencode("&" . $key . "=" . $value); 
  456.  
  457. $nvpStr .= "&CANCELURL=" . urlencode(pmpro_url("levels")); 
  458.  
  459. $account_optional = apply_filters('pmpro_paypal_account_optional', true); 
  460. if ($account_optional) 
  461. $nvpStr .= '&SOLUTIONTYPE=Sole&LANDINGPAGE=Billing'; 
  462.  
  463. $nvpStr = apply_filters("pmpro_set_express_checkout_nvpstr", $nvpStr, $order); 
  464.  
  465. ///echo str_replace("&", "&<br />", $nvpStr); 
  466. ///exit; 
  467.  
  468. $this->httpParsedResponseAr = $this->PPHttpPost('SetExpressCheckout', $nvpStr); 
  469.  
  470. if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) { 
  471. $order->status = "token"; 
  472. $order->paypal_token = urldecode($this->httpParsedResponseAr['TOKEN']); 
  473.  
  474. //update order 
  475. $order->saveOrder(); 
  476.  
  477. //redirect to paypal 
  478. $paypal_url = "https://www.paypal.com/webscr?cmd=_express-checkout&useraction=commit&token=" . $this->httpParsedResponseAr['TOKEN']; 
  479. $environment = pmpro_getOption("gateway_environment"); 
  480. if("sandbox" === $environment || "beta-sandbox" === $environment) 
  481. $paypal_url = "https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&useraction=commit&token=" . $this->httpParsedResponseAr['TOKEN']; 
  482.  
  483. wp_redirect($paypal_url); 
  484. exit; 
  485.  
  486. //exit('SetExpressCheckout Completed Successfully: '.print_r($this->httpParsedResponseAr, true)); 
  487. } else { 
  488. $order->status = "error"; 
  489. $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0']; 
  490. $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']); 
  491. $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']); 
  492. return false; 
  493. //exit('SetExpressCheckout failed: ' . print_r($httpParsedResponseAr, true)); 
  494.  
  495. //write session? 
  496.  
  497. //redirect to PayPal 
  498.  
  499. function getExpressCheckoutDetails(&$order) 
  500. $nvpStr="&TOKEN=".$order->Token; 
  501.  
  502. $nvpStr = apply_filters("pmpro_get_express_checkout_details_nvpstr", $nvpStr, $order); 
  503.  
  504. /** Make the API call and store the results in an array. If the 
  505. call was a success, show the authorization details, and provide 
  506. an action to complete the payment. If failed, show the error 
  507. */ 
  508. $this->httpParsedResponseAr = $this->PPHttpPost('GetExpressCheckoutDetails', $nvpStr); 
  509.  
  510. if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) { 
  511. $order->status = "review"; 
  512.  
  513. //update order 
  514. $order->saveOrder(); 
  515.  
  516. return true; 
  517. } else { 
  518. $order->status = "error"; 
  519. $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0']; 
  520. $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']); 
  521. $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']); 
  522. return false; 
  523. //exit('SetExpressCheckout failed: ' . print_r($httpParsedResponseAr, true)); 
  524.  
  525. function charge(&$order) 
  526. global $pmpro_currency; 
  527.  
  528. if(empty($order->code)) 
  529. $order->code = $order->getRandomCode(); 
  530.  
  531. //taxes on the amount 
  532. $amount = $order->InitialPayment; 
  533. $amount_tax = $order->getTaxForPrice($amount); 
  534. $order->subtotal = $amount; 
  535. $amount = round((float)$amount + (float)$amount_tax, 2); 
  536.  
  537. //paypal profile stuff 
  538. $nvpStr = ""; 
  539. if(!empty($order->Token)) 
  540. $nvpStr .= "&TOKEN=" . $order->Token; 
  541. $nvpStr .="&AMT=" . $amount . "&CURRENCYCODE=" . $pmpro_currency; 
  542. /** 
  543. if(!empty($amount_tax)) 
  544. $nvpStr .= "&TAXAMT=" . $amount_tax; 
  545. */ 
  546. if(!empty($order->BillingFrequency)) 
  547. $nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLOUTAMT=AddToNextBilling"; 
  548. $nvpStr .= "&DESC=" . urlencode( apply_filters( 'pmpro_paypal_level_description', substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127), $order->membership_level->name, $order, get_bloginfo("name")) ); 
  549. $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler"); 
  550. $nvpStr .= "&NOSHIPPING=1"; 
  551.  
  552. $nvpStr .= "&PAYERID=" . $_SESSION['payer_id'] . "&PAYMENTACTION=sale"; 
  553.  
  554. $nvpStr = apply_filters("pmpro_do_express_checkout_payment_nvpstr", $nvpStr, $order); 
  555.  
  556. $order->nvpStr = $nvpStr; 
  557.  
  558. $this->httpParsedResponseAr = $this->PPHttpPost('DoExpressCheckoutPayment', $nvpStr); 
  559.  
  560. if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) { 
  561. $order->payment_transaction_id = urldecode($this->httpParsedResponseAr['TRANSACTIONID']); 
  562. $order->status = "success"; 
  563.  
  564. //update order 
  565. $order->saveOrder(); 
  566.  
  567. return true; 
  568. } else { 
  569. $order->status = "error"; 
  570. $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0']; 
  571. $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']); 
  572. $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']); 
  573. return false; 
  574. //exit('SetExpressCheckout failed: ' . print_r($httpParsedResponseAr, true)); 
  575.  
  576. function subscribe(&$order) 
  577. global $pmpro_currency; 
  578.  
  579. if(empty($order->code)) 
  580. $order->code = $order->getRandomCode(); 
  581.  
  582. //filter order before subscription. use with care. 
  583. $order = apply_filters("pmpro_subscribe_order", $order, $this); 
  584.  
  585. //taxes on initial amount 
  586. $initial_payment = $order->InitialPayment; 
  587. $initial_payment_tax = $order->getTaxForPrice($initial_payment); 
  588. $initial_payment = round((float)$initial_payment + (float)$initial_payment_tax, 2); 
  589.  
  590. //taxes on the amount 
  591. $amount = $order->PaymentAmount; 
  592. $amount_tax = $order->getTaxForPrice($amount); 
  593. //$amount = round((float)$amount + (float)$amount_tax, 2); 
  594.  
  595. //paypal profile stuff 
  596. $nvpStr = ""; 
  597. if(!empty($order->Token)) 
  598. $nvpStr .= "&TOKEN=" . $order->Token; 
  599. $nvpStr .="&INITAMT=" . $initial_payment . "&AMT=" . $amount . "&CURRENCYCODE=" . $pmpro_currency . "&PROFILESTARTDATE=" . $order->ProfileStartDate; 
  600. if(!empty($amount_tax)) 
  601. $nvpStr .= "&TAXAMT=" . $amount_tax; 
  602. $nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLOUTAMT=AddToNextBilling"; 
  603. $nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler"); 
  604. $nvpStr .= "&DESC=" . urlencode( apply_filters( 'pmpro_paypal_level_description', substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127), $order->membership_level->name, $order, get_bloginfo("name")) ); 
  605.  
  606. //if billing cycles are defined 
  607. if(!empty($order->TotalBillingCycles)) 
  608. $nvpStr .= "&TOTALBILLINGCYCLES=" . $order->TotalBillingCycles; 
  609.  
  610. //if a trial period is defined 
  611. if(!empty($order->TrialBillingPeriod)) 
  612. $trial_amount = $order->TrialAmount; 
  613. $trial_tax = $order->getTaxForPrice($trial_amount); 
  614. $trial_amount = round((float)$trial_amount + (float)$trial_tax, 2); 
  615.  
  616. $nvpStr .= "&TRIALBILLINGPERIOD=" . $order->TrialBillingPeriod . "&TRIALBILLINGFREQUENCY=" . $order->TrialBillingFrequency . "&TRIALAMT=" . $trial_amount; 
  617. if(!empty($order->TrialBillingCycles)) 
  618. $nvpStr .= "&TRIALTOTALBILLINGCYCLES=" . $order->TrialBillingCycles; 
  619.  
  620. $nvpStr = apply_filters("pmpro_create_recurring_payments_profile_nvpstr", $nvpStr, $order); 
  621.  
  622. $this->nvpStr = $nvpStr; 
  623.  
  624. ///echo str_replace("&", "&<br />", $nvpStr); 
  625. ///exit; 
  626.  
  627. $this->httpParsedResponseAr = $this->PPHttpPost('CreateRecurringPaymentsProfile', $nvpStr); 
  628.  
  629. if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) { 
  630. $order->status = "success"; 
  631. $order->payment_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']); 
  632. $order->subscription_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']); 
  633.  
  634. //update order 
  635. $order->saveOrder(); 
  636.  
  637. return true; 
  638. } else { 
  639. $order->status = "error"; 
  640. $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0']; 
  641. $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']); 
  642. $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']); 
  643.  
  644. return false; 
  645.  
  646. function cancel(&$order) 
  647. //paypal profile stuff 
  648. $nvpStr = ""; 
  649. $nvpStr .= "&PROFILEID=" . urlencode($order->subscription_transaction_id) . "&ACTION=Cancel&NOTE=" . urlencode("User requested cancel."); 
  650.  
  651. $nvpStr = apply_filters("pmpro_manage_recurring_payments_profile_status_nvpstr", $nvpStr, $order); 
  652.  
  653. $this->httpParsedResponseAr = $this->PPHttpPost('ManageRecurringPaymentsProfileStatus', $nvpStr); 
  654.  
  655. if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) 
  656. $order->updateStatus("cancelled"); 
  657. return true; 
  658. else 
  659. $order->status = "error"; 
  660. $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0']; 
  661. $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']) . ". " . __("Please contact the site owner or cancel your subscription from within PayPal to make sure you are not charged going forward.", 'paid-memberships-pro' ); 
  662. $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']); 
  663.  
  664. return false; 
  665.  
  666. function getSubscriptionStatus(&$order) 
  667. if(empty($order->subscription_transaction_id)) 
  668. return false; 
  669.  
  670. //paypal profile stuff 
  671. $nvpStr = ""; 
  672. $nvpStr .= "&PROFILEID=" . urlencode($order->subscription_transaction_id); 
  673.  
  674. $nvpStr = apply_filters("pmpro_get_recurring_payments_profile_details_nvpstr", $nvpStr, $order); 
  675.  
  676. $this->httpParsedResponseAr = $this->PPHttpPost('GetRecurringPaymentsProfileDetails', $nvpStr); 
  677.  
  678. if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) 
  679. return $this->httpParsedResponseAr; 
  680. else 
  681. $order->status = "error"; 
  682. $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0']; 
  683. $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']); 
  684. $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']); 
  685.  
  686. return false; 
  687.  
  688. /** 
  689. * Filter pmpro_next_payment to get date via API if possible 
  690. * @since 1.8.5 
  691. */ 
  692. static function pmpro_next_payment($timestamp, $user_id, $order_status) 
  693. //find the last order for this user 
  694. if(!empty($user_id)) 
  695. //get last order 
  696. $order = new MemberOrder(); 
  697. $order->getLastMemberOrder($user_id, $order_status); 
  698.  
  699. //check if this is a paypal express order with a subscription transaction id 
  700. if(!empty($order->id) && !empty($order->subscription_transaction_id) && $order->gateway == "paypalexpress") 
  701. //get the subscription status 
  702. $status = $order->getGatewaySubscriptionStatus();  
  703.  
  704. if(!empty($status) && !empty($status['NEXTBILLINGDATE'])) 
  705. //found the next billing date at PayPal, going to use that  
  706. $timestamp = strtotime(urldecode($status['NEXTBILLINGDATE']), current_time('timestamp')); 
  707. elseif(!empty($status) && !empty($status['PROFILESTARTDATE']) && $order_status == "cancelled") 
  708. //startdate is in the future and we cancelled so going to use that as the next payment date 
  709. $startdate_timestamp = strtotime(urldecode($status['PROFILESTARTDATE']), current_time('timestamp')); 
  710. if($startdate_timestamp > current_time('timestamp')) 
  711. $timestamp = $startdate_timestamp; 
  712.  
  713. return $timestamp; 
  714.  
  715. /** 
  716. * PAYPAL Function 
  717. * Send HTTP POST Request 
  718. * @param string The API method name 
  719. * @param string The POST Message fields in &name=value pair format 
  720. * @return array Parsed HTTP Response body 
  721. */ 
  722. function PPHttpPost($methodName_, $nvpStr_) { 
  723. global $gateway_environment; 
  724. $environment = $gateway_environment; 
  725.  
  726. $API_UserName = pmpro_getOption("apiusername"); 
  727. $API_Password = pmpro_getOption("apipassword"); 
  728. $API_Signature = pmpro_getOption("apisignature"); 
  729. $API_Endpoint = "https://api-3t.paypal.com/nvp"; 
  730. if("sandbox" === $environment || "beta-sandbox" === $environment) { 
  731. $API_Endpoint = "https://api-3t.$environment.paypal.com/nvp"; 
  732.  
  733. $version = urlencode('72.0'); 
  734.  
  735. //NVPRequest for submitting to server 
  736. $nvpreq = "METHOD=" . urlencode($methodName_) . "&VERSION=" . urlencode($version) . "&PWD=" . urlencode($API_Password) . "&USER=" . urlencode($API_UserName) . "&SIGNATURE=" . urlencode($API_Signature) . "&BUTTONSOURCE=" . urlencode(PAYPAL_BN_CODE) . $nvpStr_; 
  737.  
  738. //post to PayPal 
  739. $response = wp_remote_post( $API_Endpoint, array( 
  740. 'timeout' => 60,  
  741. 'sslverify' => FALSE,  
  742. 'httpversion' => '1.1',  
  743. 'body' => $nvpreq 
  744. ); 
  745.  
  746. if ( is_wp_error( $response ) ) { 
  747. $error_message = $response->get_error_message(); 
  748. die( "methodName_ failed: $error_message" ); 
  749. } else { 
  750. //extract the response details 
  751. $httpParsedResponseAr = array(); 
  752. parse_str(wp_remote_retrieve_body($response), $httpParsedResponseAr); 
  753.  
  754. //check for valid response 
  755. if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) { 
  756. exit("Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint."); 
  757.  
  758. return $httpParsedResponseAr;