PMProGateway_stripe

PMProGateway_stripe Class.

Defined (1)

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

/classes/gateways/class.pmprogateway_stripe.php  
  1. class PMProGateway_stripe extends PMProGateway 
  2. /** 
  3. * @var bool Is the Stripe/PHP Library loaded 
  4. */ 
  5. private static $is_loaded = false; 
  6. /** 
  7. * Stripe Class Constructor 
  8. * @since 1.4 
  9. */ 
  10. function __construct($gateway = NULL) 
  11. $this->gateway = $gateway; 
  12. $this->gateway_environment = pmpro_getOption("gateway_environment"); 
  13.  
  14. if( true === $this->dependencies() ) { 
  15. $this->loadStripeLibrary(); 
  16. Stripe\Stripe::setApiKey(pmpro_getOption("stripe_secretkey")); 
  17. Stripe\Stripe::setAPIVersion("2015-07-13"); 
  18. self::$is_loaded = true; 
  19.  
  20. return $this->gateway; 
  21.  
  22. /** 
  23. * Warn if required extensions aren't loaded. 
  24. * @return bool 
  25. * @since 1.8.6.8.1 
  26. * @since 1.8.13.6 - Add json dependency 
  27. */ 
  28. public static function dependencies() 
  29. global $msg, $msgt, $pmpro_stripe_error; 
  30.  
  31. if ( version_compare( PHP_VERSION, '5.3.29', '<' )) { 
  32.  
  33. $pmpro_stripe_error = true; 
  34. $msg = -1; 
  35. $msgt = sprintf(__("The Stripe Gateway requires PHP 5.3.29 or greater. We recommend upgrading to PHP %s or greater. Ask your host to upgrade.", "paid-memberships-pro" ), PMPRO_PHP_MIN_VERSION ); 
  36.  
  37. if ( !is_admin() ) { 
  38. pmpro_setMessage( $msgt, "pmpro_error" ); 
  39.  
  40. return false; 
  41.  
  42. $modules = array( 'curl', 'mbstring', 'json' ); 
  43.  
  44. foreach($modules as $module) { 
  45. if(!extension_loaded($module)) { 
  46. $pmpro_stripe_error = true;  
  47. $msg = -1; 
  48. $msgt = sprintf(__("The %s gateway depends on the %s PHP extension. Please enable it, or ask your hosting provider to enable it.", 'paid-memberships-pro' ), 'Stripe', $module); 
  49.  
  50. //throw error on checkout page 
  51. if(!is_admin()) 
  52. pmpro_setMessage($msgt, 'pmpro_error'); 
  53.  
  54. return false; 
  55.  
  56. self::$is_loaded = true; 
  57. return true; 
  58.  
  59. /** 
  60. * Load the Stripe API library. 
  61. * @since 1.8 
  62. * Moved into a method in version 1.8 so we only load it when needed. 
  63. */ 
  64. function loadStripeLibrary() 
  65. //load Stripe library if it hasn't been loaded already (usually by another plugin using Stripe) 
  66. if(!class_exists("\\Stripe")) { 
  67. require_once( PMPRO_DIR . "/includes/lib/Stripe/init.php" ); 
  68.  
  69. /** 
  70. * Run on WP init 
  71. * @since 1.8 
  72. */ 
  73. static function init() 
  74. //make sure Stripe is a gateway option 
  75. add_filter('pmpro_gateways', array('PMProGateway_stripe', 'pmpro_gateways')); 
  76.  
  77. //add fields to payment settings 
  78. add_filter('pmpro_payment_options', array('PMProGateway_stripe', 'pmpro_payment_options')); 
  79. add_filter('pmpro_payment_option_fields', array('PMProGateway_stripe', 'pmpro_payment_option_fields'), 10, 2); 
  80.  
  81. //add some fields to edit user page (Updates) 
  82. add_action('pmpro_after_membership_level_profile_fields', array('PMProGateway_stripe', 'user_profile_fields')); 
  83. add_action('profile_update', array('PMProGateway_stripe', 'user_profile_fields_save')); 
  84.  
  85. //old global RE showing billing address or not 
  86. global $pmpro_stripe_lite; 
  87. $pmpro_stripe_lite = apply_filters("pmpro_stripe_lite", !pmpro_getOption("stripe_billingaddress")); //default is oposite of the stripe_billingaddress setting 
  88. add_filter('pmpro_required_billing_fields', array('PMProGateway_stripe', 'pmpro_required_billing_fields')); 
  89.  
  90. //updates cron 
  91. add_action('pmpro_cron_stripe_subscription_updates', array('PMProGateway_stripe', 'pmpro_cron_stripe_subscription_updates')); 
  92.  
  93. /** 
  94. Filter pmpro_next_payment to get actual value 
  95. via the Stripe API. This is disabled by default 
  96. for performance reasons, but you can enable it 
  97. by copying this line into a custom plugin or 
  98. your active theme's functions.php and uncommenting 
  99. it there. 
  100. */ 
  101. //add_filter('pmpro_next_payment', array('PMProGateway_stripe', 'pmpro_next_payment'), 10, 3); 
  102.  
  103. //code to add at checkout if Stripe is the current gateway 
  104. $default_gateway = pmpro_getOption('gateway'); 
  105. $current_gateway = pmpro_getGateway(); 
  106.  
  107. if( ($default_gateway == "stripe" || $current_gateway == "stripe") && empty($_REQUEST['review'] ) ) //$_REQUEST['review'] means the PayPal Express review page 
  108. add_action('pmpro_checkout_preheader', array('PMProGateway_stripe', 'pmpro_checkout_preheader')); 
  109. add_action('pmpro_billing_preheader', array('PMProGateway_stripe', 'pmpro_checkout_preheader')); 
  110. add_filter('pmpro_checkout_order', array('PMProGateway_stripe', 'pmpro_checkout_order')); 
  111. add_filter('pmpro_billing_order', array('PMProGateway_stripe', 'pmpro_checkout_order')); 
  112. add_filter('pmpro_include_billing_address_fields', array('PMProGateway_stripe', 'pmpro_include_billing_address_fields')); 
  113. add_filter('pmpro_include_cardtype_field', array('PMProGateway_stripe', 'pmpro_include_billing_address_fields')); 
  114. add_filter('pmpro_include_payment_information_fields', array('PMProGateway_stripe', 'pmpro_include_payment_information_fields')); 
  115.  
  116. /** 
  117. * Make sure Stripe is in the gateways list 
  118. * @since 1.8 
  119. */ 
  120. static function pmpro_gateways($gateways) 
  121. if(empty($gateways['stripe'])) 
  122. $gateways['stripe'] = __('Stripe', 'paid-memberships-pro' ); 
  123.  
  124. return $gateways; 
  125.  
  126. /** 
  127. * Get a list of payment options that the Stripe gateway needs/supports. 
  128. * @since 1.8 
  129. */ 
  130. static function getGatewayOptions() 
  131. $options = array( 
  132. 'sslseal',  
  133. 'nuclear_HTTPS',  
  134. 'gateway_environment',  
  135. 'stripe_secretkey',  
  136. 'stripe_publishablekey',  
  137. 'stripe_billingaddress',  
  138. 'currency',  
  139. 'use_ssl',  
  140. 'tax_state',  
  141. 'tax_rate',  
  142. 'accepted_credit_cards' 
  143. ); 
  144.  
  145. return $options; 
  146.  
  147. /** 
  148. * Set payment options for payment settings page. 
  149. * @since 1.8 
  150. */ 
  151. static function pmpro_payment_options($options) 
  152. //get stripe options 
  153. $stripe_options = self::getGatewayOptions(); 
  154.  
  155. //merge with others. 
  156. $options = array_merge($stripe_options, $options); 
  157.  
  158. return $options; 
  159.  
  160. /** 
  161. * Display fields for Stripe options. 
  162. * @since 1.8 
  163. */ 
  164. static function pmpro_payment_option_fields($values, $gateway) 
  165. ?> 
  166. <tr class="pmpro_settings_divider gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>> 
  167. <td colspan="2"> 
  168. <?php _e('Stripe Settings', 'paid-memberships-pro' ); ?> 
  169. </td> 
  170. </tr> 
  171. <tr class="gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>> 
  172. <th scope="row" valign="top"> 
  173. <label for="stripe_secretkey"><?php _e('Secret Key', 'paid-memberships-pro' );?>:</label> 
  174. </th> 
  175. <td> 
  176. <input type="text" id="stripe_secretkey" name="stripe_secretkey" size="60" value="<?php echo esc_attr($values['stripe_secretkey'])?>" /> 
  177. </td> 
  178. </tr> 
  179. <tr class="gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>> 
  180. <th scope="row" valign="top"> 
  181. <label for="stripe_publishablekey"><?php _e('Publishable Key', 'paid-memberships-pro' );?>:</label> 
  182. </th> 
  183. <td> 
  184. <input type="text" id="stripe_publishablekey" name="stripe_publishablekey" size="60" value="<?php echo esc_attr($values['stripe_publishablekey'])?>" /> 
  185. </td> 
  186. </tr> 
  187. <tr class="gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>> 
  188. <th scope="row" valign="top"> 
  189. <label for="stripe_billingaddress"><?php _e('Show Billing Address Fields', 'paid-memberships-pro' );?>:</label> 
  190. </th> 
  191. <td> 
  192. <select id="stripe_billingaddress" name="stripe_billingaddress"> 
  193. <option value="0" <?php if(empty($values['stripe_billingaddress'])) { ?>selected="selected"<?php } ?>><?php _e('No', 'paid-memberships-pro' );?></option> 
  194. <option value="1" <?php if(!empty($values['stripe_billingaddress'])) { ?>selected="selected"<?php } ?>><?php _e('Yes', 'paid-memberships-pro' );?></option> 
  195. </select> 
  196. <small><?php _e("Stripe doesn't require billing address fields. Choose 'No' to hide them on the checkout page.<br /><strong>If No, make sure you disable address verification in the Stripe dashboard settings.</strong>", 'paid-memberships-pro' );?></small> 
  197. </td> 
  198. </tr> 
  199. <tr class="gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>> 
  200. <th scope="row" valign="top"> 
  201. <label><?php _e('Web Hook URL', 'paid-memberships-pro' );?>:</label> 
  202. </th> 
  203. <td> 
  204. <p><?php _e('To fully integrate with Stripe, be sure to set your Web Hook URL to', 'paid-memberships-pro' );?> <pre><?php echo admin_url("admin-ajax.php") . "?action=stripe_webhook";?></pre></p> 
  205. </td> 
  206. </tr> 
  207. <?php 
  208.  
  209. /** 
  210. * Code added to checkout preheader. 
  211. * @since 1.8 
  212. */ 
  213. static function pmpro_checkout_preheader() 
  214. global $gateway, $pmpro_level; 
  215.  
  216. $default_gateway = pmpro_getOption("gateway"); 
  217.  
  218. if(($gateway == "stripe" || $default_gateway == "stripe") && !pmpro_isLevelFree($pmpro_level)) 
  219. //stripe js library 
  220. wp_enqueue_script("stripe", "https://js.stripe.com/v2/", array(), NULL); 
  221.  
  222. //stripe js code for checkout 
  223. function pmpro_stripe_javascript() 
  224. global $pmpro_gateway, $pmpro_level, $pmpro_stripe_lite; 
  225. ?> 
  226. <script type="text/javascript"> 
  227. <!-- 
  228. // this identifies your website in the createToken call below 
  229. Stripe.setPublishableKey('<?php echo pmpro_getOption("stripe_publishablekey"); ?>'); 
  230.  
  231. pmpro_require_billing = true; 
  232.  
  233. var tokenNum = 0; 
  234.  
  235. jQuery(document).ready(function() { 
  236. jQuery(".pmpro_form").submit(function(event) { 
  237.  
  238. // prevent the form from submitting with the default action 
  239. event.preventDefault(); 
  240.  
  241. //double check in case a discount code made the level free 
  242. if(pmpro_require_billing) { 
  243. //build array for creating token 
  244. var args = { 
  245. number: jQuery('#AccountNumber').val(),  
  246. exp_month: jQuery('#ExpirationMonth').val(),  
  247. exp_year: jQuery('#ExpirationYear').val() 
  248. <?php 
  249. $pmpro_stripe_verify_address = apply_filters("pmpro_stripe_verify_address", pmpro_getOption('stripe_billingaddress')); 
  250. if(!empty($pmpro_stripe_verify_address)) 
  251. ?> 
  252. , address_line1: jQuery('#baddress1').val(),  
  253. address_line2: jQuery('#baddress2').val(),  
  254. address_city: jQuery('#bcity').val(),  
  255. address_state: jQuery('#bstate').val(),  
  256. address_zip: jQuery('#bzipcode').val(),  
  257. address_country: jQuery('#bcountry').val() 
  258. <?php 
  259. ?> 
  260. }; 
  261.  
  262. //add CVC if not blank 
  263. if(jQuery('#CVV').val().length) 
  264. args['cvc'] = jQuery('#CVV').val(); 
  265.  
  266. //add first and last name if not blank 
  267. if (jQuery('#bfirstname').length && jQuery('#blastname').length) 
  268. args['name'] = jQuery.trim(jQuery('#bfirstname').val() + ' ' + jQuery('#blastname').val()); 
  269.  
  270. //create token(s) 
  271. if (jQuery('#level').length) { 
  272. var levelnums = jQuery("#level").val().split(", "); 
  273. for(var cnt = 0, len = levelnums.length; cnt < len; cnt++) { 
  274. Stripe.createToken(args, stripeResponseHandler); 
  275. } else { 
  276. Stripe.createToken(args, stripeResponseHandler); 
  277.  
  278. // prevent the form from submitting with the default action  
  279. return false; 
  280. } else { 
  281. this.submit(); 
  282. return true; //not using Stripe anymore 
  283. }  
  284. }); 
  285. }); 
  286.  
  287. function stripeResponseHandler(status, response) { 
  288. if (response.error) { 
  289. // re-enable the submit button 
  290. jQuery('.pmpro_btn-submit-checkout, .pmpro_btn-submit').removeAttr("disabled"); 
  291.  
  292. //hide processing message 
  293. jQuery('#pmpro_processing_message').css('visibility', 'hidden'); 
  294.  
  295. // show the errors on the form 
  296. alert(response.error.message); 
  297. jQuery(".payment-errors").text(response.error.message); 
  298. } else { 
  299. var form$ = jQuery("#pmpro_form, .pmpro_form"); 
  300. // token contains id, last4, and card type 
  301. var token = response['id']; 
  302. // insert the token into the form so it gets submitted to the server 
  303. form$.append("<input type='hidden' name='stripeToken" + tokenNum + "' value='" + token + "'/>"); 
  304. tokenNum++; 
  305.  
  306. //console.log(response); 
  307.  
  308. //insert fields for other card fields 
  309. if(jQuery('#CardType[name=CardType]').length) 
  310. jQuery('#CardType').val(response['card']['brand']); 
  311. else 
  312. form$.append("<input type='hidden' name='CardType' value='" + response['card']['brand'] + "'/>");  
  313. form$.append("<input type='hidden' name='AccountNumber' value='XXXXXXXXXXXX" + response['card']['last4'] + "'/>"); 
  314. form$.append("<input type='hidden' name='ExpirationMonth' value='" + ("0" + response['card']['exp_month']).slice(-2) + "'/>"); 
  315. form$.append("<input type='hidden' name='ExpirationYear' value='" + response['card']['exp_year'] + "'/>"); 
  316.  
  317. // and submit 
  318. form$.get(0).submit(); 
  319. --> 
  320. </script> 
  321. <?php 
  322. add_action("wp_head", "pmpro_stripe_javascript"); 
  323.  
  324. //don't require the CVV 
  325. function pmpro_stripe_dont_require_CVV($fields) 
  326. unset($fields['CVV']); 
  327. return $fields; 
  328. add_filter("pmpro_required_billing_fields", "pmpro_stripe_dont_require_CVV"); 
  329.  
  330. /** 
  331. * Don't require the CVV. 
  332. * Don't require address fields if they are set to hide. 
  333. */ 
  334. static function pmpro_required_billing_fields($fields) 
  335. global $pmpro_stripe_lite, $current_user, $bemail, $bconfirmemail;  
  336.  
  337. //CVV is not required if set that way at Stripe. The Stripe JS will require it if it is required. 
  338. unset($fields['CVV']);  
  339.  
  340. //if using stripe lite, remove some fields from the required array  
  341. if ($pmpro_stripe_lite) { 
  342. //some fields to remove 
  343. $remove = array('bfirstname', 'blastname', 'baddress1', 'bcity', 'bstate', 'bzipcode', 'bphone', 'bcountry', 'CardType'); 
  344. //if a user is logged in, don't require bemail either 
  345. if (!empty($current_user->user_email)) { 
  346. $remove[] = 'bemail'; 
  347. $bemail = $current_user->user_email; 
  348. $bconfirmemail = $bemail; 
  349. //remove the fields 
  350. foreach ($remove as $field) 
  351. unset($fields[$field]); 
  352.  
  353. return $fields; 
  354.  
  355. /** 
  356. * Filtering orders at checkout. 
  357. * @since 1.8 
  358. */ 
  359. static function pmpro_checkout_order($morder) 
  360. //load up token values 
  361. if(isset($_REQUEST['stripeToken0'])) 
  362. // find the highest one still around, and use it - then remove it from $_REQUEST. 
  363. $thetoken = ""; 
  364. $tokennum = -1; 
  365. foreach($_REQUEST as $key => $param) { 
  366. if(preg_match('/stripeToken(\d+)/', $key, $matches)) { 
  367. if(intval($matches[1])>$tokennum) { 
  368. $thetoken = $param; 
  369. $tokennum = intval($matches[1]); 
  370. $morder->stripeToken = $thetoken; 
  371. unset($_REQUEST['stripeToken'.$tokennum]); 
  372.  
  373. //stripe lite code to get name from other sources if available 
  374. global $pmpro_stripe_lite, $current_user; 
  375. if(!empty($pmpro_stripe_lite) && empty($morder->FirstName) && empty($morder->LastName)) 
  376. if(!empty($current_user->ID)) 
  377. $morder->FirstName = get_user_meta($current_user->ID, "first_name", true); 
  378. $morder->LastName = get_user_meta($current_user->ID, "last_name", true); 
  379. elseif(!empty($_REQUEST['first_name']) && !empty($_REQUEST['last_name'])) 
  380. $morder->FirstName = $_REQUEST['first_name']; 
  381. $morder->LastName = $_REQUEST['last_name']; 
  382.  
  383. return $morder; 
  384.  
  385. /** 
  386. * Code to run after checkout 
  387. * @since 1.8 
  388. */ 
  389. static function pmpro_after_checkout($user_id, $morder) 
  390. global $gateway; 
  391.  
  392. if($gateway == "stripe") 
  393. if(static::$is_loaded && !empty($morder) && !empty($morder->Gateway) && !empty($morder->Gateway->customer) && !empty($morder->Gateway->customer->id)) 
  394. update_user_meta($user_id, "pmpro_stripe_customerid", $morder->Gateway->customer->id); 
  395.  
  396. /** 
  397. * Check settings if billing address should be shown. 
  398. * @since 1.8 
  399. */ 
  400. static function pmpro_include_billing_address_fields($include) 
  401. //check settings RE showing billing address 
  402. if(!pmpro_getOption("stripe_billingaddress")) 
  403. $include = false; 
  404.  
  405. return $include; 
  406.  
  407. /** 
  408. * Use our own payment fields at checkout. (Remove the name attributes.)  
  409. * @since 1.8 
  410. */ 
  411. static function pmpro_include_payment_information_fields($include) 
  412. //global vars 
  413. global $pmpro_requirebilling, $pmpro_show_discount_code, $discount_code, $CardType, $AccountNumber, $ExpirationMonth, $ExpirationYear; 
  414.  
  415. //get accepted credit cards 
  416. $pmpro_accepted_credit_cards = pmpro_getOption("accepted_credit_cards"); 
  417. $pmpro_accepted_credit_cards = explode(", ", $pmpro_accepted_credit_cards); 
  418. $pmpro_accepted_credit_cards_string = pmpro_implodeToEnglish($pmpro_accepted_credit_cards); 
  419.  
  420. //include ours 
  421. ?> 
  422. <table id="pmpro_payment_information_fields" class="pmpro_checkout top1em" width="100%" cellpadding="0" cellspacing="0" border="0" <?php if(!$pmpro_requirebilling || apply_filters("pmpro_hide_payment_information_fields", false) ) { ?>style="display: none;"<?php } ?>> 
  423. <thead> 
  424. <tr> 
  425. <th> 
  426. <span class="pmpro_thead-name"><?php _e('Payment Information', 'paid-memberships-pro' );?></span> 
  427. <span class="pmpro_thead-msg"><?php printf(__('We Accept %s', 'paid-memberships-pro' ), $pmpro_accepted_credit_cards_string);?></span> 
  428. </th> 
  429. </tr> 
  430. </thead> 
  431. <tbody> 
  432. <tr valign="top"> 
  433. <td> 
  434. <?php 
  435. $sslseal = pmpro_getOption("sslseal"); 
  436. if($sslseal) 
  437. ?> 
  438. <div class="pmpro_sslseal"><?php echo stripslashes($sslseal)?></div> 
  439. <?php 
  440. ?> 
  441. <?php 
  442. $pmpro_include_cardtype_field = apply_filters('pmpro_include_cardtype_field', false); 
  443. if($pmpro_include_cardtype_field) 
  444. ?> 
  445. <div class="pmpro_payment-card-type"> 
  446. <label for="CardType"><?php _e('Card Type', 'paid-memberships-pro' );?></label> 
  447. <select id="CardType" class=" <?php echo pmpro_getClassForField("CardType");?>"> 
  448. <?php foreach($pmpro_accepted_credit_cards as $cc) { ?> 
  449. <option value="<?php echo $cc?>" <?php if($CardType == $cc) { ?>selected="selected"<?php } ?>><?php echo $cc?></option> 
  450. <?php } ?> 
  451. </select> 
  452. </div> 
  453. <?php 
  454. else 
  455. ?> 
  456. <input type="hidden" id="CardType" name="CardType" value="<?php echo esc_attr($CardType);?>" /> 
  457. <script> 
  458. <!-- 
  459. jQuery(document).ready(function() { 
  460. jQuery('#AccountNumber').validateCreditCard(function(result) { 
  461. var cardtypenames = { 
  462. "amex":"American Express",  
  463. "diners_club_carte_blanche":"Diners Club Carte Blanche",  
  464. "diners_club_international":"Diners Club International",  
  465. "discover":"Discover",  
  466. "jcb":"JCB",  
  467. "laser":"Laser",  
  468. "maestro":"Maestro",  
  469. "mastercard":"Mastercard",  
  470. "visa":"Visa",  
  471. "visa_electron":"Visa Electron" 
  472.  
  473. if(result.card_type) 
  474. jQuery('#CardType').val(cardtypenames[result.card_type.name]); 
  475. else 
  476. jQuery('#CardType').val('Unknown Card Type'); 
  477. }); 
  478. }); 
  479. --> 
  480. </script> 
  481. <?php 
  482. ?> 
  483.  
  484. <div class="pmpro_payment-account-number"> 
  485. <label for="AccountNumber"><?php _e('Card Number', 'paid-memberships-pro' );?></label> 
  486. <input id="AccountNumber" class="input <?php echo pmpro_getClassForField("AccountNumber");?>" type="text" size="25" value="<?php echo esc_attr($AccountNumber)?>" autocomplete="off" /> 
  487. </div> 
  488.  
  489. <div class="pmpro_payment-expiration"> 
  490. <label for="ExpirationMonth"><?php _e('Expiration Date', 'paid-memberships-pro' );?></label> 
  491. <select id="ExpirationMonth" class=" <?php echo pmpro_getClassForField("ExpirationMonth");?>"> 
  492. <option value="01" <?php if($ExpirationMonth == "01") { ?>selected="selected"<?php } ?>>01</option> 
  493. <option value="02" <?php if($ExpirationMonth == "02") { ?>selected="selected"<?php } ?>>02</option> 
  494. <option value="03" <?php if($ExpirationMonth == "03") { ?>selected="selected"<?php } ?>>03</option> 
  495. <option value="04" <?php if($ExpirationMonth == "04") { ?>selected="selected"<?php } ?>>04</option> 
  496. <option value="05" <?php if($ExpirationMonth == "05") { ?>selected="selected"<?php } ?>>05</option> 
  497. <option value="06" <?php if($ExpirationMonth == "06") { ?>selected="selected"<?php } ?>>06</option> 
  498. <option value="07" <?php if($ExpirationMonth == "07") { ?>selected="selected"<?php } ?>>07</option> 
  499. <option value="08" <?php if($ExpirationMonth == "08") { ?>selected="selected"<?php } ?>>08</option> 
  500. <option value="09" <?php if($ExpirationMonth == "09") { ?>selected="selected"<?php } ?>>09</option> 
  501. <option value="10" <?php if($ExpirationMonth == "10") { ?>selected="selected"<?php } ?>>10</option> 
  502. <option value="11" <?php if($ExpirationMonth == "11") { ?>selected="selected"<?php } ?>>11</option> 
  503. <option value="12" <?php if($ExpirationMonth == "12") { ?>selected="selected"<?php } ?>>12</option> 
  504. </select>/<select id="ExpirationYear" class=" <?php echo pmpro_getClassForField("ExpirationYear");?>"> 
  505. <?php 
  506. for($i = date_i18n("Y"); $i < date_i18n("Y") + 10; $i++) 
  507. ?> 
  508. <option value="<?php echo $i?>" <?php if($ExpirationYear == $i) { ?>selected="selected"<?php } ?>><?php echo $i?></option> 
  509. <?php 
  510. ?> 
  511. </select> 
  512. </div> 
  513.  
  514. <?php 
  515. $pmpro_show_cvv = apply_filters("pmpro_show_cvv", true); 
  516. if($pmpro_show_cvv) 
  517. {  
  518. ?> 
  519. <div class="pmpro_payment-cvv"> 
  520. <label for="CVV"><?php _e('CVV', 'paid-memberships-pro' );?></label> 
  521. <input id="CVV" type="text" size="4" value="<?php if(!empty($_REQUEST['CVV'])) { echo esc_attr($_REQUEST['CVV']); }?>" class="input <?php echo pmpro_getClassForField("CVV");?>" /> <small>(<a href="javascript:void(0);" onclick="javascript:window.open('<?php echo pmpro_https_filter(PMPRO_URL)?>/pages/popup-cvv.html', 'cvv', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=600, height=475');"><?php _e("what's this?", 'paid-memberships-pro' );?></a>)</small> 
  522. </div> 
  523. <?php 
  524. ?> 
  525.  
  526. <?php if($pmpro_show_discount_code) { ?> 
  527. <div class="pmpro_payment-discount-code"> 
  528. <label for="discount_code"><?php _e('Discount Code', 'paid-memberships-pro' );?></label> 
  529. <input class="input <?php echo pmpro_getClassForField("discount_code");?>" id="discount_code" name="discount_code" type="text" size="20" value="<?php echo esc_attr($discount_code)?>" /> 
  530. <input type="button" id="discount_code_button" name="discount_code_button" value="<?php _e('Apply', 'paid-memberships-pro' );?>" /> 
  531. <p id="discount_code_message" class="pmpro_message" style="display: none;"></p> 
  532. </div> 
  533. <?php } ?> 
  534.  
  535. </td> 
  536. </tr> 
  537. </tbody> 
  538. </table> 
  539. <?php 
  540.  
  541. //don't include the default 
  542. return false; 
  543.  
  544. /** 
  545. * Fields shown on edit user page 
  546. * @since 1.8 
  547. */ 
  548. static function user_profile_fields($user) 
  549. global $wpdb, $current_user, $pmpro_currency_symbol; 
  550.  
  551. $cycles = array( __('Day(s)', 'paid-memberships-pro' ) => 'Day', __('Week(s)', 'paid-memberships-pro' ) => 'Week', __('Month(s)', 'paid-memberships-pro' ) => 'Month', __('Year(s)', 'paid-memberships-pro' ) => 'Year' ); 
  552. $current_year = date_i18n("Y"); 
  553. $current_month = date_i18n("m"); 
  554.  
  555. //make sure the current user has privileges 
  556. $membership_level_capability = apply_filters("pmpro_edit_member_capability", "manage_options"); 
  557. if(!current_user_can($membership_level_capability)) 
  558. return false; 
  559.  
  560. //more privelges they should have 
  561. $show_membership_level = apply_filters("pmpro_profile_show_membership_level", true, $user); 
  562. if(!$show_membership_level) 
  563. return false; 
  564.  
  565. //check that user has a current subscription at Stripe 
  566. $last_order = new MemberOrder(); 
  567. $last_order->getLastMemberOrder($user->ID); 
  568.  
  569. //assume no sub to start 
  570. $sub = false; 
  571.  
  572. //check that gateway is Stripe 
  573. if($last_order->gateway == "stripe" && self::$is_loaded ) 
  574. //is there a customer? 
  575. $sub = $last_order->Gateway->getSubscription($last_order); 
  576.  
  577. $customer_id = $user->pmpro_stripe_customerid; 
  578.  
  579. if(empty($sub)) 
  580. //make sure we delete stripe updates 
  581. update_user_meta($user->ID, "pmpro_stripe_updates", array()); 
  582.  
  583. //if the last order has a sub id, let the admin know there is no sub at Stripe 
  584. if(!empty($last_order) && $last_order->gateway == "stripe" && !empty($last_order->subscription_transaction_id) && strpos($last_order->subscription_transaction_id, "sub_") !== false) 
  585. ?> 
  586. <p><?php printf( __('%1$sNote:%2$s Subscription %3$s%4$s%5$s could not be found at Stripe. It may have been deleted.', 'paid-memberships-pro'), '<strong>', '</strong>', '<strong>', esc_attr($last_order->subscription_transaction_id), '</strong>' ); ?></p> 
  587. <?php 
  588. elseif ( true === self::$is_loaded ) 
  589. ?> 
  590. <h3><?php _e("Subscription Updates", 'paid-memberships-pro' ); ?></h3> 
  591. <p> 
  592. <?php 
  593. if(empty($_REQUEST['user_id'])) 
  594. _e("Subscription updates, allow you to change the member's subscription values at predefined times. Be sure to click Update Profile after making changes.", 'paid-memberships-pro' ); 
  595. else 
  596. _e("Subscription updates, allow you to change the member's subscription values at predefined times. Be sure to click Update User after making changes.", 'paid-memberships-pro' ); 
  597. ?> 
  598. </p> 
  599. <table class="form-table"> 
  600. <tr> 
  601. <th><label for="membership_level"><?php _e("Update", 'paid-memberships-pro' ); ?></label></th> 
  602. <td id="updates_td"> 
  603. <?php 
  604. $old_updates = $user->pmpro_stripe_updates; 
  605. if(is_array($old_updates)) 
  606. $updates = array_merge( 
  607. array(array('template'=>true, 'when'=>'now', 'date_month'=>'', 'date_day'=>'', 'date_year'=>'', 'billing_amount'=>'', 'cycle_number'=>'', 'cycle_period'=>'Month')),  
  608. $old_updates 
  609. ); 
  610. else 
  611. $updates = array(array('template'=>true, 'when'=>'now', 'date_month'=>'', 'date_day'=>'', 'date_year'=>'', 'billing_amount'=>'', 'cycle_number'=>'', 'cycle_period'=>'Month')); 
  612.  
  613. foreach($updates as $update) 
  614. ?> 
  615. <div class="updates_update" <?php if(!empty($update['template'])) { ?>style="display: none;"<?php } ?>> 
  616. <select class="updates_when" name="updates_when[]"> 
  617. <option value="now" <?php selected($update['when'], "now");?>>Now</option> 
  618. <option value="payment" <?php selected($update['when'], "payment");?>>After Next Payment</option> 
  619. <option value="date" <?php selected($update['when'], "date");?>>On Date</option> 
  620. </select> 
  621. <span class="updates_date" <?php if($update['when'] != "date") { ?>style="display: none;"<?php } ?>> 
  622. <select name="updates_date_month[]"> 
  623. <?php 
  624. for($i = 1; $i < 13; $i++) 
  625. ?> 
  626. <option value="<?php echo str_pad($i, 2, "0", STR_PAD_LEFT);?>" <?php if(!empty($update['date_month']) && $update['date_month'] == $i) { ?>selected="selected"<?php } ?>> 
  627. <?php echo date_i18n("M", strtotime($i . "/1/" . $current_year));?> 
  628. </option> 
  629. <?php 
  630. ?> 
  631. </select> 
  632. <input name="updates_date_day[]" type="text" size="2" value="<?php if(!empty($update['date_day'])) echo esc_attr($update['date_day']);?>" /> 
  633. <input name="updates_date_year[]" type="text" size="4" value="<?php if(!empty($update['date_year'])) echo esc_attr($update['date_year']);?>" /> 
  634. </span> 
  635. <span class="updates_billing" <?php if($update['when'] == "now") { ?>style="display: none;"<?php } ?>> 
  636. <?php echo $pmpro_currency_symbol?><input name="updates_billing_amount[]" type="text" size="10" value="<?php echo esc_attr($update['billing_amount']);?>" /> 
  637. <small><?php _e('per', 'paid-memberships-pro' );?></small> 
  638. <input name="updates_cycle_number[]" type="text" size="5" value="<?php echo esc_attr($update['cycle_number']);?>" /> 
  639. <select name="updates_cycle_period[]"> 
  640. <?php 
  641. foreach ( $cycles as $name => $value ) { 
  642. echo "<option value='$value'"; 
  643. if(!empty($update['cycle_period']) && $update['cycle_period'] == $value) echo " selected='selected'"; 
  644. echo ">$name</option>"; 
  645. ?> 
  646. </select> 
  647. </span> 
  648. <span> 
  649. <a class="updates_remove" href="javascript:void(0);">Remove</a> 
  650. </span> 
  651. </div> 
  652. <?php 
  653. ?> 
  654. <p><a id="updates_new_update" href="javascript:void(0);">+ New Update</a></p> 
  655. </td> 
  656. </tr> 
  657. </table> 
  658. <script> 
  659. <!-- 
  660. jQuery(document).ready(function() { 
  661. //function to update dropdowns/etc based on when field 
  662. function updateSubscriptionUpdateFields(when) 
  663. if(jQuery(when).val() == 'date') 
  664. jQuery(when).parent().children('.updates_date').show(); 
  665. else 
  666. jQuery(when).parent().children('.updates_date').hide(); 
  667.  
  668. if(jQuery(when).val() == 'no') 
  669. jQuery(when).parent().children('.updates_billing').hide(); 
  670. else 
  671. jQuery(when).parent().children('.updates_billing').show(); 
  672.  
  673. //and update on page load 
  674. jQuery('.updates_when').each(function() { if(jQuery(this).parent().css('display') != 'none') updateSubscriptionUpdateFields(this); }); 
  675.  
  676. //add a new update when clicking to 
  677. var num_updates_divs = <?php echo count($updates);?>; 
  678. jQuery('#updates_new_update').click(function() { 
  679. //get updates 
  680. updates = jQuery('.updates_update').toArray(); 
  681.  
  682. //clone the first one 
  683. new_div = jQuery(updates[0]).clone(); 
  684.  
  685. //append 
  686. new_div.insertBefore('#updates_new_update'); 
  687.  
  688. //update events 
  689. addUpdateEvents() 
  690.  
  691. //unhide it 
  692. new_div.show(); 
  693. updateSubscriptionUpdateFields(new_div.children('.updates_when')); 
  694. }); 
  695.  
  696. function addUpdateEvents() 
  697. //update when when changes 
  698. jQuery('.updates_when').change(function() { 
  699. updateSubscriptionUpdateFields(this); 
  700. }); 
  701.  
  702. //remove updates when clicking 
  703. jQuery('.updates_remove').click(function() { 
  704. jQuery(this).parent().parent().remove(); 
  705. }); 
  706. addUpdateEvents(); 
  707. }); 
  708. --> 
  709. </script> 
  710. <?php 
  711.  
  712. /** 
  713. * Process fields from the edit user page 
  714. * @since 1.8 
  715. */ 
  716. static function user_profile_fields_save($user_id) 
  717. global $wpdb; 
  718.  
  719. //check capabilities 
  720. $membership_level_capability = apply_filters("pmpro_edit_member_capability", "manage_options"); 
  721. if(!current_user_can($membership_level_capability)) 
  722. return false; 
  723.  
  724. //make sure some value was passed 
  725. if(!isset($_POST['updates_when']) || !is_array($_POST['updates_when'])) 
  726. return; 
  727.  
  728. //vars 
  729. $updates = array(); 
  730. $next_on_date_update = ""; 
  731.  
  732. //build array of updates (we skip the first because it's the template field for the JavaScript 
  733. for($i = 1; $i < count($_POST['updates_when']); $i++) 
  734. $update = array(); 
  735.  
  736. //all updates have these values 
  737. $update['when'] = $_POST['updates_when'][$i]; 
  738. $update['billing_amount'] = $_POST['updates_billing_amount'][$i]; 
  739. $update['cycle_number'] = $_POST['updates_cycle_number'][$i]; 
  740. $update['cycle_period'] = $_POST['updates_cycle_period'][$i]; 
  741.  
  742. //these values only for on date updates 
  743. if($_POST['updates_when'][$i] == "date") 
  744. $update['date_month'] = str_pad($_POST['updates_date_month'][$i], 2, "0", STR_PAD_LEFT); 
  745. $update['date_day'] = str_pad($_POST['updates_date_day'][$i], 2, "0", STR_PAD_LEFT); 
  746. $update['date_year'] = $_POST['updates_date_year'][$i]; 
  747.  
  748. //make sure the update is valid 
  749. if(empty($update['cycle_number'])) 
  750. continue; 
  751.  
  752. //if when is now, update the subscription 
  753. if($update['when'] == "now") 
  754. //get level for user 
  755. $user_level = pmpro_getMembershipLevelForUser($user_id); 
  756.  
  757. //get current plan at Stripe to get payment date 
  758. $last_order = new MemberOrder(); 
  759. $last_order->getLastMemberOrder($user_id); 
  760. $last_order->setGateway('stripe'); 
  761. $last_order->Gateway->getCustomer($last_order); 
  762.  
  763. $subscription = $last_order->Gateway->getSubscription($last_order); 
  764.  
  765. if(!empty($subscription)) 
  766. $end_timestamp = $subscription->current_period_end; 
  767.  
  768. //cancel the old subscription 
  769. if(!$last_order->Gateway->cancelSubscriptionAtGateway($subscription)) 
  770. //throw error and halt save 
  771. function pmpro_stripe_user_profile_fields_save_error($errors, $update, $user) 
  772. $errors->add('pmpro_stripe_updates', __('Could not cancel the old subscription. Updates have not been processed.', 'paid-memberships-pro' )); 
  773. add_filter('user_profile_update_errors', 'pmpro_stripe_user_profile_fields_save_error', 10, 3); 
  774.  
  775. //stop processing updates 
  776. return; 
  777.  
  778. //if we didn't get an end date, let's set one one cycle out 
  779. if(empty($end_timestamp)) 
  780. $end_timestamp = strtotime("+" . $update['cycle_number'] . " " . $update['cycle_period'], current_time('timestamp')); 
  781.  
  782. //build order object 
  783. $update_order = new MemberOrder(); 
  784. $update_order->setGateway('stripe'); 
  785. $update_order->user_id = $user_id; 
  786. $update_order->membership_id = $user_level->id; 
  787. $update_order->membership_name = $user_level->name; 
  788. $update_order->InitialPayment = 0; 
  789. $update_order->PaymentAmount = $update['billing_amount']; 
  790. $update_order->ProfileStartDate = date_i18n("Y-m-d", $end_timestamp); 
  791. $update_order->BillingPeriod = $update['cycle_period']; 
  792. $update_order->BillingFrequency = $update['cycle_number']; 
  793.  
  794. //need filter to reset ProfileStartDate 
  795. add_filter('pmpro_profile_start_date', create_function('$startdate, $order', 'return "' . $update_order->ProfileStartDate . 'T0:0:0";'), 10, 2); 
  796.  
  797. //update subscription 
  798. $update_order->Gateway->subscribe($update_order, false); 
  799.  
  800. //update membership 
  801. $sqlQuery = "UPDATE $wpdb->pmpro_memberships_users 
  802. SET billing_amount = '" . esc_sql($update['billing_amount']) . "',  
  803. cycle_number = '" . esc_sql($update['cycle_number']) . "',  
  804. cycle_period = '" . esc_sql($update['cycle_period']) . "',  
  805. trial_amount = '',  
  806. trial_limit = '' 
  807. WHERE user_id = '" . esc_sql($user_id) . "' 
  808. AND membership_id = '" . esc_sql($last_order->membership_id) . "' 
  809. AND status = 'active' 
  810. LIMIT 1"; 
  811.  
  812. $wpdb->query($sqlQuery); 
  813.  
  814. //save order so we know which plan to look for at stripe (order code = plan id) 
  815. $update_order->status = "success"; 
  816. $update_order->saveOrder(); 
  817.  
  818. continue; 
  819. elseif($update['when'] == 'date') 
  820. if(!empty($next_on_date_update)) 
  821. $next_on_date_update = min($next_on_date_update, $update['date_year'] . "-" . $update['date_month'] . "-" . $update['date_day']); 
  822. else 
  823. $next_on_date_update = $update['date_year'] . "-" . $update['date_month'] . "-" . $update['date_day']; 
  824.  
  825. //add to array 
  826. $updates[] = $update; 
  827.  
  828. //save in user meta 
  829. update_user_meta($user_id, "pmpro_stripe_updates", $updates); 
  830.  
  831. //save date of next on-date update to make it easier to query for these in cron job 
  832. update_user_meta($user_id, "pmpro_stripe_next_on_date_update", $next_on_date_update); 
  833.  
  834. /** 
  835. * Cron activation for subscription updates. 
  836. * @since 1.8 
  837. */ 
  838. static function pmpro_activation() 
  839. pmpro_maybe_schedule_event(time(), 'daily', 'pmpro_cron_stripe_subscription_updates'); 
  840.  
  841. /** 
  842. * Cron deactivation for subscription updates. 
  843. * @since 1.8 
  844. */ 
  845. static function pmpro_deactivation() 
  846. wp_clear_scheduled_hook('pmpro_cron_stripe_subscription_updates'); 
  847.  
  848. /** 
  849. * Cron job for subscription updates. 
  850. * @since 1.8 
  851. */ 
  852. static function pmpro_cron_stripe_subscription_updates() 
  853. global $wpdb; 
  854.  
  855. //get all updates for today (or before today) 
  856. $sqlQuery = "SELECT * 
  857. FROM $wpdb->usermeta 
  858. WHERE meta_key = 'pmpro_stripe_next_on_date_update' 
  859. AND meta_value IS NOT NULL 
  860. AND meta_value <> '' 
  861. AND meta_value < '" . date_i18n("Y-m-d", strtotime("+1 day", current_time('timestamp'))) . "'"; 
  862. $updates = $wpdb->get_results($sqlQuery); 
  863.  
  864. if(!empty($updates)) 
  865. //loop through 
  866. foreach($updates as $update) 
  867. //pull values from update 
  868. $user_id = $update->user_id; 
  869.  
  870. $user = get_userdata($user_id); 
  871.  
  872. //if user is missing, delete the update info and continue 
  873. if(empty($user) || empty($user->ID)) 
  874. {  
  875. delete_user_meta($user_id, "pmpro_stripe_updates"); 
  876. delete_user_meta($user_id, "pmpro_stripe_next_on_date_update"); 
  877.  
  878. continue; 
  879.  
  880. $user_updates = $user->pmpro_stripe_updates; 
  881. $next_on_date_update = "";  
  882.  
  883. //loop through updates looking for updates happening today or earlier 
  884. if(!empty($user_updates)) 
  885. foreach($user_updates as $key => $ud) 
  886. if($ud['when'] == 'date' && 
  887. $ud['date_year'] . "-" . $ud['date_month'] . "-" . $ud['date_day'] <= date_i18n("Y-m-d", current_time('timestamp') ) 
  888. //get level for user 
  889. $user_level = pmpro_getMembershipLevelForUser($user_id); 
  890.  
  891. //get current plan at Stripe to get payment date 
  892. $last_order = new MemberOrder(); 
  893. $last_order->getLastMemberOrder($user_id); 
  894. $last_order->setGateway('stripe'); 
  895. $last_order->Gateway->getCustomer($last_order); 
  896.  
  897. if(!empty($last_order->Gateway->customer)) 
  898. //find the first subscription 
  899. if(!empty($last_order->Gateway->customer->subscriptions['data'][0])) 
  900. $first_sub = $last_order->Gateway->customer->subscriptions['data'][0]->__toArray(); 
  901. $end_timestamp = $first_sub['current_period_end']; 
  902.  
  903. //if we didn't get an end date, let's set one one cycle out 
  904. $end_timestamp = strtotime("+" . $ud['cycle_number'] . " " . $ud['cycle_period'], current_time( 'timestamp' )); 
  905.  
  906. //build order object 
  907. $update_order = new MemberOrder(); 
  908. $update_order->setGateway('stripe'); 
  909. $update_order->user_id = $user_id; 
  910. $update_order->membership_id = $user_level->id; 
  911. $update_order->membership_name = $user_level->name; 
  912. $update_order->InitialPayment = 0; 
  913. $update_order->PaymentAmount = $ud['billing_amount']; 
  914. $update_order->ProfileStartDate = date_i18n("Y-m-d", $end_timestamp); 
  915. $update_order->BillingPeriod = $ud['cycle_period']; 
  916. $update_order->BillingFrequency = $ud['cycle_number']; 
  917.  
  918. //update subscription 
  919. $update_order->Gateway->subscribe($update_order, false); 
  920.  
  921. //update membership 
  922. $sqlQuery = "UPDATE $wpdb->pmpro_memberships_users 
  923. SET billing_amount = '" . esc_sql($ud['billing_amount']) . "',  
  924. cycle_number = '" . esc_sql($ud['cycle_number']) . "',  
  925. cycle_period = '" . esc_sql($ud['cycle_period']) . "' 
  926. WHERE user_id = '" . esc_sql($user_id) . "' 
  927. AND membership_id = '" . esc_sql($last_order->membership_id) . "' 
  928. AND status = 'active' 
  929. LIMIT 1"; 
  930.  
  931. $wpdb->query($sqlQuery); 
  932.  
  933. //save order 
  934. $update_order->status = "success"; 
  935. $update_order->saveOrder(); 
  936.  
  937. //remove update from list 
  938. unset($user_updates[$key]); 
  939. elseif($ud['when'] == 'date') 
  940. //this is an on date update for the future, update the next on date update 
  941. if(!empty($next_on_date_update)) 
  942. $next_on_date_update = min($next_on_date_update, $ud['date_year'] . "-" . $ud['date_month'] . "-" . $ud['date_day']); 
  943. else 
  944. $next_on_date_update = $ud['date_year'] . "-" . $ud['date_month'] . "-" . $ud['date_day']; 
  945.  
  946. //save updates in case we removed some 
  947. update_user_meta($user_id, "pmpro_stripe_updates", $user_updates); 
  948.  
  949. //save date of next on-date update to make it easier to query for these in cron job 
  950. update_user_meta($user_id, "pmpro_stripe_next_on_date_update", $next_on_date_update); 
  951.  
  952. /** 
  953. * Process checkout and decide if a charge and or subscribe is needed 
  954. * @since 1.4 
  955. */ 
  956. function process(&$order) 
  957. //check for initial payment 
  958. if(floatval($order->InitialPayment) == 0) 
  959. //just subscribe 
  960. return $this->subscribe($order); 
  961. else 
  962. //charge then subscribe 
  963. if($this->charge($order)) 
  964. if(pmpro_isLevelRecurring($order->membership_level)) 
  965. if($this->subscribe($order)) 
  966. //yay! 
  967. return true; 
  968. else 
  969. //try to refund initial charge 
  970. return false; 
  971. else 
  972. //only a one time charge 
  973. $order->status = "success"; //saved on checkout page 
  974. return true; 
  975. else 
  976. if(empty($order->error)) { 
  977. if ( ! self::$is_loaded ) { 
  978.  
  979. $order->error = __( "Payment error: Please contact the webmaster (stripe-load-error)", 'paid-memberships-pro' ); 
  980.  
  981. } else { 
  982.  
  983. $order->error = __( "Unknown error: Initial payment failed.", 'paid-memberships-pro' ); 
  984.  
  985. return false; 
  986.  
  987. /** 
  988. * Make a one-time charge with Stripe 
  989. * @since 1.4 
  990. */ 
  991. function charge(&$order) 
  992. global $pmpro_currency, $pmpro_currencies; 
  993. $currency_unit_multiplier = 100; //ie 100 cents per USD 
  994.  
  995. //account for zero-decimal currencies like the Japanese Yen 
  996. if(is_array($pmpro_currencies[$pmpro_currency]) && isset($pmpro_currencies[$pmpro_currency]['decimals']) && $pmpro_currencies[$pmpro_currency]['decimals'] == 0) 
  997. $currency_unit_multiplier = 1; 
  998.  
  999. //create a code for the order 
  1000. if(empty($order->code)) 
  1001. $order->code = $order->getRandomCode(); 
  1002.  
  1003. //what amount to charge? 
  1004. $amount = $order->InitialPayment; 
  1005.  
  1006. //tax 
  1007. $order->subtotal = $amount; 
  1008. $tax = $order->getTax(true); 
  1009. $amount = round((float)$order->subtotal + (float)$tax, 2); 
  1010.  
  1011. //create a customer 
  1012. $result = $this->getCustomer($order); 
  1013.  
  1014. if(empty($result)) 
  1015. //failed to create customer 
  1016. return false; 
  1017.  
  1018. //charge 
  1019. try 
  1020. $response = Stripe_Charge::create(array( 
  1021. "amount" => $amount * $currency_unit_multiplier, # amount in cents, again 
  1022. "currency" => strtolower($pmpro_currency),  
  1023. "customer" => $this->customer->id,  
  1024. "description" => apply_filters('pmpro_stripe_order_description', "Order #" . $order->code . ", " . trim($order->FirstName . " " . $order->LastName) . " (" . $order->Email . ")", $order) 
  1025. ); 
  1026. catch (Exception $e) 
  1027. //$order->status = "error"; 
  1028. $order->errorcode = true; 
  1029. $order->error = "Error: " . $e->getMessage(); 
  1030. $order->shorterror = $order->error; 
  1031. return false; 
  1032.  
  1033. if(empty($response["failure_message"])) 
  1034. //successful charge 
  1035. $order->payment_transaction_id = $response["id"]; 
  1036. $order->updateStatus("success"); 
  1037. $order->saveOrder(); 
  1038. return true; 
  1039. else 
  1040. //$order->status = "error"; 
  1041. $order->errorcode = true; 
  1042. $order->error = $response['failure_message']; 
  1043. $order->shorterror = $response['failure_message']; 
  1044. return false; 
  1045.  
  1046. /** 
  1047. * Get a Stripe customer object. 
  1048. * If $this->customer is set, it returns it. 
  1049. * It first checks if the order has a subscription_transaction_id. If so, that's the customer id. 
  1050. * If not, it checks for a user_id on the order and searches for a customer id in the user meta. 
  1051. * If a customer id is found, it checks for a customer through the Stripe API. 
  1052. * If a customer is found and there is a stripeToken on the order passed, it will update the customer. 
  1053. * If no customer is found and there is a stripeToken on the order passed, it will create a customer. 
  1054. * @since 1.4 
  1055. * @return Stripe_Customer|false 
  1056. */ 
  1057. function getCustomer(&$order = false, $force = false) 
  1058. global $current_user; 
  1059.  
  1060. //already have it? 
  1061. if(!empty($this->customer) && !$force) 
  1062. return $this->customer; 
  1063.  
  1064. //figure out user_id and user 
  1065. if(!empty($order->user_id)) 
  1066. $user_id = $order->user_id; 
  1067.  
  1068. //if no id passed, check the current user 
  1069. if(empty($user_id) && !empty($current_user->ID)) 
  1070. $user_id = $current_user->ID; 
  1071.  
  1072. if(!empty($user_id)) 
  1073. $user = get_userdata($user_id); 
  1074. else 
  1075. $user = NULL; 
  1076.  
  1077. //transaction id? 
  1078. if(!empty($order->subscription_transaction_id) && strpos($order->subscription_transaction_id, "cus_") !== false) 
  1079. $customer_id = $order->subscription_transaction_id; 
  1080. else 
  1081. //try based on user id 
  1082. if(!empty($user_id)) 
  1083. $customer_id = get_user_meta($user_id, "pmpro_stripe_customerid", true); 
  1084.  
  1085. //look up by transaction id 
  1086. if(empty($customer_id) && !empty($user_id))  
  1087. //user id from this order or the user's last stripe order 
  1088. if(!empty($order->payment_transaction_id)) 
  1089. $payment_transaction_id = $order->payment_transaction_id; 
  1090. else 
  1091. //find the user's last stripe order 
  1092. $last_order = new MemberOrder();  
  1093. $last_order->getLastMemberOrder($user_id, array('success', 'cancelled'), NULL, 'stripe', $order->Gateway->gateway_environment); 
  1094. if(!empty($last_order->payment_transaction_id)) 
  1095. $payment_transaction_id = $last_order->payment_transaction_id; 
  1096.  
  1097. //we have a transaction id to look up 
  1098. if(!empty($payment_transaction_id)) 
  1099. if(strpos($payment_transaction_id, "ch_") !== false) 
  1100. //charge, look it up 
  1101. $charge = Stripe_Charge::retrieve($payment_transaction_id); 
  1102. if(!empty($charge) && !empty($charge->customer)) 
  1103. $customer_id = $charge->customer; 
  1104. }  
  1105. else if(strpos($payment_transaction_id, "in_") !== false) 
  1106. //invoice look it up 
  1107. $invoice = Stripe_Invoice::retrieve($payment_transaction_id); 
  1108. if(!empty($invoice) && !empty($invoice->customer)) 
  1109. $customer_id = $invoice->customer; 
  1110.  
  1111. //if we found it, save to user meta for future reference 
  1112. if(!empty($customer_id)) 
  1113. update_user_meta($user_id, "pmpro_stripe_customerid", $customer_id); 
  1114.  
  1115. //get name and email values from order in case we update 
  1116. if(!empty($order->FirstName) && !empty($order->LastName)) 
  1117. $name = trim($order->FirstName . " " . $order->LastName); 
  1118. elseif(!empty($order->FirstName)) 
  1119. $name = $order->FirstName; 
  1120. elseif(!empty($order->LastName)) 
  1121. $name = $order->LastName;  
  1122.  
  1123. if(empty($name) && !empty($user->ID)) 
  1124. $name = trim($user->first_name . " " . $user->last_name); 
  1125.  
  1126. //still empty? 
  1127. if(empty($name)) 
  1128. $name = $user->user_login; 
  1129. elseif(empty($name)) 
  1130. $name = "No Name"; 
  1131.  
  1132. if(!empty($order->Email)) 
  1133. $email = $order->Email; 
  1134. else 
  1135. $email = ""; 
  1136. if(empty($email) && !empty($user->ID) && !empty($user->user_email)) 
  1137. $email = $user->user_email; 
  1138. elseif(empty($email)) 
  1139. $email = "No Email"; 
  1140.  
  1141. //check for an existing stripe customer 
  1142. if(!empty($customer_id)) 
  1143. try 
  1144. $this->customer = Stripe_Customer::retrieve($customer_id); 
  1145.  
  1146. //update the customer description and card 
  1147. if(!empty($order->stripeToken)) 
  1148. $this->customer->description = $name . " (" . $email . ")"; 
  1149. $this->customer->email = $email; 
  1150. $this->customer->card = $order->stripeToken; 
  1151. $this->customer->save(); 
  1152.  
  1153. return $this->customer; 
  1154. catch (Exception $e) 
  1155. //assume no customer found 
  1156.  
  1157. //no customer id, create one 
  1158. if(!empty($order->stripeToken)) 
  1159. try 
  1160. $this->customer = Stripe_Customer::create(array( 
  1161. "description" => $name . " (" . $email . ")",  
  1162. "email" => $order->Email,  
  1163. "card" => $order->stripeToken 
  1164. )); 
  1165. catch (Exception $e) 
  1166. $order->error = __("Error creating customer record with Stripe:", 'paid-memberships-pro' ) . " " . $e->getMessage(); 
  1167. $order->shorterror = $order->error; 
  1168. return false; 
  1169.  
  1170. if(!empty($user_id)) 
  1171. //user logged in/etc 
  1172. update_user_meta($user_id, "pmpro_stripe_customerid", $this->customer->id); 
  1173. else 
  1174. //user not registered yet, queue it up 
  1175. global $pmpro_stripe_customer_id; 
  1176. $pmpro_stripe_customer_id = $this->customer->id; 
  1177. if(! function_exists('pmpro_user_register_stripe_customerid')) { 
  1178. function pmpro_user_register_stripe_customerid($user_id) 
  1179. global $pmpro_stripe_customer_id; 
  1180. update_user_meta($user_id, "pmpro_stripe_customerid", $pmpro_stripe_customer_id); 
  1181. add_action("user_register", "pmpro_user_register_stripe_customerid"); 
  1182.  
  1183. return apply_filters('pmpro_stripe_create_customer', $this->customer); 
  1184.  
  1185. return false; 
  1186.  
  1187. /** 
  1188. * Get a Stripe subscription from a PMPro order 
  1189. * @since 1.8 
  1190. */ 
  1191. function getSubscription(&$order) 
  1192. global $wpdb; 
  1193.  
  1194. //no order? 
  1195. if(empty($order) || empty($order->code)) 
  1196. return false; 
  1197.  
  1198. $result = $this->getCustomer($order, true); //force so we don't get a cached sub for someone else 
  1199.  
  1200. //no customer? 
  1201. if(empty($result)) 
  1202. return false; 
  1203.  
  1204. //is there a subscription transaction id pointing to a sub? 
  1205. if(!empty($order->subscription_transaction_id) && strpos($order->subscription_transaction_id, "sub_") !== false) 
  1206. try 
  1207. $sub = $this->customer->subscriptions->retrieve($order->subscription_transaction_id); 
  1208. catch (Exception $e) 
  1209. $order->error = __("Error getting subscription with Stripe:", 'paid-memberships-pro' ) . $e->getMessage(); 
  1210. $order->shorterror = $order->error; 
  1211. return false; 
  1212.  
  1213. return $sub; 
  1214.  
  1215. //no subscriptions object in customer 
  1216. if(empty($this->customer->subscriptions)) 
  1217. return false; 
  1218.  
  1219. //find subscription based on customer id and order/plan id 
  1220. $subscriptions = $this->customer->subscriptions->all(); 
  1221.  
  1222. //no subscriptions 
  1223. if(empty($subscriptions) || empty($subscriptions->data)) 
  1224. return false; 
  1225.  
  1226. //we really want to test against the order codes of all orders with the same subscription_transaction_id (customer id) 
  1227. $codes = $wpdb->get_col("SELECT code FROM $wpdb->pmpro_membership_orders WHERE user_id = '" . $order->user_id . "' AND subscription_transaction_id = '" . $order->subscription_transaction_id . "' AND status NOT IN('refunded', 'review', 'token', 'error')"); 
  1228.  
  1229. //find the one for this order 
  1230. foreach($subscriptions->data as $sub) 
  1231. if(in_array($sub->plan->id, $codes)) 
  1232. return $sub; 
  1233.  
  1234. //didn't find anything yet 
  1235. return false; 
  1236.  
  1237. /** 
  1238. * Create a new subscription with Stripe 
  1239. * @since 1.4 
  1240. */ 
  1241. function subscribe(&$order, $checkout = true) 
  1242. global $pmpro_currency, $pmpro_currencies; 
  1243.  
  1244. $currency_unit_multiplier = 100; //ie 100 cents per USD 
  1245.  
  1246. //account for zero-decimal currencies like the Japanese Yen 
  1247. if(is_array($pmpro_currencies[$pmpro_currency]) && isset($pmpro_currencies[$pmpro_currency]['decimals']) && $pmpro_currencies[$pmpro_currency]['decimals'] == 0) 
  1248. $currency_unit_multiplier = 1; 
  1249.  
  1250. //create a code for the order 
  1251. if(empty($order->code)) 
  1252. $order->code = $order->getRandomCode(); 
  1253.  
  1254. //filter order before subscription. use with care. 
  1255. $order = apply_filters("pmpro_subscribe_order", $order, $this); 
  1256.  
  1257. //figure out the user 
  1258. if(!empty($order->user_id)) 
  1259. $user_id = $order->user_id; 
  1260. else 
  1261. global $current_user; 
  1262. $user_id = $current_user->ID; 
  1263.  
  1264. //set up customer 
  1265. $result = $this->getCustomer($order); 
  1266. if(empty($result)) 
  1267. return false; //error retrieving customer 
  1268.  
  1269. //set subscription id to custom id 
  1270. $order->subscription_transaction_id = $this->customer['id']; //transaction id is the customer id, we save it in user meta later too 
  1271.  
  1272. //figure out the amounts 
  1273. $amount = $order->PaymentAmount; 
  1274. $amount_tax = $order->getTaxForPrice($amount); 
  1275. $amount = round((float)$amount + (float)$amount_tax, 2); 
  1276.  
  1277. /** 
  1278. There are two parts to the trial. Part 1 is simply the delay until the first payment 
  1279. since we are doing the first payment as a separate transaction. 
  1280. The second part is the actual "trial" set by the admin. 
  1281.   
  1282. Stripe only supports Year or Month for billing periods, but we account for Days and Weeks just in case. 
  1283. */ 
  1284. //figure out the trial length (first payment handled by initial charge) 
  1285. if($order->BillingPeriod == "Year") 
  1286. $trial_period_days = $order->BillingFrequency * 365; //annual 
  1287. elseif($order->BillingPeriod == "Day") 
  1288. $trial_period_days = $order->BillingFrequency * 1; //daily 
  1289. elseif($order->BillingPeriod == "Week") 
  1290. $trial_period_days = $order->BillingFrequency * 7; //weekly 
  1291. else 
  1292. $trial_period_days = $order->BillingFrequency * 30; //assume monthly 
  1293.  
  1294. //convert to a profile start date 
  1295. $order->ProfileStartDate = date_i18n("Y-m-d", strtotime("+ " . $trial_period_days . " Day", current_time("timestamp"))) . "T0:0:0"; 
  1296.  
  1297. //filter the start date 
  1298. $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order); 
  1299.  
  1300. //convert back to days 
  1301. $trial_period_days = ceil(abs(strtotime(date_i18n("Y-m-d"), current_time("timestamp")) - strtotime($order->ProfileStartDate, current_time("timestamp"))) / 86400); 
  1302.  
  1303. //for free trials, just push the start date of the subscription back 
  1304. if(!empty($order->TrialBillingCycles) && $order->TrialAmount == 0) 
  1305. $trialOccurrences = (int)$order->TrialBillingCycles; 
  1306. if($order->BillingPeriod == "Year") 
  1307. $trial_period_days = $trial_period_days + (365 * $order->BillingFrequency * $trialOccurrences); //annual 
  1308. elseif($order->BillingPeriod == "Day") 
  1309. $trial_period_days = $trial_period_days + (1 * $order->BillingFrequency * $trialOccurrences); //daily 
  1310. elseif($order->BillingPeriod == "Week") 
  1311. $trial_period_days = $trial_period_days + (7 * $order->BillingFrequency * $trialOccurrences); //weekly 
  1312. else 
  1313. $trial_period_days = $trial_period_days + (30 * $order->BillingFrequency * $trialOccurrences); //assume monthly 
  1314. elseif(!empty($order->TrialBillingCycles)) 
  1315. /** 
  1316. Let's set the subscription to the trial and give the user an "update" to change the sub later to full price (since v2.0) 
  1317.   
  1318. This will force TrialBillingCycles > 1 to act as if they were 1 
  1319. */ 
  1320. $new_user_updates = array(); 
  1321. $new_user_updates[] = array( 
  1322. 'when' => 'payment',  
  1323. 'billing_amount' => $order->PaymentAmount,  
  1324. 'cycle_period' => $order->BillingPeriod,  
  1325. 'cycle_number' => $order->BillingFrequency 
  1326. ); 
  1327.  
  1328. //now amount to equal the trial #s 
  1329. $amount = $order->TrialAmount; 
  1330. $amount_tax = $order->getTaxForPrice($amount); 
  1331. $amount = round((float)$amount + (float)$amount_tax, 2); 
  1332.  
  1333. //create a plan 
  1334. try 
  1335. $plan = array( 
  1336. "amount" => $amount * $currency_unit_multiplier,  
  1337. "interval_count" => $order->BillingFrequency,  
  1338. "interval" => strtolower($order->BillingPeriod),  
  1339. "trial_period_days" => $trial_period_days,  
  1340. "name" => $order->membership_name . " for order " . $order->code,  
  1341. "currency" => strtolower($pmpro_currency),  
  1342. "id" => $order->code 
  1343. ); 
  1344.  
  1345. $plan = Stripe_Plan::create(apply_filters('pmpro_stripe_create_plan_array', $plan)); 
  1346. catch (Exception $e) 
  1347. $order->error = __("Error creating plan with Stripe:", 'paid-memberships-pro' ) . $e->getMessage(); 
  1348. $order->shorterror = $order->error; 
  1349. return false; 
  1350.  
  1351. //before subscribing, let's clear out the updates so we don't trigger any during sub 
  1352. if(!empty($user_id)) 
  1353. $old_user_updates = get_user_meta($user_id, "pmpro_stripe_updates", true); 
  1354. update_user_meta($user_id, "pmpro_stripe_updates", array()); 
  1355.  
  1356. if(empty($order->subscription_transaction_id) && !empty($this->customer['id'])) 
  1357. $order->subscription_transaction_id = $this->customer['id']; 
  1358.  
  1359. //subscribe to the plan 
  1360. try 
  1361. $subscription = array("plan" => $order->code); 
  1362. $result = $this->customer->subscriptions->create(apply_filters('pmpro_stripe_create_subscription_array', $subscription)); 
  1363. catch (Exception $e) 
  1364. //try to delete the plan 
  1365. $plan->delete(); 
  1366.  
  1367. //give the user any old updates back 
  1368. if(!empty($user_id)) 
  1369. update_user_meta($user_id, "pmpro_stripe_updates", $old_user_updates); 
  1370.  
  1371. //return error 
  1372. $order->error = __("Error subscribing customer to plan with Stripe:", 'paid-memberships-pro' ) . $e->getMessage(); 
  1373. $order->shorterror = $order->error; 
  1374. return false; 
  1375.  
  1376. //delete the plan 
  1377. $plan = Stripe_Plan::retrieve($order->code); 
  1378. $plan->delete(); 
  1379.  
  1380. //if we got this far, we're all good 
  1381. $order->status = "success"; 
  1382. $order->subscription_transaction_id = $result['id']; 
  1383.  
  1384. //save new updates if this is at checkout 
  1385. if($checkout) 
  1386. //empty out updates unless set above 
  1387. if(empty($new_user_updates)) 
  1388. $new_user_updates = array(); 
  1389.  
  1390. //update user meta 
  1391. if(!empty($user_id)) 
  1392. update_user_meta($user_id, "pmpro_stripe_updates", $new_user_updates); 
  1393. else 
  1394. //need to remember the user updates to save later 
  1395. global $pmpro_stripe_updates; 
  1396. $pmpro_stripe_updates = $new_user_updates; 
  1397. function pmpro_user_register_stripe_updates($user_id) 
  1398. global $pmpro_stripe_updates; 
  1399. update_user_meta($user_id, "pmpro_stripe_updates", $pmpro_stripe_updates); 
  1400. add_action("user_register", "pmpro_user_register_stripe_updates"); 
  1401. else 
  1402. //give them their old updates back 
  1403. update_user_meta($user_id, "pmpro_stripe_updates", $old_user_updates); 
  1404.  
  1405. return true; 
  1406.  
  1407. /** 
  1408. * Helper method to update the customer info via getCustomer 
  1409. * @since 1.4 
  1410. */ 
  1411. function update(&$order) 
  1412. //we just have to run getCustomer which will look for the customer and update it with the new token 
  1413. $result = $this->getCustomer($order); 
  1414.  
  1415. if(!empty($result)) 
  1416. return true; 
  1417. else 
  1418. return false; //couldn't find the customer 
  1419.  
  1420. /** 
  1421. * Cancel a subscription at Stripe 
  1422. * @since 1.4 
  1423. */ 
  1424. function cancel(&$order, $update_status = true) 
  1425. //no matter what happens below, we're going to cancel the order in our system 
  1426. if($update_status) 
  1427. $order->updateStatus("cancelled"); 
  1428.  
  1429. //require a subscription id 
  1430. if(empty($order->subscription_transaction_id)) 
  1431. return false; 
  1432.  
  1433. //find the customer 
  1434. $result = $this->getCustomer($order); 
  1435.  
  1436. if(!empty($result)) 
  1437. //find subscription with this order code 
  1438. $subscription = $this->getSubscription($order); 
  1439.  
  1440. if(!empty($subscription)) 
  1441. if($this->cancelSubscriptionAtGateway($subscription)) 
  1442. //we're okay, going to return true later 
  1443. else 
  1444. $order->error = __("Could not cancel old subscription.", 'paid-memberships-pro' ); 
  1445. $order->shorterror = $order->error; 
  1446.  
  1447. return false; 
  1448.  
  1449. /** 
  1450. Clear updates for this user. (But not if checking out, we would have already done that.) 
  1451. */ 
  1452. if(empty($_REQUEST['submit-checkout'])) 
  1453. update_user_meta($order->user_id, "pmpro_stripe_updates", array()); 
  1454.  
  1455. return true; 
  1456. else 
  1457. $order->error = __("Could not find the customer.", 'paid-memberships-pro' ); 
  1458. $order->shorterror = $order->error; 
  1459. return false; //no customer found 
  1460.  
  1461. /** 
  1462. * Helper method to cancel a subscription at Stripe and also clear up any upaid invoices. 
  1463. * @since 1.8 
  1464. */ 
  1465. function cancelSubscriptionAtGateway($subscription) 
  1466. //need a valid sub 
  1467. if(empty($subscription->id)) 
  1468. return false; 
  1469.  
  1470. //make sure we get the customer for this subscription 
  1471. $order = new MemberOrder(); 
  1472. $order->getLastMemberOrderBySubscriptionTransactionID($subscription->id); 
  1473.  
  1474. //no order? 
  1475. if(empty($order)) 
  1476. //lets cancel anyway, but this is suspicious 
  1477. $r = $subscription->cancel(); 
  1478.  
  1479. return true; 
  1480.  
  1481. //okay have an order, so get customer so we can cancel invoices too 
  1482. $this->getCustomer($order); 
  1483.  
  1484. //get open invoices 
  1485. $invoices = $this->customer->invoices(); 
  1486. $invoices = $invoices->all(); 
  1487.  
  1488. //found it, cancel it 
  1489. try 
  1490. //find any open invoices for this subscription and forgive them 
  1491. if(!empty($invoices)) 
  1492. foreach($invoices->data as $invoice) 
  1493. if(!$invoice->closed && $invoice->subscription == $subscription->id) 
  1494. $invoice->closed = true; 
  1495. $invoice->save(); 
  1496.  
  1497. //cancel 
  1498. $r = $subscription->cancel(); 
  1499.  
  1500. return true; 
  1501. catch(Exception $e) 
  1502. return false; 
  1503.  
  1504. /** 
  1505. * Filter pmpro_next_payment to get date via API if possible 
  1506. * @since 1.8.6 
  1507. */ 
  1508. static function pmpro_next_payment($timestamp, $user_id, $order_status) 
  1509. //find the last order for this user 
  1510. if(!empty($user_id)) 
  1511. //get last order 
  1512. $order = new MemberOrder(); 
  1513. $order->getLastMemberOrder($user_id, $order_status); 
  1514.  
  1515. //check if this is a Stripe order with a subscription transaction id 
  1516. if(!empty($order->id) && !empty($order->subscription_transaction_id) && $order->gateway == "stripe") 
  1517. //get the subscription and return the current_period end or false 
  1518. $subscription = $order->Gateway->getSubscription($order);  
  1519.  
  1520. if(!empty($subscription->current_period_end)) 
  1521. return $subscription->current_period_end; 
  1522. else 
  1523. return false; 
  1524.  
  1525. return $timestamp; 
  1526.  
  1527. /** 
  1528. * Refund a payment or invoice 
  1529. * @param object &$order Related PMPro order object. 
  1530. * @param string $transaction_id Payment or Invoice id to void. 
  1531. * @return bool True or false if the void worked 
  1532. */ 
  1533. function void(&$order, $transaction_id = null) 
  1534. //stripe doesn't differentiate between voids and refunds, so let's just pass on to the refund function 
  1535. return $this->refund($order, $transaction_id); 
  1536.  
  1537. /** 
  1538. * Refund a payment or invoice 
  1539. * @param object &$order Related PMPro order object. 
  1540. * @param string $transaction_id Payment or invoice id to void. 
  1541. * @return bool True or false if the refund worked. 
  1542. */ 
  1543. function refund(&$order, $transaction_id = NULL) 
  1544. //default to using the payment id from the order 
  1545. if(empty($transaction_id) && !empty($order->payment_transaction_id)) 
  1546. $transaction_id = $order->payment_transaction_id; 
  1547.  
  1548. //need a transaction id 
  1549. if(empty($transaction_id)) 
  1550. return false; 
  1551.  
  1552. //if an invoice ID is passed, get the charge/payment id 
  1553. if(strpos($transaction_id, "in_") !== false) { 
  1554. $invoice = Stripe_Invoice::retrieve($transaction_id); 
  1555.  
  1556. if(!empty($invoice) && !empty($invoice->payment)) 
  1557. $transaction_id = $invoice->payment; 
  1558.  
  1559. //get the charge 
  1560. $charge = Stripe_Charge::retrieve($transaction_id); 
  1561.  
  1562. //can't find the charge? 
  1563. if(empty($charge)) { 
  1564. $order->status = "error"; 
  1565. $order->errorcode = ""; 
  1566. $order->error = ""; 
  1567. $order->shorterror = ""; 
  1568.  
  1569. return false; 
  1570.  
  1571. //attempt refund 
  1572. try 
  1573. $refund = $charge->refund(); 
  1574. catch (Exception $e) 
  1575. //$order->status = "error"; 
  1576. $order->errorcode = true; 
  1577. $order->error = __("Error: ", 'paid-memberships-pro' ) . $e->getMessage(); 
  1578. $order->shorterror = $order->error; 
  1579. return false; 
  1580.  
  1581. if($refund->status == "succeeded") { 
  1582. $order->status = "refunded"; 
  1583. $order->saveOrder(); 
  1584.  
  1585. return true; 
  1586. } else { 
  1587. $order->status = "error"; 
  1588. $order->errorcode = true; 
  1589. $order->error = sprintf(__("Error: Unkown error while refunding charge #%s", 'paid-memberships-pro' ), $transaction_id); 
  1590. $order->shorterror = $order->error; 
  1591.  
  1592. return false;