Paid Memberships Pro - Version 2.9.3

Version Description

  • 2022-08-25 =
  • ENHANCEMENT: Added pmpro_add_user_field_where( $where, $field ) and pmpro_add_user_field( $field, $where ) filters.
  • BUG FIX/ENHANCEMENT: Added MMPU support for some emails so correct level information is shown. #2200 (@dparker1005)
  • BUG FIX/ENHANCEMENT: The pmpro_checkout_box-{groupname} id given to checkout box divs is now sanitized to avoid spaces and special characters there. #2209 (@dparker1005)
  • BUG FIX/ENHANCEMENT: Trimming underscores off the front/back of suggested group names in the user field settings. #2209 (@dparker1005)
  • BUG FIX: Fixed issues with fields showing in some checkout checkbox/group locations. #2204 #2205 (@ipokkel)
  • BUG FIX: Fixed issue where discount code uses weren't being tracked when using the Stripe Checkout beta. #2196 (@dparker1005)
Download this release

Release Info

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

Code changes from version 2.9.2 to 2.9.3

CHANGELOG.txt CHANGED
@@ -1,4 +1,12 @@
1
  == Changelog ==
 
 
 
 
 
 
 
 
2
  = 2.9.2 - 2022-08-10 =
3
  * BUG FIX/ENHANCEMENT: Now correctly deprecating the pmprorh_section_header() function. We accidentally had it reversed and throwing a warning when using the new pmpro_default_field_group_label() function. (@kimcoleman)
4
  * BUG FIX/ENHANCEMENT: When saving user fields, now making sure that the group name is not blank and unique. Blank or duplicate group names could cause other issues, e.g. with required fields or fields being shown multiple times at checkout. #2187 (@ideadude)
1
  == Changelog ==
2
+ = 2.9.3 - 2022-08-25 =
3
+ * ENHANCEMENT: Added pmpro_add_user_field_where( $where, $field ) and pmpro_add_user_field( $field, $where ) filters.
4
+ * BUG FIX/ENHANCEMENT: Added MMPU support for some emails so correct level information is shown. #2200 (@dparker1005)
5
+ * BUG FIX/ENHANCEMENT: The pmpro_checkout_box-{groupname} id given to checkout box divs is now sanitized to avoid spaces and special characters there. #2209 (@dparker1005)
6
+ * BUG FIX/ENHANCEMENT: Trimming underscores off the front/back of suggested group names in the user field settings. #2209 (@dparker1005)
7
+ * BUG FIX: Fixed issues with fields showing in some checkout checkbox/group locations. #2204 #2205 (@ipokkel)
8
+ * BUG FIX: Fixed issue where discount code uses weren't being tracked when using the Stripe Checkout beta. #2196 (@dparker1005)
9
+
10
  = 2.9.2 - 2022-08-10 =
11
  * BUG FIX/ENHANCEMENT: Now correctly deprecating the pmprorh_section_header() function. We accidentally had it reversed and throwing a warning when using the new pmpro_default_field_group_label() function. (@kimcoleman)
12
  * BUG FIX/ENHANCEMENT: When saving user fields, now making sure that the group name is not blank and unique. Blank or duplicate group names could cause other issues, e.g. with required fields or fields being shown multiple times at checkout. #2187 (@ideadude)
adminpages/userfields.php CHANGED
@@ -28,14 +28,14 @@
28
  foreach ( $group->fields as $field ) {
29
  $field_name = pmpro_format_field_name( $field->name ); //Replace spaces and dashes with underscores.
30
  $field->name = sanitize_text_field( $field_name );
31
- $field->label = sanitize_text_field( $field->label );
32
  $field->type = sanitize_text_field( $field->type );
33
  $field->required = 'yes' === $field->required ? 'yes' : 'no';
34
  $field->readonly = 'yes' === $field->readonly ? 'yes' : 'no';
35
  $field->profile = sanitize_text_field( $field->profile );
36
  $field->wrapper_class = sanitize_text_field( $field->wrapper_class );
37
  $field->element_class = sanitize_text_field( $field->element_class );
38
- $field->hint = sanitize_textarea_field( $field->hint );
39
  $field->options = sanitize_textarea_field( $field->options );
40
  }
41
  }
28
  foreach ( $group->fields as $field ) {
29
  $field_name = pmpro_format_field_name( $field->name ); //Replace spaces and dashes with underscores.
30
  $field->name = sanitize_text_field( $field_name );
31
+ $field->label = wp_kses_post( $field->label );
32
  $field->type = sanitize_text_field( $field->type );
33
  $field->required = 'yes' === $field->required ? 'yes' : 'no';
34
  $field->readonly = 'yes' === $field->readonly ? 'yes' : 'no';
35
  $field->profile = sanitize_text_field( $field->profile );
36
  $field->wrapper_class = sanitize_text_field( $field->wrapper_class );
37
  $field->element_class = sanitize_text_field( $field->element_class );
38
+ $field->hint = wp_kses_post( $field->hint );
39
  $field->options = sanitize_textarea_field( $field->options );
40
  }
41
  }
blocks/blocks.php CHANGED
@@ -64,7 +64,7 @@ function pmpro_block_editor_scripts() {
64
  // Enqueue the bundled block JS file.
65
  wp_enqueue_script(
66
  'pmpro-blocks-editor-js',
67
- plugins_url( 'js/blocks.build.js', PMPRO_BASE_FILE ),
68
  [
69
  'wp-i18n',
70
  'wp-element',
64
  // Enqueue the bundled block JS file.
65
  wp_enqueue_script(
66
  'pmpro-blocks-editor-js',
67
+ plugins_url( 'js/blocks/blocks.build.js', PMPRO_BASE_FILE ),
68
  [
69
  'wp-i18n',
70
  'wp-element',
classes/class.pmproemail.php CHANGED
@@ -383,10 +383,16 @@
383
 
384
  if(!$user)
385
  return false;
386
-
387
- $confirmation_in_email = get_pmpro_membership_level_meta( $user->membership_level->id, 'confirmation_in_email', true );
 
 
 
 
 
 
388
  if ( ! empty( $confirmation_in_email ) ) {
389
- $confirmation_message = $user->membership_level->confirmation;
390
  } else {
391
  $confirmation_message = '';
392
  }
@@ -401,10 +407,10 @@
401
  "user_login" => $user->user_login,
402
  "sitename" => get_option("blogname"),
403
  "siteemail" => pmpro_getOption("from_email"),
404
- "membership_id" => $user->membership_level->id,
405
- "membership_level_name" => $user->membership_level->name,
406
  "membership_level_confirmation_message" => $confirmation_message,
407
- "membership_cost" => pmpro_getLevelCost($user->membership_level),
408
  "login_link" => pmpro_login_url(),
409
  "login_url" => pmpro_login_url(),
410
  "display_name" => $user->display_name,
@@ -413,17 +419,17 @@
413
 
414
  // Figure out which template to use.
415
  if ( empty( $this->template ) ) {
416
- if( ! empty( $invoice ) && ! pmpro_isLevelFree( $user->membership_level ) ) {
417
  if( $invoice->gateway == "paypalexpress") {
418
  $this->template = "checkout_express";
419
  } elseif( $invoice->gateway == "check" ) {
420
  $this->template = "checkout_check";
421
- } elseif( pmpro_isLevelTrial( $user->membership_level ) ) {
422
  $this->template = "checkout_trial";
423
  } else {
424
  $this->template = "checkout_paid";
425
  }
426
- } elseif( pmpro_isLevelFree( $user->membership_level ) ) {
427
  $this->template = "checkout_free";
428
  } else {
429
  $this->template = "checkout_freetrial";
@@ -498,9 +504,15 @@
498
 
499
  if(!$user)
500
  return false;
 
 
 
 
 
 
501
 
502
  $this->email = get_bloginfo("admin_email");
503
- $this->subject = sprintf(__("Member checkout for %s at %s", 'paid-memberships-pro' ), $user->membership_level->name, get_option("blogname"));
504
 
505
  $this->data = array(
506
  "subject" => $this->subject,
@@ -508,9 +520,9 @@
508
  "user_login" => $user->user_login,
509
  "sitename" => get_option("blogname"),
510
  "siteemail" => pmpro_getOption("from_email"),
511
- "membership_id" => $user->membership_level->id,
512
- "membership_level_name" => $user->membership_level->name,
513
- "membership_cost" => pmpro_getLevelCost($user->membership_level),
514
  "login_link" => pmpro_login_url(),
515
  "login_url" => pmpro_login_url(),
516
  "display_name" => $user->display_name,
@@ -519,17 +531,17 @@
519
 
520
  // Figure out which template to use.
521
  if ( empty( $this->template ) ) {
522
- if( ! empty( $invoice ) && ! pmpro_isLevelFree( $user->membership_level ) ) {
523
  if( $invoice->gateway == "paypalexpress") {
524
  $this->template = "checkout_express_admin";
525
  } elseif( $invoice->gateway == "check" ) {
526
  $this->template = "checkout_check_admin";
527
- } elseif( pmpro_isLevelTrial( $user->membership_level ) ) {
528
  $this->template = "checkout_trial_admin";
529
  } else {
530
  $this->template = "checkout_paid_admin";
531
  }
532
- } elseif( pmpro_isLevelFree( $user->membership_level ) ) {
533
  $this->template = "checkout_free_admin";
534
  } else {
535
  $this->template = "checkout_freetrial_admin";
@@ -596,6 +608,12 @@
596
 
597
  if(!$user || !$invoice)
598
  return false;
 
 
 
 
 
 
599
 
600
  $this->email = $user->user_email;
601
  $this->subject = sprintf(__("Your billing information has been updated at %s", "paid-memberships-pro"), get_option("blogname"));
@@ -606,8 +624,8 @@
606
  "user_login" => $user->user_login,
607
  "sitename" => get_option("blogname"),
608
  "siteemail" => pmpro_getOption("from_email"),
609
- "membership_id" => $user->membership_level->id,
610
- "membership_level_name" => $user->membership_level->name,
611
  "display_name" => $user->display_name,
612
  "user_email" => $user->user_email,
613
  "billing_name" => $invoice->billing->name,
@@ -647,6 +665,12 @@
647
  if(!$user || !$invoice)
648
  return false;
649
 
 
 
 
 
 
 
650
  $this->email = get_bloginfo("admin_email");
651
  $this->subject = sprintf(__("Billing information has been updated for %s at %s", "paid-memberships-pro"), $user->user_login, get_option("blogname"));
652
 
@@ -656,8 +680,8 @@
656
  "user_login" => $user->user_login,
657
  "sitename" => get_option("blogname"),
658
  "siteemail" => pmpro_getOption("from_email"),
659
- "membership_id" => $user->membership_level->id,
660
- "membership_level_name" => $user->membership_level->name,
661
  "display_name" => $user->display_name,
662
  "user_email" => $user->user_email,
663
  "billing_name" => $invoice->billing->name,
@@ -797,6 +821,12 @@
797
  if(!$user || !$invoice)
798
  return false;
799
 
 
 
 
 
 
 
800
  $this->email = $user->user_email;
801
  $this->subject = sprintf(__("Credit card on file expiring soon at %s", "paid-memberships-pro"), get_option("blogname"));
802
 
@@ -806,8 +836,8 @@
806
  "user_login" => $user->user_login,
807
  "sitename" => get_option("blogname"),
808
  "siteemail" => pmpro_getOption("from_email"),
809
- "membership_id" => $user->membership_level->id,
810
- "membership_level_name" => $user->membership_level->name,
811
  "display_name" => $user->display_name,
812
  "user_email" => $user->user_email,
813
  "billing_name" => $invoice->billing->name,
@@ -847,7 +877,11 @@
847
  if(!$user || !$invoice)
848
  return false;
849
 
850
- $user->membership_level = pmpro_getMembershipLevelForUser($user->ID);
 
 
 
 
851
 
852
  $this->email = $user->user_email;
853
  $this->subject = sprintf(__("Invoice for %s membership", "paid-memberships-pro"), get_option("blogname"));
@@ -858,8 +892,8 @@
858
  "user_login" => $user->user_login,
859
  "sitename" => get_option("blogname"),
860
  "siteemail" => pmpro_getOption("from_email"),
861
- "membership_id" => $user->membership_level->id,
862
- "membership_level_name" => $user->membership_level->name,
863
  "display_name" => $user->display_name,
864
  "user_email" => $user->user_email,
865
  "invoice_id" => $invoice->code,
@@ -911,7 +945,7 @@
911
  return $this->sendEmail();
912
  }
913
 
914
- function sendTrialEndingEmail($user = NULL)
915
  {
916
  global $current_user, $wpdb;
917
  if(!$user)
@@ -921,12 +955,12 @@
921
  return false;
922
 
923
  //make sure we have the current membership level data
924
- /*$user->membership_level = $wpdb->get_row("SELECT l.id AS ID, l.name AS name, UNIX_TIMESTAMP(CONVERT_TZ(mu.startdate, '+00:00', @@global.time_zone)) as startdate, mu.billing_amount, mu.cycle_number, mu.cycle_period, mu.trial_amount, mu.trial_limit
925
- FROM {$wpdb->pmpro_membership_levels} AS l
926
- JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
927
- WHERE mu.user_id = " . $user->ID . "
928
- LIMIT 1");*/
929
- $user->membership_level = pmpro_getMembershipLevelForUser($user->ID);
930
 
931
  $this->email = $user->user_email;
932
  $this->subject = sprintf(__("Your trial at %s is ending soon", "paid-memberships-pro"), get_option("blogname"));
@@ -936,19 +970,19 @@
936
  "name" => $user->display_name,
937
  "user_login" => $user->user_login,
938
  "sitename" => get_option("blogname"),
939
- "membership_id" => $user->membership_level->id,
940
- "membership_level_name" => $user->membership_level->name,
941
  "siteemail" => pmpro_getOption("from_email"),
942
  "login_link" => pmpro_login_url(),
943
  "login_url" => pmpro_login_url(),
944
  "display_name" => $user->display_name,
945
  "user_email" => $user->user_email,
946
- "billing_amount" => pmpro_formatPrice($user->membership_level->billing_amount),
947
- "cycle_number" => $user->membership_level->cycle_number,
948
- "cycle_period" => $user->membership_level->cycle_period,
949
- "trial_amount" => pmpro_formatPrice($user->membership_level->trial_amount),
950
- "trial_limit" => $user->membership_level->trial_limit,
951
- "trial_end" => date_i18n(get_option('date_format'), strtotime(date_i18n("m/d/Y", $user->membership_level->startdate) . " + " . $user->membership_level->trial_limit . " " . $user->membership_level->cycle_period), current_time("timestamp"))
952
  );
953
 
954
  $this->template = apply_filters("pmpro_email_template", "trial_ending", $this);
@@ -956,7 +990,7 @@
956
  return $this->sendEmail();
957
  }
958
 
959
- function sendMembershipExpiredEmail($user = NULL)
960
  {
961
  global $current_user, $wpdb;
962
  if(!$user)
@@ -964,7 +998,7 @@
964
 
965
  if(!$user)
966
  return false;
967
-
968
  $this->email = $user->user_email;
969
  $this->subject = sprintf(__("Your membership at %s has ended", "paid-memberships-pro"), get_option("blogname"));
970
 
@@ -975,7 +1009,7 @@
975
  return $this->sendEmail();
976
  }
977
 
978
- function sendMembershipExpiringEmail($user = NULL)
979
  {
980
  global $current_user, $wpdb;
981
  if(!$user)
@@ -984,18 +1018,16 @@
984
  if(!$user)
985
  return false;
986
 
987
- //make sure we have the current membership level data
988
- /*$user->membership_level = $wpdb->get_row("SELECT l.id AS ID, l.name AS name, UNIX_TIMESTAMP(CONVERT_TZ(mu.enddate, '+00:00', @@global.time_zone)) as enddate
989
- FROM {$wpdb->pmpro_membership_levels} AS l
990
- JOIN {$wpdb->pmpro_memberships_users} AS mu ON (l.id = mu.membership_id)
991
- WHERE mu.user_id = " . $user->ID . "
992
- LIMIT 1");*/
993
- $user->membership_level = pmpro_getMembershipLevelForUser($user->ID);
994
 
995
  $this->email = $user->user_email;
996
  $this->subject = sprintf(__("Your membership at %s will end soon", "paid-memberships-pro"), get_option("blogname"));
997
 
998
- $this->data = array("subject" => $this->subject, "name" => $user->display_name, "user_login" => $user->user_login, "sitename" => get_option("blogname"), "membership_id" => $user->membership_level->id, "membership_level_name" => $user->membership_level->name, "siteemail" => pmpro_getOption("from_email"), "login_link" => pmpro_login_url(), "login_url" => pmpro_login_url(), "enddate" => date_i18n(get_option('date_format'), $user->membership_level->enddate), "display_name" => $user->display_name, "user_email" => $user->user_email);
999
 
1000
  $this->template = apply_filters("pmpro_email_template", "membership_expiring", $this);
1001
 
383
 
384
  if(!$user)
385
  return false;
386
+
387
+ if ( empty( $invoice->membership_id ) ) {
388
+ return false;
389
+ }
390
+
391
+ $membership_level = pmpro_getSpecificMembershipLevelForUser($user->ID, $invoice->membership_id);
392
+
393
+ $confirmation_in_email = get_pmpro_membership_level_meta( $membership_level->id, 'confirmation_in_email', true );
394
  if ( ! empty( $confirmation_in_email ) ) {
395
+ $confirmation_message = $membership_level->confirmation;
396
  } else {
397
  $confirmation_message = '';
398
  }
407
  "user_login" => $user->user_login,
408
  "sitename" => get_option("blogname"),
409
  "siteemail" => pmpro_getOption("from_email"),
410
+ "membership_id" => $membership_level->id,
411
+ "membership_level_name" => $membership_level->name,
412
  "membership_level_confirmation_message" => $confirmation_message,
413
+ "membership_cost" => pmpro_getLevelCost($membership_level),
414
  "login_link" => pmpro_login_url(),
415
  "login_url" => pmpro_login_url(),
416
  "display_name" => $user->display_name,
419
 
420
  // Figure out which template to use.
421
  if ( empty( $this->template ) ) {
422
+ if( ! empty( $invoice ) && ! pmpro_isLevelFree( $membership_level ) ) {
423
  if( $invoice->gateway == "paypalexpress") {
424
  $this->template = "checkout_express";
425
  } elseif( $invoice->gateway == "check" ) {
426
  $this->template = "checkout_check";
427
+ } elseif( pmpro_isLevelTrial( $membership_level ) ) {
428
  $this->template = "checkout_trial";
429
  } else {
430
  $this->template = "checkout_paid";
431
  }
432
+ } elseif( pmpro_isLevelFree( $membership_level ) ) {
433
  $this->template = "checkout_free";
434
  } else {
435
  $this->template = "checkout_freetrial";
504
 
505
  if(!$user)
506
  return false;
507
+
508
+ if ( empty( $invoice->membership_id ) ) {
509
+ return false;
510
+ }
511
+
512
+ $membership_level = pmpro_getSpecificMembershipLevelForUser($user->ID, $invoice->membership_id);
513
 
514
  $this->email = get_bloginfo("admin_email");
515
+ $this->subject = sprintf(__("Member checkout for %s at %s", 'paid-memberships-pro' ), $membership_level->name, get_option("blogname"));
516
 
517
  $this->data = array(
518
  "subject" => $this->subject,
520
  "user_login" => $user->user_login,
521
  "sitename" => get_option("blogname"),
522
  "siteemail" => pmpro_getOption("from_email"),
523
+ "membership_id" => $membership_level->id,
524
+ "membership_level_name" => $membership_level->name,
525
+ "membership_cost" => pmpro_getLevelCost($membership_level),
526
  "login_link" => pmpro_login_url(),
527
  "login_url" => pmpro_login_url(),
528
  "display_name" => $user->display_name,
531
 
532
  // Figure out which template to use.
533
  if ( empty( $this->template ) ) {
534
+ if( ! empty( $invoice ) && ! pmpro_isLevelFree( $membership_level ) ) {
535
  if( $invoice->gateway == "paypalexpress") {
536
  $this->template = "checkout_express_admin";
537
  } elseif( $invoice->gateway == "check" ) {
538
  $this->template = "checkout_check_admin";
539
+ } elseif( pmpro_isLevelTrial( $membership_level ) ) {
540
  $this->template = "checkout_trial_admin";
541
  } else {
542
  $this->template = "checkout_paid_admin";
543
  }
544
+ } elseif( pmpro_isLevelFree( $membership_level ) ) {
545
  $this->template = "checkout_free_admin";
546
  } else {
547
  $this->template = "checkout_freetrial_admin";
608
 
609
  if(!$user || !$invoice)
610
  return false;
611
+
612
+ if ( empty( $invoice->membership_id ) ) {
613
+ return false;
614
+ }
615
+
616
+ $membership_level = pmpro_getSpecificMembershipLevelForUser($user->ID, $invoice->membership_id);
617
 
618
  $this->email = $user->user_email;
619
  $this->subject = sprintf(__("Your billing information has been updated at %s", "paid-memberships-pro"), get_option("blogname"));
624
  "user_login" => $user->user_login,
625
  "sitename" => get_option("blogname"),
626
  "siteemail" => pmpro_getOption("from_email"),
627
+ "membership_id" => $membership_level->id,
628
+ "membership_level_name" => $membership_level->name,
629
  "display_name" => $user->display_name,
630
  "user_email" => $user->user_email,
631
  "billing_name" => $invoice->billing->name,
665
  if(!$user || !$invoice)
666
  return false;
667
 
668
+ if ( empty( $invoice->membership_id ) ) {
669
+ return false;
670
+ }
671
+
672
+ $membership_level = pmpro_getSpecificMembershipLevelForUser($user->ID, $invoice->membership_id);
673
+
674
  $this->email = get_bloginfo("admin_email");
675
  $this->subject = sprintf(__("Billing information has been updated for %s at %s", "paid-memberships-pro"), $user->user_login, get_option("blogname"));
676
 
680
  "user_login" => $user->user_login,
681
  "sitename" => get_option("blogname"),
682
  "siteemail" => pmpro_getOption("from_email"),
683
+ "membership_id" => $membership_level->id,
684
+ "membership_level_name" => $membership_level->name,
685
  "display_name" => $user->display_name,
686
  "user_email" => $user->user_email,
687
  "billing_name" => $invoice->billing->name,
821
  if(!$user || !$invoice)
822
  return false;
823
 
824
+ if ( empty( $invoice->membership_id ) ) {
825
+ return false;
826
+ }
827
+
828
+ $membership_level = pmpro_getSpecificMembershipLevelForUser($user->ID, $invoice->membership_id);
829
+
830
  $this->email = $user->user_email;
831
  $this->subject = sprintf(__("Credit card on file expiring soon at %s", "paid-memberships-pro"), get_option("blogname"));
832
 
836
  "user_login" => $user->user_login,
837
  "sitename" => get_option("blogname"),
838
  "siteemail" => pmpro_getOption("from_email"),
839
+ "membership_id" => $membership_level->id,
840
+ "membership_level_name" => $membership_level->name,
841
  "display_name" => $user->display_name,
842
  "user_email" => $user->user_email,
843
  "billing_name" => $invoice->billing->name,
877
  if(!$user || !$invoice)
878
  return false;
879
 
880
+ if ( empty( $invoice->membership_id ) ) {
881
+ return false;
882
+ }
883
+
884
+ $membership_level = pmpro_getSpecificMembershipLevelForUser($user->ID, $invoice->membership_id);
885
 
886
  $this->email = $user->user_email;
887
  $this->subject = sprintf(__("Invoice for %s membership", "paid-memberships-pro"), get_option("blogname"));
892
  "user_login" => $user->user_login,
893
  "sitename" => get_option("blogname"),
894
  "siteemail" => pmpro_getOption("from_email"),
895
+ "membership_id" => $membership_level->id,
896
+ "membership_level_name" => $membership_level->name,
897
  "display_name" => $user->display_name,
898
  "user_email" => $user->user_email,
899
  "invoice_id" => $invoice->code,
945
  return $this->sendEmail();
946
  }
947
 
948
+ function sendTrialEndingEmail( $user = NULL, $membership_id = NULL )
949
  {
950
  global $current_user, $wpdb;
951
  if(!$user)
955
  return false;
956
 
957
  //make sure we have the current membership level data
958
+ if ( empty( $membership_id ) ) {
959
+ $membership_level = pmpro_getMembershipLevelForUser($user->ID);
960
+ } else {
961
+ $membership_level = pmpro_getMembershipLevelForUser($user->ID, $membership_id);
962
+ }
963
+
964
 
965
  $this->email = $user->user_email;
966
  $this->subject = sprintf(__("Your trial at %s is ending soon", "paid-memberships-pro"), get_option("blogname"));
970
  "name" => $user->display_name,
971
  "user_login" => $user->user_login,
972
  "sitename" => get_option("blogname"),
973
+ "membership_id" => $membership_level->id,
974
+ "membership_level_name" => $membership_level->name,
975
  "siteemail" => pmpro_getOption("from_email"),
976
  "login_link" => pmpro_login_url(),
977
  "login_url" => pmpro_login_url(),
978
  "display_name" => $user->display_name,
979
  "user_email" => $user->user_email,
980
+ "billing_amount" => pmpro_formatPrice($membership_level->billing_amount),
981
+ "cycle_number" => $membership_level->cycle_number,
982
+ "cycle_period" => $membership_level->cycle_period,
983
+ "trial_amount" => pmpro_formatPrice($membership_level->trial_amount),
984
+ "trial_limit" => $membership_level->trial_limit,
985
+ "trial_end" => date_i18n(get_option('date_format'), strtotime(date_i18n("m/d/Y", $membership_level->startdate) . " + " . $membership_level->trial_limit . " " . $membership_level->cycle_period), current_time("timestamp"))
986
  );
987
 
988
  $this->template = apply_filters("pmpro_email_template", "trial_ending", $this);
990
  return $this->sendEmail();
991
  }
992
 
993
+ function sendMembershipExpiredEmail( $user = NULL, $membership_id = NULL )
994
  {
995
  global $current_user, $wpdb;
996
  if(!$user)
998
 
999
  if(!$user)
1000
  return false;
1001
+
1002
  $this->email = $user->user_email;
1003
  $this->subject = sprintf(__("Your membership at %s has ended", "paid-memberships-pro"), get_option("blogname"));
1004
 
1009
  return $this->sendEmail();
1010
  }
1011
 
1012
+ function sendMembershipExpiringEmail( $user = NULL, $membership_id = NULL )
1013
  {
1014
  global $current_user, $wpdb;
1015
  if(!$user)
1018
  if(!$user)
1019
  return false;
1020
 
1021
+ if ( empty( $membership_id ) ) {
1022
+ $membership_level = pmpro_getMembershipLevelForUser($user->ID);
1023
+ } else {
1024
+ $membership_level = pmpro_getMembershipLevelForUser($user->ID, $membership_id);
1025
+ }
 
 
1026
 
1027
  $this->email = $user->user_email;
1028
  $this->subject = sprintf(__("Your membership at %s will end soon", "paid-memberships-pro"), get_option("blogname"));
1029
 
1030
+ $this->data = array("subject" => $this->subject, "name" => $user->display_name, "user_login" => $user->user_login, "sitename" => get_option("blogname"), "membership_id" => $membership_level->id, "membership_level_name" => $membership_level->name, "siteemail" => pmpro_getOption("from_email"), "login_link" => pmpro_login_url(), "login_url" => pmpro_login_url(), "enddate" => date_i18n(get_option('date_format'), $membership_level->enddate), "display_name" => $user->display_name, "user_email" => $user->user_email);
1031
 
1032
  $this->template = apply_filters("pmpro_email_template", "membership_expiring", $this);
1033
 
classes/gateways/class.pmprogateway_stripe.php CHANGED
@@ -1548,7 +1548,7 @@ class PMProGateway_stripe extends PMProGateway {
1548
  */
1549
  static function pmpro_checkout_before_change_membership_level($user_id, $morder)
1550
  {
1551
- global $pmpro_level, $discount_code, $discount_code_id, $wpdb, $pmpro_currency;
1552
 
1553
  //if no order, no need to pay
1554
  if ( empty( $morder ) || $morder->gateway != 'stripe' ) {
@@ -1572,8 +1572,7 @@ class PMProGateway_stripe extends PMProGateway {
1572
  update_pmpro_membership_order_meta( $morder->id, 'checkout_level', $pmpro_level_arr );
1573
 
1574
  // Save the discount code.
1575
- $pmpro_discount_code_arr = (array) $discount_code;
1576
- update_pmpro_membership_order_meta( $morder->id, 'checkout_discount_code', $pmpro_discount_code_arr );
1577
 
1578
  // Time to send the user to pay with Stripe!
1579
  $stripe = new PMProGateway_stripe();
1548
  */
1549
  static function pmpro_checkout_before_change_membership_level($user_id, $morder)
1550
  {
1551
+ global $pmpro_level, $discount_code, $wpdb, $pmpro_currency;
1552
 
1553
  //if no order, no need to pay
1554
  if ( empty( $morder ) || $morder->gateway != 'stripe' ) {
1572
  update_pmpro_membership_order_meta( $morder->id, 'checkout_level', $pmpro_level_arr );
1573
 
1574
  // Save the discount code.
1575
+ update_pmpro_membership_order_meta( $morder->id, 'checkout_discount_code', $discount_code );
 
1576
 
1577
  // Time to send the user to pay with Stripe!
1578
  $stripe = new PMProGateway_stripe();
includes/fields.php CHANGED
@@ -37,7 +37,28 @@ function pmpro_is_field( $var ) {
37
  */
38
  function pmpro_add_user_field( $where, $field ) {
39
  global $pmpro_user_fields;
40
- if(empty($pmpro_user_fields[$where])) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  $pmpro_user_fields[$where] = array();
42
  }
43
  if ( ! empty( $field ) && pmpro_is_field( $field ) ) {
@@ -232,7 +253,7 @@ function pmpro_display_fields_in_group( $group, $scope = 'checkout' ) {
232
  continue;
233
  }
234
 
235
- if ( $scope == 'checkout ' ) {
236
  if( ! isset( $field->profile ) || $field->profile !== 'only' && $field->profile !== 'only_admin' ) {
237
  $field->displayAtCheckout();
238
  }
@@ -254,7 +275,7 @@ add_action( 'pmpro_checkout_after_username', 'pmpro_checkout_after_username_fiel
254
  function pmpro_checkout_after_password_fields() {
255
  pmpro_display_fields_in_group( 'after_password', 'checkout' );
256
  }
257
- add_action( 'pmpro_checkout_after_passwor', 'pmpro_checkout_after_password_fields' );
258
 
259
  //after_email
260
  function pmpro_checkout_after_email_fields() {
@@ -282,7 +303,7 @@ function pmpro_checkout_boxes_fields() {
282
 
283
  if($n > 0) {
284
  ?>
285
- <div id="pmpro_checkout_box-<?php echo esc_attr( $cb->name ); ?>" class="pmpro_checkout">
286
  <hr />
287
  <h3>
288
  <span class="pmpro_checkout-h3-name"><?php echo wp_kses_post( $cb->label );?></span>
@@ -1125,25 +1146,17 @@ function pmpro_cron_delete_tmp() {
1125
  }
1126
  add_action( 'pmpro_cron_delete_tmp', 'pmpro_cron_delete_tmp' );
1127
 
1128
- // Code for the user fields settings page.
1129
- /**
1130
- * Get user fields from settings.
1131
- */
1132
- function pmpro_get_user_fields_from_settings() {
1133
-
1134
- }
1135
-
1136
  /**
1137
  * Get user fields from global.
 
1138
  */
1139
  function pmpro_get_user_fields() {
1140
-
 
 
1141
  }
1142
 
1143
- /**
1144
- * Save user fields settings to DB.
1145
- */
1146
-
1147
  /**
1148
  * Get field group HTML for settings.
1149
  */
@@ -1330,7 +1343,7 @@ function pmpro_get_field_html( $field = null ) {
1330
  </div> <!-- end pmpro_userfield-group-buttons -->
1331
  </li>
1332
  <li class="pmpro_userfield-group-column-label">
1333
- <span class="pmpro_userfield-label"><?php echo wp_kses_post( $field_label );?></span>
1334
  <div class="pmpro_userfield-field-options">
1335
  <a class="edit-field" title="<?php esc_attr_e( 'Edit field', 'paid-memberships-pro' ); ?>" href="javascript:void(0);"><?php esc_html_e( 'Edit', 'paid-memberships-pro' ); ?></a> |
1336
  <a class="duplicate-field" title="<?php esc_attr_e( 'Duplicate field', 'paid-memberships-pro' ); ?>" href="javascript:void(0);"><?php esc_html_e( 'Duplicate', 'paid-memberships-pro' ); ?></a> |
37
  */
38
  function pmpro_add_user_field( $where, $field ) {
39
  global $pmpro_user_fields;
40
+
41
+ /**
42
+ * Filter the group to add the field to.
43
+ *
44
+ * @since 2.9.3
45
+ *
46
+ * @param string $where The name of the group to add the field to.
47
+ * @param PMProField $field The field being added.
48
+ */
49
+ $where = apply_filters( 'pmpro_add_user_field_where', $where, $field );
50
+
51
+ /**
52
+ * Filter the field to add.
53
+ *
54
+ * @since 2.9.3
55
+ *
56
+ * @param PMProField $field The field being added.
57
+ * @param string $where The name of the group to add the field to.
58
+ */
59
+ $field = apply_filters( 'pmpro_add_user_field', $field, $where );
60
+
61
+ if(empty($pmpro_user_fields[$where])) {
62
  $pmpro_user_fields[$where] = array();
63
  }
64
  if ( ! empty( $field ) && pmpro_is_field( $field ) ) {
253
  continue;
254
  }
255
 
256
+ if ( $scope == 'checkout' ) {
257
  if( ! isset( $field->profile ) || $field->profile !== 'only' && $field->profile !== 'only_admin' ) {
258
  $field->displayAtCheckout();
259
  }
275
  function pmpro_checkout_after_password_fields() {
276
  pmpro_display_fields_in_group( 'after_password', 'checkout' );
277
  }
278
+ add_action( 'pmpro_checkout_after_password', 'pmpro_checkout_after_password_fields' );
279
 
280
  //after_email
281
  function pmpro_checkout_after_email_fields() {
303
 
304
  if($n > 0) {
305
  ?>
306
+ <div id="pmpro_checkout_box-<?php echo sanitize_title( $cb->name ); ?>" class="pmpro_checkout">
307
  <hr />
308
  <h3>
309
  <span class="pmpro_checkout-h3-name"><?php echo wp_kses_post( $cb->label );?></span>
1146
  }
1147
  add_action( 'pmpro_cron_delete_tmp', 'pmpro_cron_delete_tmp' );
1148
 
 
 
 
 
 
 
 
 
1149
  /**
1150
  * Get user fields from global.
1151
+ * @since 2.9.3
1152
  */
1153
  function pmpro_get_user_fields() {
1154
+ global $pmpro_user_fields;
1155
+
1156
+ return (array)$pmpro_user_fields;
1157
  }
1158
 
1159
+ // Code for the user fields settings page.
 
 
 
1160
  /**
1161
  * Get field group HTML for settings.
1162
  */
1343
  </div> <!-- end pmpro_userfield-group-buttons -->
1344
  </li>
1345
  <li class="pmpro_userfield-group-column-label">
1346
+ <span class="pmpro_userfield-label"><?php echo strip_tags( wp_kses_post( $field_label ) );?></span>
1347
  <div class="pmpro_userfield-field-options">
1348
  <a class="edit-field" title="<?php esc_attr_e( 'Edit field', 'paid-memberships-pro' ); ?>" href="javascript:void(0);"><?php esc_html_e( 'Edit', 'paid-memberships-pro' ); ?></a> |
1349
  <a class="duplicate-field" title="<?php esc_attr_e( 'Duplicate field', 'paid-memberships-pro' ); ?>" href="javascript:void(0);"><?php esc_html_e( 'Duplicate', 'paid-memberships-pro' ); ?></a> |
js/{blocks.build.js → blocks/blocks.build.js} RENAMED
File without changes
js/pmpro-admin.js CHANGED
@@ -366,7 +366,7 @@ function pmpro_userfields_prep_click_events() {
366
  var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
367
  var fieldheading = fieldsettings.prev();
368
  // Update label, name, and type.
369
- fieldheading.find('span.pmpro_userfield-label').html(fieldsettings.find('input[name=pmpro_userfields_field_label]').val());
370
  fieldheading.find('li.pmpro_userfield-group-column-name').html(fieldsettings.find('input[name=pmpro_userfields_field_name]').val());
371
  fieldheading.find('li.pmpro_userfield-group-column-type').html(fieldsettings.find('select[name=pmpro_userfields_field_type]').val());
372
 
@@ -425,7 +425,7 @@ function pmpro_userfields_prep_click_events() {
425
  var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
426
  var fieldname = fieldsettings.find('input[name=pmpro_userfields_field_name]');
427
  if ( ! fieldname.val() ) {
428
- fieldname.val( jQuery(this).val().toLowerCase().replace(/[^a-z0-9]/gi, '_') );
429
  }
430
  });
431
 
366
  var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
367
  var fieldheading = fieldsettings.prev();
368
  // Update label, name, and type.
369
+ fieldheading.find('span.pmpro_userfield-label').html(fieldsettings.find('input[name=pmpro_userfields_field_label]').val().replace(/(<([^>]+)>)/gi, ''));
370
  fieldheading.find('li.pmpro_userfield-group-column-name').html(fieldsettings.find('input[name=pmpro_userfields_field_name]').val());
371
  fieldheading.find('li.pmpro_userfield-group-column-type').html(fieldsettings.find('select[name=pmpro_userfields_field_type]').val());
372
 
425
  var fieldsettings = fieldcontainer.children('.pmpro_userfield-field-settings');
426
  var fieldname = fieldsettings.find('input[name=pmpro_userfields_field_name]');
427
  if ( ! fieldname.val() ) {
428
+ fieldname.val( jQuery(this).val().toLowerCase().replace(/[^a-z0-9]/gi, '_').replace(/(^\_+|\_+$)/mg, '') );
429
  }
430
  });
431
 
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.9.2
7
  * Author: Paid Memberships Pro
8
  * Author URI: https://www.paidmembershipspro.com
9
  * Text Domain: paid-memberships-pro
@@ -16,7 +16,7 @@
16
  */
17
 
18
  // version constant
19
- define( 'PMPRO_VERSION', '2.9.2' );
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.9.3
7
  * Author: Paid Memberships Pro
8
  * Author URI: https://www.paidmembershipspro.com
9
  * Text Domain: paid-memberships-pro
16
  */
17
 
18
  // version constant
19
+ define( 'PMPRO_VERSION', '2.9.3' );
20
  define( 'PMPRO_USER_AGENT', 'Paid Memberships Pro v' . PMPRO_VERSION . '; ' . site_url() );
21
  define( 'PMPRO_MIN_PHP_VERSION', '5.6' );
22
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: memberships, members, subscriptions, ecommerce, user registration, member,
4
  Requires at least: 5.2
5
  Tested up to: 6.0.1
6
  Requires PHP: 5.6
7
- Stable tag: 2.9.2
8
 
9
  WordPress membership plugin: restrict content, accept member subscriptions with recurring payment. Includes user registration, login, & profile fields
10
 
@@ -156,6 +156,14 @@ Not sure? You can find out by doing a bit a research.
156
  9. Membership Account page, display all sections or show specific sections using shortcode attributes.
157
 
158
  == Changelog ==
 
 
 
 
 
 
 
 
159
  = 2.9.2 - 2022-08-10 =
160
  * BUG FIX/ENHANCEMENT: Now correctly deprecating the pmprorh_section_header() function. We accidentally had it reversed and throwing a warning when using the new pmpro_default_field_group_label() function. (@kimcoleman)
161
  * BUG FIX/ENHANCEMENT: When saving user fields, now making sure that the group name is not blank and unique. Blank or duplicate group names could cause other issues, e.g. with required fields or fields being shown multiple times at checkout. #2187 (@ideadude)
4
  Requires at least: 5.2
5
  Tested up to: 6.0.1
6
  Requires PHP: 5.6
7
+ Stable tag: 2.9.3
8
 
9
  WordPress membership plugin: restrict content, accept member subscriptions with recurring payment. Includes user registration, login, & profile fields
10
 
156
  9. Membership Account page, display all sections or show specific sections using shortcode attributes.
157
 
158
  == Changelog ==
159
+ = 2.9.3 - 2022-08-25 =
160
+ * ENHANCEMENT: Added pmpro_add_user_field_where( $where, $field ) and pmpro_add_user_field( $field, $where ) filters.
161
+ * BUG FIX/ENHANCEMENT: Added MMPU support for some emails so correct level information is shown. #2200 (@dparker1005)
162
+ * BUG FIX/ENHANCEMENT: The pmpro_checkout_box-{groupname} id given to checkout box divs is now sanitized to avoid spaces and special characters there. #2209 (@dparker1005)
163
+ * BUG FIX/ENHANCEMENT: Trimming underscores off the front/back of suggested group names in the user field settings. #2209 (@dparker1005)
164
+ * BUG FIX: Fixed issues with fields showing in some checkout checkbox/group locations. #2204 #2205 (@ipokkel)
165
+ * BUG FIX: Fixed issue where discount code uses weren't being tracked when using the Stripe Checkout beta. #2196 (@dparker1005)
166
+
167
  = 2.9.2 - 2022-08-10 =
168
  * BUG FIX/ENHANCEMENT: Now correctly deprecating the pmprorh_section_header() function. We accidentally had it reversed and throwing a warning when using the new pmpro_default_field_group_label() function. (@kimcoleman)
169
  * BUG FIX/ENHANCEMENT: When saving user fields, now making sure that the group name is not blank and unique. Blank or duplicate group names could cause other issues, e.g. with required fields or fields being shown multiple times at checkout. #2187 (@ideadude)
services/stripe-webhook.php CHANGED
@@ -853,18 +853,14 @@
853
  * @return bool
854
  */
855
  function pmpro_stripe_webhook_change_membership_level( $morder ) {
856
-
857
- global $wpdb, $pmpro_level, $discount_code;
858
 
859
  // We need to pull the checkout level and fields data from the order.
860
  $checkout_level_arr = get_pmpro_membership_order_meta( $morder->id, 'checkout_level', true );
861
  $pmpro_level = (object) $checkout_level_arr;
862
 
863
- // Set $discount_code.
864
- $discount_code_arr = get_pmpro_membership_order_meta( $morder->id, 'discount_code', true );
865
- if ( ! empty( $discount_code_arr ) ) {
866
- $discount_code = (object) $discount_code_arr;
867
- }
868
 
869
  // Set $_REQUEST.
870
  $checkout_request_vars = get_pmpro_membership_order_meta( $morder->id, 'checkout_request_vars', true );
@@ -887,15 +883,6 @@ function pmpro_stripe_webhook_change_membership_level( $morder ) {
887
  //filter the enddate (documented in preheaders/checkout.php)
888
  $enddate = apply_filters( "pmpro_checkout_end_date", $enddate, $morder->user_id, $pmpro_level, $startdate );
889
 
890
- //get discount code
891
- if ( ! empty( $discount_code ) ) {
892
- //update membership level
893
- $discount_code_id = $discount_code->id;
894
- } else {
895
- $discount_code_id = "";
896
- }
897
-
898
-
899
  //custom level to change user to
900
  $custom_level = array(
901
  'user_id' => $morder->user_id,
@@ -925,18 +912,22 @@ function pmpro_stripe_webhook_change_membership_level( $morder ) {
925
  $morder->saveOrder();
926
 
927
  //add discount code use
928
- if ( ! empty( $discount_code ) && ! empty( $use_discount_code ) ) {
929
-
930
- $wpdb->query(
931
- $wpdb->prepare(
932
- "INSERT INTO {$wpdb->pmpro_discount_codes_uses}
933
- ( code_id, user_id, order_id, timestamp )
934
- VALUES( %d, %d, %s, %s )",
935
- $discount_code_id),
936
- $morder->user_id,
937
- $morder->id,
938
- current_time( 'mysql' )
 
 
939
  );
 
 
940
  }
941
 
942
  //save first and last name fields
853
  * @return bool
854
  */
855
  function pmpro_stripe_webhook_change_membership_level( $morder ) {
856
+ global $wpdb, $pmpro_level, $discount_code, $discount_code_id;
 
857
 
858
  // We need to pull the checkout level and fields data from the order.
859
  $checkout_level_arr = get_pmpro_membership_order_meta( $morder->id, 'checkout_level', true );
860
  $pmpro_level = (object) $checkout_level_arr;
861
 
862
+ // Set $discount_code_id.
863
+ $discount_code = get_pmpro_membership_order_meta( $morder->id, 'checkout_discount_code', true );
 
 
 
864
 
865
  // Set $_REQUEST.
866
  $checkout_request_vars = get_pmpro_membership_order_meta( $morder->id, 'checkout_request_vars', true );
883
  //filter the enddate (documented in preheaders/checkout.php)
884
  $enddate = apply_filters( "pmpro_checkout_end_date", $enddate, $morder->user_id, $pmpro_level, $startdate );
885
 
 
 
 
 
 
 
 
 
 
886
  //custom level to change user to
887
  $custom_level = array(
888
  'user_id' => $morder->user_id,
912
  $morder->saveOrder();
913
 
914
  //add discount code use
915
+ if ( ! empty( $discount_code ) ) {
916
+ $discount_code_id = $wpdb->get_var( "SELECT id FROM $wpdb->pmpro_discount_codes WHERE code = '" . esc_sql( $discount_code ) . "' LIMIT 1" );
917
+ if ( ! empty( $discount_code_id ) ) {
918
+ $wpdb->query(
919
+ $wpdb->prepare(
920
+ "INSERT INTO {$wpdb->pmpro_discount_codes_uses}
921
+ ( code_id, user_id, order_id, timestamp )
922
+ VALUES( %d, %d, %s, %s )",
923
+ $discount_code_id,
924
+ $morder->user_id,
925
+ $morder->id,
926
+ current_time( 'mysql' )
927
+ )
928
  );
929
+ do_action( 'pmpro_discount_code_used', $discount_code_id, $user_id, $morder->id );
930
+ }
931
  }
932
 
933
  //save first and last name fields