Paid Memberships Pro - Version 1.8.1

Version Description

  • BUG: Fixed typos in pmpro_memberslist_csv and pmpro_orderscsv capabilities. (Thanks, Arnaud Devic)
  • BUG: Only loading the Braintree API when using it now.
  • BUG: Fixed fatal error that would occur at checkout if PayPal Standard were used with a discount code. (Thanks, John Zeiger)
  • BUG: Fixed issue where discount codes would not work if billing address fields were hidden. (e.g. paying by PayPal or check)
  • BUG: Fixed issue with the logic around sending emails when admin's change a member's level or expiration date. Admins will always get an email. Members will only get an email if the checkbox is checked.
  • ENHANCEMENT: No longer showing check instructions at checkout if the level is free.
  • ENHANCEMENT: Added pmpro_stripe_create_subscription filter. (Thanks, nickd32 on GitHub)
  • ENHANCEMENT: Added Czech (cs_CZ) language files and support for using decimals as separators. (Thanks, Martin "shr3k" Koke on GitHub)
Download this release

Release Info

Developer strangerstudios
Plugin Icon 128x128 Paid Memberships Pro
Version 1.8.1
Comparing to
See all releases

Code changes from version 1.8 to 1.8.1

adminpages/orders-csv.php CHANGED
@@ -1,6 +1,6 @@
1
<?php
2
//only admins can get this
3
- if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_orders_csv")))
4
{
5
die(__("You do not have permissions to perform this action.", "pmpro"));
6
}
1
<?php
2
//only admins can get this
3
+ if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_orderscsv")))
4
{
5
die(__("You do not have permissions to perform this action.", "pmpro"));
6
}
classes/gateways/class.pmprogateway_braintree.php CHANGED
@@ -3,17 +3,17 @@
3
require_once(dirname(__FILE__) . "/class.pmprogateway.php");
4
5
//load classes init method
6
- add_action('init', array('PMProGateway_braintree', 'init'));
7
8
- if(!class_exists("Braintree"))
9
- require_once(dirname(__FILE__) . "/../../includes/lib/Braintree/Braintree.php");
10
class PMProGateway_braintree extends PMProGateway
11
{
12
function PMProGateway_braintree($gateway = NULL)
13
- {
14
$this->gateway = $gateway;
15
$this->gateway_environment = pmpro_getOption("gateway_environment");
16
17
//convert to braintree nomenclature
18
$environment = $this->gateway_environment;
19
if($environment == "live")
@@ -27,6 +27,19 @@
27
return $this->gateway;
28
}
29
30
/**
31
* Run on WP init
32
*
3
require_once(dirname(__FILE__) . "/class.pmprogateway.php");
4
5
//load classes init method
6
+ add_action('init', array('PMProGateway_braintree', 'init'));
7
8
class PMProGateway_braintree extends PMProGateway
9
{
10
function PMProGateway_braintree($gateway = NULL)
11
+ {
12
$this->gateway = $gateway;
13
$this->gateway_environment = pmpro_getOption("gateway_environment");
14
15
+ $this->loadBraintreeLibrary();
16
+
17
//convert to braintree nomenclature
18
$environment = $this->gateway_environment;
19
if($environment == "live")
27
return $this->gateway;
28
}
29
30
+ /**
31
+ * Load the Braintree API library.
32
+ *
33
+ * @since 1.8.1
34
+ * Moved into a method in version 1.8.1 so we only load it when needed.
35
+ */
36
+ function loadBraintreeLibrary()
37
+ {
38
+ //load Braintree library if it hasn't been loaded already (usually by another plugin using Braintree)
39
+ if(!class_exists("Braintree"))
40
+ require_once(dirname(__FILE__) . "/../../includes/lib/Braintree/Braintree.php");
41
+ }
42
+
43
/**
44
* Run on WP init
45
*
classes/gateways/class.pmprogateway_paypalstandard.php CHANGED
@@ -220,7 +220,7 @@
220
*/
221
static function pmpro_checkout_before_change_membership_level($user_id, $morder)
222
{
223
- global $discount_code_id;
224
225
//if no order, no need to pay
226
if(empty($morder))
220
*/
221
static function pmpro_checkout_before_change_membership_level($user_id, $morder)
222
{
223
+ global $discount_code_id, $wpdb;
224
225
//if no order, no need to pay
226
if(empty($morder))
classes/gateways/class.pmprogateway_stripe.php CHANGED
@@ -1,10 +1,10 @@
1
- <?php
2
//include pmprogateway
3
- require_once(dirname(__FILE__) . "/class.pmprogateway.php");
4
-
5
//load classes init method
6
add_action('init', array('PMProGateway_stripe', 'init'));
7
-
8
/**
9
* PMProGateway_stripe Class
10
*
@@ -16,25 +16,25 @@
16
{
17
/**
18
* Stripe Class Constructor
19
- *
20
* @since 1.4
21
*/
22
function PMProGateway_stripe($gateway = NULL)
23
{
24
$this->gateway = $gateway;
25
$this->gateway_environment = pmpro_getOption("gateway_environment");
26
-
27
- $this->loadStripeLibrary();
28
Stripe::setApiKey(pmpro_getOption("stripe_secretkey"));
29
-
30
return $this->gateway;
31
- }
32
-
33
/**
34
* Load the Stripe API library.
35
- *
36
* @since 1.8
37
- * Moved into a method in version 2.0 so we only load it when needed.
38
*/
39
function loadStripeLibrary()
40
{
@@ -42,66 +42,66 @@
42
if(!class_exists("Stripe"))
43
require_once(dirname(__FILE__) . "/../../includes/lib/Stripe/Stripe.php");
44
}
45
-
46
/**
47
* Run on WP init
48
- *
49
* @since 1.8
50
*/
51
static function init()
52
- {
53
//make sure Stripe is a gateway option
54
add_filter('pmpro_gateways', array('PMProGateway_stripe', 'pmpro_gateways'));
55
-
56
//add fields to payment settings
57
add_filter('pmpro_payment_options', array('PMProGateway_stripe', 'pmpro_payment_options'));
58
add_filter('pmpro_payment_option_fields', array('PMProGateway_stripe', 'pmpro_payment_option_fields'), 10, 2);
59
-
60
//add some fields to edit user page (Updates)
61
add_action('pmpro_after_membership_level_profile_fields', array('PMProGateway_stripe', 'user_profile_fields'));
62
add_action('profile_update', array('PMProGateway_stripe', 'user_profile_fields_save'));
63
-
64
//old global RE showing billing address or not
65
global $pmpro_stripe_lite;
66
$pmpro_stripe_lite = apply_filters("pmpro_stripe_lite", !pmpro_getOption("stripe_billingaddress")); //default is oposite of the stripe_billingaddress setting
67
-
68
//updates cron
69
add_action('pmpro_activation', array('PMProGateway_stripe', 'pmpro_activation'));
70
add_action('pmpro_deactivation', array('PMProGateway_stripe', 'pmpro_deactivation'));
71
add_action('pmpro_cron_stripe_subscription_updates', array('PMProGateway_stripe', 'pmpro_cron_stripe_subscription_updates'));
72
-
73
//code to add at checkout if Stripe is the current gateway
74
$gateway = pmpro_getOption("gateway");
75
if($gateway == "stripe")
76
{
77
- add_action('pmpro_checkout_preheader', array('PMProGateway_stripe', 'pmpro_checkout_preheader'));
78
add_filter('pmpro_checkout_order', array('PMProGateway_stripe', 'pmpro_checkout_order'));
79
add_filter('pmpro_include_billing_address_fields', array('PMProGateway_stripe', 'pmpro_include_billing_address_fields'));
80
add_filter('pmpro_include_cardtype_field', array('PMProGateway_stripe', 'pmpro_include_billing_address_fields'));
81
add_filter('pmpro_include_payment_information_fields', array('PMProGateway_stripe', 'pmpro_include_payment_information_fields'));
82
}
83
}
84
-
85
/**
86
* Make sure Stripe is in the gateways list
87
- *
88
* @since 1.8
89
*/
90
static function pmpro_gateways($gateways)
91
{
92
if(empty($gateways['stripe']))
93
$gateways['stripe'] = __('Stripe', 'pmpro');
94
-
95
return $gateways;
96
}
97
-
98
/**
99
* Get a list of payment options that the Stripe gateway needs/supports.
100
- *
101
* @since 1.8
102
*/
103
static function getGatewayOptions()
104
- {
105
$options = array(
106
'sslseal',
107
'nuclear_HTTPS',
@@ -115,35 +115,35 @@
115
'tax_rate',
116
'accepted_credit_cards'
117
);
118
-
119
return $options;
120
}
121
-
122
/**
123
* Set payment options for payment settings page.
124
- *
125
* @since 1.8
126
*/
127
static function pmpro_payment_options($options)
128
- {
129
//get stripe options
130
$stripe_options = PMProGateway_stripe::getGatewayOptions();
131
-
132
//merge with others.
133
$options = array_merge($stripe_options, $options);
134
-
135
return $options;
136
}
137
-
138
/**
139
* Display fields for Stripe options.
140
- *
141
* @since 1.8
142
*/
143
static function pmpro_payment_option_fields($values, $gateway)
144
{
145
?>
146
- <tr class="pmpro_settings_divider gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>>
147
<td colspan="2">
148
<?php _e('Stripe Settings', 'pmpro'); ?>
149
</td>
@@ -171,7 +171,7 @@
171
<td>
172
<select id="stripe_billingaddress" name="stripe_billingaddress">
173
<option value="0" <?php if(empty($values['stripe_billingaddress'])) { ?>selected="selected"<?php } ?>><?php _e('No', 'pmpro');?></option>
174
- <option value="1" <?php if(!empty($values['stripe_billingaddress'])) { ?>selected="selected"<?php } ?>><?php _e('Yes', 'pmpro');?></option>
175
</select>
176
<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>", 'pmpro');?></small>
177
</td>
@@ -183,39 +183,39 @@
183
<td>
184
<p><?php _e('To fully integrate with Stripe, be sure to set your Web Hook URL to', 'pmpro');?> <pre><?php echo admin_url("admin-ajax.php") . "?action=stripe_webhook";?></pre></p>
185
</td>
186
- </tr>
187
<?php
188
}
189
-
190
/**
191
* Code added to checkout preheader.
192
- *
193
* @since 1.8
194
*/
195
static function pmpro_checkout_preheader()
196
- {
197
global $gateway, $pmpro_level;
198
-
199
if($gateway == "stripe" && !pmpro_isLevelFree($pmpro_level))
200
{
201
//stripe js library
202
wp_enqueue_script("stripe", "https://js.stripe.com/v2/", array(), NULL);
203
-
204
//stripe js code for checkout
205
function pmpro_stripe_javascript()
206
{
207
global $pmpro_gateway, $pmpro_level, $pmpro_stripe_lite;
208
?>
209
<script type="text/javascript">
210
- // this identifies your website in the createToken call below
211
Stripe.setPublishableKey('<?php echo pmpro_getOption("stripe_publishablekey"); ?>');
212
-
213
- var pmpro_require_billing = true;
214
-
215
jQuery(document).ready(function() {
216
jQuery("#pmpro_form, .pmpro_form").submit(function(event) {
217
-
218
- //double check in case a discount code made the level free
219
if(pmpro_require_billing)
220
{
221
//build array for creating token
@@ -231,18 +231,18 @@
231
?>
232
,address_line1: jQuery('#baddress1').val(),
233
address_line2: jQuery('#baddress2').val(),
234
- address_city: jQuery('#bcity').val(),
235
- address_state: jQuery('#bstate').val(),
236
- address_zip: jQuery('#bzipcode').val(),
237
address_country: jQuery('#bcountry').val()
238
<?php
239
}
240
- ?>
241
};
242
-
243
if (jQuery('#bfirstname').length && jQuery('#blastname').length)
244
args['name'] = jQuery.trim(jQuery('#bfirstname').val() + ' ' + jQuery('#blastname').val());
245
-
246
//create token
247
Stripe.createToken(args, stripeResponseHandler);
248
@@ -261,19 +261,19 @@
261
262
//hide processing message
263
jQuery('#pmpro_processing_message').css('visibility', 'hidden');
264
-
265
// show the errors on the form
266
alert(response.error.message);
267
jQuery(".payment-errors").text(response.error.message);
268
} else {
269
- var form$ = jQuery("#pmpro_form, .pmpro_form");
270
// token contains id, last4, and card type
271
- var token = response['id'];
272
// insert the token into the form so it gets submitted to the server
273
form$.append("<input type='hidden' name='stripeToken' value='" + token + "'/>");
274
-
275
console.log(response);
276
-
277
//insert fields for other card fields
278
if(jQuery('#CardType[name=CardType]').length)
279
jQuery('#CardType').val(response['card']['brand']);
@@ -281,8 +281,8 @@
281
form$.append("<input type='hidden' name='CardType' value='" + response['card']['brand'] + "'/>");
282
form$.append("<input type='hidden' name='AccountNumber' value='XXXXXXXXXXXXX" + response['card']['last4'] + "'/>");
283
form$.append("<input type='hidden' name='ExpirationMonth' value='" + ("0" + response['card']['exp_month']).slice(-2) + "'/>");
284
- form$.append("<input type='hidden' name='ExpirationYear' value='" + response['card']['exp_year'] + "'/>");
285
-
286
// and submit
287
form$.get(0).submit();
288
}
@@ -291,20 +291,20 @@
291
<?php
292
}
293
add_action("wp_head", "pmpro_stripe_javascript");
294
-
295
//don't require the CVV
296
function pmpro_stripe_dont_require_CVV($fields)
297
{
298
- unset($fields['CVV']);
299
return $fields;
300
}
301
add_filter("pmpro_required_billing_fields", "pmpro_stripe_dont_require_CVV");
302
}
303
}
304
-
305
/**
306
* Filtering orders at checkout.
307
- *
308
* @since 1.8
309
*/
310
static function pmpro_checkout_order($morder)
@@ -314,13 +314,13 @@
314
{
315
$morder->stripeToken = $_REQUEST['stripeToken'];
316
}
317
-
318
//stripe lite code to get name from other sources if available
319
global $pmpro_stripe_lite, $current_user;
320
if(!empty($pmpro_stripe_lite) && empty($morder->FirstName) && empty($morder->LastName))
321
{
322
if(!empty($current_user->ID))
323
- {
324
$morder->FirstName = get_user_meta($current_user->ID, "first_name", true);
325
$morder->LastName = get_user_meta($current_user->ID, "last_name", true);
326
}
@@ -330,19 +330,19 @@
330
$morder->LastName = $_REQUEST['last_name'];
331
}
332
}
333
-
334
return $morder;
335
}
336
-
337
/**
338
* Code to run after checkout
339
- *
340
* @since 1.8
341
*/
342
- static function pmpro_after_checkout($user_id, $morder)
343
{
344
global $gateway;
345
-
346
if($gateway == "stripe")
347
{
348
if(!empty($morder) && !empty($morer->Gateway) && !empty($morder->Gateway->customer) && !empty($morder->Gateway->customer->id))
@@ -351,7 +351,7 @@
351
}
352
}
353
}
354
-
355
/**
356
* Check settings if billing address should be shown.
357
* @since 1.8
@@ -361,24 +361,24 @@
361
//check settings RE showing billing address
362
if(!pmpro_getOption("stripe_billingaddress"))
363
$include = false;
364
-
365
return $include;
366
}
367
-
368
/**
369
* Use our own payment fields at checkout. (Remove the name attributes.)
370
* @since 1.8
371
*/
372
static function pmpro_include_payment_information_fields($include)
373
- {
374
//global vars
375
global $pmpro_requirebilling, $pmpro_show_discount_code, $discount_code, $CardType, $AccountNumber, $ExpirationMonth, $ExpirationYear;
376
-
377
//get accepted credit cards
378
$pmpro_accepted_credit_cards = pmpro_getOption("accepted_credit_cards");
379
$pmpro_accepted_credit_cards = explode(",", $pmpro_accepted_credit_cards);
380
- $pmpro_accepted_credit_cards_string = pmpro_implodeToEnglish($pmpro_accepted_credit_cards);
381
-
382
//include ours
383
?>
384
<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 } ?>>
@@ -388,8 +388,8 @@
388
</tr>
389
</thead>
390
<tbody>
391
- <tr valign="top">
392
- <td>
393
<?php
394
$sslseal = pmpro_getOption("sslseal");
395
if($sslseal)
@@ -409,7 +409,7 @@
409
<select id="CardType" class=" <?php echo pmpro_getClassForField("CardType");?>">
410
<?php foreach($pmpro_accepted_credit_cards as $cc) { ?>
411
<option value="<?php echo $cc?>" <?php if($CardType == $cc) { ?>selected="selected"<?php } ?>><?php echo $cc?></option>
412
- <?php } ?>
413
</select>
414
</div>
415
<?php
@@ -419,8 +419,8 @@
419
?>
420
<input type="hidden" id="CardType" name="CardType" value="<?php echo esc_attr($CardType);?>" />
421
<script>
422
- jQuery(document).ready(function() {
423
- jQuery('#AccountNumber').validateCreditCard(function(result) {
424
var cardtypenames = {
425
"amex":"American Express",
426
"diners_club_carte_blanche":"Diners Club Carte Blanche",
@@ -433,23 +433,23 @@
433
"visa":"Visa",
434
"visa_electron":"Visa Electron"
435
}
436
-
437
if(result.card_type)
438
jQuery('#CardType').val(cardtypenames[result.card_type.name]);
439
else
440
jQuery('#CardType').val('Unknown Card Type');
441
- });
442
});
443
</script>
444
<?php
445
}
446
?>
447
-
448
<div class="pmpro_payment-account-number">
449
<label for="AccountNumber"><?php _e('Card Number', 'pmpro');?></label>
450
<input id="AccountNumber" class="input <?php echo pmpro_getClassForField("AccountNumber");?>" type="text" size="25" value="<?php echo esc_attr($AccountNumber)?>" autocomplete="off" />
451
</div>
452
-
453
<div class="pmpro_payment-expiration">
454
<label for="ExpirationMonth"><?php _e('Expiration Date', 'pmpro');?></label>
455
<select id="ExpirationMonth" class=" <?php echo pmpro_getClassForField("ExpirationMonth");?>">
@@ -474,9 +474,9 @@
474
<?php
475
}
476
?>
477
- </select>
478
</div>
479
-
480
<?php
481
$pmpro_show_cvv = apply_filters("pmpro_show_cvv", true);
482
if($pmpro_show_cvv)
@@ -489,7 +489,7 @@
489
<?php
490
}
491
?>
492
-
493
<?php if($pmpro_show_discount_code) { ?>
494
<div class="pmpro_payment-discount-code">
495
<label for="discount_code"><?php _e('Discount Code', 'pmpro');?></label>
@@ -498,20 +498,20 @@
498
<p id="discount_code_message" class="pmpro_message" style="display: none;"></p>
499
</div>
500
<?php } ?>
501
-
502
- </td>
503
</tr>
504
</tbody>
505
</table>
506
<?php
507
-
508
//don't include the default
509
return false;
510
}
511
-
512
/**
513
* Fields shown on edit user page
514
- *
515
* @since 1.8
516
*/
517
static function user_profile_fields($user)
@@ -521,48 +521,48 @@
521
$cycles = array( __('Day(s)', 'pmpro') => 'Day', __('Week(s)', 'pmpro') => 'Week', __('Month(s)', 'pmpro') => 'Month', __('Year(s)', 'pmpro') => 'Year' );
522
$current_year = date("Y");
523
$current_month = date("m");
524
-
525
//make sure the current user has privileges
526
$membership_level_capability = apply_filters("pmpro_edit_member_capability", "manage_options");
527
if(!current_user_can($membership_level_capability))
528
return false;
529
530
- //more privelges they should have
531
$show_membership_level = apply_filters("pmpro_profile_show_membership_level", true, $user);
532
if(!$show_membership_level)
533
return false;
534
-
535
//check that user has a current subscription at Stripe
536
$last_order = new MemberOrder();
537
$last_order->getLastMemberOrder($user->ID);
538
-
539
//assume no sub to start
540
$sub = false;
541
-
542
//check that gateway is Stripe
543
if($last_order->gateway == "stripe")
544
- {
545
//is there a customer?
546
- $sub = $last_order->Gateway->getSubscription($last_order);
547
- }
548
-
549
$customer_id = $user->pmpro_stripe_customerid;
550
-
551
if(empty($sub))
552
{
553
//make sure we delete stripe updates
554
update_user_meta($user->ID, "pmpro_stripe_updates", array());
555
-
556
//if the last order has a sub id, let the admin know there is no sub at Stripe
557
if(!empty($last_order) && $last_order->gateway == "stripe" && !empty($last_order->subscription_transaction_id) && strpos($last_order->subscription_transaction_id, "sub_") !== false)
558
{
559
?>
560
<p><strong>Note:</strong> Subscription <strong><?php echo $last_order->subscription_transaction_id;?></strong> could not be found at Stripe. It might have been deleted.</p>
561
<?php
562
- }
563
}
564
- else
565
- {
566
?>
567
<h3><?php _e("Subscription Updates", "pmpro"); ?></h3>
568
<p>
@@ -578,7 +578,7 @@
578
<th><label for="membership_level"><?php _e("Update", "pmpro"); ?></label></th>
579
<td id="updates_td">
580
<?php
581
- $old_updates = $user->pmpro_stripe_updates;
582
if(is_array($old_updates))
583
{
584
$updates = array_merge(
@@ -588,19 +588,19 @@
588
}
589
else
590
$updates = array(array('template'=>true, 'when'=>'now', 'date_month'=>'', 'date_day'=>'', 'date_year'=>'', 'billing_amount'=>'', 'cycle_number'=>'', 'cycle_period'=>'Month'));
591
-
592
foreach($updates as $update)
593
{
594
?>
595
<div class="updates_update" <?php if(!empty($update['template'])) { ?>style="display: none;"<?php } ?>>
596
- <select class="updates_when" name="updates_when[]">
597
<option value="now" <?php selected($update['when'], "now");?>>Now</option>
598
<option value="payment" <?php selected($update['when'], "payment");?>>After Next Payment</option>
599
<option value="date" <?php selected($update['when'], "date");?>>On Date</option>
600
</select>
601
<span class="updates_date" <?php if($uwhen != "date") { ?>style="display: none;"<?php } ?>>
602
<select name="updates_date_month[]">
603
- <?php
604
for($i = 1; $i < 13; $i++)
605
{
606
?>
@@ -619,7 +619,7 @@
619
<small><?php _e('per', 'pmpro');?></small>
620
<input name="updates_cycle_number[]" type="text" size="5" value="<?php echo esc_attr($update['cycle_number']);?>" />
621
<select name="updates_cycle_period[]">
622
- <?php
623
foreach ( $cycles as $name => $value ) {
624
echo "<option value='$value'";
625
if(!empty($update['cycle_period']) && $update['cycle_period'] == $value) echo " selected='selected'";
@@ -627,18 +627,18 @@
627
}
628
?>
629
</select>
630
- </span>
631
<span>
632
- <a class="updates_remove" href="javascript:void(0);">Remove</a>
633
</span>
634
</div>
635
<?php
636
}
637
- ?>
638
<p><a id="updates_new_update" href="javascript:void(0);">+ New Update</a></p>
639
</td>
640
- </tr>
641
- </table>
642
<script>
643
jQuery(document).ready(function() {
644
//function to update dropdowns/etc based on when field
@@ -648,45 +648,45 @@
648
jQuery(when).parent().children('.updates_date').show();
649
else
650
jQuery(when).parent().children('.updates_date').hide();
651
-
652
if(jQuery(when).val() == 'no')
653
jQuery(when).parent().children('.updates_billing').hide();
654
else
655
jQuery(when).parent().children('.updates_billing').show();
656
- }
657
658
//and update on page load
659
jQuery('.updates_when').each(function() { if(jQuery(this).parent().css('display') != 'none') updateSubscriptionUpdateFields(this); });
660
-
661
//add a new update when clicking to
662
var num_updates_divs = <?php echo count($updates);?>;
663
jQuery('#updates_new_update').click(function() {
664
//get updates
665
updates = jQuery('.updates_update').toArray();
666
-
667
//clone the first one
668
- new_div = jQuery(updates[0]).clone();
669
-
670
//append
671
new_div.insertBefore('#updates_new_update');
672
-
673
//update events
674
addUpdateEvents()
675
-
676
//unhide it
677
new_div.show();
678
- updateSubscriptionUpdateFields(new_div.children('.updates_when'));
679
});
680
-
681
function addUpdateEvents()
682
{
683
//update when when changes
684
jQuery('.updates_when').change(function() {
685
updateSubscriptionUpdateFields(this);
686
});
687
-
688
//remove updates when clicking
689
- jQuery('.updates_remove').click(function() {
690
jQuery(this).parent().parent().remove();
691
});
692
}
@@ -696,40 +696,40 @@
696
<?php
697
}
698
}
699
-
700
/**
701
* Process fields from the edit user page
702
- *
703
* @since 1.8
704
*/
705
static function user_profile_fields_save($user_id)
706
{
707
global $wpdb;
708
-
709
//check capabilities
710
$membership_level_capability = apply_filters("pmpro_edit_member_capability", "manage_options");
711
if(!current_user_can($membership_level_capability))
712
return false;
713
-
714
//make sure some value was passed
715
if(!isset($_POST['updates_when']) || !is_array($_POST['updates_when']))
716
return;
717
-
718
//vars
719
$updates = array();
720
$next_on_date_update = "";
721
-
722
//build array of updates (we skip the first because it's the template field for the JavaScript
723
for($i = 1; $i < count($_POST['updates_when']); $i++)
724
{
725
$update = array();
726
-
727
//all updates have these values
728
$update['when'] = $_POST['updates_when'][$i];
729
$update['billing_amount'] = $_POST['updates_billing_amount'][$i];
730
$update['cycle_number'] = $_POST['updates_cycle_number'][$i];
731
$update['cycle_period'] = $_POST['updates_cycle_period'][$i];
732
-
733
//these values only for on date updates
734
if($_POST['updates_when'][$i] == "date")
735
{
@@ -737,17 +737,17 @@
737
$update['date_day'] = str_pad($_POST['updates_date_day'][$i], 2, "0", STR_PAD_LEFT);
738
$update['date_year'] = $_POST['updates_date_year'][$i];
739
}
740
-
741
//make sure the update is valid
742
if(empty($update['cycle_number']))
743
continue;
744
-
745
//if when is now, update the subscription
746
if($update['when'] == "now")
747
{
748
//get level for user
749
$user_level = pmpro_getMembershipLevelForUser($user_id);
750
-
751
//get current plan at Stripe to get payment date
752
$last_order = new MemberOrder();
753
$last_order->getLastMemberOrder($user_id);
@@ -755,30 +755,30 @@
755
$last_order->Gateway->getCustomer($last_order);
756
757
$subscription = $last_order->Gateway->getSubscription($last_order);
758
-
759
if(!empty($subscription))
760
- {
761
$end_timestamp = $subscription->current_period_end;
762
-
763
- //cancel the old subscription
764
if(!$last_order->Gateway->cancelSubscriptionAtGateway($subscription))
765
{
766
//throw error and halt save
767
- function pmpro_stripe_user_profile_fields_save_error($errors, $update, $user)
768
{
769
$errors->add('pmpro_stripe_updates',__('Could not cancel the old subscription. Updates have not been processed.', 'pmpro'));
770
}
771
add_filter('user_profile_update_errors', 'pmpro_stripe_user_profile_fields_save_error', 10, 3);
772
-
773
//stop processing updates
774
return;
775
}
776
}
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');
@@ -789,14 +789,14 @@
789
$update_order->PaymentAmount = $update['billing_amount'];
790
$update_order->ProfileStartDate = date("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']) . "',
@@ -808,13 +808,13 @@
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
}
820
elseif($update['when'] == 'date')
@@ -824,41 +824,41 @@
824
else
825
$next_on_date_update = $update['date_year'] . "-" . $update['date_month'] . "-" . $update['date_day'];
826
}
827
-
828
- //add to array
829
- $updates[] = $update;
830
}
831
-
832
//save in user meta
833
update_user_meta($user_id, "pmpro_stripe_updates", $updates);
834
-
835
//save date of next on-date update to make it easier to query for these in cron job
836
update_user_meta($user_id, "pmpro_stripe_next_on_date_update", $next_on_date_update);
837
}
838
-
839
/**
840
* Cron activation for subscription updates.
841
- *
842
* @since 1.8
843
*/
844
static function pmpro_activation()
845
{
846
wp_schedule_event(time(), 'daily', 'pmpro_cron_stripe_subscription_updates');
847
}
848
-
849
/**
850
* Cron deactivation for subscription updates.
851
- *
852
* @since 1.8
853
*/
854
static function pmpro_deactivation()
855
{
856
wp_clear_scheduled_hook('pmpro_cron_stripe_subscription_updates');
857
}
858
-
859
/**
860
* Cron job for subscription updates.
861
- *
862
* @since 1.8
863
*/
864
static function pmpro_cron_stripe_subscription_updates()
@@ -866,41 +866,41 @@
866
global $wpdb;
867
868
//get all updates for today (or before today)
869
- $sqlQuery = "SELECT *
870
- FROM $wpdb->usermeta
871
- WHERE meta_key = 'pmpro_stripe_next_on_date_update'
872
- AND meta_value IS NOT NULL
873
- AND meta_value < '" . date("Y-m-d", strtotime("+1 day")) . "'";
874
$updates = $wpdb->get_results($sqlQuery);
875
-
876
if(!empty($updates))
877
- {
878
//loop through
879
foreach($updates as $update)
880
- {
881
//pull values from update
882
$user_id = $update->user_id;
883
-
884
$user = get_userdata($user_id);
885
$user_updates = $user->pmpro_stripe_updates;
886
- $next_on_date_update = "";
887
-
888
//loop through updates looking for updates happening today or earlier
889
foreach($user_updates as $key => $update)
890
- {
891
if($update['when'] == 'date' &&
892
$update['date_year'] . "-" . $update['date_month'] . "-" . $update['date_day'] <= date("Y-m-d")
893
)
894
{
895
//get level for user
896
$user_level = pmpro_getMembershipLevelForUser($user_id);
897
-
898
//get current plan at Stripe to get payment date
899
$last_order = new MemberOrder();
900
$last_order->getLastMemberOrder($user_id);
901
$last_order->setGateway('stripe');
902
$last_order->Gateway->getCustomer($last_order);
903
-
904
if(!empty($last_order->Gateway->customer))
905
{
906
//find the first subscription
@@ -910,10 +910,10 @@
910
$end_timestamp = $first_sub['current_period_end'];
911
}
912
}
913
-
914
//if we didn't get an end date, let's set one one cycle out
915
$end_timestamp = strtotime("+" . $update['cycle_number'] . " " . $update['cycle_period']);
916
-
917
//build order object
918
$update_order = new MemberOrder();
919
$update_order->setGateway('stripe');
@@ -925,28 +925,28 @@
925
$update_order->ProfileStartDate = date("Y-m-d", $end_timestamp);
926
$update_order->BillingPeriod = $update['cycle_period'];
927
$update_order->BillingFrequency = $update['cycle_number'];
928
-
929
//update subscription
930
$update_order->Gateway->subscribe($update_order, false);
931
-
932
//update membership
933
- $sqlQuery = "UPDATE $wpdb->pmpro_memberships_users
934
- SET billing_amount = '" . esc_sql($update['billing_amount']) . "',
935
- cycle_number = '" . esc_sql($update['cycle_number']) . "',
936
- cycle_period = '" . esc_sql($update['cycle_period']) . "'
937
- WHERE user_id = '" . esc_sql($user_id) . "'
938
- AND membership_id = '" . esc_sql($last_order->membership_id) . "'
939
- AND status = 'active'
940
LIMIT 1";
941
-
942
$wpdb->query($sqlQuery);
943
-
944
//save order
945
$update_order->status = "success";
946
$update_order->save();
947
-
948
//remove update from list
949
- unset($user_updates[$key]);
950
}
951
elseif($update['when'] == 'date')
952
{
@@ -957,19 +957,19 @@
957
$next_on_date_update = $update['date_year'] . "-" . $update['date_month'] . "-" . $update['date_day'];
958
}
959
}
960
-
961
//save updates in case we removed some
962
update_user_meta($user_id, "pmpro_stripe_updates", $user_updates);
963
-
964
//save date of next on-date update to make it easier to query for these in cron job
965
update_user_meta($user_id, "pmpro_stripe_next_on_date_update", $next_on_date_update);
966
}
967
}
968
}
969
-
970
/**
971
* Process checkout and decide if a charge and or subscribe is needed
972
- *
973
* @since 1.4
974
*/
975
function process(&$order)
@@ -986,7 +986,7 @@
986
if($this->charge($order))
987
{
988
if(pmpro_isLevelRecurring($order->membership_level))
989
- {
990
if($this->subscribe($order))
991
{
992
//yay!
@@ -1001,7 +1001,7 @@
1001
else
1002
{
1003
//only a one time charge
1004
- $order->status = "success"; //saved on checkout page
1005
return true;
1006
}
1007
}
@@ -1011,39 +1011,39 @@
1011
$order->error = __("Unknown error: Initial payment failed.", "pmpro");
1012
return false;
1013
}
1014
- }
1015
- }
1016
-
1017
/**
1018
* Make a one-time charge with Stripe
1019
- *
1020
* @since 1.4
1021
*/
1022
function charge(&$order)
1023
{
1024
global $pmpro_currency;
1025
-
1026
//create a code for the order
1027
if(empty($order->code))
1028
$order->code = $order->getRandomCode();
1029
-
1030
- //what amount to charge?
1031
$amount = $order->InitialPayment;
1032
-
1033
//tax
1034
$order->subtotal = $amount;
1035
$tax = $order->getTax(true);
1036
$amount = round((float)$order->subtotal + (float)$tax, 2);
1037
-
1038
//create a customer
1039
$result = $this->getCustomer($order);
1040
-
1041
if(empty($result))
1042
- {
1043
//failed to create customer
1044
return false;
1045
- }
1046
-
1047
//charge
1048
try
1049
{
@@ -1063,13 +1063,13 @@
1063
$order->shorterror = $order->error;
1064
return false;
1065
}
1066
-
1067
if(empty($response["failure_message"]))
1068
{
1069
//successful charge
1070
$order->payment_transaction_id = $response["id"];
1071
- $order->updateStatus("success");
1072
- return true;
1073
}
1074
else
1075
{
@@ -1078,12 +1078,12 @@
1078
$order->error = $response['failure_message'];
1079
$order->shorterror = $response['failure_message'];
1080
return false;
1081
- }
1082
}
1083
-
1084
/**
1085
* Get a Stripe customer object.
1086
- *
1087
* If $this->customer is set, it returns it.
1088
* It first checks if the order has a subscription_transaction_id. If so, that's the customer id.
1089
* If not, it checks for a user_id on the order and searches for a customer id in the user meta.
@@ -1097,42 +1097,42 @@
1097
function getCustomer(&$order = false, $force = false)
1098
{
1099
global $current_user;
1100
-
1101
//already have it?
1102
if(!empty($this->customer) && !$force)
1103
return $this->customer;
1104
-
1105
//figure out user_id and user
1106
if(!empty($order->user_id))
1107
$user_id = $order->user_id;
1108
-
1109
//if no id passed, check the current user
1110
if(empty($user_id) && !empty($current_user->ID))
1111
$user_id = $current_user->ID;
1112
-
1113
if(!empty($user_id))
1114
$user = get_userdata($user_id);
1115
else
1116
$user = NULL;
1117
-
1118
//transaction id?
1119
if(!empty($order->subscription_transaction_id) && strpos($order->subscription_transaction_id, "cus_") !== false)
1120
$customer_id = $order->subscription_transaction_id;
1121
else
1122
{
1123
- //try based on user id
1124
if(!empty($user_id))
1125
- {
1126
- $customer_id = get_user_meta($user_id, "pmpro_stripe_customerid", true);
1127
}
1128
- }
1129
-
1130
//get name and email values from order in case we update
1131
$name = trim($order->FirstName . " " . $order->LastName);
1132
if(empty($name) && !empty($user->ID))
1133
{
1134
$name = trim($user->first_name . " " . $user->last_name);
1135
-
1136
//still empty?
1137
if(empty($name))
1138
$name = $user->user_login;
@@ -1140,41 +1140,41 @@
1140
elseif(empty($name))
1141
$name = "No Name";
1142
1143
- $email = $order->Email;
1144
if(empty($email) && !empty($user->ID))
1145
{
1146
$email = $user->user_email;
1147
}
1148
elseif(empty($email))
1149
$email = "No Email";
1150
-
1151
//check for an existing stripe customer
1152
if(!empty($customer_id))
1153
{
1154
try
1155
{
1156
$this->customer = Stripe_Customer::retrieve($customer_id);
1157
-
1158
//update the customer description and card
1159
if(!empty($order->stripeToken))
1160
- {
1161
$this->customer->description = $name . " (" . $email . ")";
1162
$this->customer->email = $email;
1163
$this->customer->card = $order->stripeToken;
1164
$this->customer->save();
1165
}
1166
-
1167
return $this->customer;
1168
}
1169
catch (Exception $e)
1170
{
1171
- //assume no customer found
1172
}
1173
}
1174
-
1175
//no customer id, create one
1176
if(!empty($order->stripeToken))
1177
- {
1178
try
1179
{
1180
$this->customer = Stripe_Customer::create(array(
@@ -1189,11 +1189,11 @@
1189
$order->shorterror = $order->error;
1190
return false;
1191
}
1192
-
1193
if(!empty($user_id))
1194
{
1195
//user logged in/etc
1196
- update_user_meta($user_id, "pmpro_stripe_customerid", $this->customer->id);
1197
}
1198
else
1199
{
@@ -1210,29 +1210,29 @@
1210
1211
return apply_filters('pmpro_stripe_create_customer', $this->customer);
1212
}
1213
-
1214
- return false;
1215
}
1216
-
1217
/**
1218
* Get a Stripe subscription from a PMPro order
1219
- *
1220
* @since 1.8
1221
*/
1222
- function getSubscription(&$order)
1223
{
1224
global $wpdb;
1225
-
1226
//no order?
1227
if(empty($order) || empty($order->code))
1228
- return false;
1229
-
1230
$result = $this->getCustomer($order, true); //force so we don't get a cached sub for someone else
1231
-
1232
//no customer?
1233
if(empty($result))
1234
return false;
1235
-
1236
//is there a subscription transaction id pointing to a sub?
1237
if(!empty($order->subscription_transaction_id) && strpos($order->subscription_transaction_id, "sub_") !== false)
1238
{
@@ -1246,49 +1246,49 @@
1246
$order->shorterror = $order->error;
1247
return false;
1248
}
1249
-
1250
return $sub;
1251
- }
1252
-
1253
//find subscription based on customer id and order/plan id
1254
- $subscriptions = $this->customer->subscriptions->all();
1255
-
1256
//no subscriptions
1257
if(empty($subscriptions) || empty($subscriptions->data))
1258
- return false;
1259
-
1260
//we really want to test against the order codes of all orders with the same subscription_transaction_id (customer id)
1261
$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')");
1262
-
1263
//find the one for this order
1264
foreach($subscriptions->data as $sub)
1265
- {
1266
if(in_array($sub->plan->id, $codes))
1267
{
1268
return $sub;
1269
}
1270
}
1271
-
1272
- //didn't find anything yet
1273
return false;
1274
}
1275
-
1276
/**
1277
* Create a new subscription with Stripe
1278
- *
1279
* @since 1.4
1280
*/
1281
function subscribe(&$order, $checkout = true)
1282
{
1283
global $pmpro_currency;
1284
-
1285
//create a code for the order
1286
if(empty($order->code))
1287
$order->code = $order->getRandomCode();
1288
-
1289
//filter order before subscription. use with care.
1290
$order = apply_filters("pmpro_subscribe_order", $order, $this);
1291
-
1292
//figure out the user
1293
if(!empty($order->user_id))
1294
$user_id = $order->user_id;
@@ -1297,28 +1297,28 @@
1297
global $current_user;
1298
$user_id = $current_user->ID;
1299
}
1300
-
1301
//setup customer
1302
$result = $this->getCustomer($order);
1303
if(empty($result))
1304
return false; //error retrieving customer
1305
-
1306
//set subscription id to custom id
1307
$order->subscription_transaction_id = $this->customer['id']; //transaction id is the customer id, we save it in user meta later too
1308
-
1309
//figure out the amounts
1310
$amount = $order->PaymentAmount;
1311
- $amount_tax = $order->getTaxForPrice($amount);
1312
$amount = round((float)$amount + (float)$amount_tax, 2);
1313
1314
/*
1315
There are two parts to the trial. Part 1 is simply the delay until the first payment
1316
since we are doing the first payment as a separate transaction.
1317
The second part is the actual "trial" set by the admin.
1318
-
1319
Stripe only supports Year or Month for billing periods, but we account for Days and Weeks just in case.
1320
*/
1321
- //figure out the trial length (first payment handled by initial charge)
1322
if($order->BillingPeriod == "Year")
1323
$trial_period_days = $order->BillingFrequency * 365; //annual
1324
elseif($order->BillingPeriod == "Day")
@@ -1327,18 +1327,18 @@
1327
$trial_period_days = $order->BillingFrequency * 7; //weekly
1328
else
1329
$trial_period_days = $order->BillingFrequency * 30; //assume monthly
1330
-
1331
//convert to a profile start date
1332
$order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $trial_period_days . " Day", current_time("timestamp"))) . "T0:0:0";
1333
-
1334
//filter the start date
1335
- $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
1336
-
1337
- //convert back to days
1338
$trial_period_days = ceil(abs(strtotime(date("Y-m-d"), current_time("timestamp")) - strtotime($order->ProfileStartDate, current_time("timestamp"))) / 86400);
1339
1340
//for free trials, just push the start date of the subscription back
1341
- if(!empty($order->TrialBillingCycles) && $order->TrialAmount == 0)
1342
{
1343
$trialOccurrences = (int)$order->TrialBillingCycles;
1344
if($order->BillingPeriod == "Year")
@@ -1354,25 +1354,25 @@
1354
{
1355
/*
1356
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)
1357
-
1358
This will force TrialBillingCycles > 1 to act as if they were 1
1359
- */
1360
$new_user_updates = array();
1361
$new_user_updates[] = array(
1362
'when' => 'payment',
1363
'billing_amount' => $order->PaymentAmount,
1364
'cycle_period' => $order->BillingPeriod,
1365
'cycle_number' => $order->BillingFrequency
1366
- );
1367
-
1368
//now amount to equal the trial #s
1369
$amount = $order->TrialAmount;
1370
$amount_tax = $order->getTaxForPrice($amount);
1371
$amount = round((float)$amount + (float)$amount_tax, 2);
1372
- }
1373
-
1374
//create a plan
1375
- try
1376
{
1377
$plan = array(
1378
"amount" => $amount * 100,
@@ -1384,7 +1384,7 @@
1384
"id" => $order->code
1385
);
1386
1387
- $plan = Stripe_Plan::create(apply_filters('pmpro_stripe_create_plan_array', $plan));
1388
}
1389
catch (Exception $e)
1390
{
@@ -1392,54 +1392,55 @@
1392
$order->shorterror = $order->error;
1393
return false;
1394
}
1395
-
1396
//before subscribing, let's clear out the updates so we don't trigger any during sub
1397
if(!empty($user_id))
1398
- {
1399
$old_user_updates = get_user_meta($user_id, "pmpro_stripe_updates", true);
1400
- update_user_meta($user_id, "pmpro_stripe_updates", array());
1401
- }
1402
-
1403
if(empty($order->subscription_transaction_id) && !empty($this->customer['id']))
1404
$order->subscription_transaction_id = $this->customer['id'];
1405
-
1406
//subscribe to the plan
1407
try
1408
{
1409
- $result = $this->customer->subscriptions->create(array("plan" => $order->code));
1410
}
1411
catch (Exception $e)
1412
{
1413
//try to delete the plan
1414
$plan->delete();
1415
-
1416
//give the user any old updates back
1417
if(!empty($user_id))
1418
update_user_meta($user_id, "pmpro_stripe_updates", $old_user_updates);
1419
-
1420
//return error
1421
$order->error = __("Error subscribing customer to plan with Stripe:", "pmpro") . $e->getMessage();
1422
$order->shorterror = $order->error;
1423
return false;
1424
}
1425
-
1426
//delete the plan
1427
$plan = Stripe_Plan::retrieve($order->code);
1428
- $plan->delete();
1429
1430
- //if we got this far, we're all good
1431
- $order->status = "success";
1432
$order->subscription_transaction_id = $result['id'];
1433
-
1434
//save new updates if this is at checkout
1435
if($checkout)
1436
- {
1437
//empty out updates unless set above
1438
if(empty($new_user_updates))
1439
$new_user_updates = array();
1440
-
1441
//update user meta
1442
- if(!empty($user_id))
1443
update_user_meta($user_id, "pmpro_stripe_updates", $new_user_updates);
1444
else
1445
{
@@ -1459,33 +1460,33 @@
1459
//give them their old updates back
1460
update_user_meta($user_id, "pmpro_stripe_updates", $old_user_updates);
1461
}
1462
-
1463
return true;
1464
- }
1465
-
1466
/**
1467
* Helper method to update the customer info via getCustomer
1468
- *
1469
* @since 1.4
1470
*/
1471
function update(&$order)
1472
{
1473
//we just have to run getCustomer which will look for the customer and update it with the new token
1474
$result = $this->getCustomer($order);
1475
-
1476
if(!empty($result))
1477
{
1478
return true;
1479
- }
1480
else
1481
{
1482
return false; //couldn't find the customer
1483
}
1484
}
1485
-
1486
/**
1487
* Cancel a subscription at Stripe
1488
- *
1489
* @since 1.4
1490
*/
1491
function cancel(&$order, $update_status = true)
@@ -1493,21 +1494,21 @@
1493
//no matter what happens below, we're going to cancel the order in our system
1494
if($update_status)
1495
$order->updateStatus("cancelled");
1496
-
1497
//require a subscription id
1498
if(empty($order->subscription_transaction_id))
1499
return false;
1500
-
1501
//find the customer
1502
- $result = $this->getCustomer($order);
1503
-
1504
if(!empty($result))
1505
{
1506
//find subscription with this order code
1507
- $subscription = $this->getSubscription($order);
1508
1509
if(!empty($subscription))
1510
- {
1511
if($this->cancelSubscriptionAtGateway($subscription))
1512
{
1513
//we're okay, going to return true later
@@ -1516,17 +1517,17 @@
1516
{
1517
$order->error = __("Could not cancel old subscription.", "pmpro");
1518
$order->shorterror = $order->error;
1519
-
1520
- return false;
1521
- }
1522
- }
1523
-
1524
/*
1525
Clear updates for this user. (But not if checking out, we would have already done that.)
1526
*/
1527
if(empty($_REQUEST['submit-checkout']))
1528
update_user_meta($order->user_id, "pmpro_stripe_updates", array());
1529
-
1530
return true;
1531
}
1532
else
@@ -1534,12 +1535,12 @@
1534
$order->error = __("Could not find the customer.", "pmpro");
1535
$order->shorterror = $order->error;
1536
return false; //no customer found
1537
- }
1538
- }
1539
-
1540
/**
1541
* Helper method to cancel a subscription at Stripe and also clear up any upaid invoices.
1542
- *
1543
* @since 1.8
1544
*/
1545
function cancelSubscriptionAtGateway($subscription)
@@ -1547,50 +1548,50 @@
1547
//need a valid sub
1548
if(empty($subscription->id))
1549
return false;
1550
-
1551
//make sure we get the customer for this subscription
1552
$order = new MemberOrder();
1553
- $order->getLastMemberOrderBySubscriptionTransactionID($subscription->id);
1554
-
1555
//no order?
1556
if(empty($order))
1557
{
1558
//lets cancel anyway, but this is suspicious
1559
$r = $subscription->cancel();
1560
-
1561
return true;
1562
}
1563
-
1564
//okay have an order, so get customer so we can cancel invoices too
1565
$this->getCustomer($order);
1566
-
1567
//get open invoices
1568
$invoices = $this->customer->invoices();
1569
$invoices = $invoices->all();
1570
-
1571
//found it, cancel it
1572
try
1573
- {
1574
//find any open invoices for this subscription and forgive them
1575
if(!empty($invoices))
1576
{
1577
foreach($invoices->data as $invoice)
1578
- {
1579
if(!$invoice->closed && $invoice->subscription == $subscription->id)
1580
- {
1581
$invoice->closed = true;
1582
$invoice->save();
1583
}
1584
}
1585
- }
1586
-
1587
//cancel
1588
$r = $subscription->cancel();
1589
-
1590
return true;
1591
}
1592
catch(Exception $e)
1593
- {
1594
return false;
1595
}
1596
}
1
+ <?php
2
//include pmprogateway
3
+ require_once(dirname(__FILE__) . "/class.pmprogateway.php");
4
+
5
//load classes init method
6
add_action('init', array('PMProGateway_stripe', 'init'));
7
+
8
/**
9
* PMProGateway_stripe Class
10
*
16
{
17
/**
18
* Stripe Class Constructor
19
+ *
20
* @since 1.4
21
*/
22
function PMProGateway_stripe($gateway = NULL)
23
{
24
$this->gateway = $gateway;
25
$this->gateway_environment = pmpro_getOption("gateway_environment");
26
+
27
+ $this->loadStripeLibrary();
28
Stripe::setApiKey(pmpro_getOption("stripe_secretkey"));
29
+
30
return $this->gateway;
31
+ }
32
+
33
/**
34
* Load the Stripe API library.
35
+ *
36
* @since 1.8
37
+ * Moved into a method in version 1.8 so we only load it when needed.
38
*/
39
function loadStripeLibrary()
40
{
42
if(!class_exists("Stripe"))
43
require_once(dirname(__FILE__) . "/../../includes/lib/Stripe/Stripe.php");
44
}
45
+
46
/**
47
* Run on WP init
48
+ *
49
* @since 1.8
50
*/
51
static function init()
52
+ {
53
//make sure Stripe is a gateway option
54
add_filter('pmpro_gateways', array('PMProGateway_stripe', 'pmpro_gateways'));
55
+
56
//add fields to payment settings
57
add_filter('pmpro_payment_options', array('PMProGateway_stripe', 'pmpro_payment_options'));
58
add_filter('pmpro_payment_option_fields', array('PMProGateway_stripe', 'pmpro_payment_option_fields'), 10, 2);
59
+
60
//add some fields to edit user page (Updates)
61
add_action('pmpro_after_membership_level_profile_fields', array('PMProGateway_stripe', 'user_profile_fields'));
62
add_action('profile_update', array('PMProGateway_stripe', 'user_profile_fields_save'));
63
+
64
//old global RE showing billing address or not
65
global $pmpro_stripe_lite;
66
$pmpro_stripe_lite = apply_filters("pmpro_stripe_lite", !pmpro_getOption("stripe_billingaddress")); //default is oposite of the stripe_billingaddress setting
67
+
68
//updates cron
69
add_action('pmpro_activation', array('PMProGateway_stripe', 'pmpro_activation'));
70
add_action('pmpro_deactivation', array('PMProGateway_stripe', 'pmpro_deactivation'));
71
add_action('pmpro_cron_stripe_subscription_updates', array('PMProGateway_stripe', 'pmpro_cron_stripe_subscription_updates'));
72
+
73
//code to add at checkout if Stripe is the current gateway
74
$gateway = pmpro_getOption("gateway");
75
if($gateway == "stripe")
76
{
77
+ add_action('pmpro_checkout_preheader', array('PMProGateway_stripe', 'pmpro_checkout_preheader'));
78
add_filter('pmpro_checkout_order', array('PMProGateway_stripe', 'pmpro_checkout_order'));
79
add_filter('pmpro_include_billing_address_fields', array('PMProGateway_stripe', 'pmpro_include_billing_address_fields'));
80
add_filter('pmpro_include_cardtype_field', array('PMProGateway_stripe', 'pmpro_include_billing_address_fields'));
81
add_filter('pmpro_include_payment_information_fields', array('PMProGateway_stripe', 'pmpro_include_payment_information_fields'));
82
}
83
}
84
+
85
/**
86
* Make sure Stripe is in the gateways list
87
+ *
88
* @since 1.8
89
*/
90
static function pmpro_gateways($gateways)
91
{
92
if(empty($gateways['stripe']))
93
$gateways['stripe'] = __('Stripe', 'pmpro');
94
+
95
return $gateways;
96
}
97
+
98
/**
99
* Get a list of payment options that the Stripe gateway needs/supports.
100
+ *
101
* @since 1.8
102
*/
103
static function getGatewayOptions()
104
+ {
105
$options = array(
106
'sslseal',
107
'nuclear_HTTPS',
115
'tax_rate',
116
'accepted_credit_cards'
117
);
118
+
119
return $options;
120
}
121
+
122
/**
123
* Set payment options for payment settings page.
124
+ *
125
* @since 1.8
126
*/
127
static function pmpro_payment_options($options)
128
+ {
129
//get stripe options
130
$stripe_options = PMProGateway_stripe::getGatewayOptions();
131
+
132
//merge with others.
133
$options = array_merge($stripe_options, $options);
134
+
135
return $options;
136
}
137
+
138
/**
139
* Display fields for Stripe options.
140
+ *
141
* @since 1.8
142
*/
143
static function pmpro_payment_option_fields($values, $gateway)
144
{
145
?>
146
+ <tr class="pmpro_settings_divider gateway gateway_stripe" <?php if($gateway != "stripe") { ?>style="display: none;"<?php } ?>>
147
<td colspan="2">
148
<?php _e('Stripe Settings', 'pmpro'); ?>
149
</td>
171
<td>
172
<select id="stripe_billingaddress" name="stripe_billingaddress">
173
<option value="0" <?php if(empty($values['stripe_billingaddress'])) { ?>selected="selected"<?php } ?>><?php _e('No', 'pmpro');?></option>
174
+ <option value="1" <?php if(!empty($values['stripe_billingaddress'])) { ?>selected="selected"<?php } ?>><?php _e('Yes', 'pmpro');?></option>
175
</select>
176
<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>", 'pmpro');?></small>
177
</td>
183
<td>
184
<p><?php _e('To fully integrate with Stripe, be sure to set your Web Hook URL to', 'pmpro');?> <pre><?php echo admin_url("admin-ajax.php") . "?action=stripe_webhook";?></pre></p>
185
</td>
186
+ </tr>
187
<?php
188
}
189
+
190
/**
191
* Code added to checkout preheader.
192
+ *
193
* @since 1.8
194
*/
195
static function pmpro_checkout_preheader()
196
+ {
197
global $gateway, $pmpro_level;
198
+
199
if($gateway == "stripe" && !pmpro_isLevelFree($pmpro_level))
200
{
201
//stripe js library
202
wp_enqueue_script("stripe", "https://js.stripe.com/v2/", array(), NULL);
203
+
204
//stripe js code for checkout
205
function pmpro_stripe_javascript()
206
{
207
global $pmpro_gateway, $pmpro_level, $pmpro_stripe_lite;
208
?>
209
<script type="text/javascript">
210
+ // this identifies your website in the createToken call below
211
Stripe.setPublishableKey('<?php echo pmpro_getOption("stripe_publishablekey"); ?>');
212
+
213
+ var pmpro_require_billing = true;
214
+
215
jQuery(document).ready(function() {
216
jQuery("#pmpro_form, .pmpro_form").submit(function(event) {
217
+
218
+ //double check in case a discount code made the level free
219
if(pmpro_require_billing)
220
{
221
//build array for creating token
231
?>
232
,address_line1: jQuery('#baddress1').val(),
233
address_line2: jQuery('#baddress2').val(),
234
+ address_city: jQuery('#bcity').val(),
235
+ address_state: jQuery('#bstate').val(),
236
+ address_zip: jQuery('#bzipcode').val(),
237
address_country: jQuery('#bcountry').val()
238
<?php
239
}
240
+ ?>
241
};
242
+
243
if (jQuery('#bfirstname').length && jQuery('#blastname').length)
244
args['name'] = jQuery.trim(jQuery('#bfirstname').val() + ' ' + jQuery('#blastname').val());
245
+
246
//create token
247
Stripe.createToken(args, stripeResponseHandler);
248
261
262
//hide processing message
263
jQuery('#pmpro_processing_message').css('visibility', 'hidden');
264
+
265
// show the errors on the form
266
alert(response.error.message);
267
jQuery(".payment-errors").text(response.error.message);
268
} else {
269
+ var form$ = jQuery("#pmpro_form, .pmpro_form");
270
// token contains id, last4, and card type
271
+ var token = response['id'];
272
// insert the token into the form so it gets submitted to the server
273
form$.append("<input type='hidden' name='stripeToken' value='" + token + "'/>");
274
+
275
console.log(response);
276
+
277
//insert fields for other card fields
278
if(jQuery('#CardType[name=CardType]').length)
279
jQuery('#CardType').val(response['card']['brand']);
281
form$.append("<input type='hidden' name='CardType' value='" + response['card']['brand'] + "'/>");
282
form$.append("<input type='hidden' name='AccountNumber' value='XXXXXXXXXXXXX" + response['card']['last4'] + "'/>");
283
form$.append("<input type='hidden' name='ExpirationMonth' value='" + ("0" + response['card']['exp_month']).slice(-2) + "'/>");
284
+ form$.append("<input type='hidden' name='ExpirationYear' value='" + response['card']['exp_year'] + "'/>");
285
+
286
// and submit
287
form$.get(0).submit();
288
}
291
<?php
292
}
293
add_action("wp_head", "pmpro_stripe_javascript");
294
+
295
//don't require the CVV
296
function pmpro_stripe_dont_require_CVV($fields)
297
{
298
+ unset($fields['CVV']);
299
return $fields;
300
}
301
add_filter("pmpro_required_billing_fields", "pmpro_stripe_dont_require_CVV");
302
}
303
}
304
+
305
/**
306
* Filtering orders at checkout.
307
+ *
308
* @since 1.8
309
*/
310
static function pmpro_checkout_order($morder)
314
{
315
$morder->stripeToken = $_REQUEST['stripeToken'];
316
}
317
+
318
//stripe lite code to get name from other sources if available
319
global $pmpro_stripe_lite, $current_user;
320
if(!empty($pmpro_stripe_lite) && empty($morder->FirstName) && empty($morder->LastName))
321
{
322
if(!empty($current_user->ID))
323
+ {
324
$morder->FirstName = get_user_meta($current_user->ID, "first_name", true);
325
$morder->LastName = get_user_meta($current_user->ID, "last_name", true);
326
}
330
$morder->LastName = $_REQUEST['last_name'];
331
}
332
}
333
+
334
return $morder;
335
}
336
+
337
/**
338
* Code to run after checkout
339
+ *
340
* @since 1.8
341
*/
342
+ static function pmpro_after_checkout($user_id, $morder)
343
{
344
global $gateway;
345
+
346
if($gateway == "stripe")
347
{
348
if(!empty($morder) && !empty($morer->Gateway) && !empty($morder->Gateway->customer) && !empty($morder->Gateway->customer->id))
351
}
352
}
353
}
354
+
355
/**
356
* Check settings if billing address should be shown.
357
* @since 1.8
361
//check settings RE showing billing address
362
if(!pmpro_getOption("stripe_billingaddress"))
363
$include = false;
364
+
365
return $include;
366
}
367
+
368
/**
369
* Use our own payment fields at checkout. (Remove the name attributes.)
370
* @since 1.8
371
*/
372
static function pmpro_include_payment_information_fields($include)
373
+ {
374
//global vars
375
global $pmpro_requirebilling, $pmpro_show_discount_code, $discount_code, $CardType, $AccountNumber, $ExpirationMonth, $ExpirationYear;
376
+
377
//get accepted credit cards
378
$pmpro_accepted_credit_cards = pmpro_getOption("accepted_credit_cards");
379
$pmpro_accepted_credit_cards = explode(",", $pmpro_accepted_credit_cards);
380
+ $pmpro_accepted_credit_cards_string = pmpro_implodeToEnglish($pmpro_accepted_credit_cards);
381
+
382
//include ours
383
?>
384
<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 } ?>>
388
</tr>
389
</thead>
390
<tbody>
391
+ <tr valign="top">
392
+ <td>
393
<?php
394
$sslseal = pmpro_getOption("sslseal");
395
if($sslseal)
409
<select id="CardType" class=" <?php echo pmpro_getClassForField("CardType");?>">
410
<?php foreach($pmpro_accepted_credit_cards as $cc) { ?>
411
<option value="<?php echo $cc?>" <?php if($CardType == $cc) { ?>selected="selected"<?php } ?>><?php echo $cc?></option>
412
+ <?php } ?>
413
</select>
414
</div>
415
<?php
419
?>
420
<input type="hidden" id="CardType" name="CardType" value="<?php echo esc_attr($CardType);?>" />
421
<script>
422
+ jQuery(document).ready(function() {
423
+ jQuery('#AccountNumber').validateCreditCard(function(result) {
424
var cardtypenames = {
425
"amex":"American Express",
426
"diners_club_carte_blanche":"Diners Club Carte Blanche",
433
"visa":"Visa",
434
"visa_electron":"Visa Electron"
435
}
436
+
437
if(result.card_type)
438
jQuery('#CardType').val(cardtypenames[result.card_type.name]);
439
else
440
jQuery('#CardType').val('Unknown Card Type');
441
+ });
442
});
443
</script>
444
<?php
445
}
446
?>
447
+
448
<div class="pmpro_payment-account-number">
449
<label for="AccountNumber"><?php _e('Card Number', 'pmpro');?></label>
450
<input id="AccountNumber" class="input <?php echo pmpro_getClassForField("AccountNumber");?>" type="text" size="25" value="<?php echo esc_attr($AccountNumber)?>" autocomplete="off" />
451
</div>
452
+
453
<div class="pmpro_payment-expiration">
454
<label for="ExpirationMonth"><?php _e('Expiration Date', 'pmpro');?></label>
455
<select id="ExpirationMonth" class=" <?php echo pmpro_getClassForField("ExpirationMonth");?>">
474
<?php
475
}
476
?>
477
+ </select>
478
</div>
479
+
480
<?php
481
$pmpro_show_cvv = apply_filters("pmpro_show_cvv", true);
482
if($pmpro_show_cvv)
489
<?php
490
}
491
?>
492
+
493
<?php if($pmpro_show_discount_code) { ?>
494
<div class="pmpro_payment-discount-code">
495
<label for="discount_code"><?php _e('Discount Code', 'pmpro');?></label>
498
<p id="discount_code_message" class="pmpro_message" style="display: none;"></p>
499
</div>
500
<?php } ?>
501
+
502
+ </td>
503
</tr>
504
</tbody>
505
</table>
506
<?php
507
+
508
//don't include the default
509
return false;
510
}
511
+
512
/**
513
* Fields shown on edit user page
514
+ *
515
* @since 1.8
516
*/
517
static function user_profile_fields($user)
521
$cycles = array( __('Day(s)', 'pmpro') => 'Day', __('Week(s)', 'pmpro') => 'Week', __('Month(s)', 'pmpro') => 'Month', __('Year(s)', 'pmpro') => 'Year' );
522
$current_year = date("Y");
523
$current_month = date("m");
524
+
525
//make sure the current user has privileges
526
$membership_level_capability = apply_filters("pmpro_edit_member_capability", "manage_options");
527
if(!current_user_can($membership_level_capability))
528
return false;
529
530
+ //more privelges they should have
531
$show_membership_level = apply_filters("pmpro_profile_show_membership_level", true, $user);
532
if(!$show_membership_level)
533
return false;
534
+
535
//check that user has a current subscription at Stripe
536
$last_order = new MemberOrder();
537
$last_order->getLastMemberOrder($user->ID);
538
+
539
//assume no sub to start
540
$sub = false;
541
+
542
//check that gateway is Stripe
543
if($last_order->gateway == "stripe")
544
+ {
545
//is there a customer?
546
+ $sub = $last_order->Gateway->getSubscription($last_order);
547
+ }
548
+
549
$customer_id = $user->pmpro_stripe_customerid;
550
+
551
if(empty($sub))
552
{
553
//make sure we delete stripe updates
554
update_user_meta($user->ID, "pmpro_stripe_updates", array());
555
+
556
//if the last order has a sub id, let the admin know there is no sub at Stripe
557
if(!empty($last_order) && $last_order->gateway == "stripe" && !empty($last_order->subscription_transaction_id) && strpos($last_order->subscription_transaction_id, "sub_") !== false)
558
{
559
?>
560
<p><strong>Note:</strong> Subscription <strong><?php echo $last_order->subscription_transaction_id;?></strong> could not be found at Stripe. It might have been deleted.</p>
561
<?php
562
+ }
563
}
564
+ else
565
+ {
566
?>
567
<h3><?php _e("Subscription Updates", "pmpro"); ?></h3>
568
<p>
578
<th><label for="membership_level"><?php _e("Update", "pmpro"); ?></label></th>
579
<td id="updates_td">
580
<?php
581
+ $old_updates = $user->pmpro_stripe_updates;
582
if(is_array($old_updates))
583
{
584
$updates = array_merge(
588
}
589
else
590
$updates = array(array('template'=>true, 'when'=>'now', 'date_month'=>'', 'date_day'=>'', 'date_year'=>'', 'billing_amount'=>'', 'cycle_number'=>'', 'cycle_period'=>'Month'));
591
+
592
foreach($updates as $update)
593
{
594
?>
595
<div class="updates_update" <?php if(!empty($update['template'])) { ?>style="display: none;"<?php } ?>>
596
+ <select class="updates_when" name="updates_when[]">
597
<option value="now" <?php selected($update['when'], "now");?>>Now</option>
598
<option value="payment" <?php selected($update['when'], "payment");?>>After Next Payment</option>
599
<option value="date" <?php selected($update['when'], "date");?>>On Date</option>
600
</select>
601
<span class="updates_date" <?php if($uwhen != "date") { ?>style="display: none;"<?php } ?>>
602
<select name="updates_date_month[]">
603
+ <?php
604
for($i = 1; $i < 13; $i++)
605
{
606
?>
619
<small><?php _e('per', 'pmpro');?></small>
620
<input name="updates_cycle_number[]" type="text" size="5" value="<?php echo esc_attr($update['cycle_number']);?>" />
621
<select name="updates_cycle_period[]">
622
+ <?php
623
foreach ( $cycles as $name => $value ) {
624
echo "<option value='$value'";
625
if(!empty($update['cycle_period']) && $update['cycle_period'] == $value) echo " selected='selected'";
627
}
628
?>
629
</select>
630
+ </span>
631
<span>
632
+ <a class="updates_remove" href="javascript:void(0);">Remove</a>
633
</span>
634
</div>
635
<?php
636
}
637
+ ?>
638
<p><a id="updates_new_update" href="javascript:void(0);">+ New Update</a></p>
639
</td>
640
+ </tr>
641
+ </table>
642
<script>
643
jQuery(document).ready(function() {
644
//function to update dropdowns/etc based on when field
648
jQuery(when).parent().children('.updates_date').show();
649
else
650
jQuery(when).parent().children('.updates_date').hide();
651
+
652
if(jQuery(when).val() == 'no')
653
jQuery(when).parent().children('.updates_billing').hide();
654
else
655
jQuery(when).parent().children('.updates_billing').show();
656
+ }
657
658
//and update on page load
659
jQuery('.updates_when').each(function() { if(jQuery(this).parent().css('display') != 'none') updateSubscriptionUpdateFields(this); });
660
+
661
//add a new update when clicking to
662
var num_updates_divs = <?php echo count($updates);?>;
663
jQuery('#updates_new_update').click(function() {
664
//get updates
665
updates = jQuery('.updates_update').toArray();
666
+
667
//clone the first one
668
+ new_div = jQuery(updates[0]).clone();
669
+
670
//append
671
new_div.insertBefore('#updates_new_update');
672
+
673
//update events
674
addUpdateEvents()
675
+
676
//unhide it
677
new_div.show();
678
+ updateSubscriptionUpdateFields(new_div.children('.updates_when'));
679
});
680
+
681
function addUpdateEvents()
682
{
683
//update when when changes
684
jQuery('.updates_when').change(function() {
685
updateSubscriptionUpdateFields(this);
686
});
687
+
688
//remove updates when clicking
689
+ jQuery('.updates_remove').click(function() {
690
jQuery(this).parent().parent().remove();
691
});
692
}
696
<?php
697
}
698
}
699
+
700
/**
701
* Process fields from the edit user page
702
+ *
703
* @since 1.8
704
*/
705
static function user_profile_fields_save($user_id)
706
{
707
global $wpdb;
708
+
709
//check capabilities
710
$membership_level_capability = apply_filters("pmpro_edit_member_capability", "manage_options");
711
if(!current_user_can($membership_level_capability))
712
return false;
713
+
714
//make sure some value was passed
715
if(!isset($_POST['updates_when']) || !is_array($_POST['updates_when']))
716
return;
717
+
718
//vars
719
$updates = array();
720
$next_on_date_update = "";
721
+
722
//build array of updates (we skip the first because it's the template field for the JavaScript
723
for($i = 1; $i < count($_POST['updates_when']); $i++)
724
{
725
$update = array();
726
+
727
//all updates have these values
728
$update['when'] = $_POST['updates_when'][$i];
729
$update['billing_amount'] = $_POST['updates_billing_amount'][$i];
730
$update['cycle_number'] = $_POST['updates_cycle_number'][$i];
731
$update['cycle_period'] = $_POST['updates_cycle_period'][$i];
732
+
733
//these values only for on date updates
734
if($_POST['updates_when'][$i] == "date")
735
{
737
$update['date_day'] = str_pad($_POST['updates_date_day'][$i], 2, "0", STR_PAD_LEFT);
738
$update['date_year'] = $_POST['updates_date_year'][$i];
739
}
740
+
741
//make sure the update is valid
742
if(empty($update['cycle_number']))
743
continue;
744
+
745
//if when is now, update the subscription
746
if($update['when'] == "now")
747
{
748
//get level for user
749
$user_level = pmpro_getMembershipLevelForUser($user_id);
750
+
751
//get current plan at Stripe to get payment date
752
$last_order = new MemberOrder();
753
$last_order->getLastMemberOrder($user_id);
755
$last_order->Gateway->getCustomer($last_order);
756
757
$subscription = $last_order->Gateway->getSubscription($last_order);
758
+
759
if(!empty($subscription))
760
+ {
761
$end_timestamp = $subscription->current_period_end;
762
+
763
+ //cancel the old subscription
764
if(!$last_order->Gateway->cancelSubscriptionAtGateway($subscription))
765
{
766
//throw error and halt save
767
+ function pmpro_stripe_user_profile_fields_save_error($errors, $update, $user)
768
{
769
$errors->add('pmpro_stripe_updates',__('Could not cancel the old subscription. Updates have not been processed.', 'pmpro'));
770
}
771
add_filter('user_profile_update_errors', 'pmpro_stripe_user_profile_fields_save_error', 10, 3);
772
+
773
//stop processing updates
774
return;
775
}
776
}
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');
789
$update_order->PaymentAmount = $update['billing_amount'];
790
$update_order->ProfileStartDate = date("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']) . "',
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
}
820
elseif($update['when'] == 'date')
824
else
825
$next_on_date_update = $update['date_year'] . "-" . $update['date_month'] . "-" . $update['date_day'];
826
}
827
+
828
+ //add to array
829
+ $updates[] = $update;
830
}
831
+
832
//save in user meta
833
update_user_meta($user_id, "pmpro_stripe_updates", $updates);
834
+
835
//save date of next on-date update to make it easier to query for these in cron job
836
update_user_meta($user_id, "pmpro_stripe_next_on_date_update", $next_on_date_update);
837
}
838
+
839
/**
840
* Cron activation for subscription updates.
841
+ *
842
* @since 1.8
843
*/
844
static function pmpro_activation()
845
{
846
wp_schedule_event(time(), 'daily', 'pmpro_cron_stripe_subscription_updates');
847
}
848
+
849
/**
850
* Cron deactivation for subscription updates.
851
+ *
852
* @since 1.8
853
*/
854
static function pmpro_deactivation()
855
{
856
wp_clear_scheduled_hook('pmpro_cron_stripe_subscription_updates');
857
}
858
+
859
/**
860
* Cron job for subscription updates.
861
+ *
862
* @since 1.8
863
*/
864
static function pmpro_cron_stripe_subscription_updates()
866
global $wpdb;
867
868
//get all updates for today (or before today)
869
+ $sqlQuery = "SELECT *
870
+ FROM $wpdb->usermeta
871
+ WHERE meta_key = 'pmpro_stripe_next_on_date_update'
872
+ AND meta_value IS NOT NULL
873
+ AND meta_value < '" . date("Y-m-d", strtotime("+1 day")) . "'";
874
$updates = $wpdb->get_results($sqlQuery);
875
+
876
if(!empty($updates))
877
+ {
878
//loop through
879
foreach($updates as $update)
880
+ {
881
//pull values from update
882
$user_id = $update->user_id;
883
+
884
$user = get_userdata($user_id);
885
$user_updates = $user->pmpro_stripe_updates;
886
+ $next_on_date_update = "";
887
+
888
//loop through updates looking for updates happening today or earlier
889
foreach($user_updates as $key => $update)
890
+ {
891
if($update['when'] == 'date' &&
892
$update['date_year'] . "-" . $update['date_month'] . "-" . $update['date_day'] <= date("Y-m-d")
893
)
894
{
895
//get level for user
896
$user_level = pmpro_getMembershipLevelForUser($user_id);
897
+
898
//get current plan at Stripe to get payment date
899
$last_order = new MemberOrder();
900
$last_order->getLastMemberOrder($user_id);
901
$last_order->setGateway('stripe');
902
$last_order->Gateway->getCustomer($last_order);
903
+
904
if(!empty($last_order->Gateway->customer))
905
{
906
//find the first subscription
910
$end_timestamp = $first_sub['current_period_end'];
911
}
912
}
913
+
914
//if we didn't get an end date, let's set one one cycle out
915
$end_timestamp = strtotime("+" . $update['cycle_number'] . " " . $update['cycle_period']);
916
+
917
//build order object
918
$update_order = new MemberOrder();
919
$update_order->setGateway('stripe');
925
$update_order->ProfileStartDate = date("Y-m-d", $end_timestamp);
926
$update_order->BillingPeriod = $update['cycle_period'];
927
$update_order->BillingFrequency = $update['cycle_number'];
928
+
929
//update subscription
930
$update_order->Gateway->subscribe($update_order, false);
931
+
932
//update membership
933
+ $sqlQuery = "UPDATE $wpdb->pmpro_memberships_users
934
+ SET billing_amount = '" . esc_sql($update['billing_amount']) . "',
935
+ cycle_number = '" . esc_sql($update['cycle_number']) . "',
936
+ cycle_period = '" . esc_sql($update['cycle_period']) . "'
937
+ WHERE user_id = '" . esc_sql($user_id) . "'
938
+ AND membership_id = '" . esc_sql($last_order->membership_id) . "'
939
+ AND status = 'active'
940
LIMIT 1";
941
+
942
$wpdb->query($sqlQuery);
943
+
944
//save order
945
$update_order->status = "success";
946
$update_order->save();
947
+
948
//remove update from list
949
+ unset($user_updates[$key]);
950
}
951
elseif($update['when'] == 'date')
952
{
957
$next_on_date_update = $update['date_year'] . "-" . $update['date_month'] . "-" . $update['date_day'];
958
}
959
}
960
+
961
//save updates in case we removed some
962
update_user_meta($user_id, "pmpro_stripe_updates", $user_updates);
963
+
964
//save date of next on-date update to make it easier to query for these in cron job
965
update_user_meta($user_id, "pmpro_stripe_next_on_date_update", $next_on_date_update);
966
}
967
}
968
}
969
+
970
/**
971
* Process checkout and decide if a charge and or subscribe is needed
972
+ *
973
* @since 1.4
974
*/
975
function process(&$order)
986
if($this->charge($order))
987
{
988
if(pmpro_isLevelRecurring($order->membership_level))
989
+ {
990
if($this->subscribe($order))
991
{
992
//yay!
1001
else
1002
{
1003
//only a one time charge
1004
+ $order->status = "success"; //saved on checkout page
1005
return true;
1006
}
1007
}
1011
$order->error = __("Unknown error: Initial payment failed.", "pmpro");
1012
return false;
1013
}
1014
+ }
1015
+ }
1016
+
1017
/**
1018
* Make a one-time charge with Stripe
1019
+ *
1020
* @since 1.4
1021
*/
1022
function charge(&$order)
1023
{
1024
global $pmpro_currency;
1025
+
1026
//create a code for the order
1027
if(empty($order->code))
1028
$order->code = $order->getRandomCode();
1029
+
1030
+ //what amount to charge?
1031
$amount = $order->InitialPayment;
1032
+
1033
//tax
1034
$order->subtotal = $amount;
1035
$tax = $order->getTax(true);
1036
$amount = round((float)$order->subtotal + (float)$tax, 2);
1037
+
1038
//create a customer
1039
$result = $this->getCustomer($order);
1040
+
1041
if(empty($result))
1042
+ {
1043
//failed to create customer
1044
return false;
1045
+ }
1046
+
1047
//charge
1048
try
1049
{
1063
$order->shorterror = $order->error;
1064
return false;
1065
}
1066
+
1067
if(empty($response["failure_message"]))
1068
{
1069
//successful charge
1070
$order->payment_transaction_id = $response["id"];
1071
+ $order->updateStatus("success");
1072
+ return true;
1073
}
1074
else
1075
{
1078
$order->error = $response['failure_message'];
1079
$order->shorterror = $response['failure_message'];
1080
return false;
1081
+ }
1082
}
1083
+
1084
/**
1085
* Get a Stripe customer object.
1086
+ *
1087
* If $this->customer is set, it returns it.
1088
* It first checks if the order has a subscription_transaction_id. If so, that's the customer id.
1089
* If not, it checks for a user_id on the order and searches for a customer id in the user meta.
1097
function getCustomer(&$order = false, $force = false)
1098
{
1099
global $current_user;
1100
+
1101
//already have it?
1102
if(!empty($this->customer) && !$force)
1103
return $this->customer;
1104
+
1105
//figure out user_id and user
1106
if(!empty($order->user_id))
1107
$user_id = $order->user_id;
1108
+
1109
//if no id passed, check the current user
1110
if(empty($user_id) && !empty($current_user->ID))
1111
$user_id = $current_user->ID;
1112
+
1113
if(!empty($user_id))
1114
$user = get_userdata($user_id);
1115
else
1116
$user = NULL;
1117
+
1118
//transaction id?
1119
if(!empty($order->subscription_transaction_id) && strpos($order->subscription_transaction_id, "cus_") !== false)
1120
$customer_id = $order->subscription_transaction_id;
1121
else
1122
{
1123
+ //try based on user id
1124
if(!empty($user_id))
1125
+ {
1126
+ $customer_id = get_user_meta($user_id, "pmpro_stripe_customerid", true);
1127
}
1128
+ }
1129
+
1130
//get name and email values from order in case we update
1131
$name = trim($order->FirstName . " " . $order->LastName);
1132
if(empty($name) && !empty($user->ID))
1133
{
1134
$name = trim($user->first_name . " " . $user->last_name);
1135
+
1136
//still empty?
1137
if(empty($name))
1138
$name = $user->user_login;
1140
elseif(empty($name))
1141
$name = "No Name";
1142
1143
+ $email = $order->Email;
1144
if(empty($email) && !empty($user->ID))
1145
{
1146
$email = $user->user_email;
1147
}
1148
elseif(empty($email))
1149
$email = "No Email";
1150
+
1151
//check for an existing stripe customer
1152
if(!empty($customer_id))
1153
{
1154
try
1155
{
1156
$this->customer = Stripe_Customer::retrieve($customer_id);
1157
+
1158
//update the customer description and card
1159
if(!empty($order->stripeToken))
1160
+ {
1161
$this->customer->description = $name . " (" . $email . ")";
1162
$this->customer->email = $email;
1163
$this->customer->card = $order->stripeToken;
1164
$this->customer->save();
1165
}
1166
+
1167
return $this->customer;
1168
}
1169
catch (Exception $e)
1170
{
1171
+ //assume no customer found
1172
}
1173
}
1174
+
1175
//no customer id, create one
1176
if(!empty($order->stripeToken))
1177
+ {
1178
try
1179
{
1180
$this->customer = Stripe_Customer::create(array(
1189
$order->shorterror = $order->error;
1190
return false;
1191
}
1192
+
1193
if(!empty($user_id))
1194
{
1195
//user logged in/etc
1196
+ update_user_meta($user_id, "pmpro_stripe_customerid", $this->customer->id);
1197
}
1198
else
1199
{
1210
1211
return apply_filters('pmpro_stripe_create_customer', $this->customer);
1212
}
1213
+
1214
+ return false;
1215
}
1216
+
1217
/**
1218
* Get a Stripe subscription from a PMPro order
1219
+ *
1220
* @since 1.8
1221
*/
1222
+ function getSubscription(&$order)
1223
{
1224
global $wpdb;
1225
+
1226
//no order?
1227
if(empty($order) || empty($order->code))
1228
+ return false;
1229
+
1230
$result = $this->getCustomer($order, true); //force so we don't get a cached sub for someone else
1231
+
1232
//no customer?
1233
if(empty($result))
1234
return false;
1235
+
1236
//is there a subscription transaction id pointing to a sub?
1237
if(!empty($order->subscription_transaction_id) && strpos($order->subscription_transaction_id, "sub_") !== false)
1238
{
1246
$order->shorterror = $order->error;
1247
return false;
1248
}
1249
+
1250
return $sub;
1251
+ }
1252
+
1253
//find subscription based on customer id and order/plan id
1254
+ $subscriptions = $this->customer->subscriptions->all();
1255
+
1256
//no subscriptions
1257
if(empty($subscriptions) || empty($subscriptions->data))
1258
+ return false;
1259
+
1260
//we really want to test against the order codes of all orders with the same subscription_transaction_id (customer id)
1261
$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')");
1262
+
1263
//find the one for this order
1264
foreach($subscriptions->data as $sub)
1265
+ {
1266
if(in_array($sub->plan->id, $codes))
1267
{
1268
return $sub;
1269
}
1270
}
1271
+
1272
+ //didn't find anything yet
1273
return false;
1274
}
1275
+
1276
/**
1277
* Create a new subscription with Stripe
1278
+ *
1279
* @since 1.4
1280
*/
1281
function subscribe(&$order, $checkout = true)
1282
{
1283
global $pmpro_currency;
1284
+
1285
//create a code for the order
1286
if(empty($order->code))
1287
$order->code = $order->getRandomCode();
1288
+
1289
//filter order before subscription. use with care.
1290
$order = apply_filters("pmpro_subscribe_order", $order, $this);
1291
+
1292
//figure out the user
1293
if(!empty($order->user_id))
1294
$user_id = $order->user_id;
1297
global $current_user;
1298
$user_id = $current_user->ID;
1299
}
1300
+
1301
//setup customer
1302
$result = $this->getCustomer($order);
1303
if(empty($result))
1304
return false; //error retrieving customer
1305
+
1306
//set subscription id to custom id
1307
$order->subscription_transaction_id = $this->customer['id']; //transaction id is the customer id, we save it in user meta later too
1308
+
1309
//figure out the amounts
1310
$amount = $order->PaymentAmount;
1311
+ $amount_tax = $order->getTaxForPrice($amount);
1312
$amount = round((float)$amount + (float)$amount_tax, 2);
1313
1314
/*
1315
There are two parts to the trial. Part 1 is simply the delay until the first payment
1316
since we are doing the first payment as a separate transaction.
1317
The second part is the actual "trial" set by the admin.
1318
+
1319
Stripe only supports Year or Month for billing periods, but we account for Days and Weeks just in case.
1320
*/
1321
+ //figure out the trial length (first payment handled by initial charge)
1322
if($order->BillingPeriod == "Year")
1323
$trial_period_days = $order->BillingFrequency * 365; //annual
1324
elseif($order->BillingPeriod == "Day")
1327
$trial_period_days = $order->BillingFrequency * 7; //weekly
1328
else
1329
$trial_period_days = $order->BillingFrequency * 30; //assume monthly
1330
+
1331
//convert to a profile start date
1332
$order->ProfileStartDate = date("Y-m-d", strtotime("+ " . $trial_period_days . " Day", current_time("timestamp"))) . "T0:0:0";
1333
+
1334
//filter the start date
1335
+ $order->ProfileStartDate = apply_filters("pmpro_profile_start_date", $order->ProfileStartDate, $order);
1336
+
1337
+ //convert back to days
1338
$trial_period_days = ceil(abs(strtotime(date("Y-m-d"), current_time("timestamp")) - strtotime($order->ProfileStartDate, current_time("timestamp"))) / 86400);
1339
1340
//for free trials, just push the start date of the subscription back
1341
+ if(!empty($order->TrialBillingCycles) && $order->TrialAmount == 0)
1342
{
1343
$trialOccurrences = (int)$order->TrialBillingCycles;
1344
if($order->BillingPeriod == "Year")
1354
{
1355
/*
1356
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)
1357
+
1358
This will force TrialBillingCycles > 1 to act as if they were 1
1359
+ */
1360
$new_user_updates = array();
1361
$new_user_updates[] = array(
1362
'when' => 'payment',
1363
'billing_amount' => $order->PaymentAmount,
1364
'cycle_period' => $order->BillingPeriod,
1365
'cycle_number' => $order->BillingFrequency
1366
+ );
1367
+
1368
//now amount to equal the trial #s
1369
$amount = $order->TrialAmount;
1370
$amount_tax = $order->getTaxForPrice($amount);
1371
$amount = round((float)$amount + (float)$amount_tax, 2);
1372
+ }
1373
+
1374
//create a plan
1375
+ try
1376
{
1377
$plan = array(
1378
"amount" => $amount * 100,
1384
"id" => $order->code
1385
);
1386
1387
+ $plan = Stripe_Plan::create(apply_filters('pmpro_stripe_create_plan_array', $plan));
1388
}
1389
catch (Exception $e)
1390
{
1392
$order->shorterror = $order->error;
1393
return false;
1394
}
1395
+
1396
//before subscribing, let's clear out the updates so we don't trigger any during sub
1397
if(!empty($user_id))
1398
+ {
1399
$old_user_updates = get_user_meta($user_id, "pmpro_stripe_updates", true);
1400
+ update_user_meta($user_id, "pmpro_stripe_updates", array());
1401
+ }
1402
+
1403
if(empty($order->subscription_transaction_id) && !empty($this->customer['id']))
1404
$order->subscription_transaction_id = $this->customer['id'];
1405
+
1406
//subscribe to the plan
1407
try
1408
{
1409
+ $subscription = array("plan" => $order->code);
1410
+ $result = $this->customer->subscriptions->create(apply_filters('pmpro_stripe_create_subscription_array', $subscription));
1411
}
1412
catch (Exception $e)
1413
{
1414
//try to delete the plan
1415
$plan->delete();
1416
+
1417
//give the user any old updates back
1418
if(!empty($user_id))
1419
update_user_meta($user_id, "pmpro_stripe_updates", $old_user_updates);
1420
+
1421
//return error
1422
$order->error = __("Error subscribing customer to plan with Stripe:", "pmpro") . $e->getMessage();
1423
$order->shorterror = $order->error;
1424
return false;
1425
}
1426
+
1427
//delete the plan
1428
$plan = Stripe_Plan::retrieve($order->code);
1429
+ $plan->delete();
1430
1431
+ //if we got this far, we're all good
1432
+ $order->status = "success";
1433
$order->subscription_transaction_id = $result['id'];
1434
+
1435
//save new updates if this is at checkout
1436
if($checkout)
1437
+ {
1438
//empty out updates unless set above
1439
if(empty($new_user_updates))
1440
$new_user_updates = array();
1441
+
1442
//update user meta
1443
+ if(!empty($user_id))
1444
update_user_meta($user_id, "pmpro_stripe_updates", $new_user_updates);
1445
else
1446
{
1460
//give them their old updates back
1461
update_user_meta($user_id, "pmpro_stripe_updates", $old_user_updates);
1462
}
1463
+
1464
return true;
1465
+ }
1466
+
1467
/**
1468
* Helper method to update the customer info via getCustomer
1469
+ *
1470
* @since 1.4
1471
*/
1472
function update(&$order)
1473
{
1474
//we just have to run getCustomer which will look for the customer and update it with the new token
1475
$result = $this->getCustomer($order);
1476
+
1477
if(!empty($result))
1478
{
1479
return true;
1480
+ }
1481
else
1482
{
1483
return false; //couldn't find the customer
1484
}
1485
}
1486
+
1487
/**
1488
* Cancel a subscription at Stripe
1489
+ *
1490
* @since 1.4
1491
*/
1492
function cancel(&$order, $update_status = true)
1494
//no matter what happens below, we're going to cancel the order in our system
1495
if($update_status)
1496
$order->updateStatus("cancelled");
1497
+
1498
//require a subscription id
1499
if(empty($order->subscription_transaction_id))
1500
return false;
1501
+
1502
//find the customer
1503
+ $result = $this->getCustomer($order);
1504
+
1505
if(!empty($result))
1506
{
1507
//find subscription with this order code
1508
+ $subscription = $this->getSubscription($order);
1509
1510
if(!empty($subscription))
1511
+ {
1512
if($this->cancelSubscriptionAtGateway($subscription))
1513
{
1514
//we're okay, going to return true later
1517
{
1518
$order->error = __("Could not cancel old subscription.", "pmpro");
1519
$order->shorterror = $order->error;
1520
+
1521
+ return false;
1522
+ }
1523
+ }
1524
+
1525
/*
1526
Clear updates for this user. (But not if checking out, we would have already done that.)
1527
*/
1528
if(empty($_REQUEST['submit-checkout']))
1529
update_user_meta($order->user_id, "pmpro_stripe_updates", array());
1530
+
1531
return true;
1532
}
1533
else
1535
$order->error = __("Could not find the customer.", "pmpro");
1536
$order->shorterror = $order->error;
1537
return false; //no customer found
1538
+ }
1539
+ }
1540
+
1541
/**
1542
* Helper method to cancel a subscription at Stripe and also clear up any upaid invoices.
1543
+ *
1544
* @since 1.8
1545
*/
1546
function cancelSubscriptionAtGateway($subscription)
1548
//need a valid sub
1549
if(empty($subscription->id))
1550
return false;
1551
+
1552
//make sure we get the customer for this subscription
1553
$order = new MemberOrder();
1554
+ $order->getLastMemberOrderBySubscriptionTransactionID($subscription->id);
1555
+
1556
//no order?
1557
if(empty($order))
1558
{
1559
//lets cancel anyway, but this is suspicious
1560
$r = $subscription->cancel();
1561
+
1562
return true;
1563
}
1564
+
1565
//okay have an order, so get customer so we can cancel invoices too
1566
$this->getCustomer($order);
1567
+
1568
//get open invoices
1569
$invoices = $this->customer->invoices();
1570
$invoices = $invoices->all();
1571
+
1572
//found it, cancel it
1573
try
1574
+ {
1575
//find any open invoices for this subscription and forgive them
1576
if(!empty($invoices))
1577
{
1578
foreach($invoices->data as $invoice)
1579
+ {
1580
if(!$invoice->closed && $invoice->subscription == $subscription->id)
1581
+ {
1582
$invoice->closed = true;
1583
$invoice->save();
1584
}
1585
}
1586
+ }
1587
+
1588
//cancel
1589
$r = $subscription->cancel();
1590
+
1591
return true;
1592
}
1593
catch(Exception $e)
1594
+ {
1595
return false;
1596
}
1597
}
email/admin_change_admin.html CHANGED
@@ -1,4 +1,4 @@
1
- <p>An administrator at !!sitename!! has changed a membership level.</p>
2
3
<p>!!membership_change!!.</p>
4
1
+ <p>An administrator at !!sitename!! has changed a membership level for !!name!!.</p>
2
3
<p>!!membership_change!!.</p>
4
includes/currencies.php CHANGED
@@ -23,7 +23,14 @@
23
),
24
'CAD' => __('Canadian Dollars (&#36;)', 'pmpro'),
25
'CNY' => __('Chinese Yuan', 'pmpro'),
26
- 'CZK' => __('Czech Koruna', 'pmpro'),
27
'DKK' => __('Danish Krone', 'pmpro'),
28
'HKD' => __('Hong Kong Dollar (&#36;)', 'pmpro'),
29
'HUF' => __('Hungarian Forint', 'pmpro'),
23
),
24
'CAD' => __('Canadian Dollars (&#36;)', 'pmpro'),
25
'CNY' => __('Chinese Yuan', 'pmpro'),
26
+ 'CZK' => array(
27
+ 'name' => __('Czech Koruna', 'pmpro'),
28
+ 'decimals' => '0',
29
+ 'thousands_separator' => '&nbsp;',
30
+ 'decimal_separator' => ',',
31
+ 'symbol' => '&nbsp;Kč',
32
+ 'position' => 'right',
33
+ ),
34
'DKK' => __('Danish Krone', 'pmpro'),
35
'HKD' => __('Hong Kong Dollar (&#36;)', 'pmpro'),
36
'HUF' => __('Hungarian Forint', 'pmpro'),
includes/filters.php CHANGED
@@ -147,4 +147,12 @@ function pmpro_required_billing_fields_stripe_lite($fields)
147
148
//ship it!
149
return $fields;
150
}
147
148
//ship it!
149
return $fields;
150
+ }
151
+
152
+ //copy other discount code to discount code if latter is not set
153
+ if(empty($_REQUEST['discount_code']) && !empty($_REQUEST['other_discount_code']))
154
+ {
155
+ $_REQUEST['discount_code'] = $_REQUEST['other_discount_code'];
156
+ $_POST['discount_code'] = $_POST['other_discount_code'];
157
+ $_GET['discount_code'] = $_GET['other_discount_code'];
158
}
includes/functions.php CHANGED
@@ -237,7 +237,7 @@ function pmpro_getLevelCost(&$level, $tags = true, $short = false)
237
if(!$short)
238
$r = sprintf(__('The price for membership is <strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) );
239
else
240
- $r = sprintf(__('<strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) );
241
}
242
} else {
243
if($level->cycle_number == '1')
@@ -422,6 +422,7 @@ if(!function_exists("formatPhone"))
422
423
function pmpro_showRequiresMembershipMessage()
424
{
425
//get the correct message
426
if(is_feed())
427
{
@@ -636,7 +637,7 @@ function pmpro_changeMembershipLevel($level, $user_id = NULL, $old_level_status
636
637
if(!empty($c_order->error))
638
$pmpro_error = $c_order->error;
639
- }
640
}
641
642
//insert current membership
@@ -1804,15 +1805,18 @@ function pmpro_formatPrice($price)
1804
//settings stored in array?
1805
if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]))
1806
{
1807
//which side is the symbol on?
1808
if(!empty($pmpro_currencies[$pmpro_currency]['position']) && $pmpro_currencies[$pmpro_currency]['position']== 'left')
1809
$formatted = $pmpro_currency_symbol . $formatted;
1810
else
1811
$formatted = $formatted . $pmpro_currency_symbol;
1812
-
1813
- //commas or periods?
1814
- if(!empty($pmpro_currencies[$pmpro_currency]['separator']) && $pmpro_currencies[$pmpro_currency]['separator'])
1815
- $formatted = str_replace(array(".",","), $pmpro_currencies[$pmpro_currency]['separator'], $formatted);
1816
}
1817
else
1818
$formatted = $pmpro_currency_symbol . $formatted; //default to symbol on the left
@@ -1834,7 +1838,7 @@ function pmpro_getCurrencyPosition()
1834
return $pmpro_currencies[$pmpro_currency]['position'];
1835
else
1836
return "left";
1837
- }
1838
1839
/*
1840
* What gateway should we be using?
@@ -1865,4 +1869,4 @@ function pmpro_getGateway()
1865
$gateway = apply_filters('pmpro_get_gateway', $gateway, $valid_gateways);
1866
1867
return $gateway;
1868
- }
237
if(!$short)
238
$r = sprintf(__('The price for membership is <strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) );
239
else
240
+ $r = sprintf(__('<strong>%s every %d %s</strong>.', 'pmpro'), pmpro_formatPrice($level->initial_payment), $level->cycle_number, pmpro_translate_billing_period($level->cycle_period, $level->cycle_number) );
241
}
242
} else {
243
if($level->cycle_number == '1')
422
423
function pmpro_showRequiresMembershipMessage()
424
{
425
+ //TODO $current_user $post_membership_levels_names are undefined variables
426
//get the correct message
427
if(is_feed())
428
{
637
638
if(!empty($c_order->error))
639
$pmpro_error = $c_order->error;
640
+ }
641
}
642
643
//insert current membership
1805
//settings stored in array?
1806
if(!empty($pmpro_currencies[$pmpro_currency]) && is_array($pmpro_currencies[$pmpro_currency]))
1807
{
1808
+ //format number do decimals, with decimal_separator and thousands_separator
1809
+ $formatted = number_format($price,
1810
+ (isset($pmpro_currencies[$pmpro_currency]['decimals']) ? (int)$pmpro_currencies[$pmpro_currency]['decimals'] : 2),
1811
+ $pmpro_currencies[$pmpro_currency]['decimal_separator'],
1812
+ $pmpro_currencies[$pmpro_currency]['thousands_separator']
1813
+ );
1814
+
1815
//which side is the symbol on?
1816
if(!empty($pmpro_currencies[$pmpro_currency]['position']) && $pmpro_currencies[$pmpro_currency]['position']== 'left')
1817
$formatted = $pmpro_currency_symbol . $formatted;
1818
else
1819
$formatted = $formatted . $pmpro_currency_symbol;
1820