Paid Memberships Pro - Version 1.8.8

Version Description

  • BUG: Fixed issue where recurring Stripe orders were being created with $0 totals.
  • BUG: Fixed issues in pmpro_has_membership_access() that was affecting some sites with files locked down for members. (Thanks, MannyC on GitHub)
  • BUG: Fixed issue where data in the Signups vs Cancellations detailed view chart was shifted back one day. (Thanks, TYT)
  • BUG: Fixed issue where whitespace in email addresses and user names could confuse the pre-existing user checks.
  • BUG: Added some closing HTML tags where needed.
  • BUG: Fixed issue where discount codes could be created with special characters even though only letters, numbers, and - will work at checkout.
  • BUG: Some fixes to the pt_BR language. (Thanks, )
  • ENHANCEMENT: Refactored the members list CSV to use less memory and scale better. It should work faster in general and better on large sites. (Thanks, Thomas Sjolshagen)
  • ENHANCEMENT: Added pmpro_reports_signups_sql and pmpro_reports_get_cancellations_sql filters to filter SQL that generates cancellation numbers in reports.
  • ENHANCEMENT: Now setting the timeout on PayPal API calls to 60 seconds from 5 seconds.
  • ENHANCEMENT: Now checking admin capabilities on each load in the dashboard in case PMPro-related admin capabilities have been changed. This avoids issues where users were upgrading PMPro but wouldn't have access to updates or new features without deactivating and reactivating PMPro.
  • ENHANCEMENT: Added a pmpro_paypal_level_description filter that can be used to filter the description of the level sent to PayPal.
  • ENHANCEMENT: Added Catalan translations (ca, ca_AD, ca_ES). (Thanks, Jordi Martn)
  • ENHANCEMENT: Added Estonian translations (et_EE). (Thanks, Enriko Ojala)
Download this release

Release Info

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

Code changes from version 1.8.7.3 to 1.8.8

Files changed (167) hide show
  1. adminpages/discountcodes.php +2 -1
  2. adminpages/membershiplevels.php +3 -3
  3. adminpages/memberslist-csv.php +402 -115
  4. adminpages/reports/memberships.php +26 -1
  5. adminpages/updates.php +4 -0
  6. classes/class.memberorder.php +1 -1
  7. classes/gateways/class.pmprogateway_payflowpro.php +3 -2
  8. classes/gateways/class.pmprogateway_paypal.php +3 -1
  9. classes/gateways/class.pmprogateway_paypalexpress.php +4 -3
  10. classes/gateways/class.pmprogateway_paypalstandard.php +2 -1
  11. classes/gateways/class.pmprogateway_stripe.php +12 -2
  12. includes/capabilities.php +68 -0
  13. includes/content.php +12 -11
  14. includes/functions.php +6 -6
  15. includes/updates.php +10 -2
  16. includes/updates/upgrade_1.php +50 -0
  17. includes/updates/upgrade_1_1_15.php +138 -0
  18. includes/updates/upgrade_1_2_3.php +42 -0
  19. includes/updates/upgrade_1_3_18.php +12 -0
  20. includes/updates/upgrade_1_4.php +16 -0
  21. includes/updates/upgrade_1_4_2.php +17 -0
  22. includes/updates/upgrade_1_4_8.php +20 -0
  23. includes/updates/upgrade_1_5.php +26 -0
  24. includes/updates/upgrade_1_5_9.php +14 -0
  25. includes/updates/upgrade_1_6.php +14 -0
  26. includes/updates/upgrade_1_7.php +8 -0
  27. includes/updates/upgrade_1_8_6_9.php +94 -0
  28. includes/updates/upgrade_1_8_7.php +35 -0
  29. includes/updates/upgrade_1_8_8.php +109 -0
  30. includes/upgradecheck.php +55 -501
  31. js/updates.js +9 -5
  32. languages/email/ca/admin_change.html +7 -0
  33. languages/email/ca/admin_change_admin.html +5 -0
  34. languages/email/ca/billable_invoice.html +6 -0
  35. languages/email/ca/billing.html +16 -0
  36. languages/email/ca/billing_admin.html +17 -0
  37. languages/email/ca/billing_failure.html +11 -0
  38. languages/email/ca/billing_failure_admin.html +11 -0
  39. languages/email/ca/cancel.html +3 -0
  40. languages/email/ca/cancel_admin.html +8 -0
  41. languages/email/ca/checkout_check.html +17 -0
  42. languages/email/ca/checkout_check_admin.html +17 -0
  43. languages/email/ca/checkout_express.html +14 -0
  44. languages/email/ca/checkout_express_admin.html +14 -0
  45. languages/email/ca/checkout_free.html +8 -0
  46. languages/email/ca/checkout_free_admin.html +8 -0
  47. languages/email/ca/checkout_freetrial.html +19 -0
  48. languages/email/ca/checkout_freetrial_admin.html +19 -0
  49. languages/email/ca/checkout_paid.html +23 -0
  50. languages/email/ca/checkout_paid_admin.html +23 -0
  51. languages/email/ca/checkout_trial.html +23 -0
  52. languages/email/ca/checkout_trial_admin.html +23 -0
  53. languages/email/ca/credit_card_expiring.html +13 -0
  54. languages/email/ca/default.html +1 -0
  55. languages/email/ca/footer.html +4 -0
  56. languages/email/ca/header.html +1 -0
  57. languages/email/ca/invoice.html +19 -0
  58. languages/email/ca/membership_expired.html +7 -0
  59. languages/email/ca/membership_expiring.html +6 -0
  60. languages/email/ca/trial_ending.html +8 -0
  61. languages/email/ca_AD/admin_change.html +7 -0
  62. languages/email/ca_AD/admin_change_admin.html +5 -0
  63. languages/email/ca_AD/billable_invoice.html +6 -0
  64. languages/email/ca_AD/billing.html +16 -0
  65. languages/email/ca_AD/billing_admin.html +17 -0
  66. languages/email/ca_AD/billing_failure.html +11 -0
  67. languages/email/ca_AD/billing_failure_admin.html +11 -0
  68. languages/email/ca_AD/cancel.html +3 -0
  69. languages/email/ca_AD/cancel_admin.html +8 -0
  70. languages/email/ca_AD/checkout_check.html +17 -0
  71. languages/email/ca_AD/checkout_check_admin.html +17 -0
  72. languages/email/ca_AD/checkout_express.html +14 -0
  73. languages/email/ca_AD/checkout_express_admin.html +14 -0
  74. languages/email/ca_AD/checkout_free.html +8 -0
  75. languages/email/ca_AD/checkout_free_admin.html +8 -0
  76. languages/email/ca_AD/checkout_freetrial.html +19 -0
  77. languages/email/ca_AD/checkout_freetrial_admin.html +19 -0
  78. languages/email/ca_AD/checkout_paid.html +23 -0
  79. languages/email/ca_AD/checkout_paid_admin.html +23 -0
  80. languages/email/ca_AD/checkout_trial.html +23 -0
  81. languages/email/ca_AD/checkout_trial_admin.html +23 -0
  82. languages/email/ca_AD/credit_card_expiring.html +13 -0
  83. languages/email/ca_AD/default.html +1 -0
  84. languages/email/ca_AD/footer.html +4 -0
  85. languages/email/ca_AD/header.html +1 -0
  86. languages/email/ca_AD/invoice.html +19 -0
  87. languages/email/ca_AD/membership_expired.html +7 -0
  88. languages/email/ca_AD/membership_expiring.html +6 -0
  89. languages/email/ca_AD/trial_ending.html +8 -0
  90. languages/email/ca_ES/admin_change.html +7 -0
  91. languages/email/ca_ES/admin_change_admin.html +5 -0
  92. languages/email/ca_ES/billable_invoice.html +6 -0
  93. languages/email/ca_ES/billing.html +16 -0
  94. languages/email/ca_ES/billing_admin.html +17 -0
  95. languages/email/ca_ES/billing_failure.html +11 -0
  96. languages/email/ca_ES/billing_failure_admin.html +11 -0
  97. languages/email/ca_ES/cancel.html +3 -0
  98. languages/email/ca_ES/cancel_admin.html +8 -0
  99. languages/email/ca_ES/checkout_check.html +17 -0
  100. languages/email/ca_ES/checkout_check_admin.html +17 -0
  101. languages/email/ca_ES/checkout_express.html +14 -0
  102. languages/email/ca_ES/checkout_express_admin.html +14 -0
  103. languages/email/ca_ES/checkout_free.html +8 -0
  104. languages/email/ca_ES/checkout_free_admin.html +8 -0
  105. languages/email/ca_ES/checkout_freetrial.html +19 -0
  106. languages/email/ca_ES/checkout_freetrial_admin.html +19 -0
  107. languages/email/ca_ES/checkout_paid.html +23 -0
  108. languages/email/ca_ES/checkout_paid_admin.html +23 -0
  109. languages/email/ca_ES/checkout_trial.html +23 -0
  110. languages/email/ca_ES/checkout_trial_admin.html +23 -0
  111. languages/email/ca_ES/credit_card_expiring.html +13 -0
  112. languages/email/ca_ES/default.html +1 -0
  113. languages/email/ca_ES/footer.html +4 -0
  114. languages/email/ca_ES/header.html +1 -0
  115. languages/email/ca_ES/invoice.html +19 -0
  116. languages/email/ca_ES/membership_expired.html +7 -0
  117. languages/email/ca_ES/membership_expiring.html +6 -0
  118. languages/email/ca_ES/trial_ending.html +8 -0
  119. languages/email/et_EE/admin_change.html +7 -0
  120. languages/email/et_EE/admin_change_admin.html +5 -0
  121. languages/email/et_EE/billable_invoice.html +6 -0
  122. languages/email/et_EE/billing.html +16 -0
  123. languages/email/et_EE/billing_admin.html +17 -0
  124. languages/email/et_EE/billing_failure.html +11 -0
  125. languages/email/et_EE/billing_failure_admin.html +11 -0
  126. languages/email/et_EE/cancel.html +3 -0
  127. languages/email/et_EE/cancel_admin.html +8 -0
  128. languages/email/et_EE/checkout_check.html +17 -0
  129. languages/email/et_EE/checkout_check_admin.html +17 -0
  130. languages/email/et_EE/checkout_express.html +14 -0
  131. languages/email/et_EE/checkout_express_admin.html +14 -0
  132. languages/email/et_EE/checkout_free.html +8 -0
  133. languages/email/et_EE/checkout_free_admin.html +8 -0
  134. languages/email/et_EE/checkout_freetrial.html +19 -0
  135. languages/email/et_EE/checkout_freetrial_admin.html +19 -0
  136. languages/email/et_EE/checkout_paid.html +23 -0
  137. languages/email/et_EE/checkout_paid_admin.html +23 -0
  138. languages/email/et_EE/checkout_trial.html +23 -0
  139. languages/email/et_EE/checkout_trial_admin.html +23 -0
  140. languages/email/et_EE/credit_card_expiring.html +15 -0
  141. languages/email/et_EE/default.html +1 -0
  142. languages/email/et_EE/footer.html +4 -0
  143. languages/email/et_EE/header.html +1 -0
  144. languages/email/et_EE/invoice.html +19 -0
  145. languages/email/et_EE/membership_expired.html +7 -0
  146. languages/email/et_EE/membership_expiring.html +6 -0
  147. languages/email/et_EE/trial_ending.html +8 -0
  148. languages/pmpro-ca.mo +0 -0
  149. languages/pmpro-ca.po +5616 -0
  150. languages/pmpro-ca_AD.mo +0 -0
  151. languages/pmpro-ca_AD.po +5616 -0
  152. languages/pmpro-ca_ES.mo +0 -0
  153. languages/pmpro-ca_ES.po +5616 -0
  154. languages/pmpro-et_EE.mo +0 -0
  155. languages/pmpro-et_EE.po +5294 -0
  156. languages/pmpro-nb_NO.mo +0 -0
  157. languages/pmpro-nb_NO.po +7 -7
  158. languages/pmpro-pt_BR.mo +0 -0
  159. languages/pmpro-pt_BR.po +4067 -1189
  160. languages/pmpro.po +102 -99
  161. languages/pmpro.pot +102 -99
  162. pages/checkout.php +1 -1
  163. paid-memberships-pro.php +5 -35
  164. preheaders/checkout.php +17 -9
  165. readme.txt +18 -2
  166. services/authnet-silent-post.php +1 -0
  167. services/stripe-webhook.php +152 -133
adminpages/discountcodes.php CHANGED
@@ -26,7 +26,8 @@
26
if($saveid)
27
{
28
//get vars
29
- $code = sanitize_text_field($_POST['code']);
30
$starts_month = intval($_POST['starts_month']);
31
$starts_day = intval($_POST['starts_day']);
32
$starts_year = intval($_POST['starts_year']);
26
if($saveid)
27
{
28
//get vars
29
+ //disallow/strip all non-alphanumeric characters except -
30
+ $code = preg_replace("/[^A-Za-z0-9\-]/", "", sanitize_text_field($_POST['code']));
31
$starts_month = intval($_POST['starts_month']);
32
$starts_day = intval($_POST['starts_day']);
33
$starts_year = intval($_POST['starts_year']);
adminpages/membershiplevels.php CHANGED
@@ -113,7 +113,7 @@
113
$wpdb->query($sqlQuery);
114
115
pmpro_updateMembershipCategories( $saveid, $ml_categories );
116
- if(!mysql_errno())
117
{
118
$edit = false;
119
$msg = 2;
@@ -133,7 +133,7 @@
133
VALUES
134
( '" . esc_sql($ml_name) . "', '" . esc_sql($ml_description) . "', '" . esc_sql($ml_confirmation) . "', '" . esc_sql($ml_initial_payment) . "', '" . esc_sql($ml_billing_amount) . "', '" . esc_sql($ml_cycle_number) . "', '" . esc_sql($ml_cycle_period) . "', '" . esc_sql($ml_billing_limit) . "', '" . esc_sql($ml_trial_amount) . "', '" . esc_sql($ml_trial_limit) . "', '" . esc_sql($ml_expiration_number) . "', '" . esc_sql($ml_expiration_period) . "', '" . esc_sql($ml_allow_signups) . "' )";
135
$wpdb->query($sqlQuery);
136
- if(!mysql_errno())
137
{
138
$saveid = $wpdb->insert_id;
139
pmpro_updateMembershipCategories( $saveid, $ml_categories );
@@ -467,7 +467,7 @@
467
468
<tr>
469
<th scope="row" valign="top"><label><?php _e('Membership Expiration', 'pmpro');?>:</label></th>
470
- <td><input id="expiration" name="expiration" type="checkbox" value="yes" <?php if(pmpro_isLevelExpiring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery('#expiration').is(':checked')) { jQuery('.expiration_info').show(); } else { jQuery('.expiration_info').hide();}" /> <label for="expiration"><?php _e('Check this to set when membership access expires.', 'pmpro');?></a></td>
471
</tr>
472
473
<tr class="expiration_info" <?php if(!pmpro_isLevelExpiring($level)) {?>style="display: none;"<?php } ?>>
113
$wpdb->query($sqlQuery);
114
115
pmpro_updateMembershipCategories( $saveid, $ml_categories );
116
+ if(empty($wpdb->last_error))
117
{
118
$edit = false;
119
$msg = 2;
133
VALUES
134
( '" . esc_sql($ml_name) . "', '" . esc_sql($ml_description) . "', '" . esc_sql($ml_confirmation) . "', '" . esc_sql($ml_initial_payment) . "', '" . esc_sql($ml_billing_amount) . "', '" . esc_sql($ml_cycle_number) . "', '" . esc_sql($ml_cycle_period) . "', '" . esc_sql($ml_billing_limit) . "', '" . esc_sql($ml_trial_amount) . "', '" . esc_sql($ml_trial_limit) . "', '" . esc_sql($ml_expiration_number) . "', '" . esc_sql($ml_expiration_period) . "', '" . esc_sql($ml_allow_signups) . "' )";
135
$wpdb->query($sqlQuery);
136
+ if(empty($wpdb->last_error))
137
{
138
$saveid = $wpdb->insert_id;
139
pmpro_updateMembershipCategories( $saveid, $ml_categories );
467
468
<tr>
469
<th scope="row" valign="top"><label><?php _e('Membership Expiration', 'pmpro');?>:</label></th>
470
+ <td><input id="expiration" name="expiration" type="checkbox" value="yes" <?php if(pmpro_isLevelExpiring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery('#expiration').is(':checked')) { jQuery('.expiration_info').show(); } else { jQuery('.expiration_info').hide();}" /> <label for="expiration"><?php _e('Check this to set when membership access expires.', 'pmpro');?></label></a></td>
471
</tr>
472
473
<tr class="expiration_info" <?php if(!pmpro_isLevelExpiring($level)) {?>style="display: none;"<?php } ?>>
adminpages/memberslist-csv.php CHANGED
@@ -1,18 +1,46 @@
1
<?php
2
- //only admins can get this
3
if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_memberslistcsv")))
4
{
5
die(__("You do not have permissions to perform this action.", "pmpro"));
6
}
7
8
global $wpdb;
9
10
- //get users
11
if(isset($_REQUEST['s']))
12
$s = sanitize_text_field($_REQUEST['s']);
13
else
14
$s = "";
15
16
if(isset($_REQUEST['l']))
17
$l = sanitize_text_field($_REQUEST['l']);
18
else
@@ -40,94 +68,29 @@
40
$start = NULL;
41
}
42
43
- if($s)
44
- {
45
- $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, mu.cycle_number, mu.billing_limit, mu.trial_amount, mu.trial_limit, UNIX_TIMESTAMP(mu.startdate) as startdate, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id ";
46
-
47
- if($l == "oldmembers" || $l == "expired" || $l == "cancelled")
48
- $sqlQuery .= " LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON u.ID = mu2.user_id AND mu2.status = 'active' ";
49
-
50
- $sqlQuery .= " WHERE mu.membership_id > 0 AND (u.user_login LIKE '%" . esc_sql($s) . "%' OR u.user_email LIKE '%" . esc_sql($s) . "%' OR um.meta_value LIKE '%" . esc_sql($s) . "%') ";
51
-
52
- if($l == "oldmembers")
53
- $sqlQuery .= " AND mu.status <> 'active' AND mu2.status IS NULL ";
54
- elseif($l == "expired")
55
- $sqlQuery .= " AND mu.status = 'expired' AND mu2.status IS NULL ";
56
- elseif($l == "cancelled")
57
- $sqlQuery .= " AND mu.status IN('cancelled', 'admin_cancelled') AND mu2.status IS NULL ";
58
- elseif($l)
59
- $sqlQuery .= " AND mu.status = 'active' AND mu.membership_id = '" . esc_sql($l) . "' ";
60
- else
61
- $sqlQuery .= " AND mu.status = 'active' ";
62
-
63
- $sqlQuery .= "GROUP BY u.ID ";
64
-
65
- if($l == "oldmembers" || $l == "expired" || $l == "cancelled")
66
- $sqlQuery .= "ORDER BY enddate DESC ";
67
- else
68
- $sqlQuery .= "ORDER BY u.user_registered DESC ";
69
-
70
- if(!empty($limit))
71
- $sqlQuery .= "LIMIT $start, $limit";
72
- }
73
- else
74
- {
75
- $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, mu.cycle_number, mu.billing_limit, mu.trial_amount, mu.trial_limit, UNIX_TIMESTAMP(mu.startdate) as startdate, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id";
76
-
77
- if($l == "oldmembers" || $l == "expired" || $l == "cancelled")
78
- $sqlQuery .= " LEFT JOIN $wpdb->pmpro_memberships_users mu2 ON u.ID = mu2.user_id AND mu2.status = 'active' ";
79
-
80
- $sqlQuery .= " WHERE mu.membership_id > 0 ";
81
-
82
- if($l == "oldmembers")
83
- $sqlQuery .= " AND mu.status <> 'active' AND mu2.status IS NULL ";
84
- elseif($l == "expired")
85
- $sqlQuery .= " AND mu.status = 'expired' AND mu2.status IS NULL ";
86
- elseif($l == "cancelled")
87
- $sqlQuery .= " AND mu.status IN('cancelled', 'admin_cancelled') AND mu2.status IS NULL ";
88
- elseif($l)
89
- $sqlQuery .= " AND mu.status = 'active' AND mu.membership_id = '" . esc_sql($l) . "' ";
90
- else
91
- $sqlQuery .= " AND mu.status = 'active' ";
92
- $sqlQuery .= "GROUP BY u.ID ";
93
-
94
- if($l == "oldmembers" || $l == "expired" || $l == "cancelled")
95
- $sqlQuery .= "ORDER BY enddate DESC ";
96
- else
97
- $sqlQuery .= "ORDER BY u.user_registered DESC ";
98
-
99
- if(!empty($limit))
100
- $sqlQuery .= "LIMIT $start, $limit";
101
- }
102
103
- //filter
104
- $sqlQuery = apply_filters("pmpro_members_list_sql", $sqlQuery);
105
-
106
- //get users
107
- $theusers = $wpdb->get_col($sqlQuery);
108
-
109
- //begin output
110
- header("Content-type: text/csv");
111
if($s && $l == "oldmembers")
112
- header("Content-Disposition: attachment; filename=members_list_expired_" . sanitize_file_name($s) . ".csv");
113
elseif($s && $l)
114
- header("Content-Disposition: attachment; filename=members_list_" . intval($l) . "_level_" . sanitize_file_name($s) . ".csv");
115
elseif($s)
116
- header("Content-Disposition: attachment; filename=members_list_" . sanitize_file_name($s) . ".csv");
117
elseif($l == "oldmembers")
118
- header("Content-Disposition: attachment; filename=members_list_expired.csv");
119
else
120
- header("Content-Disposition: attachment; filename=members_list.csv");
121
122
- $heading = "id,username,firstname,lastname,email,billing firstname,billing lastname,address1,address2,city,state,zipcode,country,phone,membership,initial payment,fee,term,discount_code_id,discount_code,joined";
123
124
if($l == "oldmembers")
125
- $heading .= ",ended";
126
else
127
- $heading .= ",expires";
128
129
- $heading = apply_filters("pmpro_members_list_csv_heading", $heading);
130
- $csvoutput = $heading;
131
132
//these are the meta_keys for the fields (arrays are object, property. so e.g. $theuser->ID)
133
$default_columns = array(
@@ -157,39 +120,260 @@
157
//filter
158
$default_columns = apply_filters("pmpro_members_list_csv_default_columns", $default_columns);
159
160
//any extra columns
161
$extra_columns = apply_filters("pmpro_members_list_csv_extra_columns", array());
162
if(!empty($extra_columns))
163
{
164
foreach($extra_columns as $heading => $callback)
165
{
166
- $csvoutput .= "," . $heading;
167
}
168
}
169
170
- $csvoutput .= "\n";
171
172
- //output
173
- echo $csvoutput;
174
- $csvoutput = "";
175
176
- if($theusers)
177
{
178
- foreach($theusers as $user_id)
179
{
180
- //MULTI: This query will need to be updated to support multiple levels per user. Should probably just dump multiple rows for each membership.
181
- //get meta
182
183
- if($l == "oldmembers")
184
- $theuser = $wpdb->get_row("SELECT u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, u.user_login, u.user_nicename, u.user_url, u.user_registered, u.user_status, u.display_name, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id WHERE u.ID = '" . $user_id . "' ORDER BY mu.id DESC LIMIT 1");
185
- else
186
- $theuser = $wpdb->get_row("SELECT u.ID, u.user_login, u.user_email, UNIX_TIMESTAMP(u.user_registered) as joindate, u.user_login, u.user_nicename, u.user_url, u.user_registered, u.user_status, u.display_name, mu.membership_id, mu.initial_payment, mu.billing_amount, mu.cycle_period, UNIX_TIMESTAMP(mu.enddate) as enddate, m.name as membership FROM $wpdb->users u LEFT JOIN $wpdb->usermeta um ON u.ID = um.user_id LEFT JOIN $wpdb->pmpro_memberships_users mu ON u.ID = mu.user_id AND mu.status = 'active' LEFT JOIN $wpdb->pmpro_membership_levels m ON mu.membership_id = m.id WHERE u.ID = '" . $user_id . "' LIMIT 1");
187
188
- $sqlQuery = "SELECT meta_key as `key`, meta_value as `value` FROM $wpdb->usermeta WHERE $wpdb->usermeta.user_id = '" . $user_id . "'";
189
- $metavalues = pmpro_getMetavalues($sqlQuery);
190
$theuser->metavalues = $metavalues;
191
- $sqlQuery = "SELECT c.id, c.code FROM $wpdb->pmpro_discount_codes_uses cu LEFT JOIN $wpdb->pmpro_discount_codes c ON cu.code_id = c.id WHERE cu.user_id = '" . $theuser->ID . "' ORDER BY c.id DESC LIMIT 1";
192
- $discount_code = $wpdb->get_row($sqlQuery);
193
194
//default columns
195
if(!empty($default_columns))
@@ -197,54 +381,157 @@
197
$count = 0;
198
foreach($default_columns as $col)
199
{
200
- //add comma after the first item
201
- $count++;
202
- if($count > 1)
203
- $csvoutput .= ",";
204
-
205
//checking $object->property. note the double $
206
- if(!empty($col[0]->$col[1]))
207
- $csvoutput .= pmpro_enclose($col[0]->$col[1]); //output the value
208
}
209
}
210
211
//joindate and enddate
212
- $csvoutput .= "," . pmpro_enclose(date("Y-m-d", $theuser->joindate)) . ",";
213
214
if($theuser->membership_id)
215
{
216
if($theuser->enddate)
217
- $csvoutput .= pmpro_enclose(apply_filters("pmpro_memberslist_expires_column", date("Y-m-d", $theuser->enddate), $theuser));
218
else
219
- $csvoutput .= pmpro_enclose(apply_filters("pmpro_memberslist_expires_column", "Never", $theuser));
220
}
221
elseif($l == "oldmembers" && $theuser->enddate)
222
{
223
- $csvoutput .= pmpro_enclose(date("Y-m-d", $theuser->enddate));
224
}
225
else
226
- $csvoutput .= "N/A";
227
228
//any extra columns
229
if(!empty($extra_columns))
230
{
231
foreach($extra_columns as $heading => $callback)
232
{
233
- $csvoutput .= "," . pmpro_enclose(call_user_func($callback, $theuser, $heading));
234
}
235
}
236
237
- $csvoutput .= "\n";
238
239
- //output
240
- echo $csvoutput;
241
- $csvoutput = "";
242
}
243
}
244
245
- print $csvoutput;
246
247
function pmpro_enclose($s)
248
{
249
return "\"" . str_replace("\"", "\\\"", $s) . "\"";
250
- }
1
<?php
2
+
3
if(!function_exists("current_user_can") || (!current_user_can("manage_options") && !current_user_can("pmpro_memberslistcsv")))
4
{
5
die(__("You do not have permissions to perform this action.", "pmpro"));
6
}
7
8
+ if (!defined('PMPRO_BENCHMARK'))
9
+ define('PMPRO_BENCHMARK', false);
10
+
11
+ if (PMPRO_BENCHMARK)
12
+ {
13
+ error_log(str_repeat('-', 10) . date('Y-m-d H:i:s') . str_repeat('-', 10));
14
+ $start_time = microtime(true);
15
+ $start_memory = memory_get_usage(true);
16
+ }
17
+
18
+
19
+ /**
20
+ * Filter to set max number of records to process at a time
21
+ * for the export (helps manage memory footprint)
22
+ *
23
+ * Rule of thumb: 2000 records: ~50-60 MB of addl. memory (memory_limit needs to be between 128MB and 256MB)
24
+ * 4000 records: ~70-100 MB of addl. memory (memory_limit needs to be >= 256MB)
25
+ * 6000 records: ~100-140 MB of addl. memory (memory_limit needs to be >= 256MB)
26
+ *
27
+ * NOTE: Use the pmpro_before_members_list_csv_export hook to increase memory "on-the-fly"
28
+ * Can reset with the pmpro_after_members_list_csv_export hook
29
+ *
30
+ * @since 1.8.7
31
+ */
32
+ //set the number of users we'll load to try and protect ourselves from OOM errors
33
+ $max_users_per_loop = apply_filters('pmpro_set_max_user_per_export_loop', 2000);
34
+
35
global $wpdb;
36
37
+ //get users (search input field)
38
if(isset($_REQUEST['s']))
39
$s = sanitize_text_field($_REQUEST['s']);
40
else
41
$s = "";
42
43
+ // requested a level id
44
if(isset($_REQUEST['l']))
45
$l = sanitize_text_field($_REQUEST['l']);
46
else
68
$start = NULL;
69
}
70
71
+ $headers = array();
72
+ $headers[] = "Content-type: text/csv";
73
74
if($s && $l == "oldmembers")
75
+ $headers[] = "Content-Disposition: attachment; filename=members_list_expired_" . sanitize_file_name($s) . ".csv";
76
elseif($s && $l)
77
+ $headers[] = "Content-Disposition: attachment; filename=members_list_" . intval($l) . "_level_" . sanitize_file_name($s) . ".csv";
78
elseif($s)
79
+ $headers[] = "Content-Disposition: attachment; filename=members_list_" . sanitize_file_name($s) . ".csv";
80
elseif($l == "oldmembers")
81
+ $headers[] = "Content-Disposition: attachment; filename=members_list_expired.csv";
82
else
83
+ $headers[] = "Content-Disposition: attachment; filename=members_list.csv";
84
85
+ //set default CSV file headers, using comma as delimiter
86
+ $csv_file_header = "id,username,firstname,lastname,email,billing firstname,billing lastname,address1,address2,city,state,zipcode,country,phone,membership,initial payment,fee,term,discount_code_id,discount_code,joined";
87
88
if($l == "oldmembers")
89
+ $csv_file_header .= ",ended";
90
else
91
+ $csv_file_header .= ",expires";
92
93
+ $csv_file_header = apply_filters("pmpro_members_list_csv_heading", $csv_file_header);
94
95
//these are the meta_keys for the fields (arrays are object, property. so e.g. $theuser->ID)
96
$default_columns = array(
120
//filter
121
$default_columns = apply_filters("pmpro_members_list_csv_default_columns", $default_columns);
122
123
+ //set the preferred date format:
124
+ $dateformat = apply_filters("pmpro_memberslist_csv_dateformat","Y-m-d");
125
+
126
//any extra columns
127
$extra_columns = apply_filters("pmpro_members_list_csv_extra_columns", array());
128
if(!empty($extra_columns))
129
{
130
foreach($extra_columns as $heading => $callback)
131
{
132
+ $csv_file_header .= "," . $heading;
133
}
134
}
135
136
+ $csv_file_header .= "\n";
137
+
138
+ //generate SQL for list of users to process
139
+ $sqlQuery = "
140
+ SELECT
141
+ DISTINCT u.ID
142
+ FROM $wpdb->users u ";
143
+
144
+ if ($s)
145
+ $sqlQuery .= "LEFT JOIN {$wpdb->usermeta} um ON u.ID = um.user_id ";
146
147
+ $sqlQuery .= "LEFT JOIN {$wpdb->pmpro_memberships_users} mu ON u.ID = mu.user_id ";
148
+ $sqlQuery .= "LEFT JOIN {$wpdb->pmpro_membership_levels} m ON mu.membership_id = m.id ";
149
150
+ $former_members = in_array($l, array( "oldmembers", "expired", "cancelled"));
151
+ $former_member_join = null;
152
+
153
+ if($former_members)
154
{
155
+ $former_member_join = "LEFT JOIN {$wpdb->pmpro_memberships_users} mu2 ON u.ID = mu2.user_id AND mu2.status = 'active' ";
156
+ $sqlQuery .= $former_member_join;
157
+ }
158
+
159
+ $sqlQuery .= "WHERE mu.membership_id > 0 ";
160
+
161
+ // looking for a specific user
162
+ if($s)
163
+ $sqlQuery .= "AND (u.user_login LIKE '%". esc_sql($s) ."%' OR u.user_email LIKE '%". esc_sql($s) ."%' OR um.meta_value LIKE '%". esc_sql($s) ."%') ";
164
+
165
+ // if ($former_members)
166
+ // $sqlQuery .= "AND mu2.status = 'active' ";
167
+
168
+ $filter = null;
169
+
170
+ //records where the user is NOT an active member
171
+ //if $l == "oldmembers"
172
+ $filter = ($l == "oldmembers" ? " AND mu.status <> 'active' AND mu2.status IS NULL " : $filter);
173
+
174
+ // prepare the status to use in the filter
175
+ // elseif ($l == "expired") elseif ($l == "cancelled")
176
+ $f_status = ($l == "expired" ? array( 'expired' ) : ( $l == "cancelled" ? array('cancelled', 'admin_cancelled') : null));
177
+
178
+ //records where the user is expired or cancelled
179
+ $filter = ( ($l == "expired" || $l == "cancelled") && is_null($filter)) ? "AND mu.status IN ('" . implode("','", $f_status) . "') AND mu2.status IS NULL " : $filter;
180
+
181
+ //records for active users with the requested membership level
182
+ // elseif($l)
183
+ $filter = ( (is_null($filter) && is_numeric($l)) ? " AND mu.status = 'active' AND mu.membership_id = " . esc_sql($l) . " " : $filter);
184
+
185
+ //any active users
186
+ // else
187
+ $filter = (is_null($filter) ? " AND mu.status = 'active' " : $filter);
188
+
189
+ //add the filter
190
+ $sqlQuery .= $filter;
191
+
192
+ //process based on limit value(s).
193
+ $sqlQuery .= "ORDER BY u.ID ";
194
+
195
+ if(!empty($limit))
196
+ $sqlQuery .= "LIMIT {$start}, {$limit}";
197
+
198
+ // Generate a temporary file to store the data in.
199
+ $tmp_dir = sys_get_temp_dir();
200
+ $filename = tempnam( $tmp_dir, 'pmpro_ml_');
201
+
202
+ // open in append mode
203
+ $csv_fh = fopen($filename, 'a');
204
+
205
+ //write the CSV header to the file
206
+ fprintf($csv_fh, '%s', $csv_file_header );
207
+
208
+ //get users
209
+ $theusers = $wpdb->get_col($sqlQuery);
210
+
211
+ //if no records just transmit file with only CSV header as content
212
+ if (empty($theusers)) {
213
+
214
+ // send the data to the remote browser
215
+ pmpro_transmit_content($csv_fh, $filename, $headers);
216
+ }
217
+
218
+ $users_found = count($theusers);
219
+
220
+ if (PMPRO_BENCHMARK)
221
+ {
222
+ $pre_action_time = microtime(true);
223
+ $pre_action_memory = memory_get_usage(true);
224
+ }
225
+
226
+ do_action('pmpro_before_members_list_csv_export', $theusers);
227
+
228
+ $i_start = 0;
229
+ $i_limit = 0;
230
+ $iterations = 1;
231
+
232
+ $csvoutput = array();
233
+
234
+ if($users_found >= $max_users_per_loop)
235
+ {
236
+ $iterations = ceil($users_found / $max_users_per_loop);
237
+ $i_limit = $max_users_per_loop;
238
+ }
239
+
240
+ $end = 0;
241
+ $time_limit = ini_get('max_execution_time');
242
+
243
+ if (PMPRO_BENCHMARK)
244
+ {
245
+ error_log("PMPRO_BENCHMARK - Total records to process: {$users_found}");
246
+ error_log("PMPRO_BENCHMARK - Will process {$iterations} iterations of max {$max_users_per_loop} records per iteration.");
247
+ $pre_iteration_time = microtime(true);
248
+ $pre_iteration_memory = memory_get_usage(true);
249
+ }
250
+
251
+ //to manage memory footprint, we'll iterate through the membership list multiple times
252
+ for ( $ic = 1 ; $ic <= $iterations ; $ic++ ) {
253
+
254
+ if (PMPRO_BENCHMARK)
255
{
256
+ $start_iteration_time = microtime(true);
257
+ $start_iteration_memory = memory_get_usage(true);
258
+ }
259
260
+ //make sure we don't timeout
261
+ if ($end != 0) {
262
+
263
+ $iteration_diff = $end - $start;
264
+ $new_time_limit = ceil($iteration_diff*$iterations * 1.2);
265
+
266
+ if ($time_limit < $new_time_limit )
267
+ {
268
+ $time_limit = $new_time_limit;
269
+ set_time_limit( $time_limit );
270
+ }
271
+ }
272
+
273
+ $start = current_time('timestamp');
274
+
275
+ // get first and last user ID to use
276
+ $first_uid = $theusers[$i_start];
277
+
278
+ //get last UID, will depend on which iteration we're on.
279
+ if ( $ic != $iterations )
280
+ $last_uid = $theusers[($i_start + ( $max_users_per_loop - 1))];
281
+ else
282
+ // Final iteration, so last UID is the last record in the users array
283
+ $last_uid = $theusers[($users_found - 1)];
284
+
285
+ //increment starting position
286
+ if(0 < $iterations)
287
+ {
288
+ $i_start += $max_users_per_loop;
289
+ }
290
+
291
+ $userSql = $wpdb->prepare("
292
+ SELECT
293
+ DISTINCT u.ID,
294
+ u.user_login,
295
+ u.user_email,
296
+ UNIX_TIMESTAMP(u.user_registered) as joindate,
297
+ u.user_login,
298
+ u.user_nicename,
299
+ u.user_url,
300
+ u.user_registered,
301
+ u.user_status,
302
+ u.display_name,
303
+ mu.membership_id,
304
+ mu.initial_payment,
305
+ mu.billing_amount,
306
+ mu.cycle_period,
307
+ UNIX_TIMESTAMP(mu.enddate) as enddate,
308
+ m.name as membership
309
+ FROM {$wpdb->users} u
310
+ LEFT JOIN {$wpdb->usermeta} um ON u.ID = um.user_id
311
+ LEFT JOIN {$wpdb->pmpro_memberships_users} mu ON u.ID = mu.user_id
312
+ LEFT JOIN {$wpdb->pmpro_membership_levels} m ON mu.membership_id = m.id
313
+ {$former_member_join}
314
+ WHERE u.ID BETWEEN %d AND %d AND mu.membership_id > 0 {$filter}
315
+ -- GROUP BY u.ID
316
+ ORDER BY u.ID",
317
+ $first_uid,
318
+ $last_uid
319
+ );
320
+
321
+ // TODO: Only return the latest record for the user(s) current (and prior) levels IDs?
322
+
323
+ $usr_data = $wpdb->get_results($userSql);
324
+ $userSql = null;
325
+
326
+ if (PMPRO_BENCHMARK)
327
+ {
328
+ $pre_userdata_time = microtime(true);
329
+ $pre_userdata_memory = memory_get_usage(true);
330
+ }
331
+
332
+ // process the actual data we want to export
333
+ foreach($usr_data as $theuser) {
334
+
335
+ $csvoutput = array();
336
+
337
+ //process usermeta
338
+ $metavalues = new stdClass();
339
+
340
+ // Returns array of meta keys containing array(s) of metavalues.
341
+ $um_values = get_user_meta($theuser->ID);
342
+
343
+ foreach( $um_values as $key => $value ) {
344
+
345
+ $metavalues->{$key} = $value[0];
346
+ }
347
348
$theuser->metavalues = $metavalues;
349
+
350
+ $um_values = null;
351
+
352
+ //grab discount code info
353
+ $disSql = $wpdb->prepare("
354
+ SELECT
355
+ c.id,
356
+ c.code
357
+ FROM {$wpdb->pmpro_discount_codes_uses} cu
358
+ LEFT JOIN $wpdb->pmpro_discount_codes c ON cu.code_id = c.id
359
+ WHERE cu.user_id = %d
360
+ ORDER BY c.id DESC
361
+ LIMIT 1",
362
+ $theuser->ID
363
+ );
364
+
365
+ $discount_code = $wpdb->get_row($disSql);
366
+
367
+ //make sure there's data for the discount code info
368
+ if (empty($discount_code))
369
+ {
370
+ $empty_dc = new stdClass();
371
+ $empty_dc->id = '';
372
+ $empty_dc->code = '';
373
+ $discount_code = $empty_dc;
374
+ }
375
+
376
+ unset($disSql);
377
378
//default columns
379
if(!empty($default_columns))
381
$count = 0;
382
foreach($default_columns as $col)
383
{
384
//checking $object->property. note the double $
385
+ array_push($csvoutput, pmpro_enclose(${$col[0]}->{$col[1]})); //output the value
386
}
387
}
388
389
//joindate and enddate
390
+ array_push($csvoutput, pmpro_enclose(date($dateformat, $theuser->joindate)));
391
392
if($theuser->membership_id)
393
{
394
if($theuser->enddate)
395
+ array_push($csvoutput, pmpro_enclose(apply_filters("pmpro_memberslist_expires_column", date($dateformat, $theuser->enddate), $theuser)));
396
else
397
+ array_push($csvoutput, pmpro_enclose(apply_filters("pmpro_memberslist_expires_column", "Never", $theuser)));
398
}
399
elseif($l == "oldmembers" && $theuser->enddate)
400
{
401
+ array_push($csvoutput, pmpro_enclose(date($dateformat, $theuser->enddate)));
402
}
403
else
404
+ array_push($csvoutput, "N/A");
405
406
//any extra columns
407
if(!empty($extra_columns))
408
{
409
foreach($extra_columns as $heading => $callback)
410
{
411
+ array_push($csvoutput, pmpro_enclose(call_user_func($callback, $theuser, $heading)));
412
}
413
}
414
415
+ //free memory for user records
416
+ $metavalues = null;
417
+ $discount_code = null;
418
+ $theuser = null;
419
+
420
+ // $csvoutput .= "\n";
421
+ $line = implode(',', $csvoutput) . "\n";
422
+
423
+ fprintf($csv_fh, "%s", $line);
424
+
425
+ //reset
426
+ $line = null;
427
+ $csvoutput = null;
428
+ } // end of foreach usr_data
429
+
430
+ if (PMPRO_BENCHMARK)
431
+ {
432
+ $end_of_iteration_time = microtime(true);
433
+ $end_of_iteration_memory = memory_get_usage(true);
434
+ }
435
+
436
+ //keep memory consumption low(ish)
437
+ wp_cache_flush();
438
+
439
+ if (PMPRO_BENCHMARK)
440
+ {
441
+ $after_flush_time = microtime(true);
442
+ $after_flush_memory = memory_get_usage(true);
443
+
444
+ $time_in_iteration = $end_of_iteration_time - $start_iteration_time;
445
+ $time_flushing = $after_flush_time - $end_of_iteration_time;
446
+ $userdata_time = $end_of_iteration_time - $pre_userdata_time;
447
+
448
+ list($iteration_sec, $iteration_usec) = explode('.', $time_in_iteration);
449
+ list($udata_sec, $udata_usec) = explode('.', $userdata_time);
450
+ list($flush_sec, $flush_usec) = explode('.', $time_flushing);
451
+
452
+ $memory_used = $end_of_iteration_memory - $start_iteration_memory;
453
454
+ error_log("PMPRO_BENCHMARK - For iteration #{$ic} of {$iterations} - Records processed: " . count($usr_data));
455
+ error_log("PMPRO_BENCHMARK - \tTime processing whole iteration: " . date("H:i:s", $iteration_sec) . ".{$iteration_sec}");
456
+ error_log("PMPRO_BENCHMARK - \tTime processing user data for iteration: " . date("H:i:s", $udata_sec) . ".{$udata_sec}");
457
+ error_log("PMPRO_BENCHMARK - \tTime flushing cache: " . date("H:i:s", $flush_sec) . ".{$flush_usec}");
458
+ error_log("PMPRO_BENCHMARK - \tAdditional memory used during iteration: ".number_format($memory_used, 2, '.', ',') . " bytes");
459
}
460
+
461
+ //need to increase max running time?
462
+ $end = current_time('timestamp');
463
+
464
+ } // end of foreach iteration
465
+
466
+ if (PMPRO_BENCHMARK)
467
+ {
468
+ $after_data_time = microtime(true);
469
+ $after_data_memory = memory_get_peak_usage(true);
470
+
471
+ $time_processing_data = $after_data_time - $start_time;
472
+ $memory_processing_data = $after_data_memory - $start_memory;
473
+
474
+ list($sec, $usec) = explode('.', $time_processing_data);
475
+
476
+ error_log("PMPRO_BENCHMARK - Time processing data: {$sec}.{$usec} seconds");
477
+ error_log("PMPRO_BENCHMARK - Peak memory usage: " . number_format($memory_processing_data, false, '.', ',') . " bytes");
478
}
479
480
+ // free memory
481
+ $usr_data = null;
482
+
483
+ // send the data to the remote browser
484
+ pmpro_transmit_content($csv_fh, $filename, $headers);
485
+
486
+ exit;
487
488
function pmpro_enclose($s)
489
{
490
return "\"" . str_replace("\"", "\\\"", $s) . "\"";
491
+ }
492
+
493
+ // responsible for trasnmitting content of file to remote browser
494
+ function pmpro_transmit_content( $csv_fh, $filename, $headers = array() ) {
495
+
496
+ //close the temp file
497
+ fclose($csv_fh);
498
+
499
+ //make sure we get the right file size
500
+ clearstatcache( true, $filename );
501
+
502
+ //did we accidentally send errors/warnings to browser?
503
+ if (headers_sent())
504
+ {
505
+ echo str_repeat('-', 75) . "<br/>\n";
506
+ echo 'Please open a support case and paste in the warnings/errors you see above this text to\n ';
507
+ echo 'the <a href="http://paidmembershipspro.com/support/" target="_blank">Paid Memberships Pro support forum</a><br/>\n';
508
+ echo str_repeat("=", 75) . "<br/>\n";
509
+ echo file_get_contents($filename);
510
+ echo str_repeat("=", 75) . "<br/>\n";
511
+ }
512
+
513
+ //transmission
514
+ if (! empty($headers) )
515
+ {
516
+ //set the download size
517
+ $headers[] = "Content/Length: " . filesize($filename);
518
+
519
+ //set headers
520
+ foreach($headers as $header)
521
+ {
522
+ header($header . "\r\n");
523
+ }
524
+
525
+ // open and send the file contents to the remote location
526
+ $fh = fopen( $filename, 'rb' );
527
+ fpassthru($fh);
528
+ fclose($fh);
529
+
530
+ // remove the temp file
531
+ unlink($filename);
532
+ }
533
+
534
+ //allow user to clean up after themselves
535
+ do_action('pmpro_after_members_list_csv_export');
536
+ exit;
537
+ }
adminpages/reports/memberships.php CHANGED
@@ -164,7 +164,7 @@ function pmpro_report_memberships_page()
164
$cols[$i]->signups = 0;
165
foreach($dates as $day => $date)
166
{
167
- if( $day == $i ) {
168
$cols[$i]->signups = $date->signups;
169
}
170
}
@@ -234,6 +234,19 @@ function pmpro_report_memberships_page()
234
235
$sqlQuery .= " GROUP BY date ORDER BY date ";
236
237
$cdates = $wpdb->get_results($sqlQuery, OBJECT_K);
238
239
foreach( $dates as $day => &$date )
@@ -518,6 +531,18 @@ function pmpro_getCancellations($period = false, $levels = 'all', $status = arra
518
if(!empty($levels) && $levels != 'all')
519
$sqlQuery .= "AND membership_id IN(" . $levels . ") ";
520
521
$cancellations = $wpdb->get_var($sqlQuery);
522
523
//save in cache
164
$cols[$i]->signups = 0;
165
foreach($dates as $day => $date)
166
{
167
+ if( $date->date == $i ) {
168
$cols[$i]->signups = $date->signups;
169
}
170
}
234
235
$sqlQuery .= " GROUP BY date ORDER BY date ";
236
237
+ /**
238
+ * Filter query to get cancellation numbers in signups vs cancellations detailed report.
239
+ *
240
+ * @since 1.8.8
241
+ *
242
+ * @param string $sqlQuery The current SQL
243
+ * @param string $type report type
244
+ * @param string $startdate Start Date in YYYY-MM-DD format
245
+ * @param string $enddate End Date in YYYY-MM-DD format
246
+ * @param int $l Level ID
247
+ */
248
+ $sqlQuery = apply_filters('pmpro_reports_signups_sql', $sqlQuery, $type, $startdate, $enddate, $l);
249
+
250
$cdates = $wpdb->get_results($sqlQuery, OBJECT_K);
251
252
foreach( $dates as $day => &$date )
531
if(!empty($levels) && $levels != 'all')
532
$sqlQuery .= "AND membership_id IN(" . $levels . ") ";
533
534
+ /**
535
+ * Filter query to get cancellation numbers in signups vs cancellations detailed report.
536
+ *
537
+ * @since 1.8.8
538
+ *
539
+ * @param string $sqlQuery The current SQL
540
+ * @param string $period Period for report. today, this month, this year, empty string for all time.
541
+ * @param array(int) $levels Level IDs to include in report.
542
+ * @param array(string) $status Statuses to include as cancelled.
543
+ */
544
+ $sqlQuery = apply_filters('pmpro_reports_get_cancellations_sql', $sqlQuery, $period, $levels, $status);
545
+
546
$cancellations = $wpdb->get_var($sqlQuery);
547
548
//save in cache
adminpages/updates.php CHANGED
@@ -5,6 +5,9 @@
5
die(__("You do not have permissions to perform this action.", "pmpro"));
6
}
7
8
require_once(dirname(__FILE__) . "/admin_header.php");
9
?>
10
@@ -16,6 +19,7 @@
16
//let's process the first one
17
?>
18
<p id="pmpro_updates_intro"><?php _e('Updates are processing. This may take a few minutes to complete.', 'pmpro');?></p>
19
<textarea id="pmpro_updates_status" rows="10" cols="60">Loading...</textarea>
20
21
<?php
5
die(__("You do not have permissions to perform this action.", "pmpro"));
6
}
7
8
+ //reset this transient so we know the page was just loaded
9
+ set_transient('pmpro_updates_first_load', true, 60*60*24);
10
+
11
require_once(dirname(__FILE__) . "/admin_header.php");
12
?>
13
19
//let's process the first one
20
?>
21
<p id="pmpro_updates_intro"><?php _e('Updates are processing. This may take a few minutes to complete.', 'pmpro');?></p>
22
+ <p id="pmpro_updates_progress">[...]</p>
23
<textarea id="pmpro_updates_status" rows="10" cols="60">Loading...</textarea>
24
25
<?php
classes/class.memberorder.php CHANGED
@@ -576,7 +576,7 @@
576
'" . esc_sql($this->billing->zip) . "',
577
'" . esc_sql($this->billing->country) . "',
578
'" . cleanPhone($this->billing->phone) . "',
579
- '" . $amount . "',
580
'" . $tax . "',
581
'" . $this->couponamount. "',
582
" . intval($this->certificate_id) . ",
576
'" . esc_sql($this->billing->zip) . "',
577
'" . esc_sql($this->billing->country) . "',
578
'" . cleanPhone($this->billing->phone) . "',
579
+ '" . $subtotal . "',
580
'" . $tax . "',
581
'" . $this->couponamount. "',
582
" . intval($this->certificate_id) . ",
classes/gateways/class.pmprogateway_payflowpro.php CHANGED
@@ -381,7 +381,7 @@
381
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
382
//$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
383
384
- $nvpStr .= "&PROFILENAME=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
385
386
$nvpStr .= "&PAYPERIOD=" . $payperiod;
387
@@ -484,7 +484,7 @@
484
$nvpStr = "&ORIGPROFILEID=" . $order->subscription_transaction_id . "&ACTION=M";
485
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
486
487
- $nvpStr .= "&PROFILENAME=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
488
489
$nvpStr .= "&CUSTIP=" . $_SERVER['REMOTE_ADDR']; // . "&INVNUM=" . $order->code;
490
@@ -587,6 +587,7 @@
587
588
//post to PayPal
589
$response = wp_remote_post( $API_Endpoint, array(
590
'sslverify' => FALSE,
591
'httpversion' => '1.1',
592
'body' => $nvpreq
381
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
382
//$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
383
384
+ $nvpStr .= "&PROFILENAME=" . urlencode( apply_filters( 'pmpro_paypal_level_description', substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127), $order->membership_level->name, $order, get_bloginfo("name")) );
385
386
$nvpStr .= "&PAYPERIOD=" . $payperiod;
387
484
$nvpStr = "&ORIGPROFILEID=" . $order->subscription_transaction_id . "&ACTION=M";
485
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
486
487
+ $nvpStr .= "&PROFILENAME=" . urlencode( apply_filters( 'pmpro_paypal_level_description', substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127), $order->membership_level->name, $order, get_bloginfo("name")) );
488
489
$nvpStr .= "&CUSTIP=" . $_SERVER['REMOTE_ADDR']; // . "&INVNUM=" . $order->code;
490
587
588
//post to PayPal
589
$response = wp_remote_post( $API_Endpoint, array(
590
+ 'timeout' => 60,
591
'sslverify' => FALSE,
592
'httpversion' => '1.1',
593
'body' => $nvpreq
classes/gateways/class.pmprogateway_paypal.php CHANGED
@@ -471,11 +471,12 @@
471
472
//paypal profile stuff
473
$nvpStr = "";
474
if(!empty($order->Token))
475
$nvpStr .= "&TOKEN=" . $order->Token;
476
$nvpStr .="&AMT=" . $order->PaymentAmount . "&TAXAMT=" . $amount_tax . "&CURRENCYCODE=" . $pmpro_currency . "&PROFILESTARTDATE=" . $order->ProfileStartDate;
477
$nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
478
- $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
479
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
480
//$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
481
@@ -638,6 +639,7 @@
638
639
//post to PayPal
640
$response = wp_remote_post( $API_Endpoint, array(
641
'sslverify' => FALSE,
642
'httpversion' => '1.1',
643
'body' => $nvpreq
471
472
//paypal profile stuff
473
$nvpStr = "";
474
+
475
if(!empty($order->Token))
476
$nvpStr .= "&TOKEN=" . $order->Token;
477
$nvpStr .="&AMT=" . $order->PaymentAmount . "&TAXAMT=" . $amount_tax . "&CURRENCYCODE=" . $pmpro_currency . "&PROFILESTARTDATE=" . $order->ProfileStartDate;
478
$nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
479
+ $nvpStr .= "&DESC=" . urlencode( apply_filters( 'pmpro_paypal_level_description', substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127), $order->membership_level->name, $order, get_bloginfo("name")) );
480
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
481
//$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
482
639
640
//post to PayPal
641
$response = wp_remote_post( $API_Endpoint, array(
642
+ 'timeout' => 60,
643
'sslverify' => FALSE,
644
'httpversion' => '1.1',
645
'body' => $nvpreq
classes/gateways/class.pmprogateway_paypalexpress.php CHANGED
@@ -490,7 +490,7 @@
490
$nvpStr .= "&PROFILESTARTDATE=" . $order->ProfileStartDate;
491
if(!empty($order->BillingFrequency))
492
$nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling&L_BILLINGTYPE0=RecurringPayments";
493
- $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
494
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
495
$nvpStr .= "&NOSHIPPING=1&L_BILLINGAGREEMENTDESCRIPTION0=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127)) . "&L_PAYMENTTYPE0=Any";
496
@@ -625,7 +625,7 @@
625
*/
626
if(!empty($order->BillingFrequency))
627
$nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
628
- $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
629
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
630
$nvpStr .= "&NOSHIPPING=1";
631
@@ -684,7 +684,7 @@
684
$nvpStr .= "&TAXAMT=" . $amount_tax;
685
$nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
686
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
687
- $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
688
689
//if billing cycles are defined
690
if(!empty($order->TotalBillingCycles))
@@ -849,6 +849,7 @@
849
850
//post to PayPal
851
$response = wp_remote_post( $API_Endpoint, array(
852
'sslverify' => FALSE,
853
'httpversion' => '1.1',
854
'body' => $nvpreq
490
$nvpStr .= "&PROFILESTARTDATE=" . $order->ProfileStartDate;
491
if(!empty($order->BillingFrequency))
492
$nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling&L_BILLINGTYPE0=RecurringPayments";
493
+ $nvpStr .= "&DESC=" . urlencode( apply_filters( 'pmpro_paypal_level_description', substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127), $order->membership_level->name, $order, get_bloginfo("name")) );
494
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
495
$nvpStr .= "&NOSHIPPING=1&L_BILLINGAGREEMENTDESCRIPTION0=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127)) . "&L_PAYMENTTYPE0=Any";
496
625
*/
626
if(!empty($order->BillingFrequency))
627
$nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
628
+ $nvpStr .= "&DESC=" . urlencode( apply_filters( 'pmpro_paypal_level_description', substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127), $order->membership_level->name, $order, get_bloginfo("name")) );
629
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
630
$nvpStr .= "&NOSHIPPING=1";
631
684
$nvpStr .= "&TAXAMT=" . $amount_tax;
685
$nvpStr .= "&BILLINGPERIOD=" . $order->BillingPeriod . "&BILLINGFREQUENCY=" . $order->BillingFrequency . "&AUTOBILLAMT=AddToNextBilling";
686
$nvpStr .= "&NOTIFYURL=" . urlencode(admin_url('admin-ajax.php') . "?action=ipnhandler");
687
+ $nvpStr .= "&DESC=" . urlencode( apply_filters( 'pmpro_paypal_level_description', substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127), $order->membership_level->name, $order, get_bloginfo("name")) );
688
689
//if billing cycles are defined
690
if(!empty($order->TotalBillingCycles))
849
850
//post to PayPal
851
$response = wp_remote_post( $API_Endpoint, array(
852
+ 'timeout' => 60,
853
'sslverify' => FALSE,
854
'httpversion' => '1.1',
855
'body' => $nvpreq
classes/gateways/class.pmprogateway_paypalstandard.php CHANGED
@@ -497,6 +497,7 @@
497
498
//post to PayPal
499
$response = wp_remote_post( $API_Endpoint, array(
500
'sslverify' => FALSE,
501
'httpversion' => '1.1',
502
'body' => $nvpreq
@@ -505,7 +506,7 @@
505
506
if ( is_wp_error( $response ) ) {
507
$error_message = $response->get_error_message();
508
- die( "methodName_ failed: $error_message" );
509
} else {
510
//extract the response details
511
$httpParsedResponseAr = array();
497
498
//post to PayPal
499
$response = wp_remote_post( $API_Endpoint, array(
500
+ 'timeout' => 60,
501
'sslverify' => FALSE,
502
'httpversion' => '1.1',
503
'body' => $nvpreq
506
507
if ( is_wp_error( $response ) ) {
508
$error_message = $response->get_error_message();
509
+ die( "{$methodName_} failed: $error_message" );
510
} else {
511
//extract the response details
512
$httpParsedResponseAr = array();
classes/gateways/class.pmprogateway_stripe.php CHANGED
@@ -1186,7 +1186,13 @@
1186
}
1187
1188
//get name and email values from order in case we update
1189
- $name = trim($order->FirstName . " " . $order->LastName);
1190
if(empty($name) && !empty($user->ID))
1191
{
1192
$name = trim($user->first_name . " " . $user->last_name);
@@ -1198,8 +1204,12 @@
1198
elseif(empty($name))
1199
$name = "No Name";
1200
1201
$email = $order->Email;
1202
- if(empty($email) && !empty($user->ID))
1203
{
1204
$email = $user->user_email;
1205
}
1186
}
1187
1188
//get name and email values from order in case we update
1189
+ if(!empty($order->FirstName) && !empty($order->LastName))
1190
+ $name = trim($order->FirstName . " " . $order->LastName);
1191
+ elseif(!empty($order->FirstName))
1192
+ $name = $order->FirstName;
1193
+ elseif(!empty($order->LastName))
1194
+ $name = $order->LastName;
1195
+
1196
if(empty($name) && !empty($user->ID))
1197
{
1198
$name = trim($user->first_name . " " . $user->last_name);
1204
elseif(empty($name))
1205
$name = "No Name";
1206
1207
+ if(!empty($order->Email))
1208
+ $email = $order->Email;
1209
+ else
1210
+ $email = "";
1211
$email = $order->Email;
1212
+ if(empty($email) && !empty($user->ID) && !empty($user->user_email))
1213
{
1214
$email = $user->user_email;
1215
}
includes/capabilities.php ADDED
@@ -0,0 +1,68 @@
1
+ <?php
2
+ //make sure administrators have correct capabilities
3
+ function pmpro_check_admin_capabilities()
4
+ {
5
+ // Grab the defined (needed) admin capabilities
6
+ $roles = pmpro_get_capability_defs('administrator');
7
+
8
+ $caps_configured = true;
9
+
10
+ // check whether the current user has those capabilities already
11
+ foreach( $roles as $r )
12
+ {
13
+ $caps_configured = $caps_configured && current_user_can($r);
14
+ }
15
+
16
+ // if not, set the
17
+ if ( false === $caps_configured && current_user_can('administrator'))
18
+ {
19
+ pmpro_set_capabilities_for_role('administrator');
20
+ }
21
+ }
22
+ add_action('admin_init', 'pmpro_check_admin_capabilities', 10, 2);
23
+
24
+ // use the capability definition for $role_name and add/remove capabilities as requested
25
+ function pmpro_set_capabilities_for_role( $role_name, $action = 'enable' )
26
+ {
27
+ $cap_array = pmpro_get_capability_defs($role_name);
28
+
29
+ //add caps to specified role
30
+ $role = get_role( $role_name );
31
+
32
+ // Iterate through the relevant caps for the role & add or remove them
33
+ foreach( $cap_array as $cap_name )
34
+ {
35
+ if ( $action == 'enable' )
36
+ $role->add_cap($cap_name);
37
+
38
+ if ( $action == 'disable' )
39
+ $role->remove_cap($cap_name);
40
+ }
41
+ }
42
+
43
+ // used to define what capabilities goes with what role.
44
+ function pmpro_get_capability_defs($role)
45
+ {
46
+ // TODO: Add other standard roles (if/when needed)
47
+
48
+ // caps for the administrator role
49
+ $cap_array = array(
50
+ 'pmpro_memberships_menu',
51
+ 'pmpro_membershiplevels',
52
+ 'pmpro_edit_memberships',
53
+ 'pmpro_pagesettings',
54
+ 'pmpro_paymentsettings',
55
+ 'pmpro_emailsettings',
56
+ 'pmpro_advancedsettings',
57
+ 'pmpro_addons',
58
+ 'pmpro_memberslist',
59
+ 'pmpro_memberslistcsv',
60
+ 'pmpro_reports',
61
+ 'pmpro_orders',
62
+ 'pmpro_orderscsv',
63
+ 'pmpro_discountcodes',
64
+ 'pmpro_updates'
65
+ );
66
+
67
+ return apply_filters( "pmpro_assigned_{$role}_capabilities", $cap_array);
68
+ }
includes/content.php CHANGED
@@ -5,22 +5,23 @@
5
function pmpro_has_membership_access($post_id = NULL, $user_id = NULL, $return_membership_levels = false)
6
{
7
global $post, $wpdb, $current_user;
8
- //use globals if no values supplied
9
- if(!$post_id && !empty($post))
10
- $post_id = $post->ID;
11
- if(!$user_id)
12
- $user_id = $current_user->ID;
13
14
//no post, return true (changed from false in version 1.7.2)
15
if(!$post_id)
16
return true;
17
-
18
- if (!isset($post->post_type))
19
- return true;
20
-
21
//if no post or current_user object, set them up
22
- if( isset($post->ID) && !empty($post->ID) && $post_id == $post->ID)
23
- $mypost = $post;
24
else
25
$mypost = get_post($post_id);
26
5
function pmpro_has_membership_access($post_id = NULL, $user_id = NULL, $return_membership_levels = false)
6
{
7
global $post, $wpdb, $current_user;
8
9
+ //use queried object if no value is supplied
10
+ $queried_object = get_queried_object();
11
+ if(!$post_id && !empty($queried_object) && !empty($queried_object->ID))
12
+ $post_id = $queried_object->ID;
13
+
14
//no post, return true (changed from false in version 1.7.2)
15
if(!$post_id)
16
return true;
17
+
18
+ //use current user if no value is supplied
19
+ if(!$user_id)
20
+ $user_id = $current_user->ID;
21
+
22
//if no post or current_user object, set them up
23
+ if( isset($queried_object->ID) && !empty($queried_object->ID) && $post_id == $queried_object->ID)
24
+ $mypost = $queried_object;
25
else
26
$mypost = get_post($post_id);
27
includes/functions.php CHANGED
@@ -739,7 +739,7 @@ function pmpro_changeMembershipLevel($level, $user_id = NULL, $old_level_status
739
740
if(!$wpdb->query($sql))
741
{
742
- $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
743
744
return false;
745
}
@@ -812,7 +812,7 @@ function pmpro_changeMembershipLevel($level, $user_id = NULL, $old_level_status
812
813
if(!$wpdb->query($sql))
814
{
815
- $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
816
return false;
817
}
818
}
@@ -836,7 +836,7 @@ function pmpro_changeMembershipLevel($level, $user_id = NULL, $old_level_status
836
837
if(!$wpdb->query($sql))
838
{
839
- $pmpro_error = __("Error interacting with database", "pmpro") . ": ".(mysql_errno()?mysql_error():'unavailable');
840
return false;
841
}
842
}
@@ -886,13 +886,13 @@ function pmpro_toggleMembershipCategory( $level, $category, $value )
886
{
887
$sql = "REPLACE INTO {$wpdb->pmpro_memberships_categories} (`membership_id`,`category_id`) VALUES ('$level','$category')";
888
$wpdb->query($sql);
889
- if(mysql_errno()) return mysql_error();
890
}
891
else
892
{
893
$sql = "DELETE FROM {$wpdb->pmpro_memberships_categories} WHERE `membership_id` = '$level' AND `category_id` = '$category' LIMIT 1";
894
$wpdb->query($sql);
895
- if(mysql_errno()) return mysql_error();
896
}
897
898
return true;
@@ -924,7 +924,7 @@ function pmpro_updateMembershipCategories($level, $categories)
924
// remove all existing links...
925
$sqlQuery = "DELETE FROM $wpdb->pmpro_memberships_categories WHERE `membership_id` = '" . esc_sql($level) . "'";
926
$wpdb->query($sqlQuery);
927
- if(mysql_errno()) return mysql_error();
928
929
// add the given links [back?] in...
930
foreach($categories as $cat)
739
740
if(!$wpdb->query($sql))
741
{
742
+ $pmpro_error = __("Error interacting with database", "pmpro") . ": ".($wpdb->last_error?$wpdb->last_error:'unavailable');
743
744
return false;
745
}
812
813
if(!$wpdb->query($sql))
814
{
815
+ $pmpro_error = __("Error interacting with database", "pmpro") . ": ".($wpdb->last_error?$wpdb->last_error:'unavailable');
816
return false;
817
}
818
}
836
837
if(!$wpdb->query($sql))
838
{
839
+ $pmpro_error = __("Error interacting with database", "pmpro") . ": ".($wpdb->last_error?$wpdb->last_error:'unavailable');
840
return false;
841
}
842
}
886
{
887
$sql = "REPLACE INTO {$wpdb->pmpro_memberships_categories} (`membership_id`,`category_id`) VALUES ('$level','$category')";
888
$wpdb->query($sql);
889
+ if($wpdb->last_error) return $wpdb->last_error;
890
}
891
else
892
{
893
$sql = "DELETE FROM {$wpdb->pmpro_memberships_categories} WHERE `membership_id` = '$level' AND `category_id` = '$category' LIMIT 1";
894
$wpdb->query($sql);
895
+ if($wpdb->last_error) return $wpdb->last_error;
896
}
897
898
return true;
924
// remove all existing links...
925
$sqlQuery = "DELETE FROM $wpdb->pmpro_memberships_categories WHERE `membership_id` = '" . esc_sql($level) . "'";
926
$wpdb->query($sqlQuery);
927
+ if($wpdb->last_error) return $wpdb->last_error;
928
929
// add the given links [back?] in...
930
foreach($categories as $cat)
includes/updates.php CHANGED
@@ -44,7 +44,7 @@ function pmpro_removeUpdate($update) {
44
*/
45
function pmpro_enqueue_update_js() {
46
if(!empty($_REQUEST['page']) && $_REQUEST['page'] == 'pmpro-updates') {
47
- wp_enqueue_script( 'pmpro-updates', plugin_dir_url( dirname(__FILE__) ) . 'js/updates.js' );
48
}
49
}
50
add_action('admin_enqueue_scripts', 'pmpro_enqueue_update_js');
@@ -62,8 +62,16 @@ function pmpro_wp_ajax_pmpro_updates() {
62
call_user_func($updates[0]);
63
echo ". ";
64
} else {
65
- echo "done";
66
}
67
68
exit;
69
}
44
*/
45
function pmpro_enqueue_update_js() {
46
if(!empty($_REQUEST['page']) && $_REQUEST['page'] == 'pmpro-updates') {
47
+ wp_enqueue_script( 'pmpro-updates', plugin_dir_url( dirname(__FILE__) ) . 'js/updates.js', array('jquery'), PMPRO_VERSION );
48
}
49
}
50
add_action('admin_enqueue_scripts', 'pmpro_enqueue_update_js');
62
call_user_func($updates[0]);
63
echo ". ";
64
} else {
65
+ echo "[done]";
66
}
67
+
68
+ //reset this transient so we know AJAX is running
69
+ set_transient('pmpro_updates_first_load', false, 60*60*24);
70
+
71
+ //show progress
72
+ global $pmpro_updates_progress;
73
+ if(!empty($pmpro_updates_progress))
74
+ echo $pmpro_updates_progress;
75
76
exit;
77
}
includes/updates/upgrade_1.php ADDED
@@ -0,0 +1,50 @@
1
+ <?php
2
+ function pmpro_upgrade_1()
3
+ {
4
+ /*
5
+ default options
6
+ */
7
+ $nonmembertext = sprintf( __( 'This content is for !!levels!! members only.<br /><a href="%s">Register</a>', 'pmpro' ), wp_login_url() . "?action=register" );
8
+ pmpro_setOption("nonmembertext", $nonmembertext);
9
+
10
+ $notloggedintext = sprintf( __( 'This content is for !!levels!! members only.<br /><a href="%s">Log In</a> <a href="%s">Register</a>', 'pmpro' ), wp_login_url(), wp_login_url() . "?action=register" );
11
+ '?action=register">Register</a>';
12
+ pmpro_setOption("notloggedintext", $notloggedintext);
13
+
14
+ $rsstext = __( "This content is for !!levels!! members only. Visit the site and log in/register to read.", 'pmpro' );
15
+ pmpro_setOption("rsstext", $rsstext);
16
+
17
+ $gateway_environment = "sandbox";
18
+ pmpro_setOption("gateway_environment", $gateway_environment);
19
+
20
+ $pmpro_currency = "USD";
21
+ pmpro_setOption("currency", $pmpro_currency);
22
+
23
+ $pmpro_accepted_credit_cards = "Visa,Mastercard,American Express,Discover";
24
+ pmpro_setOption("accepted_credit_cards", $pmpro_accepted_credit_cards);
25
+
26
+ $parsed = parse_url(home_url());
27
+ $hostname = $parsed['host'];
28
+ $hostparts = explode(".", $hostname);
29
+ $email_domain = $hostparts[count($hostparts) - 2] . "." . $hostparts[count($hostparts) - 1];
30
+ $from_email = "wordpress@" . $email_domain;
31
+ pmpro_setOption("from_email", $from_email);
32
+
33
+ $from_name = "WordPress";
34
+ pmpro_setOption("from_name", $from_name);
35
+
36
+ //setting new email settings defaults
37
+ pmpro_setOption("email_admin_checkout", "1");
38
+ pmpro_setOption("email_admin_changes", "1");
39
+ pmpro_setOption("email_admin_cancels", "1");
40
+ pmpro_setOption("email_admin_billing", "1");
41
+
42
+ pmpro_setOption("tospage", "");
43
+
44
+ //db update
45
+ pmpro_db_delta();
46
+
47
+ //update version and return
48
+ pmpro_setOption("db_version", "1.71"); //no need to run other updates
49
+ return 1.71;
50
+ }
includes/updates/upgrade_1_1_15.php ADDED
@@ -0,0 +1,138 @@
1
+ <?php
2
+ function pmpro_upgrade_1_1_15()
3
+ {
4
+ /*
5
+ DB table setup
6
+ */
7
+ global $wpdb;
8
+ $wpdb->hide_errors();
9
+ $wpdb->pmpro_membership_levels = $wpdb->prefix . 'pmpro_membership_levels';
10
+ $wpdb->pmpro_memberships_users = $wpdb->prefix . 'pmpro_memberships_users';
11
+ $wpdb->pmpro_memberships_categories = $wpdb->prefix . 'pmpro_memberships_categories';
12
+ $wpdb->pmpro_memberships_pages = $wpdb->prefix . 'pmpro_memberships_pages';
13
+ $wpdb->pmpro_membership_orders = $wpdb->prefix . 'pmpro_membership_orders';
14
+ $wpdb->pmpro_discount_codes = $wpdb->prefix . 'pmpro_discount_codes';
15
+ $wpdb->pmpro_discount_codes_levels = $wpdb->prefix . 'pmpro_discount_codes_levels';
16
+ $wpdb->pmpro_discount_codes_uses = $wpdb->prefix . 'pmpro_discount_codes_uses';
17
+
18
+ /*
19
+ Changing some id columns to unsigned.
20
+ */
21
+ $sqlQuery = "
22
+ ALTER TABLE `" . $wpdb->pmpro_membership_levels . "` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT
23
+ ";
24
+ $wpdb->query($sqlQuery);
25
+
26
+ $sqlQuery = "
27
+ ALTER TABLE `" . $wpdb->pmpro_memberships_categories . "` CHANGE `membership_id` `membership_id` INT( 11 ) UNSIGNED NOT NULL
28
+ ";
29
+ $wpdb->query($sqlQuery);
30
+
31
+ $sqlQuery = "
32
+ ALTER TABLE `" . $wpdb->pmpro_memberships_categories . "` CHANGE `category_id` `category_id` INT( 11 ) UNSIGNED NOT NULL
33
+ ";
34
+ $wpdb->query($sqlQuery);
35
+
36
+ $sqlQuery = "
37
+ ALTER TABLE `" . $wpdb->pmpro_memberships_pages . "` CHANGE `membership_id` `membership_id` INT( 11 ) UNSIGNED NOT NULL
38
+ ";
39
+ $wpdb->query($sqlQuery);
40
+
41
+ $sqlQuery = "
42
+ ALTER TABLE `" . $wpdb->pmpro_memberships_pages . "` CHANGE `page_id` `page_id` INT( 11 ) UNSIGNED NOT NULL
43
+ ";
44
+ $wpdb->query($sqlQuery);
45
+
46
+ $sqlQuery = "
47
+ ALTER TABLE `" . $wpdb->pmpro_memberships_users . "` CHANGE `user_id` `user_id` INT( 11 ) UNSIGNED NOT NULL
48
+ ";
49
+ $wpdb->query($sqlQuery);
50
+
51
+ $sqlQuery = "
52
+ ALTER TABLE `" . $wpdb->pmpro_memberships_users . "` CHANGE `membership_id` `membership_id` INT( 11 ) UNSIGNED NOT NULL
53
+ ";
54
+ $wpdb->query($sqlQuery);
55
+
56
+ $sqlQuery = "
57
+ ALTER TABLE `" . $wpdb->pmpro_membership_orders . "` CHANGE `id` `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT
58
+ ";
59
+ $wpdb->query($sqlQuery);
60
+
61
+ $sqlQuery = "
62
+ ALTER TABLE `" . $wpdb->pmpro_membership_orders . "` CHANGE `user_id` `user_id` INT( 11 ) UNSIGNED NOT NULL DEFAULT '0'
63
+ ";
64
+ $wpdb->query($sqlQuery);
65
+
66
+ $sqlQuery = "
67
+ ALTER TABLE `" . $wpdb->pmpro_membership_orders . "` CHANGE `membership_id` `membership_id` INT( 11 ) UNSIGNED NOT NULL DEFAULT '0'
68
+ ";
69
+ $wpdb->query($sqlQuery);
70
+
71
+ $sqlQuery = "
72
+ ALTER TABLE `" . $wpdb->pmpro_memberships_users . "` ADD `code_id` INT UNSIGNED NOT NULL AFTER `membership_id` ;
73
+ ";
74
+ $wpdb->query($sqlQuery);
75
+
76
+ $sqlQuery = "
77
+ ALTER TABLE `" . $wpdb->pmpro_memberships_users . "` ADD INDEX ( `code_id` )
78
+ ";
79
+ $wpdb->query($sqlQuery);
80
+
81
+ /*
82
+ New tables for discount codes
83
+ */
84
+
85
+ //wp_pmpro_discount_codes
86
+ $sqlQuery = "
87
+ CREATE TABLE `" . $wpdb->pmpro_discount_codes . "` (
88
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
89
+ `code` varchar(32) NOT NULL,
90
+ `starts` date NOT NULL,
91
+ `expires` date NOT NULL,
92
+ `uses` int(11) NOT NULL,
93
+ PRIMARY KEY (`id`),
94
+ UNIQUE KEY `code` (`code`),
95
+ KEY `starts` (`starts`),
96
+ KEY `expires` (`expires`)
97
+ );
98
+ ";
99
+ $wpdb->query($sqlQuery);
100
+
101
+ //wp_pmpro_discount_codes_levels
102
+ $sqlQuery = "
103
+ CREATE TABLE `" . $wpdb->pmpro_discount_codes_levels . "` (
104
+ `code_id` int(11) unsigned NOT NULL,
105
+ `level_id` int(11) unsigned NOT NULL,
106
+ `initial_payment` decimal(10,2) NOT NULL DEFAULT '0.00',
107
+ `billing_amount` decimal(10,2) NOT NULL DEFAULT '0.00',
108
+ `cycle_number` int(11) NOT NULL DEFAULT '0',
109
+ `cycle_period` enum('Day','Week','Month','Year') DEFAULT 'Month',
110
+ `billing_limit` int(11) NOT NULL COMMENT 'After how many cycles should billing stop?',
111
+ `trial_amount` decimal(10,2) NOT NULL DEFAULT '0.00',
112
+ `trial_limit` int(11) NOT NULL DEFAULT '0',
113
+ PRIMARY KEY (`code_id`,`level_id`),
114
+ KEY `initial_payment` (`initial_payment`)
115
+ );
116
+ ";
117
+ $wpdb->query($sqlQuery);
118
+
119
+ //wp_pmpro_discount_codes_uses
120
+ $sqlQuery = "
121
+ CREATE TABLE `" . $wpdb->pmpro_discount_codes_uses . "` (
122
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
123
+ `code_id` int(10) unsigned NOT NULL,
124
+ `user_id` int(10) unsigned NOT NULL,
125
+ `order_id` int(10) unsigned NOT NULL,
126
+ `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
127
+ PRIMARY KEY (`id`),
128
+ KEY `user_id` (`user_id`),
129
+ KEY `timestamp` (`timestamp`)
130
+ );
131
+ ";
132
+ $wpdb->query($sqlQuery);
133
+
134
+ pmpro_setOption("db_version", "1.115");
135
+
136
+ //do the next update
137
+ return 1.115;
138
+ }
includes/updates/upgrade_1_2_3.php ADDED
@@ -0,0 +1,42 @@
1
+ <?php
2
+ function pmpro_upgrade_1_2_3()
3
+ {
4
+ global $wpdb;
5
+ $wpdb->hide_errors();
6
+ $wpdb->pmpro_membership_levels = $wpdb->prefix . 'pmpro_membership_levels';
7
+ $wpdb->pmpro_memberships_users = $wpdb->prefix . 'pmpro_memberships_users';
8
+ $wpdb->pmpro_memberships_categories = $wpdb->prefix . 'pmpro_memberships_categories';
9
+ $wpdb->pmpro_memberships_pages = $wpdb->prefix . 'pmpro_memberships_pages';
10
+ $wpdb->pmpro_membership_orders = $wpdb->prefix . 'pmpro_membership_orders';
11
+ $wpdb->pmpro_discount_codes = $wpdb->prefix . 'pmpro_discount_codes';
12
+ $wpdb->pmpro_discount_codes_levels = $wpdb->prefix . 'pmpro_discount_codes_levels';
13
+ $wpdb->pmpro_discount_codes_uses = $wpdb->prefix . 'pmpro_discount_codes_uses';
14
+
15
+ //expiration number and period for levels
16
+ $sqlQuery = "
17
+ ALTER TABLE `" . $wpdb->pmpro_membership_levels . "` ADD `expiration_number` INT UNSIGNED NOT NULL ,
18
+ ADD `expiration_period` ENUM( 'Day', 'Week', 'Month', 'Year' ) NOT NULL
19
+ ";
20
+ $wpdb->query($sqlQuery);
21
+
22
+ //expiration number and period for discount code levels
23
+ $sqlQuery = "
24
+ ALTER TABLE `" . $wpdb->pmpro_discount_codes_levels . "` ADD `expiration_number` INT UNSIGNED NOT NULL ,
25
+ ADD `expiration_period` ENUM( 'Day', 'Week', 'Month', 'Year' ) NOT NULL
26
+ ";
27
+ $wpdb->query($sqlQuery);
28
+
29
+ //end date for members
30
+ $sqlQuery = "
31
+ ALTER TABLE `" . $wpdb->pmpro_memberships_users . "` ADD `enddate` DATETIME NULL AFTER `startdate`
32
+ ";
33
+ $wpdb->query($sqlQuery);
34
+
35
+ $sqlQuery = "
36
+ ALTER TABLE `" . $wpdb->pmpro_memberships_users . "` ADD INDEX ( `enddate` )
37
+ ";
38
+ $wpdb->query($sqlQuery);
39
+
40
+ pmpro_setOption("db_version", "1.23");
41
+ return 1.23;
42
+ }
includes/updates/upgrade_1_3_18.php ADDED
@@ -0,0 +1,12 @@
1
+ <?php
2
+ function pmpro_upgrade_1_3_18()
3
+ {
4
+ //setting new email settings defaults
5
+ pmpro_setOption("email_admin_checkout", "1");
6
+ pmpro_setOption("email_admin_changes", "1");
7
+ pmpro_setOption("email_admin_cancels", "1");
8
+ pmpro_setOption("email_admin_billing", "1");
9
+
10
+ pmpro_setOption("db_version", "1.318");
11
+ return 1.318;
12
+ }
includes/updates/upgrade_1_4.php ADDED
@@ -0,0 +1,16 @@
1
+ <?php
2
+ function pmpro_upgrade_1_4()
3
+ {
4
+ global $wpdb;
5
+ $wpdb->hide_errors();
6
+ $wpdb->pmpro_membership_levels = $wpdb->prefix . 'pmpro_membership_levels';
7
+
8
+ //confirmation message
9
+ $sqlQuery = "
10
+ ALTER TABLE `" . $wpdb->pmpro_membership_levels . "` ADD `confirmation` LONGTEXT NOT NULL AFTER `description`
11
+ ";
12
+ $wpdb->query($sqlQuery);
13
+
14
+ pmpro_setOption("db_version", "1.4");
15
+ return 1.4;
16
+ }
includes/updates/upgrade_1_4_2.php ADDED
@@ -0,0 +1,17 @@
1
+ <?php
2
+ function pmpro_upgrade_1_4_2()
3
+ {
4
+ /*
5
+ Setting the new use_ssl setting.
6
+ PayPal Website Payments Pro, Authorize.net, and Stripe will default to use ssl.
7
+ PayPal Express and the test gateway (no gateway) will default to not use ssl.
8
+ */
9
+ $gateway = pmpro_getOption("gateway");
10
+ if($gateway == "paypal" || $gateway == "authorizenet" || $gateway == "stripe")
11
+ pmpro_setOption("use_ssl", 1);
12
+ else
13
+ pmpro_setOption("use_ssl", 0);
14
+
15
+ pmpro_setOption("db_version", "1.42");
16
+ return 1.42;
17
+ }
includes/updates/upgrade_1_4_8.php ADDED
@@ -0,0 +1,20 @@
1
+ <?php
2
+ function pmpro_upgrade_1_4_8()
3
+ {
4
+ /*
5
+ Adding a billing_country field to the orders table.
6
+ */
7
+
8
+ global $wpdb;
9
+ $wpdb->hide_errors();
10
+ $wpdb->pmpro_membership_orders = $wpdb->prefix . 'pmpro_membership_orders';
11
+
12
+ //billing_country
13
+ $sqlQuery = "
14
+ ALTER TABLE `" . $wpdb->pmpro_membership_orders . "` ADD `billing_country` VARCHAR( 128 ) NOT NULL AFTER `billing_zip`
15
+ ";
16
+ $wpdb->query($sqlQuery);
17
+
18
+ pmpro_setOption("db_version", "1.48");
19
+ return 1.48;
20
+ }
includes/updates/upgrade_1_5.php ADDED
@@ -0,0 +1,26 @@
1
+ <?php
2
+ function pmpro_upgrade_1_5()
3
+ {
4
+ /*
5
+ Add the id and status fields to pmpro_memberships_users, change primary key to id instead of user_id
6
+ */
7
+
8
+ global $wpdb;
9
+ $wpdb->hide_errors();
10
+ $wpdb->pmpro_memberships_users = $wpdb->prefix . 'pmpro_memberships_users';
11
+
12
+ //remove primary key
13
+ $sqlQuery = "ALTER TABLE `" . $wpdb->pmpro_memberships_users . "` DROP PRIMARY KEY";
14
+ $wpdb->query($sqlQuery);
15
+
16
+ //id
17
+ $sqlQuery = "ALTER TABLE `" . $wpdb->pmpro_memberships_users . "` ADD `id` BIGINT( 20 ) UNSIGNED AUTO_INCREMENT FIRST, ADD PRIMARY KEY(id)";
18
+ $wpdb->query($sqlQuery);
19
+
20
+ //status
21
+ $sqlQuery = "ALTER TABLE `" . $wpdb->pmpro_memberships_users . "` ADD `status` varchar( 20 ) NOT NULL DEFAULT 'active' AFTER `trial_limit`";
22
+ $wpdb->query($sqlQuery);
23
+
24
+ pmpro_setOption("db_version", "1.5");
25
+ return 1.5;
26
+ }
includes/updates/upgrade_1_5_9.php ADDED
@@ -0,0 +1,14 @@
1
+ <?php
2
+ function pmpro_upgrade_1_5_9()
3
+ {
4
+ global $wpdb;
5
+ $wpdb->hide_errors();
6
+ $wpdb->pmpro_membership_orders = $wpdb->prefix . 'pmpro_membership_orders';
7
+
8
+ //fix firstpayment statuses
9
+ $sqlQuery = "UPDATE " . $wpdb->pmpro_membership_orders . " SET status = 'success' WHERE status = 'firstpayment'";
10
+ $wpdb->query($sqlQuery);
11
+
12
+ pmpro_setOption("db_version", "1.59");
13
+ return 1.59;
14
+ }
includes/updates/upgrade_1_6.php ADDED
@@ -0,0 +1,14 @@
1
+ <?php
2
+ function pmpro_upgrade_1_6()
3
+ {
4
+ global $wpdb;
5
+ $wpdb->hide_errors();
6
+ $wpdb->pmpro_membership_orders = $wpdb->prefix . 'pmpro_membership_orders';
7
+
8
+ //add notes column to orders
9
+ $sqlQuery = "ALTER TABLE `" . $wpdb->pmpro_membership_orders . "` ADD `notes` TEXT NOT NULL";
10
+ $wpdb->query($sqlQuery);
11
+
12
+ pmpro_setOption("db_version", "1.6");
13
+ return 1.6;
14
+ }
includes/updates/upgrade_1_7.php ADDED
@@ -0,0 +1,8 @@
1
+ <?php
2
+ function pmpro_upgrade_1_7()
3
+ {
4
+ pmpro_db_delta(); //just a db delta
5
+
6
+ pmpro_setOption("db_version", "1.7");
7
+ return 1.7;
8
+ }
includes/updates/upgrade_1_8_6_9.php ADDED
@@ -0,0 +1,94 @@
1
+ <?php
2
+ /*
3
+ Upgrade to 1.8.6.9
4
+
5
+ 1. Find all orders for stripe gateway with a subscription_transaction_id LIKE 'cus_%'
6
+ 2. Search for an order for the same user_id and membership_id with a subscription_transaction_id LIKE 'sub_%'
7
+ 3. Replace subscription_transaction_id field.
8
+ */
9
+ function pmpro_upgrade_1_8_6_9() {
10
+ global $wpdb;
11
+ $orders = $wpdb->get_results("SELECT id, user_id, membership_id, subscription_transaction_id FROM $wpdb->pmpro_membership_orders WHERE gateway = 'stripe' AND subscription_transaction_id LIKE 'cus_%'");
12
+
13
+ if(!empty($orders)) {
14
+ if(count($orders) > 100) {
15
+ //if more than 100 orders, we'll need to do this via AJAX
16
+ pmpro_addUpdate('pmpro_upgrade_1_8_6_9_ajax');
17
+ } else {
18
+ //less than 100, let's just do them now
19
+ $subids = array();
20
+
21
+ foreach($orders as $order) {
22
+ if(!empty($subids[$order->subscription_transaction_id])) {
23
+ $wpdb->query("UPDATE $wpdb->pmpro_membership_orders SET subscription_transaction_id = '" . esc_sql($subids[$order->subscription_transaction_id]) . "' WHERE id = '" . $order->id . "' LIMIT 1");
24
+
25
+ //echo "Updating subid for #" . $order->id . " " . $order->subscription_transaction_id . ".<br />";
26
+ }
27
+ elseif(isset($subids[$order->subscription_transaction_id])) {
28
+ //no sub id found, so let it go
29
+
30
+ //echo "No subid found for #" . $order->id . " " . $order->subscription_transaction_id . " in cache.<br />";
31
+ }
32
+ else {
33
+ //need to look for a sub id in the database
34
+ $subid = $wpdb->get_var("SELECT subscription_transaction_id FROM $wpdb->pmpro_membership_orders WHERE membership_id = '" . $order->membership_id . "' AND user_id = '" . $order->user_id . "' AND subscription_transaction_id LIKE 'sub_%' LIMIT 1");
35
+ $subids[$order->subscription_transaction_id] = $subid;
36
+ if(!empty($subid)) {
37
+ $wpdb->query("UPDATE $wpdb->pmpro_membership_orders SET subscription_transaction_id = '" . esc_sql($subid) . "' WHERE id = '" . $order->id . "' LIMIT 1");
38
+
39
+ //echo "Updating subid for #" . $order->id . " " . $order->subscription_transaction_id . ".<br />";
40
+ }
41
+ else {
42
+ //echo "No subid found for #" . $order->id . " " . $order->subscription_transaction_id . ".<br />";
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ pmpro_setOption("db_version", "1.869");
50
+ return 1.869;
51
+ }
52
+
53
+ /*
54
+ If a site has > 100 orders then we run this pasrt of the update via AJAX from the updates page.
55
+ */
56
+ function pmpro_upgrade_1_8_6_9_ajax() {
57
+ global $wpdb;
58
+
59
+ //keeping track of which order we're working on
60
+ $last_order_id = get_option('pmpro_upgrade_1_8_6_9_last_order_id', 0);
61
+
62
+ //get orders
63
+ $orders = $wpdb->get_results("SELECT id, user_id, membership_id, subscription_transaction_id FROM $wpdb->pmpro_membership_orders WHERE id > $last_order_id AND gateway = 'stripe' AND subscription_transaction_id LIKE 'cus_%' ORDER BY id LIMIT 100");
64
+
65
+ if(empty($orders)) {
66
+ //done with this update
67
+ pmpro_removeUpdate('pmpro_upgrade_1_8_6_9_ajax');
68
+ delete_option('pmpro_upgrade_1_8_6_9_last_order_id');
69
+ } else {
70
+ $subids = array(); //cache of subids found
71
+ foreach($orders as $order) {
72
+ $last_order_id = $order->id; //keeping track of the last order we processed
73
+ if(!empty($subids[$order->subscription_transaction_id])) {
74
+ $wpdb->query("UPDATE $wpdb->pmpro_membership_orders SET subscription_transaction_id = '" . esc_sql($subids[$order->subscription_transaction_id]) . "' WHERE id = '" . $order->id . "' LIMIT 1");
75
+ }
76
+ elseif(isset($subids[$order->subscription_transaction_id])) {
77
+ //no sub id found, so let it go
78
+ }
79
+ else {
80
+ //need to look for a sub id in the database
81
+ $subid = $wpdb->get_var("SELECT subscription_transaction_id FROM $wpdb->pmpro_membership_orders WHERE membership_id = '" . $order->membership_id . "' AND user_id = '" . $order->user_id . "' AND subscription_transaction_id LIKE 'sub_%' LIMIT 1");
82
+ $subids[$order->subscription_transaction_id] = $subid;
83
+ if(!empty($subid)) {
84
+ $wpdb->query("UPDATE $wpdb->pmpro_membership_orders SET subscription_transaction_id = '" . esc_sql($subid) . "' WHERE id = '" . $order->id . "' LIMIT 1");
85
+ }
86
+ else {
87
+ //no sub id found, so let it go
88
+ }
89
+ }
90
+ }
91
+
92
+ update_option('pmpro_upgrade_1_8_6_9_last_order_id', $last_order_id);
93
+ }
94
+ }
includes/updates/upgrade_1_8_7.php ADDED
@@ -0,0 +1,35 @@
1
+ <?php
2
+ /*
3
+ Remove extra cron jobs inserted in version 1.8.7 and 1.8.7.1
4
+ */
5
+ function pmpro_upgrade_1_8_7() {
6
+
7
+ //fix cron jobs
8
+ $jobs = _get_cron_array();
9
+
10
+ // Remove all pmpro cron jobs (for now).
11
+ foreach( $jobs as $when => $job_array ) {
12
+
13
+ foreach($job_array as $name => $job) {
14
+ //delete pmpro cron
15
+ if ( false !== stripos( $name, 'pmpro_cron') )
16
+ unset($jobs[$when][$name]);
17
+ }
18
+
19
+ //delete empty cron time slots
20
+ if( empty($jobs[$when]) )
21
+ unset($jobs[$when]);
22
+ }
23
+
24
+ // Save the data
25
+ _set_cron_array($jobs);
26
+
27
+ //add the three we want back
28
+ pmpro_maybe_schedule_event(current_time('timestamp'), 'daily', 'pmpro_cron_expire_memberships');
29
+ pmpro_maybe_schedule_event(current_time('timestamp')+1, 'daily', 'pmpro_cron_expiration_warnings');
30
+ pmpro_maybe_schedule_event(current_time('timestamp'), 'monthly', 'pmpro_cron_credit_card_expiring_warnings');
31
+
32
+ pmpro_setOption("db_version", "1.87");
33
+
34
+ return 1.87;
35
+ }
includes/updates/upgrade_1_8_8.php ADDED
@@ -0,0 +1,109 @@
1
+ <?php
2
+ /*
3
+ Upgrade to 1.8.8
4
+ * Running the cron job cleanup again.
5
+ * Fixing old Authorize.net orders with empty status.
6
+ * Fixing old $0 Stripe orders.
7
+ */
8
+ function pmpro_upgrade_1_8_8() {
9
+ global $wpdb;
10
+
11
+ //Running the cron job cleanup again.
12
+ require_once(PMPRO_DIR . "/includes/updates/upgrade_1_8_7.php");
13
+ pmpro_upgrade_1_8_7();
14
+
15
+ //Fixing old Authorize.net orders with empty status.
16
+ $sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET status = 'success' WHERE gateway = 'authorizenet' AND status = ''";
17
+ $wpdb->query($sqlQuery);
18
+
19
+ //Fixing old $0 Stripe orders. (Sets up update via AJAX)
20
+ $orders = $wpdb->get_col("SELECT id FROM $wpdb->pmpro_membership_orders WHERE gateway = 'stripe' AND total = 0");
21
+ if(!empty($orders))
22
+ pmpro_addUpdate('pmpro_upgrade_1_8_8_ajax');
23
+
24
+ pmpro_setOption("db_version", "1.88");
25
+ return 1.88;
26
+ }
27
+
28
+ /*
29
+ If a site has > 100 orders then we run this pasrt of the update via AJAX from the updates page.
30
+ */
31
+ function pmpro_upgrade_1_8_8_ajax() {
32
+ global $wpdb;
33
+
34
+ //keeping track of which order we're working on
35
+ $last_order_id = get_option('pmpro_upgrade_1_8_8_last_order_id', 0);
36
+
37
+ //Fixing old $0 Stripe orders.
38
+ $orders = $wpdb->get_col("SELECT id FROM $wpdb->pmpro_membership_orders WHERE id > $last_order_id AND gateway = 'stripe' AND total = 0 ORDER BY id LIMIT 2");
39
+
40
+ //track progress
41
+ $first_load = get_transient('pmpro_updates_first_load');
42
+ if($first_load) {
43
+ $total_orders = $wpdb->get_var("SELECT COUNT(id) FROM $wpdb->pmpro_membership_orders WHERE id > $last_order_id AND gateway = 'stripe' AND total = 0");
44
+ update_option('pmpro_upgrade_1_8_8_total', $total_orders, 'no');
45
+ $progress = 0;
46
+ } else {
47
+ $total_orders = get_option('pmpro_upgrade_1_8_8_total', 0);
48
+ $progress = get_option('pmpro_upgrade_1_8_8_progress', 0);
49
+ }
50
+ update_option('pmpro_upgrade_1_8_8_progress', $progress + count($orders), 'no');
51
+ global $pmpro_updates_progress;
52
+ if($total_orders > 0)
53
+ $pmpro_updates_progress = "[" . $progress . "/" . $total_orders . "]";
54
+ else
55
+ $pmpro_updates_progress = "";
56
+
57
+ if(empty($orders)) {
58
+ //done with this update
59
+ pmpro_removeUpdate('pmpro_upgrade_1_8_8_ajax');
60
+ delete_option('pmpro_upgrade_1_8_8_last_order_id');
61
+ delete_option('pmpro_upgrade_1_8_8_total');
62
+ delete_option('pmpro_upgrade_1_8_8_progress');
63
+ } else {
64
+ //need to keep working
65
+ foreach($orders as $order_id) {
66
+ $last_order_id = $order_id; //keeping track of the last order we processed
67
+
68
+ //get order
69
+ $order = new MemberOrder($order_id);
70
+
71
+ //get customer
72
+ $order->Gateway->getCustomer($order);
73
+
74
+ //get all invoices
75
+ if(!empty($order->Gateway->customer)) {
76
+ try {
77
+ $invoices = $order->Gateway->customer->invoices();
78
+ } catch(Exception $e) {
79
+ //probably no invoices, stay quiet
80
+ }
81
+
82
+ //get our invoice
83
+ if(!empty($invoices)) {
84
+ try {
85
+ $invoice = $invoices->retrieve($order->payment_transaction_id);
86
+ } catch(Exception $e) {
87
+ //probably no invoice, stay quiet
88
+ }
89
+
90
+ //get total
91
+ if(!empty($invoice)) {
92
+ if($invoice->total > 0) {
93
+ //invoice we accidentally saved $0 for. update the real total.
94
+ $order->subtotal = (! empty( $invoice->subtotal ) ? $invoice->subtotal / 100 : 0);
95
+ $order->tax = (! empty($invoice->tax) ? $invoice->tax / 100 : null);
96
+ $order->total = (! empty($invoice->total) ? $invoice->total / 100 : 0);
97
+ $order->saveOrder();
98
+ } else {
99
+ //we don't want to track $0 invoices. delete it.
100
+ $order->deleteMe();
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ update_option('pmpro_upgrade_1_8_8_last_order_id', $last_order_id, 'no');
108
+ }
109
+ }
includes/upgradecheck.php CHANGED
@@ -14,35 +14,65 @@ function pmpro_checkForUpgrades()
14
if(!$table_exists)
15
$pmpro_db_version = 0;
16
17
- if(!$pmpro_db_version)
18
$pmpro_db_version = pmpro_upgrade_1();
19
20
- if($pmpro_db_version < 1.115)
21
$pmpro_db_version = pmpro_upgrade_1_1_15();
22
23
- if($pmpro_db_version < 1.23)
24
$pmpro_db_version = pmpro_upgrade_1_2_3();
25
26
- if($pmpro_db_version < 1.318)