Paid Memberships Pro - Version 2.5.10

Version Description

  • 2021-06-25 =
  • SECURITY: Fixed XSS vulnerability on the edit order page in the dashboard. (Thanks, Scott Kingsley Clark)
  • ENHANCEMENT: Improved escaping and localization for the message returned when clicking to apply discount code.
  • ENHANCEMENT: Now hiding gateway setting API keys behind asterisks.
  • BUG FIX/ENHANCEMENT: Now passing a CARDONFILE parameter with PayPal Payflow payment and subscription transactions.
  • BUG FIX/ENHANCEMENT: Using the wp.passwordStrength.userInputDisallowedList function from WP 4.5 if available.
  • BUG FIX: Fixed issue in getfile script where parameters in the URL would cause File not found errors.
  • BUG FIX: Fixed how the PayPal IPN handler handles cases where a subscription is set up correctly but the initial payment failed. We now correctly cancel these users and mark their order as error.
  • BUG FIX: Improved error handling in the PayPal Express integration, particularly when a subscriptions PROFILESTATUS is missing.
  • BUG FIX: User registered date is now shown in local time.
  • BUG FIX: Fixed issue where the deprecated pmpro_getClassForField function wasn't returning a value properly. (Thanks, Elena Draculet)
  • BUG FIX: Updated the pmpro_sort_levels_by_order function to use level IDs for keys, since some code expects that for level arrays. This matches the behavior we had before introducing this function.
  • BUG FIX: Updated the pmpro_changeMembershipLevel function always set the order status to error if that was passed in as the "old level status".
  • BUG FIX: Fixed warning in searches/pages when PMPro pages is not set.
  • BUG FIX: Fixed warnings being generated when using PHP 8 and Divi
  • BUG FIX: Fixed warnings related to PayPal Express session variables.
Download this release

Release Info

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

Code changes from version 2.5.9.1 to 2.5.10

CHANGELOG.txt CHANGED
@@ -1,4 +1,21 @@
1
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  = 2.5.9.1 - 2021-05-12 =
3
  * BUG FIX/ENHANCEMENT: Updated pmpro_changeMembershipLevel() to return null if the user's level is not changed. For the past 2 vesions, we've been returning true in these cases, which caused PMPro to send emails to the admin when the edit use page was saved, even if there was no level change. This change has been backported to versions 2.5.8 and 2.5.9.
4
 
1
  == Changelog ==
2
+ = 2.5.10 - 2021-06-25 =
3
+ * SECURITY: Fixed XSS vulnerability on the edit order page in the dashboard. (Thanks, Scott Kingsley Clark)
4
+ * ENHANCEMENT: Improved escaping and localization for the message returned when clicking to apply discount code.
5
+ * ENHANCEMENT: Now hiding gateway setting API keys behind asterisks.
6
+ * BUG FIX/ENHANCEMENT: Now passing a CARDONFILE parameter with PayPal Payflow payment and subscription transactions.
7
+ * BUG FIX/ENHANCEMENT: Using the wp.passwordStrength.userInputDisallowedList function from WP 4.5 if available.
8
+ * BUG FIX: Fixed issue in getfile script where parameters in the URL would cause File not found errors.
9
+ * BUG FIX: Fixed how the PayPal IPN handler handles cases where a subscription is set up correctly but the initial payment failed. We now correctly cancel these users and mark their order as error.
10
+ * BUG FIX: Improved error handling in the PayPal Express integration, particularly when a subscriptions PROFILESTATUS is missing.
11
+ * BUG FIX: User registered date is now shown in local time.
12
+ * BUG FIX: Fixed issue where the deprecated pmpro_getClassForField function wasn't returning a value properly. (Thanks, Elena Draculet)
13
+ * BUG FIX: Updated the pmpro_sort_levels_by_order function to use level IDs for keys, since some code expects that for level arrays. This matches the behavior we had before introducing this function.
14
+ * BUG FIX: Updated the pmpro_changeMembershipLevel function always set the order status to error if that was passed in as the "old level status".
15
+ * BUG FIX: Fixed warning in searches/pages when PMPro pages is not set.
16
+ * BUG FIX: Fixed warnings being generated when using PHP 8 and Divi
17
+ * BUG FIX: Fixed warnings related to PayPal Express session variables.
18
+
19
  = 2.5.9.1 - 2021-05-12 =
20
  * BUG FIX/ENHANCEMENT: Updated pmpro_changeMembershipLevel() to return null if the user's level is not changed. For the past 2 vesions, we've been returning true in these cases, which caused PMPro to send emails to the admin when the edit use page was saved, even if there was no level change. This change has been backported to versions 2.5.8 and 2.5.9.
21
 
adminpages/dashboard.php CHANGED
@@ -244,7 +244,7 @@ function pmpro_dashboard_report_recent_members_callback() {
244
  </strong>
245
  </td>
246
  <td><?php esc_attr_e( $auser->membership ); ?></td>
247
- <td><?php echo date_i18n( get_option( 'date_format' ), strtotime( $theuser->user_registered, current_time( 'timestamp' ) ) ); ?></td>
248
  <td>
249
  <?php
250
  if($auser->enddate)
244
  </strong>
245
  </td>
246
  <td><?php esc_attr_e( $auser->membership ); ?></td>
247
+ <td><?php echo date_i18n( get_option( 'date_format' ), strtotime( get_date_from_gmt( $theuser->user_registered ), current_time( 'timestamp' ) ) ); ?></td>
248
  <td>
249
  <?php
250
  if($auser->enddate)
adminpages/membershiplevels.php CHANGED
@@ -134,7 +134,7 @@
134
  '%d', //allow_signups
135
  )
136
  );
137
-
138
  if($saveid < 1) {
139
  //added a level
140
  $saveid = $wpdb->insert_id;
@@ -164,10 +164,10 @@
164
  $msgt = __("Error updating membership level.", 'paid-memberships-pro' );
165
  }
166
  }
167
-
168
  if( ! empty( $msgt ) && $ml_recurring && $ml_expiration ) {
169
  $msgt .= ' <strong class="red">' . sprintf( __( 'WARNING: A level was set with both a recurring billing amount and an expiration date. You only need to set one of these unless you really want this membership to expire after a specific time period. For more information, <a target="_blank" href="%s">see our post here</a>.', 'paid-memberships-pro' ), 'https://www.paidmembershipspro.com/important-notes-on-recurring-billing-and-expiration-dates-for-membership-levels/?utm_source=plugin&utm_medium=pmpro-membershiplevels&utm_campaign=blog&utm_content=important-notes-on-recurring-billing-and-expiration-dates-for-membership-levels' ) . '</strong>';
170
-
171
  // turn success to errors
172
  if( $msg > 0 ) {
173
  $msg = 0 - $msg;
@@ -178,7 +178,7 @@
178
  if ( isset( $ml_confirmation_in_email ) ) {
179
  update_pmpro_membership_level_meta( $saveid, 'confirmation_in_email', $ml_confirmation_in_email );
180
  }
181
-
182
  do_action("pmpro_save_membership_level", $saveid);
183
  }
184
  elseif($action == "delete_membership_level")
@@ -269,7 +269,7 @@
269
  ?>
270
  </h1>
271
  <hr class="wp-header-end">
272
-
273
  <div>
274
  <?php
275
  // get the level...
@@ -328,7 +328,7 @@
328
  ) );
329
  if(empty($level->categories))
330
  $level->categories = array();
331
-
332
  // grab the meta for the given level...
333
  if ( ! empty( $temp_id ) ) {
334
  $confirmation_in_email = get_pmpro_membership_level_meta( $temp_id, 'confirmation_in_email', true );
@@ -534,7 +534,16 @@
534
  </tbody>
535
  </table>
536
 
537
- <?php do_action( 'pmpro_membership_level_after_billing_details_settings' ); ?>
 
 
 
 
 
 
 
 
 
538
 
539
  <hr />
540
 
@@ -562,7 +571,7 @@
562
  echo '<tr><th>&nbsp;</th><td><p class="description">' . sprintf( wp_kses( __( 'Optional: Allow more customizable expiration dates using the <a href="%s" title="Paid Memberships Pro - Set Expiration Date Add On" target="_blank">Set Expiration Date Add On</a>.', 'paid-memberships-pro' ), $allowed_sed_html ), 'https://www.paidmembershipspro.com/add-ons/pmpro-expiration-date/?utm_source=plugin&utm_medium=pmpro-membershiplevels&utm_campaign=add-ons&utm_content=pmpro-expiration-date' ) . '</p></td></tr>';
563
  } ?>
564
 
565
- <tr class="expiration_info" <?php if(!pmpro_isLevelExpiring($level)) {?>style="display: none;"<?php } ?>>
566
  <th scope="row" valign="top"><label for="billing_amount"><?php _e('Expires In', 'paid-memberships-pro' );?>:</label></th>
567
  <td>
568
  <input id="expiration_number" name="expiration_number" type="text" value="<?php echo esc_attr($level->expiration_number);?>" class="small-text" />
@@ -577,7 +586,7 @@
577
  ?>
578
  </select>
579
  <p class="description"><?php _e('Set the duration of membership access. Note that the any future payments (recurring subscription, if any) will be cancelled when the membership expires.', 'paid-memberships-pro' );?></p>
580
-
581
  <div id="pmpro_expiration_warning" style="display: none;" class="notice error inline">
582
  <p><?php printf( __( 'WARNING: This level is set with both a recurring billing amount and an expiration date. You only need to set one of these unless you really want this membership to expire after a certain number of payments. For more information, <a target="_blank" href="%s">see our post here</a>.', 'paid-memberships-pro' ), 'https://www.paidmembershipspro.com/important-notes-on-recurring-billing-and-expiration-dates-for-membership-levels/?utm_source=plugin&utm_medium=pmpro-membershiplevels&utm_campaign=blog&utm_content=important-notes-on-recurring-billing-and-expiration-dates-for-membership-levels' ); ?></p>
583
  </div>
@@ -590,9 +599,9 @@
590
  jQuery('#pmpro_expiration_warning').hide();
591
  }
592
  }
593
-
594
  pmpro_expirationWarningCheck();
595
-
596
  jQuery('#recurring,#expiration').change(function() { pmpro_expirationWarningCheck(); });
597
  });
598
  </script>
@@ -601,7 +610,16 @@
601
  </tbody>
602
  </table>
603
 
604
- <?php do_action("pmpro_membership_level_after_other_settings"); ?>
 
 
 
 
 
 
 
 
 
605
 
606
  <hr />
607
 
@@ -642,6 +660,18 @@
642
  </tr>
643
  </tbody>
644
  </table>
 
 
 
 
 
 
 
 
 
 
 
 
645
  <p class="submit topborder">
646
  <input name="save" type="submit" class="button button-primary" value="<?php _e('Save Level', 'paid-memberships-pro' ); ?>" />
647
  <input name="cancel" type="button" class="button" value="<?php _e('Cancel', 'paid-memberships-pro' ); ?>" onclick="location.href='<?php echo add_query_arg( 'page', 'pmpro-membershiplevels' , get_admin_url(NULL, '/admin.php') ); ?>';" />
@@ -790,7 +820,7 @@
790
  <td colspan="5">
791
  <?php echo esc_attr_e( 'No Membership Levels Found', 'paid-memberships-pro' ); ?>
792
  </td>
793
- </tr>
794
  <?php } ?>
795
  <?php
796
  $count = 0;
@@ -830,7 +860,7 @@
830
  }
831
  } else {
832
  _e('No', 'paid-memberships-pro' );
833
- }
834
  ?></td>
835
  <?php do_action( 'pmpro_membership_levels_table_extra_cols_body', $level ); ?>
836
  </tr>
134
  '%d', //allow_signups
135
  )
136
  );
137
+
138
  if($saveid < 1) {
139
  //added a level
140
  $saveid = $wpdb->insert_id;
164
  $msgt = __("Error updating membership level.", 'paid-memberships-pro' );
165
  }
166
  }
167
+
168
  if( ! empty( $msgt ) && $ml_recurring && $ml_expiration ) {
169
  $msgt .= ' <strong class="red">' . sprintf( __( 'WARNING: A level was set with both a recurring billing amount and an expiration date. You only need to set one of these unless you really want this membership to expire after a specific time period. For more information, <a target="_blank" href="%s">see our post here</a>.', 'paid-memberships-pro' ), 'https://www.paidmembershipspro.com/important-notes-on-recurring-billing-and-expiration-dates-for-membership-levels/?utm_source=plugin&utm_medium=pmpro-membershiplevels&utm_campaign=blog&utm_content=important-notes-on-recurring-billing-and-expiration-dates-for-membership-levels' ) . '</strong>';
170
+
171
  // turn success to errors
172
  if( $msg > 0 ) {
173
  $msg = 0 - $msg;
178
  if ( isset( $ml_confirmation_in_email ) ) {
179
  update_pmpro_membership_level_meta( $saveid, 'confirmation_in_email', $ml_confirmation_in_email );
180
  }
181
+
182
  do_action("pmpro_save_membership_level", $saveid);
183
  }
184
  elseif($action == "delete_membership_level")
269
  ?>
270
  </h1>
271
  <hr class="wp-header-end">
272
+
273
  <div>
274
  <?php
275
  // get the level...
328
  ) );
329
  if(empty($level->categories))
330
  $level->categories = array();
331
+
332
  // grab the meta for the given level...
333
  if ( ! empty( $temp_id ) ) {
334
  $confirmation_in_email = get_pmpro_membership_level_meta( $temp_id, 'confirmation_in_email', true );
534
  </tbody>
535
  </table>
536
 
537
+ <?php
538
+ /**
539
+ * Allow adding form fields after the Billing Details Settings section.
540
+ *
541
+ * @since 2.5.10
542
+ *
543
+ * @param object $level The Membership Level object.
544
+ */
545
+ do_action( 'pmpro_membership_level_after_billing_details_settings', $level );
546
+ ?>
547
 
548
  <hr />
549
 
571
  echo '<tr><th>&nbsp;</th><td><p class="description">' . sprintf( wp_kses( __( 'Optional: Allow more customizable expiration dates using the <a href="%s" title="Paid Memberships Pro - Set Expiration Date Add On" target="_blank">Set Expiration Date Add On</a>.', 'paid-memberships-pro' ), $allowed_sed_html ), 'https://www.paidmembershipspro.com/add-ons/pmpro-expiration-date/?utm_source=plugin&utm_medium=pmpro-membershiplevels&utm_campaign=add-ons&utm_content=pmpro-expiration-date' ) . '</p></td></tr>';
572
  } ?>
573
 
574
+ <tr class="expiration_info" <?php if(!pmpro_isLevelExpiring($level)) {?>style="display: none;"<?php } ?>>
575
  <th scope="row" valign="top"><label for="billing_amount"><?php _e('Expires In', 'paid-memberships-pro' );?>:</label></th>
576
  <td>
577
  <input id="expiration_number" name="expiration_number" type="text" value="<?php echo esc_attr($level->expiration_number);?>" class="small-text" />
586
  ?>
587
  </select>
588
  <p class="description"><?php _e('Set the duration of membership access. Note that the any future payments (recurring subscription, if any) will be cancelled when the membership expires.', 'paid-memberships-pro' );?></p>
589
+
590
  <div id="pmpro_expiration_warning" style="display: none;" class="notice error inline">
591
  <p><?php printf( __( 'WARNING: This level is set with both a recurring billing amount and an expiration date. You only need to set one of these unless you really want this membership to expire after a certain number of payments. For more information, <a target="_blank" href="%s">see our post here</a>.', 'paid-memberships-pro' ), 'https://www.paidmembershipspro.com/important-notes-on-recurring-billing-and-expiration-dates-for-membership-levels/?utm_source=plugin&utm_medium=pmpro-membershiplevels&utm_campaign=blog&utm_content=important-notes-on-recurring-billing-and-expiration-dates-for-membership-levels' ); ?></p>
592
  </div>
599
  jQuery('#pmpro_expiration_warning').hide();
600
  }
601
  }
602
+
603
  pmpro_expirationWarningCheck();
604
+
605
  jQuery('#recurring,#expiration').change(function() { pmpro_expirationWarningCheck(); });
606
  });
607
  </script>
610
  </tbody>
611
  </table>
612
 
613
+ <?php
614
+ /**
615
+ * Allow adding form fields after the Other Settings section.
616
+ *
617
+ * @since 2.5.10
618
+ *
619
+ * @param object $level The Membership Level object.
620
+ */
621
+ do_action( 'pmpro_membership_level_after_other_settings', $level );
622
+ ?>
623
 
624
  <hr />
625
 
660
  </tr>
661
  </tbody>
662
  </table>
663
+
664
+ <?php
665
+ /**
666
+ * Allow adding form fields after the Content Settings section.
667
+ *
668
+ * @since 2.5.10
669
+ *
670
+ * @param object $level The Membership Level object.
671
+ */
672
+ do_action( 'pmpro_membership_level_after_content_settings', $level );
673
+ ?>
674
+
675
  <p class="submit topborder">
676
  <input name="save" type="submit" class="button button-primary" value="<?php _e('Save Level', 'paid-memberships-pro' ); ?>" />
677
  <input name="cancel" type="button" class="button" value="<?php _e('Cancel', 'paid-memberships-pro' ); ?>" onclick="location.href='<?php echo add_query_arg( 'page', 'pmpro-membershiplevels' , get_admin_url(NULL, '/admin.php') ); ?>';" />
820
  <td colspan="5">
821
  <?php echo esc_attr_e( 'No Membership Levels Found', 'paid-memberships-pro' ); ?>
822
  </td>
823
+ </tr>
824
  <?php } ?>
825
  <?php
826
  $count = 0;
860
  }
861
  } else {
862
  _e('No', 'paid-memberships-pro' );
863
+ }
864
  ?></td>
865
  <?php do_action( 'pmpro_membership_levels_table_extra_cols_body', $level ); ?>
866
  </tr>
adminpages/orders.php CHANGED
@@ -304,13 +304,15 @@ if ( ! empty( $_REQUEST['save'] ) ) {
304
  }
305
 
306
  // save
307
- if ( $order->saveOrder() !== false && $nonceokay ) {
308
  $order_id = $order->id;
 
 
309
  } else {
310
  $pmpro_msg = __( 'Error saving order.', 'paid-memberships-pro' );
311
  $pmpro_msgt = 'error';
312
  }
313
-
314
  // also update the discount code if needed
315
  if( isset( $_REQUEST['discount_code_id'] ) ) {
316
  $order->updateDiscountCode( intval( $_REQUEST['discount_code_id'] ) );
@@ -424,7 +426,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
424
  echo esc_html( $order->code );
425
  } else { ?>
426
  <input id="code" name="code" type="text" value="<?php echo esc_attr( $order->code ); ?>" class="regular-text" />
427
- <?php
428
  }
429
  ?>
430
  <?php if ( $order_id < 0 ) { ?>
@@ -440,7 +442,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
440
  echo esc_html( $order->user_id );
441
  } else { ?>
442
  <input id="user_id" name="user_id" type="text" value="<?php echo esc_attr( $order->user_id ); ?>" class="regular-text" />
443
- <?php
444
  }
445
  ?>
446
  </td>
@@ -453,7 +455,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
453
  echo esc_html( $order->membership_id );
454
  } else { ?>
455
  <input id="membership_id" name="membership_id" type="text" value="<?php echo esc_attr( $order->membership_id ); ?>" class="regular-text" />
456
- <?php
457
  }
458
  ?>
459
  </td>
@@ -630,7 +632,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
630
  } else {
631
  ?>
632
  <input id="couponamount" name="couponamount" type="text" size="10" value="<?php echo esc_attr( $order->couponamount ); ?>"/>
633
- <?php
634
  }
635
  ?>
636
  </td>
@@ -746,8 +748,8 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
746
  value="<?php echo esc_attr( $status ); ?>" <?php selected( $order->status, $status ); ?>><?php echo esc_html( $status ); ?></option>
747
  <?php } ?>
748
  </select>
749
- <?php
750
- }
751
  ?>
752
  </td>
753
  </tr>
@@ -836,7 +838,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
836
  } else {
837
  $timestamp = current_time( 'timestamp' );
838
  }
839
-
840
  $year = date( 'Y', $timestamp );
841
  $month = date( 'n', $timestamp );
842
  $day = date( 'j', $timestamp );
@@ -921,7 +923,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
921
  <th scope="row" valign="top"><label for="notes"><?php esc_html_e( 'Notes', 'paid-memberships-pro' ); ?>:</label></th>
922
  <td>
923
  <?php
924
- if ( in_array( 'notes', $read_only_fields ) && $order_id > 0 ) {
925
  echo wp_kses_post( $order->notes );
926
  } else {
927
  ?>
@@ -935,6 +937,17 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
935
  </tbody>
936
  </table>
937
 
 
 
 
 
 
 
 
 
 
 
 
938
  <p class="submit topborder">
939
  <input name="order" type="hidden" value="
940
  <?php
@@ -979,7 +992,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
979
  $export_url = add_query_arg( $url_params, $export_url );
980
  ?>
981
  <a target="_blank" href="<?php echo esc_url( $export_url ); ?>" class="page-title-action"><?php esc_html_e( 'Export to CSV', 'paid-memberships-pro' ); ?></a>
982
-
983
  <hr class="wp-header-end">
984
 
985
 
@@ -1011,9 +1024,9 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
1011
  value="with-discount-code" <?php selected( $filter, 'with-discount-code' ); ?>><?php esc_html_e( 'With a Discount Code', 'paid-memberships-pro' ); ?></option>
1012
  <option
1013
  value="within-a-status" <?php selected( $filter, 'within-a-status' ); ?>><?php esc_html_e( 'Within a Status', 'paid-memberships-pro' ); ?></option>
1014
- <option
1015
  value="only-paid" <?php selected( $filter, 'only-paid' ); ?>><?php esc_html_e( 'Only Paid Orders', 'paid-memberships-pro' ); ?></option>
1016
- <option
1017
  value="only-free" <?php selected( $filter, 'only-free' ); ?>><?php esc_html_e( 'Only Free Orders', 'paid-memberships-pro' ); ?></option>
1018
 
1019
  <?php $custom_filters = apply_filters( 'pmpro_admin_orders_filters', array() ); ?>
@@ -1076,7 +1089,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
1076
  <?php } ?>
1077
 
1078
  </select>
1079
-
1080
  <?php
1081
  $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS * FROM $wpdb->pmpro_discount_codes ";
1082
  $sqlQuery .= "ORDER BY id DESC ";
@@ -1248,7 +1261,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
1248
  if ( $join_with_usermeta ) {
1249
  $sqlQuery .= "LEFT JOIN $wpdb->usermeta um ON o.user_id = um.user_id ";
1250
  }
1251
-
1252
  if ( $filter === 'with-discount-code' ) {
1253
  $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON o.id = dc.order_id ";
1254
  }
@@ -1294,18 +1307,18 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
1294
  $sqlQuery .= 'GROUP BY o.id ORDER BY o.id DESC, o.timestamp DESC ';
1295
  } else {
1296
  $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS o.id FROM $wpdb->pmpro_membership_orders o ";
1297
-
1298
  if ( $filter === 'with-discount-code' ) {
1299
  $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON o.id = dc.order_id ";
1300
  }
1301
-
1302
  $sqlQuery .= "WHERE " . $condition . ' ORDER BY o.id DESC, o.timestamp DESC ';
1303
  }
1304
 
1305
  $sqlQuery .= "LIMIT $start, $limit";
1306
 
1307
  $order_ids = $wpdb->get_col( $sqlQuery );
1308
-
1309
  $totalrows = $wpdb->get_var( 'SELECT FOUND_ROWS() as found_rows' );
1310
 
1311
  if ( $order_ids ) {
@@ -1393,7 +1406,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
1393
  [<?php esc_html_e( 'deleted', 'paid-memberships-pro' ); ?>]
1394
  <?php } else { ?>
1395
  [<?php esc_html_e( 'none', 'paid-memberships-pro' ); ?>]
1396
- <?php } ?>
1397
  </td>
1398
  <?php do_action( 'pmpro_orders_extra_cols_body', $order ); ?>
1399
  <td>
@@ -1446,7 +1459,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
1446
  ?>
1447
  </td>
1448
  <td>
1449
- <?php esc_html_e( 'Payment', 'paid-memberships-pro' ); ?>:
1450
  <?php
1451
  if ( ! empty( $order->payment_transaction_id ) ) {
1452
  echo esc_html( $order->payment_transaction_id );
@@ -1456,7 +1469,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
1456
  ?>
1457
  <br/>
1458
  <?php esc_html_e( 'Subscription', 'paid-memberships-pro' ); ?>
1459
- :
1460
  <?php
1461
  if ( ! empty( $order->subscription_transaction_id ) ) {
1462
  echo esc_html( $order->subscription_transaction_id );
@@ -1475,7 +1488,7 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
1475
  <a title="<?php esc_attr_e('edit', 'paid-memberships-pro' ); ?>" href="<?php echo esc_url( add_query_arg( array( 'page' => 'pmpro-discountcodes', 'edit' => $order->discount_code->id ), admin_url('admin.php' ) ) ); ?>">
1476
  <?php echo esc_html( $order->discount_code->code ); ?>
1477
  </a>
1478
- <?php } ?>
1479
  </td>
1480
  </tr>
1481
  <?php
304
  }
305
 
306
  // save
307
+ if ( $nonceokay && false !== $order->saveOrder() ) {
308
  $order_id = $order->id;
309
+ $pmpro_msg = __( 'Order saved successfully.', 'paid-memberships-pro' );
310
+ $pmpro_msgt = 'success';
311
  } else {
312
  $pmpro_msg = __( 'Error saving order.', 'paid-memberships-pro' );
313
  $pmpro_msgt = 'error';
314
  }
315
+
316
  // also update the discount code if needed
317
  if( isset( $_REQUEST['discount_code_id'] ) ) {
318
  $order->updateDiscountCode( intval( $_REQUEST['discount_code_id'] ) );
426
  echo esc_html( $order->code );
427
  } else { ?>
428
  <input id="code" name="code" type="text" value="<?php echo esc_attr( $order->code ); ?>" class="regular-text" />
429
+ <?php
430
  }
431
  ?>
432
  <?php if ( $order_id < 0 ) { ?>
442
  echo esc_html( $order->user_id );
443
  } else { ?>
444
  <input id="user_id" name="user_id" type="text" value="<?php echo esc_attr( $order->user_id ); ?>" class="regular-text" />
445
+ <?php
446
  }
447
  ?>
448
  </td>
455
  echo esc_html( $order->membership_id );
456
  } else { ?>
457
  <input id="membership_id" name="membership_id" type="text" value="<?php echo esc_attr( $order->membership_id ); ?>" class="regular-text" />
458
+ <?php
459
  }
460
  ?>
461
  </td>
632
  } else {
633
  ?>
634
  <input id="couponamount" name="couponamount" type="text" size="10" value="<?php echo esc_attr( $order->couponamount ); ?>"/>
635
+ <?php
636
  }
637
  ?>
638
  </td>
748
  value="<?php echo esc_attr( $status ); ?>" <?php selected( $order->status, $status ); ?>><?php echo esc_html( $status ); ?></option>
749
  <?php } ?>
750
  </select>
751
+ <?php
752
+ }
753
  ?>
754
  </td>
755
  </tr>
838
  } else {
839
  $timestamp = current_time( 'timestamp' );
840
  }
841
+
842
  $year = date( 'Y', $timestamp );
843
  $month = date( 'n', $timestamp );
844
  $day = date( 'j', $timestamp );
923
  <th scope="row" valign="top"><label for="notes"><?php esc_html_e( 'Notes', 'paid-memberships-pro' ); ?>:</label></th>
924
  <td>
925
  <?php
926
+ if ( in_array( 'notes', $read_only_fields ) && $order_id > 0 ) {
927
  echo wp_kses_post( $order->notes );
928
  } else {
929
  ?>
937
  </tbody>
938
  </table>
939
 
940
+ <?php
941
+ /**
942
+ * Allow adding other content after the Order Settings table.
943
+ *
944
+ * @since 2.5.10
945
+ *
946
+ * @param MemberOrder $order Member order object.
947
+ */
948
+ do_action( 'pmpro_after_order_settings_table', $order );
949
+ ?>
950
+
951
  <p class="submit topborder">
952
  <input name="order" type="hidden" value="
953
  <?php
992
  $export_url = add_query_arg( $url_params, $export_url );
993
  ?>
994
  <a target="_blank" href="<?php echo esc_url( $export_url ); ?>" class="page-title-action"><?php esc_html_e( 'Export to CSV', 'paid-memberships-pro' ); ?></a>
995
+
996
  <hr class="wp-header-end">
997
 
998
 
1024
  value="with-discount-code" <?php selected( $filter, 'with-discount-code' ); ?>><?php esc_html_e( 'With a Discount Code', 'paid-memberships-pro' ); ?></option>
1025
  <option
1026
  value="within-a-status" <?php selected( $filter, 'within-a-status' ); ?>><?php esc_html_e( 'Within a Status', 'paid-memberships-pro' ); ?></option>
1027
+ <option
1028
  value="only-paid" <?php selected( $filter, 'only-paid' ); ?>><?php esc_html_e( 'Only Paid Orders', 'paid-memberships-pro' ); ?></option>
1029
+ <option
1030
  value="only-free" <?php selected( $filter, 'only-free' ); ?>><?php esc_html_e( 'Only Free Orders', 'paid-memberships-pro' ); ?></option>
1031
 
1032
  <?php $custom_filters = apply_filters( 'pmpro_admin_orders_filters', array() ); ?>
1089
  <?php } ?>
1090
 
1091
  </select>
1092
+
1093
  <?php
1094
  $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS * FROM $wpdb->pmpro_discount_codes ";
1095
  $sqlQuery .= "ORDER BY id DESC ";
1261
  if ( $join_with_usermeta ) {
1262
  $sqlQuery .= "LEFT JOIN $wpdb->usermeta um ON o.user_id = um.user_id ";
1263
  }
1264
+
1265
  if ( $filter === 'with-discount-code' ) {
1266
  $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON o.id = dc.order_id ";
1267
  }
1307
  $sqlQuery .= 'GROUP BY o.id ORDER BY o.id DESC, o.timestamp DESC ';
1308
  } else {
1309
  $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS o.id FROM $wpdb->pmpro_membership_orders o ";
1310
+
1311
  if ( $filter === 'with-discount-code' ) {
1312
  $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON o.id = dc.order_id ";
1313
  }
1314
+
1315
  $sqlQuery .= "WHERE " . $condition . ' ORDER BY o.id DESC, o.timestamp DESC ';
1316
  }
1317
 
1318
  $sqlQuery .= "LIMIT $start, $limit";
1319
 
1320
  $order_ids = $wpdb->get_col( $sqlQuery );
1321
+
1322
  $totalrows = $wpdb->get_var( 'SELECT FOUND_ROWS() as found_rows' );
1323
 
1324
  if ( $order_ids ) {
1406
  [<?php esc_html_e( 'deleted', 'paid-memberships-pro' ); ?>]
1407
  <?php } else { ?>
1408
  [<?php esc_html_e( 'none', 'paid-memberships-pro' ); ?>]
1409
+ <?php } ?>
1410
  </td>
1411
  <?php do_action( 'pmpro_orders_extra_cols_body', $order ); ?>
1412
  <td>
1459
  ?>
1460
  </td>
1461
  <td>
1462
+ <?php esc_html_e( 'Payment', 'paid-memberships-pro' ); ?>:
1463
  <?php
1464
  if ( ! empty( $order->payment_transaction_id ) ) {
1465
  echo esc_html( $order->payment_transaction_id );
1469
  ?>
1470
  <br/>
1471
  <?php esc_html_e( 'Subscription', 'paid-memberships-pro' ); ?>
1472
+ :
1473
  <?php
1474
  if ( ! empty( $order->subscription_transaction_id ) ) {
1475
  echo esc_html( $order->subscription_transaction_id );
1488
  <a title="<?php esc_attr_e('edit', 'paid-memberships-pro' ); ?>" href="<?php echo esc_url( add_query_arg( array( 'page' => 'pmpro-discountcodes', 'edit' => $order->discount_code->id ), admin_url('admin.php' ) ) ); ?>">
1489
  <?php echo esc_html( $order->discount_code->code ); ?>
1490
  </a>
1491
+ <?php } ?>
1492
  </td>
1493
  </tr>
1494
  <?php
adminpages/reports/login.php CHANGED
@@ -228,7 +228,8 @@ function pmpro_report_login_page()
228
  <?php echo $theuser->display_name;?>
229
  </td>
230
  <td><?php echo $auser->membership?></td>
231
- <td><?php echo date_i18n("m/d/Y", strtotime($theuser->user_registered, current_time("timestamp")))?></td>
 
232
  <td>
233
  <?php
234
  if($auser->enddate)
228
  <?php echo $theuser->display_name;?>
229
  </td>
230
  <td><?php echo $auser->membership?></td>
231
+ <td><?php echo date_i18n( 'm/d/Y', strtotime( get_date_from_gmt( $theuser->user_registered ), current_time( 'timestamp' ) ) ); ?></td>
232
+
233
  <td>
234
  <?php
235
  if($auser->enddate)
classes/class-pmpro-members-list-table.php CHANGED
@@ -574,7 +574,7 @@ class PMPro_Members_List_Table extends WP_List_Table {
574
  if ( empty( $joindate ) ) {
575
  return;
576
  }
577
- return date_i18n( get_option('date_format'), $joindate );
578
  }
579
 
580
  /**
574
  if ( empty( $joindate ) ) {
575
  return;
576
  }
577
+ return date_i18n( get_option( 'date_format' ), strtotime( get_date_from_gmt( date( 'Y-m-d H:i:s', $joindate ) ) ) );
578
  }
579
 
580
  /**
classes/class.memberorder.php CHANGED
@@ -620,8 +620,11 @@
620
  global $wpdb;
621
  $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET timestamp = '" . $date . "' WHERE id = '" . $this->id . "' LIMIT 1";
622
 
 
623
  if($wpdb->query($this->sqlQuery) !== "false") {
624
  $this->timestamp = strtotime( $date );
 
 
625
  return $this->getMemberOrderByID($this->id);
626
  } else {
627
  return false;
@@ -867,12 +870,17 @@
867
  if(empty($this->id))
868
  return false;
869
 
870
- $this->status = $newstatus;
871
  $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET status = '" . esc_sql($newstatus) . "' WHERE id = '" . $this->id . "' LIMIT 1";
872
- if($wpdb->query($this->sqlQuery) !== false)
 
 
 
 
 
873
  return true;
874
- else
875
  return false;
 
876
  }
877
 
878
  /**
@@ -929,8 +937,10 @@
929
  $this->gateway,
930
  $this->gateway_environment,
931
  $this->subscription_transaction_id
932
- );
 
933
  $wpdb->query($sqlQuery);
 
934
 
935
  //cancel the gateway subscription first
936
  if (is_object($this->Gateway)) {
@@ -1090,4 +1100,4 @@
1090
  else
1091
  return false;
1092
  }
1093
- }
620
  global $wpdb;
621
  $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET timestamp = '" . $date . "' WHERE id = '" . $this->id . "' LIMIT 1";
622
 
623
+ do_action('pmpro_update_order', $this);
624
  if($wpdb->query($this->sqlQuery) !== "false") {
625
  $this->timestamp = strtotime( $date );
626
+ do_action('pmpro_updated_order', $this);
627
+
628
  return $this->getMemberOrderByID($this->id);
629
  } else {
630
  return false;
870
  if(empty($this->id))
871
  return false;
872
 
 
873
  $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET status = '" . esc_sql($newstatus) . "' WHERE id = '" . $this->id . "' LIMIT 1";
874
+
875
+ do_action('pmpro_update_order', $this);
876
+ if($wpdb->query($this->sqlQuery) !== false){
877
+ $this->status = $newstatus;
878
+ do_action('pmpro_updated_order', $this);
879
+
880
  return true;
881
+ }else{
882
  return false;
883
+ }
884
  }
885
 
886
  /**
937
  $this->gateway,
938
  $this->gateway_environment,
939
  $this->subscription_transaction_id
940
+ );
941
+ do_action('pmpro_update_order', $this);
942
  $wpdb->query($sqlQuery);
943
+ do_action('pmpro_updated_order', $this);
944
 
945
  //cancel the gateway subscription first
946
  if (is_object($this->Gateway)) {
1100
  else
1101
  return false;
1102
  }
1103
+ }
classes/gateways/class.pmprogateway_authorizenet.php CHANGED
@@ -123,7 +123,7 @@ class PMProGateway_authorizenet extends PMProGateway
123
  <label for="transactionkey"><?php _e('Transaction Key', 'paid-memberships-pro' );?>:</label>
124
  </th>
125
  <td>
126
- <input type="text" id="transactionkey" name="transactionkey" value="<?php echo esc_attr($values['transactionkey'])?>" class="regular-text code" />
127
  </td>
128
  </tr>
129
  <tr class="gateway gateway_authorizenet" <?php if($gateway != "authorizenet") { ?>style="display: none;"<?php } ?>>
@@ -1097,4 +1097,4 @@ class PMProGateway_authorizenet extends PMProGateway
1097
  return substr($haystack,$start_position,$end_position-$start_position);
1098
  }
1099
  }
1100
- }
123
  <label for="transactionkey"><?php _e('Transaction Key', 'paid-memberships-pro' );?>:</label>
124
  </th>
125
  <td>
126
+ <input type="text" id="transactionkey" name="transactionkey" value="<?php echo esc_attr($values['transactionkey'])?>" autocomplete="off" class="regular-text code pmpro-admin-secure-key" />
127
  </td>
128
  </tr>
129
  <tr class="gateway gateway_authorizenet" <?php if($gateway != "authorizenet") { ?>style="display: none;"<?php } ?>>
1097
  return substr($haystack,$start_position,$end_position-$start_position);
1098
  }
1099
  }
1100
+ }
classes/gateways/class.pmprogateway_braintree.php CHANGED
@@ -329,7 +329,7 @@ use Braintree\WebhookNotification as Braintree_WebhookNotification;
329
  <label for="braintree_privatekey"><?php _e('Private Key', 'paid-memberships-pro' );?>:</label>
330
  </th>
331
  <td>
332
- <input type="text" id="braintree_privatekey" name="braintree_privatekey" value="<?php echo esc_attr($values['braintree_privatekey'])?>" class="regular-text code" />
333
  </td>
334
  </tr>
335
  <tr class="gateway gateway_braintree" <?php if($gateway != "braintree") { ?>style="display: none;"<?php } ?>>
@@ -337,7 +337,7 @@ use Braintree\WebhookNotification as Braintree_WebhookNotification;
337
  <label for="braintree_encryptionkey"><?php _e('Client-Side Encryption Key', 'paid-memberships-pro' );?>:</label>
338
  </th>
339
  <td>
340
- <textarea id="braintree_encryptionkey" name="braintree_encryptionkey" rows="3" cols="50" class="large-text code"><?php echo esc_textarea($values['braintree_encryptionkey'])?></textarea>
341
  </td>
342
  </tr>
343
  <tr class="gateway gateway_braintree" <?php if($gateway != "braintree") { ?>style="display: none;"<?php } ?>>
329
  <label for="braintree_privatekey"><?php _e('Private Key', 'paid-memberships-pro' );?>:</label>
330
  </th>
331
  <td>
332
+ <input type="text" id="braintree_privatekey" name="braintree_privatekey" value="<?php echo esc_attr($values['braintree_privatekey'])?>" autocomplete="off" class="regular-text code pmpro-admin-secure-key" />
333
  </td>
334
  </tr>
335
  <tr class="gateway gateway_braintree" <?php if($gateway != "braintree") { ?>style="display: none;"<?php } ?>>
337
  <label for="braintree_encryptionkey"><?php _e('Client-Side Encryption Key', 'paid-memberships-pro' );?>:</label>
338
  </th>
339
  <td>
340
+ <textarea id="braintree_encryptionkey" name="braintree_encryptionkey" autocomplete="off" rows="3" cols="50" class="large-text code pmpro-admin-secure-key"><?php echo esc_textarea($values['braintree_encryptionkey'])?></textarea>
341
  </td>
342
  </tr>
343
  <tr class="gateway gateway_braintree" <?php if($gateway != "braintree") { ?>style="display: none;"<?php } ?>>
classes/gateways/class.pmprogateway_cybersource.php CHANGED
@@ -102,7 +102,7 @@
102
  <label for="cybersource_securitykey"><?php _e('Transaction Security Key', 'paid-memberships-pro' );?>:</label>
103
  </th>
104
  <td>
105
- <textarea id="cybersource_securitykey" name="cybersource_securitykey" rows="3" cols="50" class="large-text code"><?php echo esc_textarea($values['cybersource_securitykey']);?></textarea>
106
  </td>
107
  </tr>
108
  <?php
102
  <label for="cybersource_securitykey"><?php _e('Transaction Security Key', 'paid-memberships-pro' );?>:</label>
103
  </th>
104
  <td>
105
+ <textarea id="cybersource_securitykey" name="cybersource_securitykey" autocomplete="off" rows="3" cols="50" class="large-text code pmpro-admin-secure-key"><?php echo esc_textarea($values['cybersource_securitykey']);?></textarea>
106
  </td>
107
  </tr>
108
  <?php
classes/gateways/class.pmprogateway_payflowpro.php CHANGED
@@ -320,7 +320,22 @@
320
 
321
  //paypal profile stuff
322
  $nvpStr = "";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  $nvpStr .="&AMT=" . $amount . "&TAXAMT=" . $amount_tax . "&CURRENCY=" . $pmpro_currency;
 
324
  /* PayFlow Pro doesn't use IPN so this is a little confusing */
325
  // $nvpStr .= "&NOTIFYURL=" . urlencode( add_query_arg( 'action', 'ipnhandler', admin_url('admin-ajax.php') ) );
326
  //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
@@ -390,7 +405,19 @@
390
 
391
  //paypal profile stuff
392
  $nvpStr = "&ACTION=A";
 
 
 
 
 
 
 
 
 
 
 
393
  $nvpStr .="&AMT=" . $amount . "&TAXAMT=" . $amount_tax . "&CURRENCY=" . $pmpro_currency;
 
394
  /* PayFlow Pro doesn't use IPN so this is a little confusing */
395
  // $nvpStr .= "&NOTIFYURL=" . urlencode( add_query_arg( 'action', 'ipnhandler', admin_url('admin-ajax.php') ) );
396
  //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
@@ -497,6 +524,17 @@
497
 
498
  //paypal profile stuff
499
  $nvpStr = "&ORIGPROFILEID=" . $order->subscription_transaction_id . "&ACTION=M";
 
 
 
 
 
 
 
 
 
 
 
500
  /* PayFlow Pro doesn't use IPN so this is a little confusing */
501
  // $nvpStr .= "&NOTIFYURL=" . urlencode( add_query_arg( 'action', 'ipnhandler', admin_url('admin-ajax.php') ) );
502
 
320
 
321
  //paypal profile stuff
322
  $nvpStr = "";
323
+
324
+ // Only add CARDONFILE for initial charge if it's recurring.
325
+ if ( pmpro_isLevelRecurring( $order->membership_level ) ) {
326
+ /*
327
+ * Card on File is now required.
328
+ *
329
+ * CITR: The customer just performed an action to make the transaction.
330
+ * MITR: The customer passively approved during CITR to make this subsequent (recurring) transaction.
331
+ *
332
+ * @link https://developer.paypal.com/docs/payflow/integration-guide/card-on-file/
333
+ */
334
+ $nvpStr .= "&CARDONFILE=CITR";
335
+ }
336
+
337
  $nvpStr .="&AMT=" . $amount . "&TAXAMT=" . $amount_tax . "&CURRENCY=" . $pmpro_currency;
338
+
339
  /* PayFlow Pro doesn't use IPN so this is a little confusing */
340
  // $nvpStr .= "&NOTIFYURL=" . urlencode( add_query_arg( 'action', 'ipnhandler', admin_url('admin-ajax.php') ) );
341
  //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
405
 
406
  //paypal profile stuff
407
  $nvpStr = "&ACTION=A";
408
+
409
+ /*
410
+ * Card on File is now required.
411
+ *
412
+ * CITR: The customer just performed an action to make the transaction.
413
+ * MITR: The customer passively approved during CITR to make this subsequent (recurring) transaction.
414
+ *
415
+ * @link https://developer.paypal.com/docs/payflow/integration-guide/card-on-file/
416
+ */
417
+ $nvpStr .="&CARDONFILE=CITR";
418
+
419
  $nvpStr .="&AMT=" . $amount . "&TAXAMT=" . $amount_tax . "&CURRENCY=" . $pmpro_currency;
420
+
421
  /* PayFlow Pro doesn't use IPN so this is a little confusing */
422
  // $nvpStr .= "&NOTIFYURL=" . urlencode( add_query_arg( 'action', 'ipnhandler', admin_url('admin-ajax.php') ) );
423
  //$nvpStr .= "&L_BILLINGTYPE0=RecurringPayments&L_BILLINGAGREEMENTDESCRIPTION0=" . $order->PaymentAmount;
524
 
525
  //paypal profile stuff
526
  $nvpStr = "&ORIGPROFILEID=" . $order->subscription_transaction_id . "&ACTION=M";
527
+
528
+ /*
529
+ * Card on File is now required.
530
+ *
531
+ * CITR: The customer just performed an action to make the transaction.
532
+ * MITR: The customer passively approved during CIT to make this subsequent (recurring) transaction.
533
+ *
534
+ * @link https://developer.paypal.com/docs/payflow/integration-guide/card-on-file/
535
+ */
536
+ $nvpStr .= "&CARDONFILE=CITR";
537
+
538
  /* PayFlow Pro doesn't use IPN so this is a little confusing */
539
  // $nvpStr .= "&NOTIFYURL=" . urlencode( add_query_arg( 'action', 'ipnhandler', admin_url('admin-ajax.php') ) );
540
 
classes/gateways/class.pmprogateway_paypal.php CHANGED
@@ -169,7 +169,7 @@
169
  <label for="apipassword"><?php _e('API Password', 'paid-memberships-pro' );?>:</label>
170
  </th>
171
  <td>
172
- <input type="text" id="apipassword" name="apipassword" value="<?php echo esc_attr($values['apipassword'])?>" class="regular-text code" />
173
  </td>
174
  </tr>
175
  <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>>
169
  <label for="apipassword"><?php _e('API Password', 'paid-memberships-pro' );?>:</label>
170
  </th>
171
  <td>
172
+ <input type="text" id="apipassword" name="apipassword" value="<?php echo esc_attr($values['apipassword'])?>" autocomplete="off" class="regular-text code pmpro-admin-secure-key" />
173
  </td>
174
  </tr>
175
  <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>>
classes/gateways/class.pmprogateway_paypalexpress.php CHANGED
@@ -178,7 +178,7 @@
178
  <label for="apipassword"><?php _e('API Password', 'paid-memberships-pro' );?>:</label>
179
  </th>
180
  <td>
181
- <input type="text" id="apipassword" name="apipassword" value="<?php echo esc_attr($values['apipassword'])?>" class="regular-text code" />
182
  </td>
183
  </tr>
184
  <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>>
@@ -421,9 +421,15 @@
421
  if(!$current_user->ID)
422
  {
423
  //reload the user fields
424
- $new_user_array['user_login'] = $_SESSION['pmpro_signup_username'];
425
- $new_user_array['user_pass'] = $_SESSION['pmpro_signup_password'];
426
- $new_user_array['user_email'] = $_SESSION['pmpro_signup_email'];
 
 
 
 
 
 
427
 
428
  //unset the user fields in session
429
  unset($_SESSION['pmpro_signup_username']);
@@ -591,7 +597,6 @@
591
 
592
  //exit('SetExpressCheckout Completed Successfully: '.print_r($this->httpParsedResponseAr, true));
593
  } else {
594
- $order->status = "error";
595
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
596
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
597
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
@@ -625,7 +630,6 @@
625
 
626
  return true;
627
  } else {
628
- $order->status = "error";
629
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
630
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
631
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
@@ -679,7 +683,6 @@
679
 
680
  return true;
681
  } else {
682
- $order->status = "error";
683
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
684
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
685
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
@@ -690,7 +693,7 @@
690
 
691
  function subscribe(&$order)
692
  {
693
- global $pmpro_currency;
694
 
695
  if(empty($order->code))
696
  $order->code = $order->getRandomCode();
@@ -749,16 +752,44 @@
749
  $this->httpParsedResponseAr = $this->PPHttpPost('CreateRecurringPaymentsProfile', $nvpStr);
750
 
751
  if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
752
- $order->status = "success";
753
- $order->payment_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
754
- $order->subscription_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
 
 
 
755
 
756
- //update order
757
- $order->saveOrder();
 
758
 
759
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
760
  } else {
761
- $order->status = "error";
 
 
762
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
763
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
764
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
@@ -796,7 +827,6 @@
796
  if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
797
  return true;
798
  } else {
799
- $order->status = "error";
800
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
801
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']) . ". " . __("Please contact the site owner or cancel your subscription from within PayPal to make sure you are not charged going forward.", 'paid-memberships-pro' );
802
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
@@ -824,7 +854,6 @@
824
  }
825
  else
826
  {
827
- $order->status = "error";
828
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
829
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
830
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
178
  <label for="apipassword"><?php _e('API Password', 'paid-memberships-pro' );?>:</label>
179
  </th>
180
  <td>
181
+ <input type="text" id="apipassword" name="apipassword" value="<?php echo esc_attr($values['apipassword'])?>" autocomplete="off" class="regular-text code pmpro-admin-secure-key" />
182
  </td>
183
  </tr>
184
  <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>>
421
  if(!$current_user->ID)
422
  {
423
  //reload the user fields
424
+ if( ! empty( $_SESSION['pmpro_signup_username'] ) ){
425
+ $new_user_array['user_login'] = $_SESSION['pmpro_signup_username'];
426
+ }
427
+ if( ! empty( $_SESSION['pmpro_signup_password'] ) ){
428
+ $new_user_array['user_pass'] = $_SESSION['pmpro_signup_password'];
429
+ }
430
+ if( ! empty( $_SESSION['pmpro_signup_email'] ) ){
431
+ $new_user_array['user_email'] = $_SESSION['pmpro_signup_email'];
432
+ }
433
 
434
  //unset the user fields in session
435
  unset($_SESSION['pmpro_signup_username']);
597
 
598
  //exit('SetExpressCheckout Completed Successfully: '.print_r($this->httpParsedResponseAr, true));
599
  } else {
 
600
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
601
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
602
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
630
 
631
  return true;
632
  } else {
 
633
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
634
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
635
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
683
 
684
  return true;
685
  } else {
 
686
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
687
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
688
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
693
 
694
  function subscribe(&$order)
695
  {
696
+ global $pmpro_currency, $pmpro_review;
697
 
698
  if(empty($order->code))
699
  $order->code = $order->getRandomCode();
752
  $this->httpParsedResponseAr = $this->PPHttpPost('CreateRecurringPaymentsProfile', $nvpStr);
753
 
754
  if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
755
+ // PayPal docs says that PROFILESTATUS can be:
756
+ // 1. ActiveProfile — The recurring payment profile has been successfully created and activated for scheduled payments according the billing instructions from the recurring payments profile.
757
+ // 2. PendingProfile — The system is in the process of creating the recurring payment profile. Please check your IPN messages for an update.
758
+ // Also, we have seen that PROFILESTATUS can be missing. That case would be an error.
759
+ if(isset($this->httpParsedResponseAr["PROFILESTATUS"]) && in_array($this->httpParsedResponseAr["PROFILESTATUS"], array("ActiveProfile", "PendingProfile"))) {
760
+ $order->status = "success";
761
 
762
+ // this is wrong, but we don't know the real transaction id at this point
763
+ $order->payment_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
764
+ $order->subscription_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
765
 
766
+ //update order
767
+ $order->saveOrder();
768
+
769
+ return true;
770
+ } else {
771
+ // stop processing the review request on checkout page
772
+ $pmpro_review = false;
773
+
774
+ $order->status = "error";
775
+
776
+ // this is wrong, but we don't know the real transaction id at this point
777
+ $order->payment_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
778
+ $order->subscription_transaction_id = urldecode($this->httpParsedResponseAr['PROFILEID']);
779
+
780
+ $order->errorcode = '';
781
+ $order->error = __( 'Something went wrong creating plan with PayPal; missing PROFILESTATUS.', 'paid-memberships-pro' );
782
+ $order->shorterror = __( 'Error creating plan with PayPal.', 'paid-memberships-pro' );
783
+
784
+ //update order
785
+ $order->saveOrder();
786
+
787
+ return false;
788
+ }
789
  } else {
790
+ // stop processing the review request on checkout page
791
+ $pmpro_review = false;
792
+
793
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
794
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
795
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
827
  if("SUCCESS" == strtoupper($this->httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($this->httpParsedResponseAr["ACK"])) {
828
  return true;
829
  } else {
 
830
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
831
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']) . ". " . __("Please contact the site owner or cancel your subscription from within PayPal to make sure you are not charged going forward.", 'paid-memberships-pro' );
832
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
854
  }
855
  else
856
  {
 
857
  $order->errorcode = $this->httpParsedResponseAr['L_ERRORCODE0'];
858
  $order->error = urldecode($this->httpParsedResponseAr['L_LONGMESSAGE0']);
859
  $order->shorterror = urldecode($this->httpParsedResponseAr['L_SHORTMESSAGE0']);
classes/gateways/class.pmprogateway_paypalstandard.php CHANGED
@@ -170,7 +170,7 @@
170
  <label for="apipassword"><?php _e('API Password', 'paid-memberships-pro' );?>:</label>
171
  </th>
172
  <td>
173
- <input type="text" id="apipassword" name="apipassword" size="60" value="<?php echo esc_attr($values['apipassword'])?>" />
174
  </td>
175
  </tr>
176
  <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>>
170
  <label for="apipassword"><?php _e('API Password', 'paid-memberships-pro' );?>:</label>
171
  </th>
172
  <td>
173
+ <input type="text" id="apipassword" name="apipassword" size="60" value="<?php echo esc_attr($values['apipassword'])?>" autocomplete="off" class="regular-text code pmpro-admin-secure-key" />
174
  </td>
175
  </tr>
176
  <tr class="gateway gateway_paypal gateway_paypalexpress" <?php if($gateway != "paypal" && $gateway != "paypalexpress") { ?>style="display: none;"<?php } ?>>
classes/gateways/class.pmprogateway_stripe.php CHANGED
@@ -348,7 +348,7 @@ class PMProGateway_stripe extends PMProGateway {
348
  <label for="stripe_secretkey"><?php _e( 'Secret Key', 'paid-memberships-pro' ); ?>:</label>
349
  </th>
350
  <td>
351
- <input type="text" id="stripe_secretkey" name="stripe_secretkey" value="<?php echo esc_attr( $values['stripe_secretkey'] ) ?>" class="regular-text code" />
352
  </td>
353
  </tr>
354
  <tr class="gateway gateway_stripe" <?php if ( $gateway != "stripe" ) { ?>style="display: none;"<?php } ?>>
348
  <label for="stripe_secretkey"><?php _e( 'Secret Key', 'paid-memberships-pro' ); ?>:</label>
349
  </th>
350
  <td>
351
+ <input type="text" id="stripe_secretkey" name="stripe_secretkey" value="<?php echo esc_attr( $values['stripe_secretkey'] ) ?>" autocomplete="off" class="regular-text code pmpro-admin-secure-key" />
352
  </td>
353
  </tr>
354
  <tr class="gateway gateway_stripe" <?php if ( $gateway != "stripe" ) { ?>style="display: none;"<?php } ?>>
classes/gateways/class.pmprogateway_twocheckout.php CHANGED
@@ -129,7 +129,7 @@
129
  <label for="twocheckout_apipassword"><?php _e('API Password', 'paid-memberships-pro' );?>:</label>
130
  </th>
131
  <td>
132
- <input type="text" id="twocheckout_apipassword" name="twocheckout_apipassword" value="<?php echo esc_attr($values['twocheckout_apipassword'])?>" class="regular-text code" />
133
  <p class="description"><?php esc_html_e( 'Password for the API user created.', 'paid-memberships-pro' ); ?></p>
134
  </td>
135
  </tr>
129
  <label for="twocheckout_apipassword"><?php _e('API Password', 'paid-memberships-pro' );?>:</label>
130
  </th>
131
  <td>
132
+ <input type="text" id="twocheckout_apipassword" name="twocheckout_apipassword" value="<?php echo esc_attr($values['twocheckout_apipassword'])?>" autocomplete="off" class="regular-text code pmpro-admin-secure-key" />
133
  <p class="description"><?php esc_html_e( 'Password for the API user created.', 'paid-memberships-pro' ); ?></p>
134
  </td>
135
  </tr>
css/admin.css CHANGED
@@ -158,6 +158,10 @@
158
  max-width: none;
159
  }
160
 
 
 
 
 
161
  /* advanced settings */
162
  .admin_page_pmpro-advancedsettings .form-table select:not(.admin_page_pmpro-advancedsettings .form-table select#tospage) {
163
  max-width: none;
158
  max-width: none;
159
  }
160
 
161
+ .admin_page_pmpro-paymentsettings .pmpro-admin-secure-key {
162
+ -webkit-text-security: disc;
163
+ }
164
+
165
  /* advanced settings */
166
  .admin_page_pmpro-advancedsettings .form-table select:not(.admin_page_pmpro-advancedsettings .form-table select#tospage) {
167
  max-width: none;
includes/compatibility/divi.php CHANGED
@@ -15,11 +15,11 @@ class PMProDivi{
15
 
16
  public function toggle( $modules ) {
17
 
18
- if ( ! empty( $modules ) && is_object( $modules['et_pb_row'] ) ) {
19
  $modules['et_pb_row']->settings_modal_toggles['custom_css']['toggles']['paid-memberships-pro'] = __( 'Paid Memberships Pro', 'paid-memberships-pro' );
20
  }
21
 
22
- if ( ! empty( $modules ) && is_object( $modules['et_pb_section'] ) ) {
23
  $modules['et_pb_section']->settings_modal_toggles['custom_css']['toggles']['paid-memberships-pro'] = __( 'Paid Memberships Pro', 'paid-memberships-pro' );
24
  }
25
 
@@ -90,4 +90,4 @@ class PMProDivi{
90
  }
91
  }
92
  }
93
- new PMProDivi();
15
 
16
  public function toggle( $modules ) {
17
 
18
+ if ( isset( $modules['et_pb_row'] ) && is_object( $modules['et_pb_row'] ) ) {
19
  $modules['et_pb_row']->settings_modal_toggles['custom_css']['toggles']['paid-memberships-pro'] = __( 'Paid Memberships Pro', 'paid-memberships-pro' );
20
  }
21
 
22
+ if ( isset( $modules['et_pb_section'] ) && is_object( $modules['et_pb_section'] ) ) {
23
  $modules['et_pb_section']->settings_modal_toggles['custom_css']['toggles']['paid-memberships-pro'] = __( 'Paid Memberships Pro', 'paid-memberships-pro' );
24
  }
25
 
90
  }
91
  }
92
  }
93
+ new PMProDivi();
includes/content.php CHANGED
@@ -147,7 +147,7 @@ function pmpro_search_filter($query)
147
  //hide pmpro pages from search results
148
  if( ! $query->is_admin && $query->is_search && empty( $query->query['post_parent'] ) ) {
149
  //avoiding post_parent queries for now
150
- if( empty( $query->query_vars['post_parent'] ) ) {
151
  $query->set( 'post__not_in', array_merge( $query->get('post__not_in'), array_values( $pmpro_pages ) ) );
152
  }
153
  }
147
  //hide pmpro pages from search results
148
  if( ! $query->is_admin && $query->is_search && empty( $query->query['post_parent'] ) ) {
149
  //avoiding post_parent queries for now
150
+ if( empty( $query->query_vars['post_parent'] ) && ! empty( $pmpro_pages ) ) {
151
  $query->set( 'post__not_in', array_merge( $query->get('post__not_in'), array_values( $pmpro_pages ) ) );
152
  }
153
  }
includes/deprecated.php CHANGED
@@ -38,7 +38,7 @@ add_action( 'init', 'pmpro_init_check_for_deprecated_filters', 99 );
38
  *
39
  */
40
  function pmpro_getClassForField( $field ) {
41
- pmpro_get_element_class( '', $field );
42
  }
43
 
44
  /**
38
  *
39
  */
40
  function pmpro_getClassForField( $field ) {
41
+ return pmpro_get_element_class( '', $field );
42
  }
43
 
44
  /**
includes/functions.php CHANGED
@@ -955,6 +955,7 @@ function pmpro_cancelMembershipLevel( $cancel_level, $user_id = null, $old_level
955
  * Return values:
956
  * Success returns boolean true.
957
  * Failure returns boolean false.
 
958
  */
959
  function pmpro_changeMembershipLevel( $level, $user_id = null, $old_level_status = 'inactive', $cancel_level = null ) {
960
  global $wpdb;
@@ -1115,10 +1116,10 @@ function pmpro_changeMembershipLevel( $level, $user_id = null, $old_level_status
1115
 
1116
  if ( ! empty( $c_order->error ) ) {
1117
  $pmpro_error = $c_order->error;
1118
- } else {
1119
- if( $old_level_status == 'error' ) {
1120
- $c_order->updateStatus("error");
1121
- }
1122
  }
1123
  }
1124
  }
@@ -1375,7 +1376,7 @@ function pmpro_getMembershipCategories( $level_id ) {
1375
 
1376
 
1377
  function pmpro_isAdmin( $user_id = null ) {
1378
- global $current_user, $wpdb;
1379
  if ( ! $user_id ) {
1380
  $user_id = $current_user->ID;
1381
  }
@@ -2373,9 +2374,9 @@ function pmpro_sort_levels_by_order( $pmpro_levels ) {
2373
  foreach ( $sort_order as $level_id ) {
2374
  foreach ( $pmpro_levels as $key => $level ) {
2375
  if ( ! empty ( $level->id ) && $level_id == $level->id ) {
2376
- $reordered_levels[] = $pmpro_levels[$key];
2377
  } elseif ( ! empty( $level ) && is_string( $level ) && $level_id == $level ) {
2378
- $reordered_levels[] = $pmpro_levels[$key];
2379
  }
2380
  }
2381
  }
955
  * Return values:
956
  * Success returns boolean true.
957
  * Failure returns boolean false.
958
+ * No change returns null.
959
  */
960
  function pmpro_changeMembershipLevel( $level, $user_id = null, $old_level_status = 'inactive', $cancel_level = null ) {
961
  global $wpdb;
1116
 
1117
  if ( ! empty( $c_order->error ) ) {
1118
  $pmpro_error = $c_order->error;
1119
+ }
1120
+
1121
+ if( $old_level_status == 'error' ) {
1122
+ $c_order->updateStatus("error");
1123
  }
1124
  }
1125
  }
1376
 
1377
 
1378
  function pmpro_isAdmin( $user_id = null ) {
1379
+ global $current_user;
1380
  if ( ! $user_id ) {
1381
  $user_id = $current_user->ID;
1382
  }
2374
  foreach ( $sort_order as $level_id ) {
2375
  foreach ( $pmpro_levels as $key => $level ) {
2376
  if ( ! empty ( $level->id ) && $level_id == $level->id ) {
2377
+ $reordered_levels[$level_id] = $pmpro_levels[$key];
2378
  } elseif ( ! empty( $level ) && is_string( $level ) && $level_id == $level ) {
2379
+ $reordered_levels[$level_id] = $pmpro_levels[$key];
2380
  }
2381
  }
2382
  }
includes/lib/stripe-apple-pay/stripe-apple-pay.php CHANGED
@@ -11,11 +11,11 @@ add_action( 'init', 'pmpro_stripe_apple_pay_rewrite_rule' );
11
  /*
12
  * Create query var to detect if Stripe is looking for domain association file.
13
  */
14
- function wpd_add_query_vars( $qvars ) {
15
  $qvars[] = 'pmpro_stripe_apple_pay';
16
  return $qvars;
17
  }
18
- add_filter( 'query_vars', 'wpd_add_query_vars' );
19
 
20
  /**
21
  * If query var is present, serve the domain association file.
11
  /*
12
  * Create query var to detect if Stripe is looking for domain association file.
13
  */
14
+ function pmpro_stripe_apple_pay_add_query_vars( $qvars ) {
15
  $qvars[] = 'pmpro_stripe_apple_pay';
16
  return $qvars;
17
  }
18
+ add_filter( 'query_vars', 'pmpro_stripe_apple_pay_add_query_vars' );
19
 
20
  /**
21
  * If query var is present, serve the domain association file.
js/pmpro-login.js CHANGED
@@ -12,7 +12,13 @@ jQuery(document).ready(function(){
12
 
13
  var strength;
14
  if ( pass1 != '' ) {
15
- strength = wp.passwordStrength.meter( pass1, wp.passwordStrength.userInputBlacklist(), pass1 );
 
 
 
 
 
 
16
  } else {
17
  strength = -1;
18
  }
@@ -66,4 +72,4 @@ jQuery(document).ready(function(){
66
  pmpro_check_password_strength( jQuery( '#pass1' ) );
67
  });
68
  }
69
- });
12
 
13
  var strength;
14
  if ( pass1 != '' ) {
15
+ // Call the disallowed list method corresponding to appropriate WP version.
16
+ const disallowedList = ( 'function' == typeof wp.passwordStrength.userInputDisallowedList )
17
+ ? wp.passwordStrength.userInputDisallowedList()
18
+ : wp.passwordStrength.userInputBlacklist();
19
+
20
+ strength = wp.passwordStrength.meter( pass1, disallowedList, pass1 );
21
+
22
  } else {
23
  strength = -1;
24
  }
72
  pmpro_check_password_strength( jQuery( '#pass1' ) );
73
  });
74
  }
75
+ });
paid-memberships-pro.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Paid Memberships Pro
4
  * Plugin URI: https://www.paidmembershipspro.com
5
  * Description: The most complete member management and membership subscriptions plugin for WordPress.
6
- * Version: 2.5.9.1
7
  * Author: Stranger Studios
8
  * Author URI: https://www.strangerstudios.com
9
  * Text Domain: paid-memberships-pro
@@ -16,7 +16,7 @@
16
  */
17
 
18
  // version constant
19
- define( 'PMPRO_VERSION', '2.5.9.1' );
20
  define( 'PMPRO_USER_AGENT', 'Paid Memberships Pro v' . PMPRO_VERSION . '; ' . site_url() );
21
  define( 'PMPRO_MIN_PHP_VERSION', '5.6' );
22
 
3
  * Plugin Name: Paid Memberships Pro
4
  * Plugin URI: https://www.paidmembershipspro.com
5
  * Description: The most complete member management and membership subscriptions plugin for WordPress.
6
+ * Version: 2.5.10
7
  * Author: Stranger Studios
8
  * Author URI: https://www.strangerstudios.com
9
  * Text Domain: paid-memberships-pro
16
  */
17
 
18
  // version constant
19
+ define( 'PMPRO_VERSION', '2.5.10' );
20
  define( 'PMPRO_USER_AGENT', 'Paid Memberships Pro v' . PMPRO_VERSION . '; ' . site_url() );
21
  define( 'PMPRO_MIN_PHP_VERSION', '5.6' );
22
 
preheaders/checkout.php CHANGED
@@ -552,13 +552,22 @@ if ( ! empty( $pmpro_confirmed ) ) {
552
  //make the user a subscriber
553
  $wpuser->set_role( get_option( 'default_role', 'subscriber' ) );
554
 
 
 
 
 
 
 
 
 
 
 
555
  //okay, log them in to WP
556
  $creds = array();
557
  $creds['user_login'] = $new_user_array['user_login'];
558
  $creds['user_password'] = $new_user_array['user_pass'];
559
  $creds['remember'] = true;
560
  $user = wp_signon( $creds, false );
561
-
562
  //setting some cookies
563
  wp_set_current_user( $user_id, $username );
564
  wp_set_auth_cookie( $user_id, true, apply_filters( 'pmpro_checkout_signon_secure', force_ssl_admin() ) );
552
  //make the user a subscriber
553
  $wpuser->set_role( get_option( 'default_role', 'subscriber' ) );
554
 
555
+ /**
556
+ * Allow hooking before the user authentication process when setting up new user.
557
+ *
558
+ * @since 2.5.10
559
+ *
560
+ * @param int $user_id The user ID that is being setting up.
561
+ */
562
+ do_action( 'pmpro_checkout_before_user_auth', $user_id );
563
+
564
+
565
  //okay, log them in to WP
566
  $creds = array();
567
  $creds['user_login'] = $new_user_array['user_login'];
568
  $creds['user_password'] = $new_user_array['user_pass'];
569
  $creds['remember'] = true;
570
  $user = wp_signon( $creds, false );
 
571
  //setting some cookies
572
  wp_set_current_user( $user_id, $username );
573
  wp_set_auth_cookie( $user_id, true, apply_filters( 'pmpro_checkout_signon_secure', force_ssl_admin() ) );
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: strangerstudios, kimannwall, andrewza, dlparker1005, paidmembershipspro
3
  Tags: memberships, members, subscriptions, ecommerce, user registration, member, membership, e-commerce, paypal, stripe, braintree, authorize.net, payflow, restrict access, restrict content, directory
4
  Requires at least: 4.7
5
- Tested up to: 5.7
6
- Stable tag: 2.5.9.1
7
 
8
  Get Paid with Paid Memberships Pro: The most complete member management and membership subscriptions plugin for your WordPress site.
9
 
@@ -153,6 +153,23 @@ Not sure? You can find out by doing a bit a research.
153
  9. Membership Account page, display all sections or show specific sections using shortcode attributes.
154
 
155
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  = 2.5.9.1 - 2021-05-12 =
157
  * BUG FIX/ENHANCEMENT: Updated pmpro_changeMembershipLevel() to return null if the user's level is not changed. For the past 2 vesions, we've been returning true in these cases, which caused PMPro to send emails to the admin when the edit use page was saved, even if there was no level change. This change has been backported to versions 2.5.8 and 2.5.9.
158
 
2
  Contributors: strangerstudios, kimannwall, andrewza, dlparker1005, paidmembershipspro
3
  Tags: memberships, members, subscriptions, ecommerce, user registration, member, membership, e-commerce, paypal, stripe, braintree, authorize.net, payflow, restrict access, restrict content, directory
4
  Requires at least: 4.7
5
+ Tested up to: 5.8
6
+ Stable tag: 2.5.10
7
 
8
  Get Paid with Paid Memberships Pro: The most complete member management and membership subscriptions plugin for your WordPress site.
9
 
153
  9. Membership Account page, display all sections or show specific sections using shortcode attributes.
154
 
155
  == Changelog ==
156
+ = 2.5.10 - 2021-06-25 =
157
+ * SECURITY: Fixed XSS vulnerability on the edit order page in the dashboard. (Thanks, Scott Kingsley Clark)
158
+ * ENHANCEMENT: Improved escaping and localization for the message returned when clicking to apply discount code.
159
+ * ENHANCEMENT: Now hiding gateway setting API keys behind asterisks.
160
+ * BUG FIX/ENHANCEMENT: Now passing a CARDONFILE parameter with PayPal Payflow payment and subscription transactions.
161
+ * BUG FIX/ENHANCEMENT: Using the wp.passwordStrength.userInputDisallowedList function from WP 4.5 if available.
162
+ * BUG FIX: Fixed issue in getfile script where parameters in the URL would cause File not found errors.
163
+ * BUG FIX: Fixed how the PayPal IPN handler handles cases where a subscription is set up correctly but the initial payment failed. We now correctly cancel these users and mark their order as error.
164
+ * BUG FIX: Improved error handling in the PayPal Express integration, particularly when a subscriptions PROFILESTATUS is missing.
165
+ * BUG FIX: User registered date is now shown in local time.
166
+ * BUG FIX: Fixed issue where the deprecated pmpro_getClassForField function wasn't returning a value properly. (Thanks, Elena Draculet)
167
+ * BUG FIX: Updated the pmpro_sort_levels_by_order function to use level IDs for keys, since some code expects that for level arrays. This matches the behavior we had before introducing this function.
168
+ * BUG FIX: Updated the pmpro_changeMembershipLevel function always set the order status to error if that was passed in as the "old level status".
169
+ * BUG FIX: Fixed warning in searches/pages when PMPro pages is not set.
170
+ * BUG FIX: Fixed warnings being generated when using PHP 8 and Divi
171
+ * BUG FIX: Fixed warnings related to PayPal Express session variables.
172
+
173
  = 2.5.9.1 - 2021-05-12 =
174
  * BUG FIX/ENHANCEMENT: Updated pmpro_changeMembershipLevel() to return null if the user's level is not changed. For the past 2 vesions, we've been returning true in these cases, which caused PMPro to send emails to the admin when the edit use page was saved, even if there was no level change. This change has been backported to versions 2.5.8 and 2.5.9.
175
 
services/applydiscountcode.php CHANGED
@@ -50,7 +50,7 @@
50
 
51
  var code_level;
52
  code_level = false;
53
-
54
  //filter to insert your own code. Not MMPU compatible.
55
  <?php do_action('pmpro_applydiscountcode_return_js', $discount_code, $discount_code_id, empty( $level_ids ) ? null : $level_ids[0], false); ?>
56
  </script>
@@ -101,7 +101,7 @@
101
  $combined_level->billing_amount = $combined_level->billing_amount + $code_level->billing_amount;
102
  }
103
  }
104
-
105
 
106
  ?>
107
  <script>
@@ -133,17 +133,27 @@
133
  });
134
 
135
  <?php
 
 
 
 
136
  if ( count( $code_levels ) <= 1 ) {
137
  $code_level = empty( $code_levels ) ? null : $code_levels[0];
138
- ?>
139
- jQuery('#pmpro_level_cost').html('<p><?php printf(__('The <strong>%s</strong> code has been applied to your order.', 'paid-memberships-pro' ), $discount_code);?></p><p><?php echo pmpro_no_quotes(pmpro_getLevelCost( $code_level, array('"', "'", "\n", "\r")))?><?php echo pmpro_no_quotes(pmpro_getLevelExpiration( $code_level, array('"', "'", "\n", "\r")))?></p>');
140
- <?php
141
  } else {
142
- ?>
143
- jQuery('#pmpro_level_cost').html('<p><?php printf(__('The <strong>%s</strong> code has been applied to your order.', 'paid-memberships-pro' ), $discount_code);?></p><p><?php echo pmpro_no_quotes(pmpro_getLevelsCost($code_levels), array('"', "'", "\n", "\r"))?><?php echo pmpro_no_quotes(pmpro_getLevelsExpiration($code_levels), array('"', "'", "\n", "\r"))?></p>');
144
- <?php
145
  }
146
 
 
 
 
 
 
 
 
147
  //tell gateway javascripts whether or not to fire (e.g. no Stripe on free levels)
148
  if(pmpro_areLevelsFree($code_levels))
149
  {
50
 
51
  var code_level;
52
  code_level = false;
53
+
54
  //filter to insert your own code. Not MMPU compatible.
55
  <?php do_action('pmpro_applydiscountcode_return_js', $discount_code, $discount_code_id, empty( $level_ids ) ? null : $level_ids[0], false); ?>
56
  </script>
101
  $combined_level->billing_amount = $combined_level->billing_amount + $code_level->billing_amount;
102
  }
103
  }
104
+
105
 
106
  ?>
107
  <script>
133
  });
134
 
135
  <?php
136
+ $html = [];
137
+
138
+ $html[] = wp_kses_post( sprintf( __( 'The <strong>%s</strong> code has been applied to your order.', 'paid-memberships-pro' ), $discount_code ) );
139
+
140
  if ( count( $code_levels ) <= 1 ) {
141
  $code_level = empty( $code_levels ) ? null : $code_levels[0];
142
+
143
+ $html[] = pmpro_getLevelCost( $code_level );
144
+ $html[] = pmpro_getLevelExpiration( $code_level );
145
  } else {
146
+ $html[] = pmpro_getLevelsCost( $code_levels );
147
+ $html[] = pmpro_getLevelsExpiration( $code_levels );
 
148
  }
149
 
150
+ $html = array_filter( $html );
151
+ $html = implode( "\n\n", $html );
152
+ $html = wpautop( $html );
153
+ ?>
154
+ jQuery('#pmpro_level_cost').html( <?php echo wp_json_encode( wp_kses_post( $html ) ); ?> );
155
+ <?php
156
+
157
  //tell gateway javascripts whether or not to fire (e.g. no Stripe on free levels)
158
  if(pmpro_areLevelsFree($code_levels))
159
  {
services/getfile.php CHANGED
@@ -23,13 +23,21 @@
23
  require_once(dirname(__FILE__) . '/../classes/class.mimetype.php');
24
 
25
  global $wpdb;
26
-
 
27
  $uri = $_SERVER['REQUEST_URI'];
28
- if($uri[0] == "/")
29
- $uri = substr($uri, 1, strlen($uri) - 1);
 
 
 
 
 
 
 
30
 
31
  // decode the file in case it's encoded.
32
- $uri = urldecode($uri);
33
 
34
  /*
35
  Remove ../-like strings from the URI.
@@ -127,4 +135,4 @@
127
  //okay show the file
128
  header("Content-type: " . $file_mimetype);
129
  readfile($filename);
130
- exit;
23
  require_once(dirname(__FILE__) . '/../classes/class.mimetype.php');
24
 
25
  global $wpdb;
26
+
27
+ // Get the file path.
28
  $uri = $_SERVER['REQUEST_URI'];
29
+
30
+ // Remove the query string from the path.
31
+ $uri_parts = explode( $uri, '?' );
32
+ $uri = $uri_parts[0];
33
+
34
+ // Take the / off of the
35
+ if ( '/' === $uri[0] ) {
36
+ $uri = substr( $uri, 1, strlen( $uri ) - 1 );
37
+ }
38
 
39
  // decode the file in case it's encoded.
40
+ $uri = urldecode( $uri );
41
 
42
  /*
43
  Remove ../-like strings from the URI.
135
  //okay show the file
136
  header("Content-type: " . $file_mimetype);
137
  readfile($filename);
138
+ exit;
services/ipnhandler.php CHANGED
@@ -263,12 +263,27 @@ if ( $txn_type == 'recurring_payment_profile_cancel' || $txn_type == 'recurring_
263
 
264
  if ( $last_subscription_order->status == "cancelled" ) {
265
  ipnlog( "We've already processed this cancellation. Probably originated from WP/PMPro. (Order #" . $last_subscription_order->id . ", Subscription Transaction ID #" . $recurring_payment_id . ")" );
 
 
 
 
 
 
 
 
 
 
266
  } elseif ( ! pmpro_hasMembershipLevel( $last_subscription_order->membership_id, $user->ID ) ) {
267
  ipnlog( "This user has a different level than the one associated with this order. Their membership was probably changed by an admin or through an upgrade/downgrade. (Order #" . $last_subscription_order->id . ", Subscription Transaction ID #" . $recurring_payment_id . ")" );
268
  } else {
269
  //if the initial payment failed, cancel with status error instead of cancelled
270
  if ( $initial_payment_status === "Failed" ) {
271
- pmpro_cancelMembershipLevel( $last_subscription_order->membership_id, $last_subscription_order->user_id, 'error' );
 
 
 
 
 
272
  } else {
273
  pmpro_cancelMembershipLevel( $last_subscription_order->membership_id, $last_subscription_order->user_id, 'cancelled' );
274
  }
263
 
264
  if ( $last_subscription_order->status == "cancelled" ) {
265
  ipnlog( "We've already processed this cancellation. Probably originated from WP/PMPro. (Order #" . $last_subscription_order->id . ", Subscription Transaction ID #" . $recurring_payment_id . ")" );
266
+
267
+ // Still check if there was an error.
268
+ if ( $initial_payment_status === "Failed" ) {
269
+ $cancelled = pmpro_cancelMembershipLevel( $last_subscription_order->membership_id, $last_subscription_order->user_id, 'error' );
270
+
271
+ // If we couldn't cancel, still set the order status to error.
272
+ if ( $cancelled === null ) {
273
+ $last_subscription_order->updateStatus('error');
274
+ }
275
+ }
276
  } elseif ( ! pmpro_hasMembershipLevel( $last_subscription_order->membership_id, $user->ID ) ) {
277
  ipnlog( "This user has a different level than the one associated with this order. Their membership was probably changed by an admin or through an upgrade/downgrade. (Order #" . $last_subscription_order->id . ", Subscription Transaction ID #" . $recurring_payment_id . ")" );
278
  } else {
279
  //if the initial payment failed, cancel with status error instead of cancelled
280
  if ( $initial_payment_status === "Failed" ) {
281
+ $cancelled = pmpro_cancelMembershipLevel( $last_subscription_order->membership_id, $last_subscription_order->user_id, 'error' );
282
+
283
+ // If we couldn't cancel, still set the order status to error.
284
+ if ( $cancelled === null ) {
285
+ $last_subscription_order->updateStatus('error');
286
+ }
287
  } else {
288
  pmpro_cancelMembershipLevel( $last_subscription_order->membership_id, $last_subscription_order->user_id, 'cancelled' );
289
  }