Paid Memberships Pro - Version 1.7.14.1

Version Description

  • BUG: Fixed warnings in PayPal Express class that could break redirects at checkout. (Thanks, Adam Warner)
  • BUG: Fixed issue where new users who checked out with Braintree weren't having their customerid's saved, which led to subscription syncronization issues if they checked out again or updated their billing.
  • BUG: Fixed warnings in the membership-billing page.
  • BUG: Fixed false positive "There are JavaScript errors on the page. Please contact the webmaster." errors.
  • BUG: Fixed issue where users on some sites running 1.7.14 could not logout.
  • OTHER: Changed the CSS class of the checkout button generated via [checkout_button] shortcode or pmpro_getCheckoutButton() function from "btn btn-primary" to "pmpro_btn" to match other buttons generated with PMPro.
Download this release

Release Info

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

Code changes from version 1.7.14 to 1.7.14.1

classes/gateways/class.pmprogateway_braintree.php CHANGED
@@ -162,7 +162,7 @@
162
  {
163
  $customer_id = get_user_meta($user_id, "pmpro_braintree_customerid", true);
164
  }
165
-
166
  //check for an existing stripe customer
167
  if(!empty($customer_id))
168
  {
@@ -190,7 +190,7 @@
190
  );
191
 
192
  if($response->success)
193
- {
194
  $this->customer = $response->customer;
195
  }
196
  else
@@ -200,12 +200,12 @@
200
  return false;
201
  }
202
  }
203
-
204
  return $this->customer;
205
  }
206
  catch (Exception $e)
207
  {
208
- //assume no customer found
209
  }
210
  }
211
 
@@ -236,7 +236,7 @@
236
  )
237
  )
238
  ));
239
-
240
  if($result->success)
241
  {
242
  $this->customer = $result->customer;
@@ -254,8 +254,17 @@
254
  $order->shorterror = $order->error;
255
  return false;
256
  }
257
-
258
- update_user_meta($user_id, "pmpro_braintree_customerid", $this->customer->id);
 
 
 
 
 
 
 
 
 
259
  return $this->customer;
260
  }
261
 
@@ -365,8 +374,8 @@
365
  function update(&$order)
366
  {
367
  //we just have to run getCustomer which will look for the customer and update it with the new token
368
- $this->getCustomer($order);
369
-
370
  if(!empty($this->customer) && empty($order->error))
371
  {
372
  return true;
@@ -418,5 +427,17 @@
418
  $order->shorterror = $order->error;
419
  return false; //no customer found
420
  }
421
- }
 
 
 
 
 
 
 
 
 
 
 
 
422
  }
162
  {
163
  $customer_id = get_user_meta($user_id, "pmpro_braintree_customerid", true);
164
  }
165
+
166
  //check for an existing stripe customer
167
  if(!empty($customer_id))
168
  {
190
  );
191
 
192
  if($response->success)
193
+ {
194
  $this->customer = $response->customer;
195
  }
196
  else
200
  return false;
201
  }
202
  }
203
+
204
  return $this->customer;
205
  }
206
  catch (Exception $e)
207
  {
208
+ //assume no customer found
209
  }
210
  }
211
 
236
  )
237
  )
238
  ));
239
+
240
  if($result->success)
241
  {
242
  $this->customer = $result->customer;
254
  $order->shorterror = $order->error;
255
  return false;
256
  }
257
+
258
+ //if we have no user id, we need to set the customer id after the user is created
259
+ if(empty($user_id))
260
+ {
261
+ global $pmpro_braintree_customerid;
262
+ $pmpro_braintree_customerid = $this->customer->id;
263
+ add_action('user_register', array('PMProGateway_braintree','user_register'));
264
+ }
265
+ else
266
+ update_user_meta($user_id, "pmpro_braintree_customerid", $this->customer->id);
267
+
268
  return $this->customer;
269
  }
270
 
374
  function update(&$order)
375
  {
376
  //we just have to run getCustomer which will look for the customer and update it with the new token
377
+ $this->getCustomer($order, true);
378
+
379
  if(!empty($this->customer) && empty($order->error))
380
  {
381
  return true;
427
  $order->shorterror = $order->error;
428
  return false; //no customer found
429
  }
430
+ }
431
+
432
+ /*
433
+ Save Braintree customer id after the user is registered.
434
+ */
435
+ static function user_register($user_id)
436
+ {
437
+ global $pmpro_braintree_customerid;
438
+ if(!empty($pmpro_braintree_customerid))
439
+ {
440
+ update_user_meta($user_id, 'pmpro_braintree_customerid', $pmpro_braintree_customerid);
441
+ }
442
+ }
443
  }
classes/gateways/class.pmprogateway_paypalexpress.php CHANGED
@@ -102,9 +102,8 @@
102
 
103
  if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
104
  $order->status = "token";
105
- $order->paypal_token = urldecode($this->httpParsedResponseAr['TOKEN']);
106
- $order->subscription_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
107
-
108
  //update order
109
  $order->saveOrder();
110
 
@@ -197,7 +196,7 @@
197
  if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
198
  $order->payment_transaction_id = urldecode($this->httpParsedResponseAr['TRANSACTIONID']);
199
  $order->status = "success";
200
-
201
  //update order
202
  $order->saveOrder();
203
 
@@ -244,7 +243,7 @@
244
  $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
245
 
246
  //if billing cycles are defined
247
- if($order->TotalBillingCycles)
248
  $nvpStr .= "&TOTALBILLINGCYCLES=" . $order->TotalBillingCycles;
249
 
250
  //if a trial period is defined
102
 
103
  if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
104
  $order->status = "token";
105
+ $order->paypal_token = urldecode($this->httpParsedResponseAr['TOKEN']);
106
+
 
107
  //update order
108
  $order->saveOrder();
109
 
196
  if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
197
  $order->payment_transaction_id = urldecode($this->httpParsedResponseAr['TRANSACTIONID']);
198
  $order->status = "success";
199
+
200
  //update order
201
  $order->saveOrder();
202
 
243
  $nvpStr .= "&DESC=" . urlencode(substr($order->membership_level->name . " at " . get_bloginfo("name"), 0, 127));
244
 
245
  //if billing cycles are defined
246
+ if(!empty($order->TotalBillingCycles))
247
  $nvpStr .= "&TOTALBILLINGCYCLES=" . $order->TotalBillingCycles;
248
 
249
  //if a trial period is defined
includes/functions.php CHANGED
@@ -1395,7 +1395,7 @@ function pmpro_getCheckoutButton($level_id, $button_text = NULL, $classes = NULL
1395
  $button_text = __("Sign Up for !!name!! Now", "pmpro");
1396
 
1397
  if(empty($classes))
1398
- $classes = "btn btn-primary";
1399
 
1400
  if(empty($level_id))
1401
  $r = __("Please specify a level id.", "pmpro");
@@ -1555,14 +1555,21 @@ function pmpro_getClassForField($field)
1555
  {
1556
  global $pmpro_error_fields, $pmpro_required_billing_fields, $pmpro_required_user_fields;
1557
  $classes = array();
1558
-
1559
  //error on this field?
1560
- if(in_array($field, $pmpro_error_fields))
1561
  {
1562
  $classes[] = "pmpro_error";
1563
  }
1564
 
1565
- $required_fields = array_merge(array_keys($pmpro_required_billing_fields), array_keys($pmpro_required_user_fields));
 
 
 
 
 
 
 
1566
 
1567
  //required?
1568
  if(in_array($field, $required_fields))
1395
  $button_text = __("Sign Up for !!name!! Now", "pmpro");
1396
 
1397
  if(empty($classes))
1398
+ $classes = "pmpro_btn";
1399
 
1400
  if(empty($level_id))
1401
  $r = __("Please specify a level id.", "pmpro");
1555
  {
1556
  global $pmpro_error_fields, $pmpro_required_billing_fields, $pmpro_required_user_fields;
1557
  $classes = array();
1558
+
1559
  //error on this field?
1560
+ if(!empty($pmpro_error_fields) && in_array($field, $pmpro_error_fields))
1561
  {
1562
  $classes[] = "pmpro_error";
1563
  }
1564
 
1565
+ if(is_array($pmpro_required_billing_fields) && is_array($pmpro_required_user_fields))
1566
+ $required_fields = array_merge(array_keys($pmpro_required_billing_fields), array_keys($pmpro_required_user_fields));
1567
+ elseif(is_array($pmpro_required_billing_fields))
1568
+ $required_fields = array_keys($pmpro_required_billing_fields);
1569
+ elseif(is_array($pmpro_required_user_fields))
1570
+ $required_fields = array_keys($pmpro_required_user_fields);
1571
+ else
1572
+ $required_fields = array();
1573
 
1574
  //required?
1575
  if(in_array($field, $required_fields))
includes/login.php CHANGED
@@ -148,7 +148,7 @@ add_action('login_init', 'pmpro_login_head');
148
  */
149
  function pmpro_redirect_to_logged_in()
150
  {
151
- if((pmpro_is_login_page() || is_page("login")) && !empty($_REQUEST['redirect_to']) && is_user_logged_in())
152
  {
153
  wp_redirect($_REQUEST['redirect_to']);
154
  exit;
148
  */
149
  function pmpro_redirect_to_logged_in()
150
  {
151
+ if((pmpro_is_login_page() || is_page("login")) && !empty($_REQUEST['redirect_to']) && is_user_logged_in() && (empty($_REQUEST['action']) || $_REQUEST['action'] == 'login'))
152
  {
153
  wp_redirect($_REQUEST['redirect_to']);
154
  exit;
pages/checkout.php CHANGED
@@ -8,6 +8,8 @@
8
  <form id="pmpro_form" class="pmpro_form" action="<?php if(!empty($_REQUEST['review'])) echo pmpro_url("checkout", "?level=" . $pmpro_level->id); ?>" method="post">
9
 
10
  <input type="hidden" id="level" name="level" value="<?php echo esc_attr($pmpro_level->id) ?>" />
 
 
11
  <?php if($pmpro_msg)
12
  {
13
  ?>
@@ -774,5 +776,5 @@
774
  </script>
775
  <script>
776
  //add javascriptok hidden field to checkout
777
- jQuery("input[name=submit-checkout]").after("<input type=hidden name=javascriptok value=1 />");
778
  </script>
8
  <form id="pmpro_form" class="pmpro_form" action="<?php if(!empty($_REQUEST['review'])) echo pmpro_url("checkout", "?level=" . $pmpro_level->id); ?>" method="post">
9
 
10
  <input type="hidden" id="level" name="level" value="<?php echo esc_attr($pmpro_level->id) ?>" />
11
+ <input type="hidden" id="checkjavascript" name="checkjavascript" value="1" />
12
+
13
  <?php if($pmpro_msg)
14
  {
15
  ?>
776
  </script>
777
  <script>
778
  //add javascriptok hidden field to checkout
779
+ jQuery("input[name=submit-checkout]").after('<input type="hidden" name="javascriptok" value="1" />');
780
  </script>
paid-memberships-pro.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Paid Memberships Pro
4
  Plugin URI: http://www.paidmembershipspro.com
5
  Description: Plugin to Handle Memberships
6
- Version: 1.7.14
7
  Author: Stranger Studios
8
  Author URI: http://www.strangerstudios.com
9
  */
@@ -13,7 +13,7 @@ Author URI: http://www.strangerstudios.com
13
  */
14
 
15
  //version constant
16
- define("PMPRO_VERSION", "1.7.14");
17
 
18
  //if the session has been started yet, start it (ignore if running from command line)
19
  if(defined('STDIN') )
3
  Plugin Name: Paid Memberships Pro
4
  Plugin URI: http://www.paidmembershipspro.com
5
  Description: Plugin to Handle Memberships
6
+ Version: 1.7.14.1
7
  Author: Stranger Studios
8
  Author URI: http://www.strangerstudios.com
9
  */
13
  */
14
 
15
  //version constant
16
+ define("PMPRO_VERSION", "1.7.14.1");
17
 
18
  //if the session has been started yet, start it (ignore if running from command line)
19
  if(defined('STDIN') )
preheaders/checkout.php CHANGED
@@ -412,7 +412,7 @@ $pmpro_required_user_fields = apply_filters("pmpro_required_user_fields", $pmpro
412
  if ($submit && $pmpro_msgt != "pmpro_error") {
413
 
414
  //make sure javascript is ok
415
- if(apply_filters("pmpro_require_javascript_for_checkout", true) && empty($_REQUEST['javascriptok'])) {
416
  pmpro_setMessage(__("There are JavaScript errors on the page. Please contact the webmaster.", "pmpro"), "pmpro_error");
417
  }
418
 
@@ -461,8 +461,8 @@ if ($submit && $pmpro_msgt != "pmpro_error") {
461
  }
462
  }
463
 
464
- if (!empty($pmpro_error_fields)) {
465
- pmpro_setMessage(__("Please complete all required fields.", "pmpro"), "pmpro_error");
466
  }
467
  if (!empty($password) && $password != $password2) {
468
  pmpro_setMessage(__("Your passwords do not match. Please try again.", "pmpro"), "pmpro_error");
412
  if ($submit && $pmpro_msgt != "pmpro_error") {
413
 
414
  //make sure javascript is ok
415
+ if(apply_filters("pmpro_require_javascript_for_checkout", true) && !empty($_REQUEST['checkjavascript']) && empty($_REQUEST['javascriptok'])) {
416
  pmpro_setMessage(__("There are JavaScript errors on the page. Please contact the webmaster.", "pmpro"), "pmpro_error");
417
  }
418
 
461
  }
462
  }
463
 
464
+ if (!empty($pmpro_error_fields)) {
465
+ pmpro_setMessage(__("Please complete all required fields.", "pmpro"), "pmpro_error");
466
  }
467
  if (!empty($password) && $password != $password2) {
468
  pmpro_setMessage(__("Your passwords do not match. Please try again.", "pmpro"), "pmpro_error");
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: strangerstudios
3
  Tags: memberships, membership, authorize.net, ecommerce, paypal, stripe, braintree, restrict access, restrict content, directory site, payflow
4
  Requires at least: 3.5
5
  Tested up to: 4.0
6
- Stable tag: 1.7.14
7
 
8
  The easiest way to GET PAID with your WordPress site. Flexible content control by Membership Level, Reports, Affiliates and Discounts
9
 
@@ -102,6 +102,14 @@ Not sure? You can find out by doing a bit a research.
102
  4. Offer Membership Discounts with specific price rules (restricted by level, unique pricing for each level, # of uses, expiration date.)
103
 
104
  == Changelog ==
 
 
 
 
 
 
 
 
105
  = 1.7.14 =
106
  * BUG: Fixed bug where level cost would sometimes have incorrect pluralization of months/weeks/etc. (Thanks, Kevin Ackerman)
107
  * BUG/ENHANCEMENT: Now checking the child and parent theme for email_header.html and email_footer.html files to use for emails. The child theme is checked first.
3
  Tags: memberships, membership, authorize.net, ecommerce, paypal, stripe, braintree, restrict access, restrict content, directory site, payflow
4
  Requires at least: 3.5
5
  Tested up to: 4.0
6
+ Stable tag: 1.7.14.1
7
 
8
  The easiest way to GET PAID with your WordPress site. Flexible content control by Membership Level, Reports, Affiliates and Discounts
9
 
102
  4. Offer Membership Discounts with specific price rules (restricted by level, unique pricing for each level, # of uses, expiration date.)
103
 
104
  == Changelog ==
105
+ = 1.7.14.1 =
106
+ * BUG: Fixed warnings in PayPal Express class that could break redirects at checkout. (Thanks, Adam Warner)
107
+ * BUG: Fixed issue where new users who checked out with Braintree weren't having their customerid's saved, which led to subscription syncronization issues if they checked out again or updated their billing.
108
+ * BUG: Fixed warnings in the membership-billing page.
109
+ * BUG: Fixed false positive "There are JavaScript errors on the page. Please contact the webmaster." errors.
110
+ * BUG: Fixed issue where users on some sites running 1.7.14 could not logout.
111
+ * OTHER: Changed the CSS class of the checkout button generated via [checkout_button] shortcode or pmpro_getCheckoutButton() function from "btn btn-primary" to "pmpro_btn" to match other buttons generated with PMPro.
112
+
113
  = 1.7.14 =
114
  * BUG: Fixed bug where level cost would sometimes have incorrect pluralization of months/weeks/etc. (Thanks, Kevin Ackerman)
115
  * BUG/ENHANCEMENT: Now checking the child and parent theme for email_header.html and email_footer.html files to use for emails. The child theme is checked first.
services/getfile.php CHANGED
@@ -1,12 +1,23 @@
1
  <?php
2
  global $isapage;
3
- $isapage = true;
4
-
5
  //in case the file is loaded directly
6
  if(!function_exists("get_userdata"))
7
  {
8
  define('WP_USE_THEMES', false);
9
  require_once(dirname(__FILE__) . '/../../../../wp-load.php');
 
 
 
 
 
 
 
 
 
 
 
10
  }
11
 
12
  require_once(dirname(__FILE__) . '/../classes/class.mimetype.php');
@@ -17,6 +28,13 @@
17
  if($uri[0] == "/")
18
  $uri = substr($uri, 1, strlen($uri) - 1);
19
 
 
 
 
 
 
 
 
20
  //if WP is installed in a subdirectory, that directory(s) will be in both the PATH and URI
21
  $home_url_parts = explode("/", str_replace("//", "", home_url()));
22
  if(count($home_url_parts) > 1)
@@ -52,6 +70,8 @@
52
  {
53
  if(!pmpro_has_membership_access($file_post_parent))
54
  {
 
 
55
  //nope
56
  header('HTTP/1.1 503 Service Unavailable', true, 503);
57
  echo "HTTP/1.1 503 Service Unavailable";
@@ -67,8 +87,40 @@
67
  //in case we want to do something else with the file
68
  do_action("pmpro_getfile_before_readfile", $filename, $file_mimetype);
69
 
70
- //show the file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  header("Content-type: " . $file_mimetype);
72
  readfile($filename);
73
- exit;
74
- ?>
1
  <?php
2
  global $isapage;
3
+ $isapage = true;
4
+
5
  //in case the file is loaded directly
6
  if(!function_exists("get_userdata"))
7
  {
8
  define('WP_USE_THEMES', false);
9
  require_once(dirname(__FILE__) . '/../../../../wp-load.php');
10
+ }
11
+
12
+ //this script must be enabled to run
13
+ if(!defined('PMPRO_GETFILE_ENABLED') || !PMPRO_GETFILE_ENABLED)
14
+ die("The getfile script is not enabled.");
15
+
16
+ //prevent loops when redirecting to .php files
17
+ if(!empty($_REQUEST['noloop']))
18
+ {
19
+ status_header( 500 );
20
+ die("This file cannot be loaded through the get file script.");
21
  }
22
 
23
  require_once(dirname(__FILE__) . '/../classes/class.mimetype.php');
28
  if($uri[0] == "/")
29
  $uri = substr($uri, 1, strlen($uri) - 1);
30
 
31
+ /*
32
+ Remove ../-like strings from the URI.
33
+ Actually removes any combination of two or more ., /, and \.
34
+ This will prevent traversal attacks and loading hidden files.
35
+ */
36
+ $uri = preg_replace("/[\.\/\\\\]{2,}/", "", $uri);
37
+
38
  //if WP is installed in a subdirectory, that directory(s) will be in both the PATH and URI
39
  $home_url_parts = explode("/", str_replace("//", "", home_url()));
40
  if(count($home_url_parts) > 1)
70
  {
71
  if(!pmpro_has_membership_access($file_post_parent))
72
  {
73
+ do_action("pmpro_getfile_before_error", $filename, $file_post_parent);
74
+
75
  //nope
76
  header('HTTP/1.1 503 Service Unavailable', true, 503);
77
  echo "HTTP/1.1 503 Service Unavailable";
87
  //in case we want to do something else with the file
88
  do_action("pmpro_getfile_before_readfile", $filename, $file_mimetype);
89
 
90
+ //if file is not found, die
91
+ if(!file_exists($filename))
92
+ {
93
+ status_header( 404 );
94
+ nocache_headers();
95
+ die("File not found.");
96
+ }
97
+
98
+ //if blacklistsed file type, redirect to it instead
99
+ $basename = basename($filename);
100
+ $parts = explode('.', $basename);
101
+ $ext = strtolower($parts[count($parts)-1]);
102
+
103
+ //build blacklist and allow for filtering
104
+ $blacklist = array("inc", "php", "php3", "php4", "php5", "phps", "phtml");
105
+ $blacklist = apply_filters("pmpro_getfile_extension_blacklist", $blacklist);
106
+
107
+ //check
108
+ if(in_array($ext, $blacklist))
109
+ {
110
+ //add a noloop param to avoid infinite loops
111
+ $uri = add_query_arg("noloop", 1, $uri);
112
+
113
+ //guess scheme and add host back to uri
114
+ if(is_ssl())
115
+ $uri = "https://" . $_SERVER['HTTP_HOST'] . "/" . $uri;
116
+ else
117
+ $uri = "http://" . $_SERVER['HTTP_HOST'] . "/" . $uri;
118
+
119
+ wp_redirect($uri);
120
+ exit;
121
+ }
122
+
123
+ //okay show the file
124
  header("Content-type: " . $file_mimetype);
125
  readfile($filename);
126
+ exit;